From 922799940c49ba53fa2dfc6ac9d2e1b15d8f598d Mon Sep 17 00:00:00 2001 From: Sergiy Dybskiy Date: Thu, 26 Mar 2026 11:14:53 -0400 Subject: [PATCH 01/10] docs: add missing command pages for trace, span, sourcemap, repo, trial, schema 6 commands were implemented but had no website docs pages. Also adds dashboard, trace, span, sourcemap, repo, trial, and schema to the commands index table. Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/src/content/docs/commands/index.md | 7 + docs/src/content/docs/commands/repo.md | 55 ++++++++ docs/src/content/docs/commands/schema.md | 56 ++++++++ docs/src/content/docs/commands/sourcemap.md | 80 +++++++++++ docs/src/content/docs/commands/span.md | 99 ++++++++++++++ docs/src/content/docs/commands/trace.md | 142 ++++++++++++++++++++ docs/src/content/docs/commands/trial.md | 76 +++++++++++ 7 files changed, 515 insertions(+) create mode 100644 docs/src/content/docs/commands/repo.md create mode 100644 docs/src/content/docs/commands/schema.md create mode 100644 docs/src/content/docs/commands/sourcemap.md create mode 100644 docs/src/content/docs/commands/span.md create mode 100644 docs/src/content/docs/commands/trace.md create mode 100644 docs/src/content/docs/commands/trial.md diff --git a/docs/src/content/docs/commands/index.md b/docs/src/content/docs/commands/index.md index 20452e259..d6ffc9ac6 100644 --- a/docs/src/content/docs/commands/index.md +++ b/docs/src/content/docs/commands/index.md @@ -17,6 +17,13 @@ The Sentry CLI provides commands for interacting with various Sentry resources. | [`issue`](./issue/) | Issue tracking | | [`event`](./event/) | Event inspection | | [`log`](./log/) | Log viewing and streaming | +| [`trace`](./trace/) | Distributed trace inspection | +| [`span`](./span/) | Span listing and details | +| [`dashboard`](./dashboard/) | Dashboard management | +| [`sourcemap`](./sourcemap/) | Sourcemap injection and upload | +| [`repo`](./repo/) | Repository listing | +| [`trial`](./trial/) | Product trial management | +| [`schema`](./schema/) | API schema browsing | | [`api`](./api/) | Direct API access | ## Global Options diff --git a/docs/src/content/docs/commands/repo.md b/docs/src/content/docs/commands/repo.md new file mode 100644 index 000000000..324d782fa --- /dev/null +++ b/docs/src/content/docs/commands/repo.md @@ -0,0 +1,55 @@ +--- +title: repo +description: Repo commands for the Sentry CLI +--- + +List repositories connected to a Sentry organization. + +## Commands + +### `sentry repo list` + +List repositories in an organization. + +```bash +# Auto-detect from DSN or config +sentry repo list + +# Explicit org +sentry repo list / + +# Org inferred from project context +sentry repo list / + +# Bare org slug +sentry repo list +``` + +**Arguments:** + +| Argument | Description | +|----------|-------------| +| `/` | Organization slug (trailing slash enables pagination) | +| `/` | Organization and project (lists repos for that org) | +| `` | Bare organization slug | + +**Options:** + +| Option | Description | +|--------|-------------| +| `-n, --limit ` | Number of repositories to show | +| `-c, --cursor ` | Pagination cursor (`next` or `prev`) | +| `--json` | Output as JSON | + +**Examples:** + +```bash +# List repositories (auto-detect org) +sentry repo list + +# List repos in a specific org with pagination +sentry repo list my-org/ -c next + +# Output as JSON +sentry repo list --json +``` diff --git a/docs/src/content/docs/commands/schema.md b/docs/src/content/docs/commands/schema.md new file mode 100644 index 000000000..0b8223332 --- /dev/null +++ b/docs/src/content/docs/commands/schema.md @@ -0,0 +1,56 @@ +--- +title: schema +description: Schema commands for the Sentry CLI +--- + +Browse and search the Sentry API schema. Shows available resources, operations, and endpoint details. + +## Usage + +```bash +# List all API resources +sentry schema + +# Show endpoints for a resource +sentry schema + +# Show details for a specific endpoint +sentry schema + +# Glob-match resources +sentry schema monitor* +``` + +**Arguments:** + +| Argument | Description | +|----------|-------------| +| `` | Resource name (e.g., `issues`, `projects`). Supports glob patterns. | +| `` | Operation name within a resource (e.g., `list`, `create`) | + +**Options:** + +| Option | Description | +|--------|-------------| +| `--all` | Show all endpoints in a flat list | +| `-q, --search ` | Search endpoints by keyword | +| `--json` | Output as JSON | + +**Examples:** + +```bash +# List all API resources +sentry schema + +# Browse issue endpoints +sentry schema issues + +# View details for a specific operation +sentry schema issues list + +# Search for monitoring-related endpoints +sentry schema --search monitor + +# Flat list of every endpoint +sentry schema --all +``` diff --git a/docs/src/content/docs/commands/sourcemap.md b/docs/src/content/docs/commands/sourcemap.md new file mode 100644 index 000000000..f423b7342 --- /dev/null +++ b/docs/src/content/docs/commands/sourcemap.md @@ -0,0 +1,80 @@ +--- +title: sourcemap +description: Sourcemap commands for the Sentry CLI +--- + +Inject debug IDs and upload sourcemaps to Sentry for readable stack traces. + +## Commands + +### `sentry sourcemap inject` + +Inject Sentry debug IDs into JavaScript files and their companion sourcemaps. + +```bash +sentry sourcemap inject +``` + +**Arguments:** + +| Argument | Description | +|----------|-------------| +| `` | Directory to scan for JS + sourcemap pairs | + +**Options:** + +| Option | Description | +|--------|-------------| +| `--ext ` | Comma-separated file extensions to process (default: `.js,.cjs,.mjs`) | +| `--dry-run` | Show what would be modified without writing | + +The injection is idempotent -- files that already have debug IDs are skipped. + +**Examples:** + +```bash +# Inject debug IDs into all JS files in dist/ +sentry sourcemap inject ./dist + +# Preview changes without writing +sentry sourcemap inject ./dist --dry-run + +# Only process specific extensions +sentry sourcemap inject ./build --ext .js,.mjs +``` + +### `sentry sourcemap upload` + +Upload JavaScript sourcemaps to Sentry using debug-ID-based matching. + +```bash +sentry sourcemap upload +``` + +Automatically injects debug IDs into any files that don't already have them. Org and project are auto-detected from DSN, env vars, or config defaults. + +**Arguments:** + +| Argument | Description | +|----------|-------------| +| `` | Directory containing sourcemaps | + +**Options:** + +| Option | Description | +|--------|-------------| +| `--release ` | Release version to associate with the upload | +| `--url-prefix ` | URL prefix for uploaded files (default: `~/`) | + +**Examples:** + +```bash +# Upload sourcemaps from dist/ +sentry sourcemap upload ./dist + +# Associate with a release +sentry sourcemap upload ./dist --release 1.0.0 + +# Set a custom URL prefix +sentry sourcemap upload ./dist --url-prefix '~/static/js/' +``` diff --git a/docs/src/content/docs/commands/span.md b/docs/src/content/docs/commands/span.md new file mode 100644 index 000000000..5e004faa6 --- /dev/null +++ b/docs/src/content/docs/commands/span.md @@ -0,0 +1,99 @@ +--- +title: span +description: Span commands for the Sentry CLI +--- + +List and inspect spans from Sentry projects or within specific traces. + +## Commands + +### `sentry span list` + +List spans in a project or within a specific trace. + +```bash +# Project mode — list spans across the project +sentry span list +sentry span list / +sentry span list + +# Trace mode — list spans within a specific trace +sentry span list +sentry span list // +sentry span list +``` + +**Arguments:** + +| Argument | Description | +|----------|-------------| +| `/` | Explicit organization and project (project mode) | +| `` | Search for project by name across all accessible organizations | +| `` | 32-character hex trace ID to list spans within (trace mode) | + +**Options:** + +| Option | Description | +|--------|-------------| +| `-n, --limit ` | Number of spans (max 1000, default: 25) | +| `-q, --query ` | Filter spans (e.g., `"op:db"`, `"duration:>100ms"`) | +| `-s, --sort ` | Sort order: `date`, `duration` (default: `date`) | +| `--period ` | Time period (e.g., `24h`, `7d`; default: `7d`) | +| `-c, --cursor ` | Pagination cursor (`next` or `prev`) | +| `--json` | Output as JSON | + +**Examples:** + +```bash +# List recent spans in the current project +sentry span list + +# Find all DB spans +sentry span list -q "op:db" + +# Slow spans in the last 24 hours +sentry span list -q "duration:>100ms" --period 24h + +# List spans within a specific trace +sentry span list abc123def456abc123def456abc12345 + +# Paginate through results +sentry span list -c next +``` + +### `sentry span view` + +View detailed information about one or more spans within a trace. + +```bash +sentry span view +sentry span view // +sentry span view +``` + +**Arguments:** + +| Argument | Description | +|----------|-------------| +| `` | The 32-character hexadecimal trace ID (optionally prefixed with `//`) | +| `` | One or more 16-character hexadecimal span IDs | + +**Options:** + +| Option | Description | +|--------|-------------| +| `--spans ` | Span tree depth limit (number, `all` for unlimited, `no` to disable) | +| `--json` | Output as JSON | + +**Examples:** + +```bash +# View a single span +sentry span view abc123def456abc123def456abc12345 a1b2c3d4e5f67890 + +# View multiple spans at once +sentry span view abc123def456abc123def456abc12345 a1b2c3d4e5f67890 b2c3d4e5f6789012 + +# With explicit org/project +sentry span view my-org/backend/abc123def456abc123def456abc12345 a1b2c3d4e5f67890 +``` diff --git a/docs/src/content/docs/commands/trace.md b/docs/src/content/docs/commands/trace.md new file mode 100644 index 000000000..5c673b6cd --- /dev/null +++ b/docs/src/content/docs/commands/trace.md @@ -0,0 +1,142 @@ +--- +title: trace +description: Trace commands for the Sentry CLI +--- + +Inspect and browse distributed traces from Sentry projects. + +## Commands + +### `sentry trace list` + +List recent traces in a project. + +```bash +# Auto-detect from DSN or config +sentry trace list + +# Explicit org and project +sentry trace list / + +# Search for project across all accessible orgs +sentry trace list +``` + +**Arguments:** + +| Argument | Description | +|----------|-------------| +| `/` | Explicit organization and project (e.g., `my-org/backend`) | +| `` | Search for project by name across all accessible organizations | + +**Options:** + +| Option | Description | +|--------|-------------| +| `-n, --limit ` | Number of traces to show (1-1000, default: 20) | +| `-q, --query ` | Search query (Sentry search syntax) | +| `-s, --sort ` | Sort by: `date`, `duration` (default: `date`) | +| `--period ` | Time period (e.g., `24h`, `7d`, `14d`; default: `7d`) | +| `-c, --cursor ` | Pagination cursor (`next` or `prev`) | +| `--json` | Output as JSON | + +**Examples:** + +```bash +# List last 20 traces (default) +sentry trace list + +# Sort by slowest first +sentry trace list --sort duration + +# Filter by transaction name, last 24 hours +sentry trace list -q "transaction:GET /api/users" --period 24h + +# Paginate through results +sentry trace list my-org/backend -c next +``` + +### `sentry trace view` + +View details of a specific trace, including a span tree. + +```bash +# Auto-detect org from DSN or config +sentry trace view + +# Explicit org and project +sentry trace view // + +# Search for project across all accessible orgs +sentry trace view +``` + +**Arguments:** + +| Argument | Description | +|----------|-------------| +| `` | The 32-character hexadecimal trace ID | +| `//` | Explicit organization, project, and trace ID | + +**Options:** + +| Option | Description | +|--------|-------------| +| `-w, --web` | Open in browser | +| `--spans ` | Span tree depth limit (number, `all` for unlimited, `no` to disable) | +| `--json` | Output as JSON | + +**Examples:** + +```bash +# View trace details with span tree +sentry trace view abc123def456abc123def456abc12345 + +# Open trace in browser +sentry trace view abc123def456abc123def456abc12345 -w + +# Auto-recover from an issue short ID +sentry trace view PROJ-123 +``` + +### `sentry trace logs` + +View logs associated with a specific trace. + +```bash +# Auto-detect org +sentry trace logs + +# Explicit org +sentry trace logs / +``` + +**Arguments:** + +| Argument | Description | +|----------|-------------| +| `` | The 32-character hexadecimal trace ID | +| `/` | Explicit organization and trace ID | + +**Options:** + +| Option | Description | +|--------|-------------| +| `-w, --web` | Open trace in browser | +| `-t, --period ` | Time period to search (e.g., `14d`, `7d`, `24h`; default: `14d`) | +| `-n, --limit ` | Number of log entries (max 1000, default: 100) | +| `-q, --query ` | Additional filter query (Sentry search syntax) | +| `--json` | Output as JSON | + +**Examples:** + +```bash +# View logs for a trace +sentry trace logs abc123def456abc123def456abc12345 + +# Search with a longer time window +sentry trace logs --period 30d abc123def456abc123def456abc12345 + +# Filter logs within a trace +sentry trace logs -q 'level:error' abc123def456abc123def456abc12345 +``` diff --git a/docs/src/content/docs/commands/trial.md b/docs/src/content/docs/commands/trial.md new file mode 100644 index 000000000..45e9a4d58 --- /dev/null +++ b/docs/src/content/docs/commands/trial.md @@ -0,0 +1,76 @@ +--- +title: trial +description: Trial commands for the Sentry CLI +--- + +View and start product trials for a Sentry organization. + +## Commands + +### `sentry trial list` + +List product trials for an organization, including available, active, and expired trials. + +```bash +# Auto-detect org +sentry trial list + +# Explicit org +sentry trial list +``` + +**Arguments:** + +| Argument | Description | +|----------|-------------| +| `` | Organization slug (auto-detected if omitted) | + +**Options:** + +| Option | Description | +|--------|-------------| +| `--json` | Output as JSON | + +**Examples:** + +```bash +# List all trials for the current org +sentry trial list + +# List trials for a specific org +sentry trial list my-org + +# Machine-readable output +sentry trial list --json +``` + +### `sentry trial start` + +Start a product trial for an organization. + +```bash +sentry trial start +sentry trial start +``` + +**Arguments:** + +| Argument | Description | +|----------|-------------| +| `` | Trial name (e.g., `seer`, `replays`, `profiling`, `plan`) | +| `` | Organization slug (auto-detected if omitted) | + +Use `plan` to start a Business plan trial (opens the billing page in a browser). + +**Examples:** + +```bash +# Start a Seer trial +sentry trial start seer + +# Start a trial for a specific org +sentry trial start replays my-org + +# Start a Business plan trial (opens browser) +sentry trial start plan +``` From 4ed54da2be9c5d162d777fb0486afa01dc66ebe4 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Fri, 27 Mar 2026 00:11:37 +0000 Subject: [PATCH 02/10] feat(docs): auto-generate command reference pages from route tree MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace hand-written command doc pages with auto-generated reference sections extracted from Stricli route tree introspection. This fixes pervasive documentation drift: phantom flags (--include, --paginate, --channel), missing flags (--fresh, --fields, --cursor, --period, --spans), and missing aliases across all command pages. Each doc page now has two parts separated by a GENERATED:END marker: 1. Auto-generated reference (args, options tables) — from source code 2. Hand-written custom content (examples, guides) — preserved on regen New infrastructure: - script/generate-command-docs.ts: generates reference sections - script/check-command-docs.ts: CI freshness checker - src/lib/introspect.ts: add extractPositionals() for arg tables - CI auto-commits regenerated docs alongside skill files Also adds extractPositionals() and PositionalInfo type to introspect.ts for structured positional argument metadata. --- .github/workflows/ci.yml | 20 +- AGENTS.md | 111 ++--- docs/src/content/docs/commands/api.md | 116 ++--- docs/src/content/docs/commands/auth.md | 107 ++--- docs/src/content/docs/commands/cli.md | 83 ++++ .../src/content/docs/commands/cli/feedback.md | 37 -- docs/src/content/docs/commands/cli/index.md | 13 - docs/src/content/docs/commands/cli/upgrade.md | 130 ------ docs/src/content/docs/commands/dashboard.md | 316 ++++--------- docs/src/content/docs/commands/event.md | 31 +- docs/src/content/docs/commands/index.md | 39 +- docs/src/content/docs/commands/init.md | 97 +--- docs/src/content/docs/commands/issue.md | 238 +++------- docs/src/content/docs/commands/log.md | 143 ++---- docs/src/content/docs/commands/org.md | 73 +-- docs/src/content/docs/commands/project.md | 97 ++-- docs/src/content/docs/commands/repo.md | 36 +- docs/src/content/docs/commands/schema.md | 30 +- docs/src/content/docs/commands/sourcemap.md | 62 ++- docs/src/content/docs/commands/span.md | 84 ++-- docs/src/content/docs/commands/team.md | 53 +-- docs/src/content/docs/commands/trace.md | 132 +++--- docs/src/content/docs/commands/trial.md | 57 +-- package.json | 2 + .../skills/sentry-cli/references/api.md | 43 -- .../skills/sentry-cli/references/auth.md | 51 +-- .../sentry-cli/references/dashboards.md | 53 --- .../skills/sentry-cli/references/events.md | 10 - .../skills/sentry-cli/references/issues.md | 86 ---- .../skills/sentry-cli/references/logs.md | 58 --- .../sentry-cli/references/organizations.md | 18 - .../skills/sentry-cli/references/projects.md | 30 -- .../skills/sentry-cli/references/teams.md | 15 - script/check-command-docs.ts | 93 ++++ script/generate-command-docs.ts | 421 ++++++++++++++++++ src/lib/introspect.ts | 49 ++ 36 files changed, 1286 insertions(+), 1748 deletions(-) create mode 100644 docs/src/content/docs/commands/cli.md delete mode 100644 docs/src/content/docs/commands/cli/feedback.md delete mode 100644 docs/src/content/docs/commands/cli/index.md delete mode 100644 docs/src/content/docs/commands/cli/upgrade.md create mode 100644 script/check-command-docs.ts create mode 100644 script/generate-command-docs.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 537af0a55..dd7e6cca8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -113,21 +113,25 @@ jobs: - name: Generate API Schema run: bun run generate:schema - name: Check skill files - id: check + id: check-skill run: bun run check:skill continue-on-error: true - - name: Auto-commit regenerated skill files - if: steps.check.outcome == 'failure' && steps.token.outcome == 'success' + - name: Check command docs + id: check-docs + run: bun run check:command-docs + continue-on-error: true + - name: Auto-commit regenerated files + if: (steps.check-skill.outcome == 'failure' || steps.check-docs.outcome == 'failure') && steps.token.outcome == 'success' run: | git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" - git add plugins/sentry-cli/skills/sentry-cli/ docs/public/.well-known/skills/index.json - git commit -m "chore: regenerate skill files" + git add plugins/sentry-cli/skills/sentry-cli/ docs/public/.well-known/skills/index.json docs/src/content/docs/commands/ + git commit -m "chore: regenerate skill files and command docs" git push - - name: Fail for fork PRs with stale skill files - if: steps.check.outcome == 'failure' && steps.token.outcome != 'success' + - name: Fail for fork PRs with stale generated files + if: (steps.check-skill.outcome == 'failure' || steps.check-docs.outcome == 'failure') && steps.token.outcome != 'success' run: | - echo "::error::Skill files are out of date. Run 'bun run generate:skill' locally and commit the result." + echo "::error::Generated files are out of date. Run 'bun run generate:skill' and 'bun run generate:command-docs' locally and commit the result." exit 1 lint: diff --git a/AGENTS.md b/AGENTS.md index 217e20f9c..a2de1456f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -893,82 +893,89 @@ mock.module("./some-module", () => ({ ### Architecture - -* **commandPrefix on SentryContext enables command identity in buildCommand wrapper**: \`SentryContext.commandPrefix\` (optional \`readonly string\[]\`) is populated in \`forCommand()\` in \`context.ts\` — Stricli calls this with the full prefix (e.g., \`\["sentry", "issue", "list"]\`) before running the command. This enables the \`buildCommand\` wrapper to identify which command is executing for help recovery and telemetry. Previously, \`forCommand\` only set telemetry span names. + +* **API client wraps all errors as CliError subclasses — no raw exceptions escape**: The API client (src/lib/api-client.ts) wraps ALL errors as CliError subclasses (ApiError or AuthError) — no raw exceptions escape. Commands don't need try-catch for error display; the central handler in app.ts formats CliError cleanly. Only add try-catch when a command needs to handle errors specially (e.g., login continuing despite user-info fetch failure). - -* **Dashboard widget interval computed from terminal width and layout before API calls**: Dashboard chart widgets compute optimal \`interval\` before making API calls using terminal width and widget layout. Formula: \`colWidth = floor(layout.w / 6 \* termWidth)\`, \`chartWidth = colWidth - 4 - gutterW\` (~5-7), \`idealSeconds = periodSeconds / chartWidth\`. Snaps to nearest Sentry interval bucket (\`1m\`, \`5m\`, \`15m\`, \`30m\`, \`1h\`, \`4h\`, \`1d\`). Lives in \`computeOptimalInterval()\` in \`src/lib/api/dashboards.ts\`. \`periodToSeconds()\` parses \`"24h"\`, \`"7d"\` etc. The \`PERIOD\_RE\` regex is hoisted to module scope (Biome requires top-level regex). \`WidgetQueryParams\` gains optional \`interval?: string\` field; \`queryWidgetTimeseries\` uses \`params.interval ?? widget.interval\` for the API call. \`queryAllWidgets\` computes per-widget intervals using \`getTermWidth()\` logic (min 80, fallback 100). + +* **Completion fast-path skips Sentry SDK via SENTRY\_CLI\_NO\_TELEMETRY and SQLite telemetry queue**: Shell completions (\`\_\_complete\`) set \`SENTRY\_CLI\_NO\_TELEMETRY=1\` in \`bin.ts\` before any imports, skipping \`createTracedDatabase\` wrapper and avoiding \`@sentry/node-core/light\` load (~85ms). Completion timing queued to \`completion\_telemetry\_queue\` SQLite table (~1ms). Normal runs drain via \`DELETE FROM ... RETURNING\` and emit as \`Sentry.metrics.distribution\`. Fast-path achieves ~60ms dev / ~140ms CI, 200ms e2e budget. - -* **defaultCommand:help blocks Stricli fuzzy matching for top-level typos**: Fuzzy matching across CLI subsystems: (1) Stricli built-in Damerau-Levenshtein for subcommand/flag typos within known routes. (2) \`defaultCommand: "help"\` bypasses this for top-level typos — fixed by \`resolveCommandPath()\` in \`introspect.ts\` returning \`UnresolvedPath\` with suggestions via \`fuzzyMatch()\` from \`fuzzy.ts\` (up to 3). Covers \`sentry \\` and \`sentry help \\`. (3) \`fuzzyMatch()\` in \`complete.ts\` for tab-completion (Levenshtein+prefix+contains). (4) \`levenshtein()\` in \`platforms.ts\` for platform suggestions. (5) Plural alias detection in \`app.ts\`. JSON includes \`suggestions\` array. + +* **Sentry API: events require org+project, issues have legacy global endpoint**: Sentry API scoping: Events require org+project in URL path (\`/projects/{org}/{project}/events/{id}/\`). Issues use legacy global endpoint (\`/api/0/issues/{id}/\`) without org context. Traces need only org (\`/organizations/{org}/trace/{traceId}/\`). Two-step lookup for events: fetch issue → extract org/project from response → fetch event. Cross-project event search possible via Discover endpoint \`/organizations/{org}/events/\` with \`query=id:{eventId}\`. - -* **DSN org prefix normalization in arg-parsing.ts**: Sentry DSN hosts encode org IDs as \`oNNNNN\` (e.g., \`o1081365.ingest.us.sentry.io\`). The Sentry API rejects the \`o\`-prefixed form. \`stripDsnOrgPrefix()\` in \`src/lib/arg-parsing.ts\` uses \`/^o(\d+)$/\` to strip the prefix — safe for slugs like \`organic\`. Applied in \`parseOrgProjectArg()\` and \`parseWithSlash()\`, covering all API call paths consuming \`parsed.org\`. + +* **Sentry CLI authenticated fetch architecture with response caching**: \`createAuthenticatedFetch()\` wraps fetch with auth, 30s timeout, retry (max 2), 401 refresh, and span tracing. Response caching via \`http-cache-semantics\` (RFC 7234) with filesystem storage at \`~/.sentry/cache/responses/\`. Fallback TTL tiers: immutable (24hr), stable (5min), volatile (60s), no-cache (0). Only GET 2xx cached. \`--fresh\` and \`SENTRY\_NO\_CACHE=1\` bypass. Cache cleared on login/logout. \`hasServerCacheDirectives(policy)\` distinguishes \`max-age=0\` from missing headers. - -* **GHCR versioned nightly tags for delta upgrade support**: GHCR nightly distribution uses three tag types: \`:nightly\` (rolling), \`:nightly-\\` (immutable), \`:patch-\\` (delta manifest). Delta patches use zig-bsdiff TRDIFF10 (zstd-compressed), ~50KB vs ~29MB full. Client bspatch via \`Bun.zstdDecompressSync()\`. N-1 patches only, full download fallback, SHA-256 verify, 60% size threshold. npm/Node excluded. Test mocks: use \`mockGhcrNightlyVersion()\` helper. + +* **Sentry CLI has two distribution channels with different runtimes**: Sentry CLI ships two ways: (1) Standalone binary via \`Bun.build()\` with \`compile: true\`. (2) npm package via esbuild producing CJS \`dist/bin.cjs\` for Node 22+, with Bun API polyfills from \`script/node-polyfills.ts\`. \`Bun.$\` has NO polyfill — use \`execSync\` instead. \`require()\` in ESM is safe (Bun native, esbuild resolves at bundle time). As of PR #474, SDK is \`@sentry/node-core/light\` (not \`@sentry/bun\`), reducing import cost from ~218ms to ~85ms. - -* **Issue list auto-pagination beyond API's 100-item cap**: Sentry API silently caps \`limit\` at 100 per request. \`listIssuesAllPages()\` auto-paginates using Link headers, bounded by MAX\_PAGINATION\_PAGES (50). \`API\_MAX\_PER\_PAGE\` constant is shared across all paginated consumers. \`--limit\` means total results everywhere (max 1000, default 25). Org-all mode uses \`fetchOrgAllIssues()\`; explicit \`--cursor\` does single-page fetch to preserve cursor chain. + +* **Sentry CLI resolve-target cascade has 5 priority levels with env var support**: Resolve-target cascade (src/lib/resolve-target.ts) has 5 priority levels: (1) Explicit CLI flags, (2) SENTRY\_ORG/SENTRY\_PROJECT env vars, (3) SQLite config defaults, (4) DSN auto-detection, (5) Directory name inference. SENTRY\_PROJECT supports combo notation \`org/project\` — when used, SENTRY\_ORG is ignored. If combo parse fails (e.g. \`org/\`), the entire value is discarded. The \`resolveFromEnvVars()\` helper is injected into all four resolution functions. - -* **resolveProjectBySlug carries full projectData to avoid redundant getProject calls**: \`resolveProjectBySlug()\` returns \`{ org, project, projectData: SentryProject }\` — the full project object from \`findProjectsBySlug()\`. \`ResolvedOrgProject\` and \`ResolvedTarget\` have optional \`projectData?\` (populated only in project-search path, not explicit/auto-detect). Downstream commands (\`project/view\`, \`project/delete\`, \`dashboard/create\`) use \`projectData\` when available to skip redundant \`getProject()\` API calls (~500-800ms savings). Pattern: \`resolved.projectData ?? await getProject(org, project)\` for callers that need both paths. +### Decision - -* **Self-hosted OAuth device flow requires Sentry 26.1.0+ and SENTRY\_CLIENT\_ID**: Self-hosted OAuth device flow requires Sentry 26.1.0+ and both \`SENTRY\_URL\` and \`SENTRY\_CLIENT\_ID\` env vars. Users must create a public OAuth app in Settings → Developer Settings. The client ID is NOT optional for self-hosted. Fallback for older instances: \`sentry auth login --token\`. \`getSentryUrl()\` and \`getClientId()\` in \`src/lib/oauth.ts\` read lazily (not at module load) so URL parsing from arguments can set \`SENTRY\_URL\` after import. + +* **Issue list global limit with fair per-project distribution and representation guarantees**: \`issue list --limit\` is a global total across all detected projects. \`fetchWithBudget\` Phase 1 divides evenly, Phase 2 redistributes surplus via cursor resume. \`trimWithProjectGuarantee\` ensures at least 1 issue per project before filling remaining slots. JSON output wraps in \`{ data, hasMore }\` with optional \`errors\` array. Compound cursor (pipe-separated) enables \`-c last\` for multi-target pagination, keyed by sorted target fingerprint. - -* **Sentry CLI markdown-first formatting pipeline replaces ad-hoc ANSI**: Formatters build CommonMark strings; \`renderMarkdown()\` renders to ANSI for TTY or raw markdown for non-TTY. Key helpers: \`colorTag()\`, \`mdKvTable()\`, \`mdRow()\`, \`mdTableHeader()\` (\`:\` suffix = right-aligned), \`renderTextTable()\`. \`isPlainOutput()\` checks \`SENTRY\_PLAIN\_OUTPUT\` > \`NO\_COLOR\` > \`!isTTY\`. Batch path: \`formatXxxTable()\`. Streaming path: \`StreamingTable\` (TTY) or raw markdown rows (plain). Both share \`buildXxxRowCells()\`. + +* **Sentry CLI config dir should stay at ~/.sentry/, not move to XDG**: Config dir stays at \`~/.sentry/\` (not XDG). The readonly DB errors on macOS are from \`sudo brew install\` creating root-owned files. Fixes: (1) bestEffort() makes setup steps non-fatal, (2) tryRepairReadonly() detects root-owned files and prints \`sudo chown\` instructions, (3) \`sentry cli fix\` handles ownership repair. Ownership must be checked BEFORE permissions — root-owned files cause chmod to EPERM. - -* **Sentry issue stats field: time-series controlled by groupStatsPeriod**: Sentry issue stats and list table layout: \`stats\` key depends on \`groupStatsPeriod\` (\`""\`, \`"14d"\`, \`"24h"\`, \`"auto"\`); \`statsPeriod\` controls window. \*\*Critical\*\*: \`count\` is period-scoped — use \`lifetime.count\` for true total. Issue list uses \`groupStatsPeriod: 'auto'\` for sparklines. Columns: SHORT ID, ISSUE, SEEN, AGE, TREND, EVENTS, USERS, TRIAGE. TREND hidden < 100 cols. \`--compact\` tri-state: explicit overrides; \`undefined\` triggers \`shouldAutoCompact(rowCount)\` — compact if \`3N + 3 > termHeight\`. Height formula \`3N + 3\` (last row has no trailing separator). +### Gotcha - -* **Sentry trace-logs API is org-scoped, not project-scoped**: The Sentry trace-logs endpoint (\`/organizations/{org}/trace-logs/\`) is org-scoped, so \`trace logs\` uses \`resolveOrg()\` not \`resolveOrgAndProject()\`. The endpoint is PRIVATE in Sentry source, excluded from the public OpenAPI schema — \`@sentry/api\` has no generated types. The hand-written \`TraceLogSchema\` in \`src/types/sentry.ts\` is required until Sentry makes it public. + +* **Biome noExcessiveCognitiveComplexity max 15 requires extracting helpers from command handlers**: Biome enforces \`noExcessiveCognitiveComplexity\` with max 15. Stricli \`func()\` handlers easily exceed this with fetch loops, pagination, and conditionals. Fix: extract logic into standalone helper functions — this also improves testability since \`func()\` handlers require full context setup. Keep \`func()\` as a thin orchestrator calling exported helpers. Property-based tests on extracted functions drove coverage from 78% to 97%. Split further if a helper still exceeds 15. - -* **Stricli route errors are uninterceptable — only post-run detection works**: Stricli route errors, exit codes, and OutputError — error propagation gaps: (1) Route failures are uninterceptable — Stricli writes to stderr and returns \`ExitCode.UnknownCommand\` internally. Only post-\`run()\` \`process.exitCode\` check works. \`exceptionWhileRunningCommand\` only fires for errors in command \`func()\`. (2) \`ExitCode.UnknownCommand\` is \`-5\`. Bun reads \`251\` (unsigned byte), Node reads \`-5\` — compare both. (3) \`OutputError\` in \`handleOutputError\` calls \`process.exit()\` immediately, bypassing telemetry and \`exceptionWhileRunningCommand\`. Top-level typos via \`defaultCommand:help\` → \`OutputError\` → \`process.exit(1)\` skip all error reporting. + +* **Biome prefers .at(-1) over arr\[arr.length - 1] indexing**: Biome's \`useAtIndex\` rule flags \`arr\[arr.length - 1]\` patterns. Use \`arr.at(-1)\` instead. This applies throughout the codebase — the lint check will fail CI otherwise. - -* **withAuthGuard returns discriminated Result type, not fallback+onError**: \`withAuthGuard\(fn)\` in \`src/lib/errors.ts\` returns a discriminated Result: \`{ ok: true, value: T } | { ok: false, error: unknown }\`. AuthErrors always re-throw (triggers bin.ts auto-login). All other errors are captured. Callers inspect \`result.ok\` to degrade gracefully. Used across 12+ files. + +* **Biome requires block statements — no single-line if/break/return**: Biome's \`useBlockStatements\` rule rejects braceless control flow like \`if (match) return match.id;\` or \`if (!nextCursor) break;\`. Always wrap in braces: \`if (match) { return match.id; }\`. Similarly, nested ternaries are banned (\`noNestedTernary\`) — use if/else chains or extract into a variable with sequential assignments. -### Gotcha + +* **brew is not in VALID\_METHODS but Homebrew formula passes --method brew**: Homebrew install: \`isHomebrewInstall()\` detects via Cellar realpath (checked before stored install info). Upgrade command tells users \`brew upgrade getsentry/tools/sentry\`. Formula runs \`sentry cli setup --method brew --no-modify-path\` as post\_install. Version pinning throws 'unsupported\_operation'. Uses .gz artifacts. Tap at getsentry/tools. - -* **Biome lint: Response.redirect() required, nested ternaries forbidden**: Biome lint rules that frequently trip up this codebase: (1) \`useResponseRedirect\`: use \`Response.redirect(url, status)\` not \`new Response\`. (2) \`noNestedTernary\`: use \`if/else\`. (3) \`noComputedPropertyAccess\`: use \`obj.property\` not \`obj\["property"]\`. (4) Max cognitive complexity 15 per function — extract helpers to stay under. + +* **Bun mock.module() leaks globally across test files in same process**: Bun's mock.module() replaces modules globally and leaks across test files in the same process. Solution: tests using mock.module() must run in a separate \`bun test\` invocation. In package.json, use \`bun run test:unit && bun run test:isolated\` instead of \`bun test\`. The \`test/isolated/\` directory exists for these tests. This was the root cause of ~100 test failures (getsentry/cli#258). - -* **Bugbot flags defensive null-checks as dead code — keep them with JSDoc justification**: Cursor Bugbot and Sentry Seer repeatedly flag two false positives: (1) defensive null-checks as "dead code" — keep them with JSDoc explaining why the guard exists for future safety, especially when removing would require \`!\` assertions banned by \`noNonNullAssertion\`. (2) stderr spinner output during \`--json\` mode — always a false positive since progress goes to stderr, JSON to stdout. Reply explaining the rationale and resolve. + +* **Making clearAuth() async breaks model-based tests — use non-async Promise\ return instead**: Making \`clearAuth()\` \`async\` breaks fast-check model-based tests — real async yields during \`asyncModelRun\` cause \`createIsolatedDbContext\` cleanup to interleave. Fix: keep non-async, return \`clearResponseCache().catch(...)\` directly. Also: model-based tests need explicit timeouts (e.g., \`30\_000\`) — Bun's default 5s causes false failures during shrinking. - -* **Bun mock.module for node:tty requires default export and class stubs**: Bun testing gotchas: (1) \`mock.module()\` for CJS built-ins requires a \`default\` re-export plus all named exports. Missing any causes \`SyntaxError: Export named 'X' not found\`. Always check the real module's full export list. (2) \`Bun.mmap()\` always opens with PROT\_WRITE — macOS SIGKILL on signed Mach-O, Linux ETXTBSY. Fix: use \`new Uint8Array(await Bun.file(path).arrayBuffer())\` in bspatch.ts. (3) Wrap \`Bun.which()\` with optional \`pathEnv\` param for deterministic testing without mocks. + +* **Multiregion mock must include all control silo API routes**: When changing which Sentry API endpoint a function uses, mock routes must be updated in BOTH \`test/mocks/routes.ts\` (single-region) AND \`test/mocks/multiregion.ts\` \`createControlSiloRoutes()\`. Missing the multiregion mock causes 404s in multi-region test scenarios. - -* **Use toMatchObject not toEqual when testing resolution results with optional fields**: When \`resolveProjectBySlug()\` or \`resolveOrgProjectTarget()\` adds optional fields (like \`projectData\`) to the return type, tests using \`expect(result).toEqual({ org, project })\` fail because \`toEqual\` requires exact match. Use \`toMatchObject({ org, project })\` instead — it checks the specified subset without failing on extra properties. This affects tests across \`event/view\`, \`log/view\`, \`trace/view\`, and \`trace/list\` test files. + +* **Sentry /users/me/ endpoint returns 403 for OAuth tokens — use /auth/ instead**: The Sentry \`/users/me/\` endpoint returns 403 for OAuth tokens. Use \`/auth/\` instead — it works with ALL token types and lives on the control silo. In the CLI, \`getControlSiloUrl()\` handles routing correctly. \`SentryUserSchema\` (with \`.passthrough()\`) handles the \`/auth/\` response since it only requires \`id\`. -### Pattern + +* **Sentry chunk upload API returns camelCase not snake\_case**: The Sentry chunk upload options endpoint (\`/api/0/organizations/{org}/chunk-upload/\`) returns camelCase keys (\`chunkSize\`, \`chunksPerRequest\`, \`maxRequestSize\`, \`hashAlgorithm\`), NOT snake\_case. Zod schemas for these responses should use camelCase field names. This is an exception to the typical Sentry API convention of snake\_case. Verified by direct API query. The \`AssembleResponse\` also uses camelCase (\`missingChunks\`). + + +* **Stricli command context uses this.stdout not this.process.stdout**: In Stricli command \`func()\` handlers, use \`this.stdout\` and \`this.stderr\` directly — NOT \`this.process.stdout\`. The \`SentryContext\` interface has both \`process\` and \`stdout\`/\`stderr\` as separate top-level properties. Test mock contexts typically provide \`stdout\` but not a full \`process\` object, so \`this.process.stdout\` causes \`TypeError: undefined is not an object\` at runtime in tests even though TypeScript doesn't flag it. - -* **Branch naming and commit message conventions for Sentry CLI**: Branch naming: \`feat/\\` or \`fix/\-\\` (e.g., \`feat/ghcr-nightly-distribution\`, \`fix/268-limit-auto-pagination\`). Commit message format: \`type(scope): description (#issue)\` (e.g., \`fix(issue-list): auto-paginate --limit beyond 100 (#268)\`, \`feat(nightly): distribute via GHCR instead of GitHub Releases\`). Types seen: fix, refactor, meta, release, feat. PRs are created as drafts via \`gh pr create --draft\`. Implementation plans are attached to commits via \`git notes add\` rather than in PR body or commit message. + +* **Stricli defaultCommand blends default command flags into route completions**: When a Stricli route map has \`defaultCommand\` set, requesting completions for that route (e.g. \`\["issues", ""]\`) returns both the subcommand names AND the default command's flags/positional completions. This means completion tests that compare against \`extractCommandTree()\` subcommand lists will fail for groups with defaultCommand, since the actual completions include extra entries like \`--limit\`, \`--query\`, etc. Solution: track \`hasDefaultCommand\` in the command tree and skip strict subcommand-matching assertions for those groups. + + +* **Upgrade command tests are flaky when run in full suite due to test ordering**: The \`upgradeCommand.func\` tests in \`test/commands/cli/upgrade.test.ts\` sometimes fail when run as part of the full \`bun run test:unit\` suite but pass consistently in isolation (\`bun test test/commands/cli/upgrade.test.ts\`). This is a test-ordering/state-leak issue, not a code bug. Don't chase these failures when your changes are unrelated to the upgrade command. + +### Pattern - -* **Codecov patch coverage only counts test:unit and test:isolated, not E2E**: CI coverage merges \`test:unit\` (\`test/lib test/commands test/types --coverage\`) and \`test:isolated\` (\`test/isolated --coverage\`) into \`coverage/merged.lcov\`. E2E tests (\`test/e2e\`) are NOT included in coverage reports. So func tests that spy on exports (e.g., \`spyOn(apiClient, 'getLogs')\`) give zero coverage to the mocked function's body. To cover \`api-client.ts\` function bodies in unit tests, mock \`globalThis.fetch\` + \`setOrgRegion()\` + \`setAuthToken()\` and call the real function. + +* **Non-essential DB cache writes should be guarded with try-catch**: Non-essential DB cache writes (e.g., \`setUserInfo()\`) must be wrapped in try-catch so a broken DB doesn't crash a command whose primary operation succeeded. In login.ts, \`getCurrentUser()\` failure after token save must not block auth — log warning, continue. Exception: \`getUserRegions()\` failure should \`clearAuth()\` and fail hard (indicates invalid token). - -* **Help-as-positional recovery uses error-path, not pre-execution interception**: Three layers of help-as-positional recovery exist: (1) \*\*Leaf commands\*\* (\`sentry issue list help\`): \`maybeRecoverWithHelp\` in \`buildCommand\` wrapper catches \`CliError\` (excluding \`OutputError\`) in the error handler. If any positional arg was \`"help"\`, shows help via \`introspectCommand()\` using \`commandPrefix\` stored on \`SentryContext\`. Only \`-h\` is NOT checked — Stricli intercepts it natively during route scanning. (2) \*\*Route groups\*\* (\`sentry dashboard help\`): Post-run check in \`bin.ts\` detects \`ExitCode.UnknownCommand\` + last arg \`"help"\`, rewrites argv to \`\["help", ...rest]\` and re-runs through the custom help command. (3) Both require \`commandPrefix\` on \`SentryContext\` (set in \`forCommand\`). Dynamic-imports \`help.js\` to avoid circular deps. + +* **Sentry CLI command docs are auto-generated from Stricli route tree with CI freshness check**: Command reference docs in \`docs/src/content/docs/commands/\*.md\` are auto-generated by \`script/generate-command-docs.ts\` using Stricli route tree introspection (\`src/lib/introspect.ts\`). Content between \`\\` and \`\\` markers is regenerated; hand-written examples go below the end marker. Run \`bun run generate:command-docs\` after changing command parameters/flags/docs. CI check \`bun run check:command-docs\` fails if docs are stale (runs in same job as \`check:skill\`). The \`cli/\` subdirectory was flattened into a single \`cli.md\`. Skill reference files under \`plugins/sentry-cli/\` are also regenerated separately via \`generate:skill\`. - -* **Pagination contextKey must include all query-varying parameters with escaping**: Pagination \`contextKey\` must encode every query-varying parameter (sort, query, period) with \`escapeContextKeyValue()\` (replaces \`|\` with \`%7C\`). Always provide a fallback before escaping since \`flags.period\` may be \`undefined\` in tests despite having a default: \`flags.period ? escapeContextKeyValue(flags.period) : "90d"\`. + +* **Stricli buildCommand output config injects json flag into func params**: When a Stricli command uses \`output: { json: true, human: formatFn }\`, \`--json\` and \`--fields\` flags are auto-injected. The \`func\` handler receives these in its first parameter — type explicitly (e.g., \`flags: { json?: boolean }\`) to access them. Commands with interactive side effects (browser prompts, QR codes) should check \`flags.json\` and skip them when true. - -* **PR review workflow: reply, resolve, amend, force-push**: PR review workflow: (1) Read unresolved threads via GraphQL, (2) make code changes, (3) run lint+typecheck+tests, (4) create a SEPARATE commit per review round (not amend) for incremental review, (5) push normally, (6) reply to comments via REST API, (7) resolve threads via GraphQL \`resolveReviewThread\`. Only amend+force-push when user explicitly asks or pre-commit hook modified files. + +* **ZipWriter and file handle cleanup: always use try/finally with close()**: ZipWriter in \`src/lib/sourcemap/zip.ts\` has \`close()\` for error cleanup; \`finalize()\` uses try/finally for \`fh.close()\`. Callers must wrap usage in try/catch and call \`zip.close()\` in catch. Pattern: create zip → try { add entries + finalize } catch { zip.close(); throw }. Prevents file handle leaks on partial failures. - -* **Redact sensitive flags in raw argv before sending to telemetry**: Telemetry context and argv redaction patterns: \`withTelemetry\` calls \`initTelemetryContext()\` BEFORE the callback — user ID, email, instance ID, runtime, and is\_self\_hosted tags are automatically set. For org context, read \`getDefaultOrganization()\` from SQLite (no API call). When sending raw argv, redact sensitive flags: \`SENSITIVE\_FLAGS\` in \`telemetry.ts\` (currently \`token\`). Scan for \`--token\`/\`-token\`, replace following value with \`\[REDACTED]\`. Handle both \`--flag value\` and \`--flag=value\` forms. \`setFlagContext\` handles parsed flags separately. +### Preference - -* **Stricli optional boolean flags produce tri-state (true/false/undefined)**: Stricli boolean flags with \`optional: true\` (no \`default\`) produce \`boolean | undefined\` in the flags type. \`--flag\` → \`true\`, \`--no-flag\` → \`false\`, omitted → \`undefined\`. This enables auto-detect patterns: explicit user choice overrides, \`undefined\` triggers heuristic. Used by \`--compact\` on issue list. The flag type must be \`readonly field?: boolean\` (not \`readonly field: boolean\`). This differs from \`default: false\` which always produces a defined boolean. + +* **Code style: Array.from() over spread for iterators, allowlist not whitelist**: User prefers \`Array.from(map.keys())\` over \`\[...map.keys()]\` for converting iterators to arrays (avoids intermediate spread). Use "allowlist" terminology instead of "whitelist" in comments and variable names. When a reviewer asks "Why not .filter() here?" — it may be a question, not a change request; the \`for..of\` loop may be intentionally more efficient. Confirm intent before changing. - -* **Testing Stricli command func() bodies via spyOn mocking**: Stricli/Bun test patterns: (1) Command func tests: \`const func = await cmd.loader()\`, then \`func.call(mockContext, flags, ...args)\`. \`loader()\` return type union causes LSP errors — false positives that pass \`tsc\`. File naming: \`\*.func.test.ts\`. (2) ESM prevents \`vi.spyOn\` on Node built-in exports. Workaround: test subclass that overrides the method calling the built-in. (3) Follow-mode uses \`setTimeout\`-based scheduling; test with \`interceptSigint()\` helper. \`Bun.sleep()\` has no AbortSignal so \`setTimeout\`/\`clearTimeout\` required. + +* **PR workflow: address review comments, resolve threads, wait for CI**: PR workflow: (1) Wait for CI, (2) Check unresolved review comments via \`gh api\`, (3) Fix in follow-up commits (not amends), (4) Reply explaining fix, (5) Resolve thread via \`gh api graphql\` \`resolveReviewThread\` mutation, (6) Push and re-check CI, (7) Final sweep. Use \`git notes add\` for implementation plans. Branch naming: \`fix/descriptive-slug\` or \`feat/descriptive-slug\`. diff --git a/docs/src/content/docs/commands/api.md b/docs/src/content/docs/commands/api.md index 2330669c7..0ec460911 100644 --- a/docs/src/content/docs/commands/api.md +++ b/docs/src/content/docs/commands/api.md @@ -1,114 +1,58 @@ --- title: api -description: Direct API access for the Sentry CLI +description: API command for the Sentry CLI --- -Make direct API calls to Sentry's REST API. +Make an authenticated API request -## Commands +## Usage -### `sentry api` +### `sentry api ` -Execute an API request. - -```bash -sentry api [options] -``` +Make an authenticated API request **Arguments:** | Argument | Description | |----------|-------------| -| `` | API endpoint path (e.g., `/organizations/`) | +| `` | API endpoint relative to /api/0/ (e.g., organizations/) | **Options:** | Option | Description | |--------|-------------| -| `--method ` | HTTP method (GET, POST, PUT, DELETE). Default: GET | -| `--field ` | Add a field to the request body (can be used multiple times) | -| `--header ` | Add a custom header (can be used multiple times) | -| `--include` | Include response headers in output | -| `--paginate` | Automatically paginate through all results | - -## Examples - -### GET Request - -```bash -# List organizations -sentry api /organizations/ +| `-X, --method ` | The HTTP method for the request (default: "GET") | +| `-d, --data ` | Inline JSON body for the request (like curl -d) | +| `-F, --field ...` | Add a typed parameter (key=value, key[sub]=value, key[]=value) | +| `-f, --raw-field ...` | Add a string parameter without JSON parsing | +| `-H, --header
...` | Add a HTTP request header in key:value format | +| `--input ` | The file to use as body for the HTTP request (use "-" to read from standard input) | +| `--silent` | Do not print the response body | +| `--verbose` | Include full HTTP request and response in the output | +| `-n, --dry-run` | Show the resolved request without sending it | -# Get a specific organization -sentry api /organizations/my-org/ +All commands support `--json` for machine-readable output and `--fields` to select specific JSON fields. -# Get project details -sentry api /projects/my-org/my-project/ -``` - -### POST Request - -```bash -# Create a new project -sentry api /teams/my-org/my-team/projects/ \ - --method POST \ - --field name="New Project" \ - --field platform=javascript -``` - -### PUT Request + -```bash -# Update an issue status -sentry api /issues/123456789/ \ - --method PUT \ - --field status=resolved - -# Assign an issue -sentry api /issues/123456789/ \ - --method PUT \ - --field assignedTo="user@example.com" -``` - -### DELETE Request +## Examples ```bash -# Delete a project -sentry api /projects/my-org/my-project/ \ - --method DELETE -``` - -### With Headers +# GET request (default) +sentry api /api/0/organizations/ -```bash -sentry api /organizations/ \ - --header "X-Custom-Header:value" -``` +# POST with JSON body +sentry api /api/0/organizations/my-org/issues/ -X POST -d '{"status": "resolved"}' -### Verbose Mode +# Pass individual fields (auto-encoded as JSON body) +sentry api /api/0/projects/my-org/my-project/ -X PUT -F name=new-name -```bash -sentry api /organizations/ --verbose -``` +# Add custom headers +sentry api /api/0/organizations/ -H "X-Custom: value" -Request and response metadata is logged to stderr: +# Read body from a file +sentry api /api/0/projects/my-org/my-project/releases/ -X POST -i release.json +# Preview the request without sending +sentry api /api/0/organizations/ --dry-run ``` -> GET /api/0/organizations/ -> -< HTTP 200 -< content-type: application/json -< -[{"slug": "my-org", ...}] -``` - -### Pagination - -```bash -# Get all issues (automatically follows pagination) -sentry api /projects/my-org/my-project/issues/ --paginate -``` - -## API Documentation - -For full API documentation, see the [Sentry API Reference](https://docs.sentry.io/api/). diff --git a/docs/src/content/docs/commands/auth.md b/docs/src/content/docs/commands/auth.md index 4354d768f..8ed8b7622 100644 --- a/docs/src/content/docs/commands/auth.md +++ b/docs/src/content/docs/commands/auth.md @@ -1,101 +1,86 @@ --- title: auth -description: Authentication commands for the Sentry CLI +description: Auth commands for the Sentry CLI --- -Manage authentication for the Sentry CLI. +Authenticate with Sentry ## Commands ### `sentry auth login` -Authenticate with Sentry. - -```bash -# OAuth device flow (recommended) -sentry auth login - -# Using an API token -sentry auth login --token YOUR_TOKEN -``` +Authenticate with Sentry **Options:** | Option | Description | |--------|-------------| -| `--token ` | Use an API token instead of OAuth | +| `--token ` | Authenticate using an API token instead of OAuth | +| `--timeout ` | Timeout for OAuth flow in seconds (default: 900) | +| `--force` | Re-authenticate without prompting | -**OAuth Flow:** - -1. Run `sentry auth login` -2. A URL and code will be displayed -3. Open the URL in your browser -4. Enter the code when prompted -5. Authorize the application -6. The CLI automatically receives your token +### `sentry auth logout` -**Self-Hosted Sentry (26.1.0+):** +Log out of Sentry -For self-hosted instances, set `SENTRY_URL` and `SENTRY_CLIENT_ID` (from a public OAuth application you create on your instance): +### `sentry auth refresh` -```bash -SENTRY_URL=https://sentry.example.com SENTRY_CLIENT_ID=your-client-id sentry auth login -``` +Refresh your authentication token -On older versions or without an OAuth application, use an API token instead: +**Options:** -```bash -SENTRY_URL=https://sentry.example.com sentry auth login --token YOUR_TOKEN -``` +| Option | Description | +|--------|-------------| +| `--force` | Force refresh even if token is still valid | -See [Self-Hosted Sentry](../self-hosted/) for full setup details. +### `sentry auth status` -### `sentry auth logout` +View authentication status -Remove stored credentials. +**Options:** -```bash -sentry auth logout -``` +| Option | Description | +|--------|-------------| +| `--show-token` | Show the stored token (masked by default) | +| `-f, --fresh` | Bypass cache, re-detect projects, and fetch fresh data | -### `sentry auth status` +### `sentry auth token` -Check your authentication status. +Print the stored authentication token -```bash -sentry auth status -``` +### `sentry auth whoami` -**Output:** +Show the currently authenticated user -``` -Authenticated as: username -Organization: my-org -Token expires: 2024-12-31 -``` +**Options:** -### `sentry auth refresh` +| Option | Description | +|--------|-------------| +| `-f, --fresh` | Bypass cache, re-detect projects, and fetch fresh data | -Refresh your OAuth token. +All commands support `--json` for machine-readable output and `--fields` to select specific JSON fields. -```bash -sentry auth refresh -``` + -This is typically handled automatically when tokens expire. +## Examples -## Credential Storage +```bash +# OAuth login (recommended) +sentry auth login -Credentials are stored in a SQLite database at `~/.sentry/cli.db` with restricted file permissions (mode 600). +# Login with an API token +sentry auth login --token YOUR_SENTRY_API_TOKEN -Use `sentry auth token` to retrieve your current access token, or `sentry auth status` to check authentication state. +# Check auth status +sentry auth status -### Environment Variable Precedence +# Show the raw token +sentry auth status --show-token -The CLI checks for auth tokens in the following order, using the first one found: +# View current user +sentry auth whoami +``` -1. `SENTRY_AUTH_TOKEN` environment variable (legacy) -2. `SENTRY_TOKEN` environment variable -3. The stored token in the SQLite database +## Credential Storage -When a token comes from an environment variable, the CLI skips expiry checks and automatic refresh. +Auth tokens are stored securely in a local SQLite database at `~/.sentry/config.db`. diff --git a/docs/src/content/docs/commands/cli.md b/docs/src/content/docs/commands/cli.md new file mode 100644 index 000000000..1b6e756b1 --- /dev/null +++ b/docs/src/content/docs/commands/cli.md @@ -0,0 +1,83 @@ +--- +title: cli +description: CLI commands for the Sentry CLI +--- + +CLI-related commands + +## Commands + +### `sentry cli feedback ` + +Send feedback about the CLI + +**Arguments:** + +| Argument | Description | +|----------|-------------| +| `` | Your feedback message (optional) | + +### `sentry cli fix` + +Diagnose and repair CLI database issues + +**Options:** + +| Option | Description | +|--------|-------------| +| `--dry-run` | Show what would be fixed without making changes | + +### `sentry cli setup` + +Configure shell integration + +**Options:** + +| Option | Description | +|--------|-------------| +| `--install` | Install the binary from a temp location to the system path | +| `--method ` | Installation method (curl, npm, pnpm, bun, yarn) | +| `--channel ` | Release channel to persist (stable or nightly) | +| `--no-modify-path` | Skip PATH modification | +| `--no-completions` | Skip shell completion installation | +| `--no-agent-skills` | Skip agent skill installation for AI coding assistants | +| `--quiet` | Suppress output (for scripted usage) | + +### `sentry cli upgrade ` + +Update the Sentry CLI to the latest version + +**Arguments:** + +| Argument | Description | +|----------|-------------| +| `` | Specific version (e.g. 0.5.0), or "nightly"/"stable" to switch channel; omit to update within current channel (optional) | + +**Options:** + +| Option | Description | +|--------|-------------| +| `--check` | Check for updates without installing | +| `--force` | Force upgrade even if already on the latest version | +| `--offline` | Upgrade using only cached version info and patches (no network) | +| `--method ` | Installation method to use (curl, brew, npm, pnpm, bun, yarn) | + +All commands support `--json` for machine-readable output and `--fields` to select specific JSON fields. + + + +## Examples + +```bash +# Check for updates +sentry cli upgrade --check + +# Upgrade to the latest version +sentry cli upgrade + +# Send feedback +sentry cli feedback "Great CLI!" + +# Fix configuration issues +sentry cli fix +``` diff --git a/docs/src/content/docs/commands/cli/feedback.md b/docs/src/content/docs/commands/cli/feedback.md deleted file mode 100644 index 065aef547..000000000 --- a/docs/src/content/docs/commands/cli/feedback.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: cli feedback -description: Send feedback about the Sentry CLI ---- - -Send feedback about your experience with the CLI. - -## Usage - -```bash -sentry cli feedback -``` - -**Arguments:** - -| Argument | Description | -|----------|-------------| -| `` | Your feedback message (all words after `feedback` are joined) | - -## Examples - -```bash -# Send positive feedback -sentry cli feedback i love this tool - -# Report an issue -sentry cli feedback the issue view is confusing - -# Suggest an improvement -sentry cli feedback would be great to have a search command -``` - -## Notes - -- Feedback is sent via Sentry's telemetry system -- If telemetry is disabled (`SENTRY_CLI_NO_TELEMETRY=1`), feedback cannot be sent -- All feedback is anonymous and used to improve the CLI diff --git a/docs/src/content/docs/commands/cli/index.md b/docs/src/content/docs/commands/cli/index.md deleted file mode 100644 index 61325cb91..000000000 --- a/docs/src/content/docs/commands/cli/index.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: cli -description: CLI-related commands for managing the Sentry CLI itself ---- - -Commands for managing the Sentry CLI itself, including sending feedback and upgrading to newer versions. - -## Commands - -| Command | Description | -|---------|-------------| -| [`feedback`](./feedback/) | Send feedback about the CLI | -| [`upgrade`](./upgrade/) | Update the CLI to the latest version | diff --git a/docs/src/content/docs/commands/cli/upgrade.md b/docs/src/content/docs/commands/cli/upgrade.md deleted file mode 100644 index ae0958613..000000000 --- a/docs/src/content/docs/commands/cli/upgrade.md +++ /dev/null @@ -1,130 +0,0 @@ ---- -title: cli upgrade -description: Update the Sentry CLI to the latest version ---- - -Self-update the Sentry CLI to the latest or a specific version. - -## Usage - -```bash -sentry cli upgrade # Update using the persisted channel (default: stable) -sentry cli upgrade nightly # Switch to nightly channel and update -sentry cli upgrade stable # Switch back to stable channel and update -sentry cli upgrade 0.5.0 # Update to a specific stable version -sentry cli upgrade --check # Check for updates without installing -sentry cli upgrade --force # Force re-download even if already up to date -sentry cli upgrade --method npm # Force using npm to upgrade -``` - -## Options - -| Option | Description | -|--------|-------------| -| `` | Target version, or `nightly`/`stable` to switch channel (defaults to latest) | -| `--check` | Check for updates without installing | -| `--force` | Re-download even if already on the latest version | -| `--channel ` | Set release channel: `stable` or `nightly` | -| `--method ` | Force installation method: curl, brew, npm, pnpm, bun, yarn | - -## Release Channels - -The CLI supports two release channels: - -| Channel | Description | -|---------|-------------| -| `stable` | Latest stable release (default) | -| `nightly` | Built from `main`, updated on every commit | - -The chosen channel is persisted locally so that subsequent bare `sentry cli upgrade` -calls use the same channel without requiring a flag. - -## Installation Detection - -The CLI auto-detects how it was installed and uses the same method to upgrade: - -| Method | Detection | -|--------|-----------| -| curl | Binary located in `~/.sentry/bin` (installed via cli.sentry.dev) | -| brew | Binary located in a Homebrew Cellar (installed via `brew install getsentry/tools/sentry`) | -| npm | Globally installed via `npm install -g sentry` | -| pnpm | Globally installed via `pnpm add -g sentry` | -| bun | Globally installed via `bun install -g sentry` | -| yarn | Globally installed via `yarn global add sentry` | - -> **Note:** Nightly builds are only available as standalone binaries (via the curl -> install method). If you switch to the nightly channel from a package manager or -> Homebrew install, the CLI will automatically migrate to a standalone binary and -> warn you about the existing package-manager installation. - -## Examples - -### Check for updates - -```bash -sentry cli upgrade --check -``` - -``` -Installation method: curl -Current version: 0.4.0 -Channel: stable -Latest version: 0.5.0 - -Run 'sentry cli upgrade' to update. -``` - -### Upgrade to latest stable - -```bash -sentry cli upgrade -``` - -``` -Installation method: curl -Current version: 0.4.0 -Channel: stable -Latest version: 0.5.0 - -Upgrading to 0.5.0... - -Successfully upgraded to 0.5.0. -``` - -### Switch to nightly channel - -```bash -sentry cli upgrade nightly -# or equivalently: -sentry cli upgrade --channel nightly -``` - -After switching, bare `sentry cli upgrade` will continue tracking nightly. - -### Switch back to stable - -```bash -sentry cli upgrade stable -# or equivalently: -sentry cli upgrade --channel stable -``` - -### Upgrade to specific version - -```bash -sentry cli upgrade 0.5.0 -``` - -### Force re-download - -```bash -sentry cli upgrade --force -``` - -### Force installation method - -If auto-detection fails or you want to switch installation methods: - -```bash -sentry cli upgrade --method npm -``` diff --git a/docs/src/content/docs/commands/dashboard.md b/docs/src/content/docs/commands/dashboard.md index 0b27e2575..15f376b1f 100644 --- a/docs/src/content/docs/commands/dashboard.md +++ b/docs/src/content/docs/commands/dashboard.md @@ -3,323 +3,163 @@ title: dashboard description: Dashboard commands for the Sentry CLI --- -View and manage dashboards in your Sentry organization. +Manage Sentry dashboards ## Commands -### `sentry dashboard list` +### `sentry dashboard list ` -List dashboards in an organization. - -```bash -# Auto-detect org from config -sentry dashboard list - -# Explicit org -sentry dashboard list my-org/ - -# Explicit org and project -sentry dashboard list my-org/my-project -``` +List dashboards **Arguments:** | Argument | Description | |----------|-------------| -| `/` | Organization slug (optional — auto-detected from config if omitted) | -| `/` | Organization and project to scope the dashboard list | +| `` | [<org/project>] [<name-glob>] (optional) | **Options:** | Option | Description | |--------|-------------| | `-w, --web` | Open in browser | -| `-n, --limit ` | Maximum number of dashboards to list (default: 30) | -| `-f, --fresh` | Bypass cache and fetch fresh data | -| `--json` | Output as JSON | - -**Examples:** - -```bash -sentry dashboard list -``` - -``` -ID TITLE WIDGETS CREATED -12345 General 4 2024-01-15 -12346 Frontend Performance 6 2024-02-20 -12347 Backend Errors 3 2024-03-10 -``` +| `-n, --limit ` | Maximum number of dashboards to list (default: "30") | +| `-f, --fresh` | Bypass cache, re-detect projects, and fetch fresh data | +| `-c, --cursor ` | Navigate pages: "next", "prev", "first" (or raw cursor string) | -**Open dashboard list in browser:** +### `sentry dashboard view ` -```bash -sentry dashboard list -w -``` - -### `sentry dashboard view` - -View details of a specific dashboard, including its widgets. - -```bash -# By numeric ID -sentry dashboard view - -# By title -sentry dashboard view '' - -# With explicit org -sentry dashboard view <org>/ <id> -``` +View a dashboard **Arguments:** | Argument | Description | |----------|-------------| -| `<id>` or `<title>` | Dashboard ID (numeric) or title (case-insensitive) | -| `<org>/` | Organization slug (optional) | +| `<args...>` | [<org/project>] <dashboard-id-or-title> (optional) | **Options:** | Option | Description | |--------|-------------| | `-w, --web` | Open in browser | -| `-f, --fresh` | Bypass cache and fetch fresh data | -| `--json` | Output as JSON | +| `-f, --fresh` | Bypass cache, re-detect projects, and fetch fresh data | +| `-r, --refresh <refresh>` | Auto-refresh interval in seconds (default: 60, min: 10) | +| `-t, --period <period>` | Time period override (e.g., "24h", "7d", "14d") | -**Examples:** +### `sentry dashboard create <args...>` -```bash -sentry dashboard view 12345 -``` - -``` -Dashboard: Frontend Performance (ID: 12345) -URL: https://my-org.sentry.io/dashboard/12345/ - -Widgets: - #0 Error Count big_number count() - #1 Errors Over Time line count() - #2 Errors by Browser bar count() group by browser.name - #3 Top Endpoints table count(), p95(span.duration) group by transaction -``` - -**View by title:** - -```bash -sentry dashboard view 'Frontend Performance' -``` - -**Open in browser:** - -```bash -sentry dashboard view 12345 -w -``` - -### `sentry dashboard create` - -Create a new dashboard. - -```bash -# Auto-detect org -sentry dashboard create '<title>' - -# Explicit org -sentry dashboard create <org>/ '<title>' - -# Explicit org and project -sentry dashboard create <org>/<project> '<title>' -``` +Create a dashboard **Arguments:** | Argument | Description | |----------|-------------| -| `<title>` | Dashboard title | -| `<org>/` or `<org>/<project>` | Organization and optional project (auto-detected if omitted) | - -**Examples:** +| `<args...>` | [<org/project>] <title> (optional) | -```bash -sentry dashboard create 'Frontend Performance' -``` - -``` -Created dashboard: Frontend Performance (ID: 12348) -URL: https://my-org.sentry.io/dashboard/12348/ -``` +### `sentry dashboard widget add <args...>` -**Add widgets after creation:** - -```bash -sentry dashboard widget add 'Frontend Performance' "Error Count" --display big_number --query count -``` - -### `sentry dashboard widget add` - -Add a widget to an existing dashboard. - -```bash -sentry dashboard widget add <dashboard> '<widget-title>' --display <type> [options] -``` +Add a widget to a dashboard **Arguments:** | Argument | Description | |----------|-------------| -| `<dashboard>` | Dashboard ID (numeric) or title | -| `<widget-title>` | Title for the new widget | -| `<org>/` | Organization slug (optional, prepend before dashboard) | +| `<args...>` | [<org/project>] <dashboard> <title> (optional) | **Options:** | Option | Description | |--------|-------------| -| `-d, --display <type>` | Display type: `line`, `bar`, `table`, `big_number`, `area`, `top_n` (required) | -| `--dataset <dataset>` | Widget dataset (default: `spans`). Also accepts `discover` | -| `-q, --query <expr>` | Aggregate expression (repeatable for multiple columns) | -| `-w, --where <filter>` | Search conditions filter | -| `-g, --group-by <col>` | Group-by column (repeatable) | -| `-s, --sort <expr>` | Sort order (prefix `-` for descending) | -| `-n, --limit <n>` | Result row limit | -| `--json` | Output as JSON | +| `-d, --display <display>` | Display type (big_number, line, area, bar, table, stacked_area, top_n, text, categorical_bar, details, wheel, rage_and_dead_clicks, server_tree, agents_traces_table) | +| `--dataset <dataset>` | Widget dataset (default: spans) | +| `-q, --query <query>...` | Aggregate expression (e.g. count, p95:span.duration) | +| `-w, --where <where>` | Search conditions filter (e.g. is:unresolved) | +| `-g, --group-by <group-by>...` | Group-by column (repeatable) | +| `-s, --sort <sort>` | Order by (prefix - for desc, e.g. -count) | +| `-n, --limit <limit>` | Result limit | -**Query shorthand:** +### `sentry dashboard widget edit <args...>` -The `--query` flag supports shorthand for aggregate functions: +Edit a widget in a dashboard -| Input | Expands to | -|-------|-----------| -| `count` | `count()` | -| `p95:span.duration` | `p95(span.duration)` | -| `avg:span.duration` | `avg(span.duration)` | -| `count()` | `count()` (passthrough) | - -**Sort shorthand:** - -| Input | Meaning | -|-------|---------| -| `count` | Sort by `count()` ascending | -| `-count` | Sort by `count()` descending | - -**Examples:** - -```bash -# Simple counter widget -sentry dashboard widget add 'My Dashboard' "Error Count" \ - --display big_number --query count -``` - -```bash -# Line chart with group-by -sentry dashboard widget add 'My Dashboard' "Errors by Browser" \ - --display line --query count --group-by browser.name -``` - -```bash -# Table with multiple aggregates, sorted descending -sentry dashboard widget add 'My Dashboard' "Top Endpoints" \ - --display table \ - --query count --query p95:span.duration \ - --group-by transaction \ - --sort -count --limit 10 -``` +**Arguments:** -```bash -# With search filter -sentry dashboard widget add 'My Dashboard' "Slow Requests" \ - --display bar --query p95:span.duration \ - --where "span.op:http.client" \ - --group-by span.description -``` +| Argument | Description | +|----------|-------------| +| `<args...>` | [<org/project>] <dashboard-id-or-title> (optional) | -### `sentry dashboard widget edit` +**Options:** -Edit an existing widget in a dashboard. Only provided flags are changed — omitted values are preserved. +| Option | Description | +|--------|-------------| +| `-i, --index <index>` | Widget index (0-based) | +| `-t, --title <title>` | Widget title to match | +| `--new-title <new-title>` | New widget title | +| `-d, --display <display>` | Display type (big_number, line, area, bar, table, stacked_area, top_n, text, categorical_bar, details, wheel, rage_and_dead_clicks, server_tree, agents_traces_table) | +| `--dataset <dataset>` | Widget dataset (default: spans) | +| `-q, --query <query>...` | Aggregate expression (e.g. count, p95:span.duration) | +| `-w, --where <where>` | Search conditions filter (e.g. is:unresolved) | +| `-g, --group-by <group-by>...` | Group-by column (repeatable) | +| `-s, --sort <sort>` | Order by (prefix - for desc, e.g. -count) | +| `-n, --limit <limit>` | Result limit | -```bash -# Identify widget by title -sentry dashboard widget edit <dashboard> --title '<widget-title>' [options] +### `sentry dashboard widget delete <args...>` -# Identify widget by index (0-based) -sentry dashboard widget edit <dashboard> --index <n> [options] -``` +Delete a widget from a dashboard **Arguments:** | Argument | Description | |----------|-------------| -| `<dashboard>` | Dashboard ID (numeric) or title | -| `<org>/` | Organization slug (optional, prepend before dashboard) | +| `<args...>` | [<org/project>] <dashboard-id-or-title> (optional) | **Options:** | Option | Description | |--------|-------------| -| `-i, --index <n>` | Widget index (0-based) | -| `-t, --title <title>` | Match widget by title (case-insensitive) | -| `--new-title <title>` | Rename the widget | -| `-d, --display <type>` | Change display type | -| `--dataset <dataset>` | Change widget dataset | -| `-q, --query <expr>` | Replace aggregate expression(s) | -| `-w, --where <filter>` | Replace search conditions | -| `-g, --group-by <col>` | Replace group-by column(s) | -| `-s, --sort <expr>` | Replace sort order | -| `-n, --limit <n>` | Change result limit | -| `--json` | Output as JSON | - -**Examples:** +| `-i, --index <index>` | Widget index (0-based) | +| `-t, --title <title>` | Widget title to match | -```bash -# Change display type -sentry dashboard widget edit 12345 --title 'Error Count' --display bar -``` +All commands support `--json` for machine-readable output and `--fields` to select specific JSON fields. -```bash -# Rename a widget -sentry dashboard widget edit 'My Dashboard' --index 0 --new-title 'Total Errors' -``` - -```bash -# Change the query -sentry dashboard widget edit 12345 --title 'Error Rate' --query p95:span.duration -``` +<!-- GENERATED:END --> -### `sentry dashboard widget delete` +## Examples -Remove a widget from a dashboard. +### List dashboards ```bash -# Delete by title -sentry dashboard widget delete <dashboard> --title '<widget-title>' +# List all dashboards +sentry dashboard list -# Delete by index (0-based) -sentry dashboard widget delete <dashboard> --index <n> +# Open in browser +sentry dashboard list -w + +# Filter by name +sentry dashboard list "Backend*" ``` -**Arguments:** +### View a dashboard -| Argument | Description | -|----------|-------------| -| `<dashboard>` | Dashboard ID (numeric) or title | -| `<org>/` | Organization slug (optional, prepend before dashboard) | +```bash +# View with live data +sentry dashboard view "Backend Performance" -**Options:** +# Auto-refresh every 30 seconds +sentry dashboard view "Backend Performance" --refresh 30 -| Option | Description | -|--------|-------------| -| `-i, --index <n>` | Widget index (0-based) | -| `-t, --title <title>` | Match widget by title (case-insensitive) | -| `--json` | Output as JSON | +# Open in browser +sentry dashboard view "Backend Performance" -w +``` -**Examples:** +### Manage widgets ```bash -# Delete by title -sentry dashboard widget delete 'My Dashboard' --title 'Error Count' -``` +# Add a widget +sentry dashboard widget add "My Dashboard" -t "Error Count" -d line -q "count()" -```bash -# Delete by index -sentry dashboard widget delete 12345 --index 2 +# Edit a widget +sentry dashboard widget edit "My Dashboard" -i 0 --new-title "Updated Title" + +# Delete a widget +sentry dashboard widget delete "My Dashboard" -i 0 ``` diff --git a/docs/src/content/docs/commands/event.md b/docs/src/content/docs/commands/event.md index 9042b5c10..3d0e1cf5a 100644 --- a/docs/src/content/docs/commands/event.md +++ b/docs/src/content/docs/commands/event.md @@ -3,32 +3,33 @@ title: event description: Event commands for the Sentry CLI --- -Inspect Sentry events. +View Sentry events ## Commands -### `sentry event view` +### `sentry event view <args...>` -View details of a specific event. - -```bash -sentry event view <event-id> -``` +View details of a specific event **Arguments:** | Argument | Description | |----------|-------------| -| `<event-id>` | The event ID | +| `<args...>` | [<org>/<project>] <event-id> - Target (optional) and event ID (required) (optional) | **Options:** | Option | Description | |--------|-------------| | `-w, --web` | Open in browser | -| `--json` | Output as JSON | +| `--spans <spans>` | Span tree depth limit (number, "all" for unlimited, "no" to disable) (default: "3") | +| `-f, --fresh` | Bypass cache, re-detect projects, and fetch fresh data | + +All commands support `--json` for machine-readable output and `--fields` to select specific JSON fields. + +<!-- GENERATED:END --> -**Example:** +## Examples ```bash sentry event view abc123def456 @@ -50,16 +51,6 @@ Tags: os: Windows 10 environment: production release: 1.2.3 - -Context: - url: https://example.com/app - user_id: 12345 -``` - -**Open in browser:** - -```bash -sentry event view abc123def456 -w ``` ## Finding Event IDs diff --git a/docs/src/content/docs/commands/index.md b/docs/src/content/docs/commands/index.md index d6ffc9ac6..f2047f036 100644 --- a/docs/src/content/docs/commands/index.md +++ b/docs/src/content/docs/commands/index.md @@ -1,6 +1,6 @@ --- -title: Commands Overview -description: Overview of all Sentry CLI commands +title: Commands +description: Available commands in the Sentry CLI --- The Sentry CLI provides commands for interacting with various Sentry resources. @@ -9,22 +9,25 @@ The Sentry CLI provides commands for interacting with various Sentry resources. | Command | Description | |---------|-------------| -| [`auth`](./auth/) | Authentication management | -| [`cli`](./cli/) | CLI-related commands (feedback, upgrade) | -| [`org`](./org/) | Organization operations | -| [`project`](./project/) | Project operations | -| [`team`](./team/) | Team operations | -| [`issue`](./issue/) | Issue tracking | -| [`event`](./event/) | Event inspection | -| [`log`](./log/) | Log viewing and streaming | -| [`trace`](./trace/) | Distributed trace inspection | -| [`span`](./span/) | Span listing and details | -| [`dashboard`](./dashboard/) | Dashboard management | -| [`sourcemap`](./sourcemap/) | Sourcemap injection and upload | -| [`repo`](./repo/) | Repository listing | -| [`trial`](./trial/) | Product trial management | -| [`schema`](./schema/) | API schema browsing | -| [`api`](./api/) | Direct API access | +| [`auth`](./auth/) | Authenticate with Sentry | +| [`cli`](./cli/) | CLI-related commands | +| [`org`](./org/) | Work with Sentry organizations | +| [`project`](./project/) | Work with Sentry projects | +| [`team`](./team/) | Work with Sentry teams | +| [`issue`](./issue/) | Manage Sentry issues | +| [`event`](./event/) | View Sentry events | +| [`log`](./log/) | View Sentry logs | +| [`trace`](./trace/) | View distributed traces | +| [`span`](./span/) | List and view spans in projects or traces | +| [`dashboard`](./dashboard/) | Manage Sentry dashboards | +| [`sourcemap`](./sourcemap/) | Manage sourcemaps | +| [`repo`](./repo/) | Work with Sentry repositories | +| [`trial`](./trial/) | Manage product trials | +| [`init`](./init/) | Initialize Sentry in your project (experimental) | +| [`schema`](./schema/) | Browse the Sentry API schema | +| [`api`](./api/) | Make an authenticated API request | + +<!-- GENERATED:END --> ## Global Options diff --git a/docs/src/content/docs/commands/init.md b/docs/src/content/docs/commands/init.md index d669e46a6..47ffcb719 100644 --- a/docs/src/content/docs/commands/init.md +++ b/docs/src/content/docs/commands/init.md @@ -1,111 +1,48 @@ --- title: init -description: AI-powered project setup wizard for the Sentry CLI +description: Init command for the Sentry CLI --- -> **Experimental:** `sentry init` is experimental and may modify your source files. Always review changes before committing. - -Set up Sentry in your project with an AI-powered wizard. The `init` command detects your platform and framework, installs the Sentry SDK, and instruments your code for error monitoring, tracing, and more. - -Run `sentry init` from your repo root — no arguments needed. The wizard auto-detects your framework and Sentry org. - -**Prerequisites:** You must be authenticated first. Run `sentry auth login` if you haven't already. +Initialize Sentry in your project (experimental) ## Usage -```bash -sentry init [target] [directory] -``` +### `sentry init <target> <directory>` + +Initialize Sentry in your project (experimental) **Arguments:** | Argument | Description | |----------|-------------| -| `[target]` | Org/project target (see [Target syntax](#target-syntax) below). Omit to auto-detect. | -| `[directory]` | Project directory (default: current directory) | +| `<target>` | <org>/<project>, <org>/, <project>, or a directory path (optional) | +| `<directory>` | Project directory (default: current directory) (optional) | **Options:** | Option | Description | |--------|-------------| -| `--force` | Continue even if Sentry is already installed | | `-y, --yes` | Non-interactive mode (accept defaults) | | `--dry-run` | Preview changes without applying them | -| `--features <list>` | Comma-separated features to enable (see [Features](#features) below) | -| `-t, --team <slug>` | Team slug to create the project under | - -## Target syntax - -The optional `[target]` argument lets you specify which Sentry org and project to use: - -| Syntax | Meaning | -|--------|---------| -| _(omitted)_ | Auto-detect org and project | -| `acme/` | Use org `acme`, auto-detect or create project | -| `acme/my-app` | Use org `acme` and project `my-app` | -| `my-app` | Search for project `my-app` across all accessible orgs | - -Path-like arguments (starting with `.`, `/`, or `~`) are always treated as the directory. The order of `[target]` and `[directory]` can be swapped — the CLI will auto-correct with a warning. - -## Features +| `--features <features>...` | Features to enable: errors,tracing,logs,replay,metrics,profiling,sourcemaps,crons,ai-monitoring,user-feedback | +| `-t, --team <team>` | Team slug to create the project under | -Pass a comma-separated list to `--features` to control which integrations are configured: +All commands support `--json` for machine-readable output and `--fields` to select specific JSON fields. -| Feature | Description | -|---------|-------------| -| `errors` | Error monitoring | -| `tracing` | Performance tracing | -| `logs` | Log integration | -| `replay` | Session replay | -| `metrics` | Custom metrics | -| `profiling` | Profiling | -| `sourcemaps` | Source map uploads | -| `crons` | Cron job monitoring | -| `ai-monitoring` | AI/LLM monitoring | -| `user-feedback` | User feedback widget | +<!-- GENERATED:END --> ## Examples ```bash -# Run the wizard in the current directory +# Interactive setup sentry init -# Target a subdirectory -sentry init ./my-app +# Non-interactive with auto-yes +sentry init -y -# Use a specific org (auto-detect project) -sentry init acme/ - -# Use a specific org and project -sentry init acme/my-app - -# Use a specific org and project in a subdirectory -sentry init acme/my-app ./my-app - -# Preview what changes would be made +# Dry run to preview changes sentry init --dry-run -# Select specific features -sentry init --features errors,tracing,logs - -# Non-interactive mode (accept all defaults) -sentry init --yes - -# Assign a team when creating a new project -sentry init acme/ --team backend +# Enable specific features +sentry init --features profiling,replays ``` - -## What the wizard does - -1. **Detects your framework** — scans your project files to identify the platform and framework -2. **Installs the SDK** — adds the appropriate Sentry SDK package to your project -3. **Instruments your code** — configures error monitoring, tracing, and any selected features - -## Supported platforms - -The wizard currently supports: - -- **JavaScript / TypeScript** — Next.js, Express, SvelteKit, React -- **Python** — Flask, FastAPI - -More platforms and frameworks are coming soon. diff --git a/docs/src/content/docs/commands/issue.md b/docs/src/content/docs/commands/issue.md index 735db6970..2d2608780 100644 --- a/docs/src/content/docs/commands/issue.md +++ b/docs/src/content/docs/commands/issue.md @@ -3,121 +3,118 @@ title: issue description: Issue commands for the Sentry CLI --- -Track and manage Sentry issues. +Manage Sentry issues ## Commands -### `sentry issue list` +### `sentry issue list <org/project>` -List issues in a project. +List issues in a project -```bash -# Explicit org and project -sentry issue list <org>/<project> +**Arguments:** -# All projects in an organization -sentry issue list <org>/ +| Argument | Description | +|----------|-------------| +| `<org/project>` | <org>/ (all projects), <org>/<project>, or <project> (search) (optional) | -# Search for project across all accessible orgs -sentry issue list <project> +**Options:** -# Auto-detect from DSN or config -sentry issue list -``` +| Option | Description | +|--------|-------------| +| `-q, --query <query>` | Search query (Sentry search syntax) | +| `-n, --limit <limit>` | Maximum number of issues to list (default: "25") | +| `-s, --sort <sort>` | Sort by: date, new, freq, user (default: "date") | +| `-t, --period <period>` | Time period for issue activity (e.g. 24h, 14d, 90d) (default: "90d") | +| `-c, --cursor <cursor>` | Pagination cursor (use "next" for next page, "prev" for previous) | +| `--compact` | Single-line rows for compact output (auto-detects if omitted) | +| `-f, --fresh` | Bypass cache, re-detect projects, and fetch fresh data | + +### `sentry issue explain <issue>` + +Analyze an issue's root cause using Seer AI **Arguments:** | Argument | Description | |----------|-------------| -| `<org>/<project>` | Explicit organization and project (e.g., `my-org/frontend`) | -| `<org>/` | All projects in the specified organization | -| `<project>` | Search for project by name across all accessible organizations | +| `<issue>` | Issue: @latest, @most_frequent, <org>/ID, <project>-suffix, ID, or suffix | **Options:** | Option | Description | |--------|-------------| -| `--query <query>` | Search query (Sentry search syntax) | -| `--sort <sort>` | Sort by: date, new, freq, user (default: date) | -| `--limit <n>` | Maximum number of issues to return (default: 10) | -| `--json` | Output as JSON | +| `--force` | Force new analysis even if one exists | +| `-f, --fresh` | Bypass cache, re-detect projects, and fetch fresh data | -**Examples:** +### `sentry issue plan <issue>` -```bash -# List issues in a specific project -sentry issue list my-org/frontend -``` +Generate a solution plan using Seer AI -``` -ID SHORT ID TITLE COUNT USERS -123456789 FRONT-ABC TypeError: Cannot read prop... 1.2k 234 -987654321 FRONT-DEF ReferenceError: x is not de... 456 89 -``` +**Arguments:** -**List issues from all projects in an org:** +| Argument | Description | +|----------|-------------| +| `<issue>` | Issue: @latest, @most_frequent, <org>/ID, <project>-suffix, ID, or suffix | -```bash -sentry issue list my-org/ -``` +**Options:** -**Search for a project across organizations:** +| Option | Description | +|--------|-------------| +| `--cause <cause>` | Root cause ID to plan (required if multiple causes exist) | +| `--force` | Force new plan even if one exists | +| `-f, --fresh` | Bypass cache, re-detect projects, and fetch fresh data | -```bash -sentry issue list frontend -``` +### `sentry issue view <issue>` -**With search query:** +View details of a specific issue -```bash -sentry issue list my-org/frontend --query "TypeError" -``` - -**Sort by frequency:** +**Arguments:** -```bash -sentry issue list my-org/frontend --sort freq --limit 20 -``` +| Argument | Description | +|----------|-------------| +| `<issue>` | Issue: @latest, @most_frequent, <org>/ID, <project>-suffix, ID, or suffix | -**Filter by status:** +**Options:** -```bash -# Show only unresolved issues -sentry issue list my-org/frontend --query "is:unresolved" +| Option | Description | +|--------|-------------| +| `-w, --web` | Open in browser | +| `--spans <spans>` | Span tree depth limit (number, "all" for unlimited, "no" to disable) (default: "3") | +| `-f, --fresh` | Bypass cache, re-detect projects, and fetch fresh data | -# Show resolved issues -sentry issue list my-org/frontend --query "is:resolved" +All commands support `--json` for machine-readable output and `--fields` to select specific JSON fields. -# Combine with other search terms -sentry issue list my-org/frontend --query "is:unresolved TypeError" -``` +<!-- GENERATED:END --> -### `sentry issue view` +## Examples -View details of a specific issue. +### List issues ```bash -# By issue ID -sentry issue view <issue-id> +# List issues in a specific project +sentry issue list my-org/frontend +``` -# By short ID -sentry issue view <short-id> +``` +ID SHORT ID TITLE COUNT USERS +123456789 FRONT-ABC TypeError: Cannot read prop... 1.2k 234 +987654321 FRONT-DEF ReferenceError: x is not de... 456 89 ``` -**Arguments:** +**Filter by status:** -| Argument | Description | -|----------|-------------| -| `<issue-id>` | The issue ID (numeric) or short ID (e.g., PROJ-ABC) | +```bash +# Show only unresolved issues +sentry issue list my-org/frontend --query "is:unresolved" -**Options:** +# Show resolved issues +sentry issue list my-org/frontend --query "is:resolved" -| Option | Description | -|--------|-------------| -| `-w, --web` | Open in browser | -| `--json` | Output as JSON | +# Sort by frequency +sentry issue list my-org/frontend --sort freq --limit 20 +``` -**Example:** +### View an issue ```bash sentry issue view FRONT-ABC @@ -138,103 +135,12 @@ Latest event: URL: https://example.com/app ``` -**Open in browser:** - -```bash -sentry issue view FRONT-ABC -w -``` - -### `sentry issue explain` +### Seer AI Requirements -Analyze an issue's root cause using Seer AI. - -```bash -sentry issue explain <issue-id> -``` - -This command analyzes the issue and provides: -- Identified root causes -- Reproduction steps -- Relevant code locations - -The analysis may take a few minutes for new issues. - -**Arguments:** - -| Argument | Description | -|----------|-------------| -| `<issue-id>` | The issue ID (numeric), short ID (e.g., PROJ-ABC), or short suffix | - -**Options:** - -| Option | Description | -|--------|-------------| -| `--force` | Force new analysis even if one already exists | -| `--json` | Output as JSON | - -**Examples:** - -```bash -# By numeric issue ID -sentry issue explain 123456789 - -# By short ID with org prefix -sentry issue explain my-org/MYPROJECT-ABC - -# By project-suffix format -sentry issue explain myproject-G - -# Force a fresh analysis -sentry issue explain 123456789 --force -``` - -**Requirements:** +The `explain` and `plan` commands require: - Seer AI enabled for your organization - GitHub integration configured with repository access - Code mappings set up to link stack frames to source files -### `sentry issue plan` - -Generate a solution plan for a Sentry issue using Seer AI. - -```bash -sentry issue plan <issue-id> -``` - -This command requires that `sentry issue explain` has been run first to identify the root cause. It generates a solution plan with specific implementation steps to fix the issue. - -**Arguments:** - -| Argument | Description | -|----------|-------------| -| `<issue-id>` | The issue ID (numeric), short ID (e.g., PROJ-ABC), or short suffix | - -**Options:** - -| Option | Description | -|--------|-------------| -| `--cause <n>` | Root cause ID to plan (required if multiple causes were identified) | -| `--json` | Output as JSON | - -**Examples:** - -```bash -# After running explain, create a plan -sentry issue plan 123456789 - -# Specify which root cause to plan for (if multiple were found) -sentry issue plan 123456789 --cause 0 - -# By short ID with org prefix -sentry issue plan my-org/MYPROJECT-ABC --cause 1 - -# By project-suffix format -sentry issue plan myproject-G --cause 0 -``` - -**Requirements:** - -- Root cause analysis must be completed first (`sentry issue explain`) -- GitHub integration configured for your organization -- Code mappings set up for your project \ No newline at end of file +Root cause analysis must be completed (`sentry issue explain`) before generating a plan (`sentry issue plan`). diff --git a/docs/src/content/docs/commands/log.md b/docs/src/content/docs/commands/log.md index 58a730f04..0ec6f6ca9 100644 --- a/docs/src/content/docs/commands/log.md +++ b/docs/src/content/docs/commands/log.md @@ -3,47 +3,57 @@ title: log description: Log commands for the Sentry CLI --- -View and stream logs from Sentry projects. +View Sentry logs ## Commands -### `sentry log list` +### `sentry log list <org/project-or-trace-id...>` -List and stream logs from a project. +List logs from a project -```bash -# Auto-detect from DSN or config -sentry log list +**Arguments:** -# Explicit org and project -sentry log list <org>/<project> +| Argument | Description | +|----------|-------------| +| `<org/project-or-trace-id...>` | [<org>/[<project>/]]<trace-id>, <org>/<project>, or <project> (optional) | -# Search for project across all accessible orgs -sentry log list <project> -``` +**Options:** + +| Option | Description | +|--------|-------------| +| `-n, --limit <limit>` | Number of log entries (1-1000) (default: "100") | +| `-q, --query <query>` | Filter query (Sentry search syntax) | +| `-f, --follow <follow>` | Stream logs (optionally specify poll interval in seconds) | +| `-t, --period <period>` | Time period (e.g., "30d", "14d", "24h"). Default: 30d (project mode), 14d (trace mode) | +| `-s, --sort <sort>` | Sort order: "newest" (default) or "oldest" (default: "newest") | +| `--fresh` | Bypass cache, re-detect projects, and fetch fresh data | + +### `sentry log view <args...>` + +View details of one or more log entries **Arguments:** | Argument | Description | |----------|-------------| -| `<org>/<project>` | Explicit organization and project (e.g., `my-org/backend`) | -| `<project>` | Search for project by name across all accessible organizations | +| `<args...>` | [<org>/<project>] <log-id> [<log-id>...] - Target (optional) and one or more log IDs (optional) | **Options:** | Option | Description | |--------|-------------| -| `-n, --limit <n>` | Number of log entries to show (1-1000, default: 100) | -| `-q, --query <query>` | Filter query (Sentry search syntax) | -| `-f, --follow [interval]` | Stream logs in real-time (optional: poll interval in seconds, default: 2) | -| `-t, --period <period>` | Time period (e.g., "30d", "14d", "24h"). Default: 30d. Log retention is 30 days. | -| `-s, --sort <order>` | Sort order: "newest" (default) or "oldest" | -| `--json` | Output as JSON | +| `-w, --web` | Open in browser | +| `-f, --fresh` | Bypass cache, re-detect projects, and fetch fresh data | + +All commands support `--json` for machine-readable output and `--fields` to select specific JSON fields. + +<!-- GENERATED:END --> -**Examples:** +## Examples + +### List logs ```bash -# List last 100 logs (default) sentry log list ``` @@ -57,7 +67,7 @@ TIMESTAMP LEVEL MESSAGE Showing 4 logs. ``` -**Stream logs in real-time:** +### Stream logs in real-time ```bash # Stream with default 2-second poll interval @@ -65,66 +75,12 @@ sentry log list -f # Stream with custom 5-second poll interval sentry log list -f 5 -``` - -**Filter logs:** - -```bash -# Show only error logs -sentry log list -q 'level:error' -# Filter by message content -sentry log list -q 'database' -``` - -**Limit results:** - -```bash -# Show last 50 logs -sentry log list --limit 50 - -# Show last 500 logs -sentry log list -n 500 -``` - -**Combine options:** - -```bash # Stream error logs from a specific project sentry log list my-org/backend -f -q 'level:error' ``` -### `sentry log view` - -View details of a specific log entry. - -```bash -# Auto-detect from DSN or config -sentry log view <log-id> - -# Explicit org and project -sentry log view <org>/<project> <log-id> - -# Search for project across all accessible orgs -sentry log view <project> <log-id> -``` - -**Arguments:** - -| Argument | Description | -|----------|-------------| -| `<log-id>` | The 32-character hexadecimal log ID | -| `<org>/<project>` | Explicit organization and project (e.g., `my-org/backend`) | -| `<project>` | Search for project by name across all accessible organizations | - -**Options:** - -| Option | Description | -|--------|-------------| -| `-w, --web` | Open in browser | -| `--json` | Output as JSON | - -**Example:** +### View a log entry ```bash sentry log view 968c763c740cfda8b6728f27fb9e9b01 @@ -132,7 +88,6 @@ sentry log view 968c763c740cfda8b6728f27fb9e9b01 ``` Log 968c763c740c... -════════════════════ ID: 968c763c740cfda8b6728f27fb9e9b01 Timestamp: 2024-01-20 14:22:05 @@ -141,38 +96,12 @@ Severity: ERROR Message: Database connection timeout after 30s -─── Context ─── - Project: backend Environment: production Release: 1.2.3 -─── SDK ─── - -SDK: sentry.python 1.40.0 - -─── Trace ─── - Trace ID: abc123def456abc123def456abc12345 Span ID: 1234567890abcdef -Link: https://sentry.io/organizations/my-org/explore/traces/abc123... - -─── Source Location ─── - -Function: connect_to_database -File: src/db/connection.py:142 -``` - -**Open in browser:** - -```bash -sentry log view 968c763c740cfda8b6728f27fb9e9b01 -w -``` - -**With explicit project:** - -```bash -sentry log view my-org/backend 968c763c740cfda8b6728f27fb9e9b01 ``` ## Finding Log IDs @@ -185,10 +114,4 @@ Log IDs can be found: ## JSON Output -Use `--json` for machine-readable output: - -```bash -sentry log list --json | jq '.[] | select(.level == "error")' -``` - In streaming mode with `--json`, each log entry is output as a separate JSON object (newline-delimited JSON), making it suitable for piping to other tools. diff --git a/docs/src/content/docs/commands/org.md b/docs/src/content/docs/commands/org.md index eb9a2b76e..54f164008 100644 --- a/docs/src/content/docs/commands/org.md +++ b/docs/src/content/docs/commands/org.md @@ -1,88 +1,53 @@ --- title: org -description: Organization commands for the Sentry CLI +description: Org commands for the Sentry CLI --- -Manage Sentry organizations. +Work with Sentry organizations ## Commands ### `sentry org list` -List all organizations you have access to. - -```bash -sentry org list -``` +List organizations **Options:** | Option | Description | |--------|-------------| -| `--json` | Output as JSON | - -**Example output:** - -``` -SLUG NAME ROLE -my-org My Organization owner -another-org Another Org member -``` - -**JSON output:** - -```bash -sentry org list --json -``` - -```json -[ - { - "slug": "my-org", - "name": "My Organization", - "role": "owner" - } -] -``` +| `-n, --limit <limit>` | Maximum number of organizations to list (default: "30") | +| `-f, --fresh` | Bypass cache, re-detect projects, and fetch fresh data | -### `sentry org view` +### `sentry org view <org>` -View details of a specific organization. - -```bash -sentry org view <org-slug> -``` +View details of an organization **Arguments:** | Argument | Description | |----------|-------------| -| `<org-slug>` | The organization slug | +| `<org>` | Organization slug (optional if auto-detected) (optional) | **Options:** | Option | Description | |--------|-------------| | `-w, --web` | Open in browser | -| `--json` | Output as JSON | +| `-f, --fresh` | Bypass cache, re-detect projects, and fetch fresh data | -**Example:** +All commands support `--json` for machine-readable output and `--fields` to select specific JSON fields. -```bash -sentry org view my-org -``` +<!-- GENERATED:END --> -``` -Organization: My Organization -Slug: my-org -Role: owner -Projects: 5 -Teams: 3 -Members: 12 -``` - -**Open in browser:** +## Examples ```bash +# List organizations +sentry org list + +# View organization details +sentry org view my-org + +# Open in browser sentry org view my-org -w ``` diff --git a/docs/src/content/docs/commands/project.md b/docs/src/content/docs/commands/project.md index e8e37a668..4f414b611 100644 --- a/docs/src/content/docs/commands/project.md +++ b/docs/src/content/docs/commands/project.md @@ -3,91 +3,98 @@ title: project description: Project commands for the Sentry CLI --- -Manage Sentry projects. +Work with Sentry projects ## Commands -### `sentry project list` +### `sentry project create <name> <platform>` -List projects you have access to. +Create a new project -```bash -# List all projects -sentry project list +**Arguments:** -# List projects in a specific organization -sentry project list <org-slug> +| Argument | Description | +|----------|-------------| +| `<name>` | Project name (supports org/name syntax) (optional) | +| `<platform>` | Project platform (e.g., node, python, javascript-nextjs) (optional) | -# Filter by platform -sentry project list --platform javascript -``` +**Options:** + +| Option | Description | +|--------|-------------| +| `-t, --team <team>` | Team to create the project under | +| `-n, --dry-run` | Validate inputs and show what would be created without creating it | + +### `sentry project delete <org/project>` + +Delete a project **Arguments:** | Argument | Description | |----------|-------------| -| `[org-slug]` | Optional organization slug to filter by | +| `<org/project>` | <org>/<project> or <project> (search across orgs) | **Options:** | Option | Description | |--------|-------------| -| `--platform <platform>` | Filter by platform (e.g., javascript, python) | -| `--json` | Output as JSON | +| `-y, --yes` | Skip confirmation prompt | +| `-f, --force` | Force deletion without confirmation | +| `-n, --dry-run` | Validate and show what would be deleted without deleting | -**Example output:** +### `sentry project list <org/project>` -``` -ORG SLUG PLATFORM TEAM -my-org frontend javascript web-team -my-org backend python api-team -my-org mobile-ios cocoa mobile-team -``` +List projects + +**Arguments:** -### `sentry project view` +| Argument | Description | +|----------|-------------| +| `<org/project>` | <org>/ (all projects), <org>/<project>, or <project> (search) (optional) | -View details of a specific project. +**Options:** -```bash -# Auto-detect from DSN or config -sentry project view +| Option | Description | +|--------|-------------| +| `-n, --limit <limit>` | Maximum number of projects to list (default: "30") | +| `-p, --platform <platform>` | Filter by platform (e.g., javascript, python) | +| `-f, --fresh` | Bypass cache, re-detect projects, and fetch fresh data | +| `-c, --cursor <cursor>` | Navigate pages: "next", "prev", "first" (or raw cursor string) | -# Explicit org and project -sentry project view <org>/<project> +### `sentry project view <org/project>` -# Find project across all orgs -sentry project view <project> -``` +View details of a project **Arguments:** | Argument | Description | |----------|-------------| -| `[target]` | Optional: `<org>/<project>`, `<project>`, or omit for auto-detect | +| `<org/project>` | <org>/<project>, <project> (search), or omit for auto-detect (optional) | **Options:** | Option | Description | |--------|-------------| | `-w, --web` | Open in browser | -| `--json` | Output as JSON | +| `-f, --fresh` | Bypass cache, re-detect projects, and fetch fresh data | + +All commands support `--json` for machine-readable output and `--fields` to select specific JSON fields. + +<!-- GENERATED:END --> -**Example:** +## Examples ```bash -sentry project view my-org/frontend -``` +# List all projects +sentry project list my-org/ -``` -Project: frontend -Organization: my-org -Platform: javascript -Team: web-team -DSN: https://abc123@sentry.io/123456 -``` +# Filter by platform +sentry project list my-org/ --platform javascript -**Open in browser:** +# View project details +sentry project view my-org/frontend -```bash +# Open project in browser sentry project view my-org/frontend -w ``` diff --git a/docs/src/content/docs/commands/repo.md b/docs/src/content/docs/commands/repo.md index 324d782fa..cad81d5be 100644 --- a/docs/src/content/docs/commands/repo.md +++ b/docs/src/content/docs/commands/repo.md @@ -3,45 +3,33 @@ title: repo description: Repo commands for the Sentry CLI --- -List repositories connected to a Sentry organization. +Work with Sentry repositories ## Commands -### `sentry repo list` +### `sentry repo list <org/project>` -List repositories in an organization. - -```bash -# Auto-detect from DSN or config -sentry repo list - -# Explicit org -sentry repo list <org>/ - -# Org inferred from project context -sentry repo list <org>/<project> - -# Bare org slug -sentry repo list <org> -``` +List repositories **Arguments:** | Argument | Description | |----------|-------------| -| `<org>/` | Organization slug (trailing slash enables pagination) | -| `<org>/<project>` | Organization and project (lists repos for that org) | -| `<org>` | Bare organization slug | +| `<org/project>` | <org>/ (all projects), <org>/<project>, or <project> (search) (optional) | **Options:** | Option | Description | |--------|-------------| -| `-n, --limit <n>` | Number of repositories to show | -| `-c, --cursor <dir>` | Pagination cursor (`next` or `prev`) | -| `--json` | Output as JSON | +| `-n, --limit <limit>` | Maximum number of repositories to list (default: "30") | +| `-f, --fresh` | Bypass cache, re-detect projects, and fetch fresh data | +| `-c, --cursor <cursor>` | Navigate pages: "next", "prev", "first" (or raw cursor string) | + +All commands support `--json` for machine-readable output and `--fields` to select specific JSON fields. + +<!-- GENERATED:END --> -**Examples:** +## Examples ```bash # List repositories (auto-detect org) diff --git a/docs/src/content/docs/commands/schema.md b/docs/src/content/docs/commands/schema.md index 0b8223332..9475836f8 100644 --- a/docs/src/content/docs/commands/schema.md +++ b/docs/src/content/docs/commands/schema.md @@ -1,42 +1,34 @@ --- title: schema -description: Schema commands for the Sentry CLI +description: Schema command for the Sentry CLI --- -Browse and search the Sentry API schema. Shows available resources, operations, and endpoint details. +Browse the Sentry API schema ## Usage -```bash -# List all API resources -sentry schema - -# Show endpoints for a resource -sentry schema <resource> +### `sentry schema <resource...>` -# Show details for a specific endpoint -sentry schema <resource> <operation> - -# Glob-match resources -sentry schema monitor* -``` +Browse the Sentry API schema **Arguments:** | Argument | Description | |----------|-------------| -| `<resource>` | Resource name (e.g., `issues`, `projects`). Supports glob patterns. | -| `<operation>` | Operation name within a resource (e.g., `list`, `create`) | +| `<resource...>` | Resource name and optional operation (optional) | **Options:** | Option | Description | |--------|-------------| | `--all` | Show all endpoints in a flat list | -| `-q, --search <query>` | Search endpoints by keyword | -| `--json` | Output as JSON | +| `-q, --search <search>` | Search endpoints by keyword | + +All commands support `--json` for machine-readable output and `--fields` to select specific JSON fields. + +<!-- GENERATED:END --> -**Examples:** +## Examples ```bash # List all API resources diff --git a/docs/src/content/docs/commands/sourcemap.md b/docs/src/content/docs/commands/sourcemap.md index f423b7342..2a1c25674 100644 --- a/docs/src/content/docs/commands/sourcemap.md +++ b/docs/src/content/docs/commands/sourcemap.md @@ -3,17 +3,13 @@ title: sourcemap description: Sourcemap commands for the Sentry CLI --- -Inject debug IDs and upload sourcemaps to Sentry for readable stack traces. +Manage sourcemaps ## Commands -### `sentry sourcemap inject` +### `sentry sourcemap inject <directory>` -Inject Sentry debug IDs into JavaScript files and their companion sourcemaps. - -```bash -sentry sourcemap inject <directory> -``` +Inject debug IDs into JavaScript files and sourcemaps **Arguments:** @@ -25,33 +21,12 @@ sentry sourcemap inject <directory> | Option | Description | |--------|-------------| -| `--ext <extensions>` | Comma-separated file extensions to process (default: `.js,.cjs,.mjs`) | +| `--ext <ext>` | Comma-separated file extensions to process (default: .js,.cjs,.mjs) | | `--dry-run` | Show what would be modified without writing | -The injection is idempotent -- files that already have debug IDs are skipped. - -**Examples:** - -```bash -# Inject debug IDs into all JS files in dist/ -sentry sourcemap inject ./dist - -# Preview changes without writing -sentry sourcemap inject ./dist --dry-run +### `sentry sourcemap upload <directory>` -# Only process specific extensions -sentry sourcemap inject ./build --ext .js,.mjs -``` - -### `sentry sourcemap upload` - -Upload JavaScript sourcemaps to Sentry using debug-ID-based matching. - -```bash -sentry sourcemap upload <directory> -``` - -Automatically injects debug IDs into any files that don't already have them. Org and project are auto-detected from DSN, env vars, or config defaults. +Upload sourcemaps to Sentry **Arguments:** @@ -63,10 +38,29 @@ Automatically injects debug IDs into any files that don't already have them. Org | Option | Description | |--------|-------------| -| `--release <version>` | Release version to associate with the upload | -| `--url-prefix <prefix>` | URL prefix for uploaded files (default: `~/`) | +| `--release <release>` | Release version to associate with the upload | +| `--url-prefix <url-prefix>` | URL prefix for uploaded files (default: ~/) | + +All commands support `--json` for machine-readable output and `--fields` to select specific JSON fields. + +<!-- GENERATED:END --> + +## Examples + +### Inject debug IDs + +```bash +# Inject debug IDs into all JS files in dist/ +sentry sourcemap inject ./dist + +# Preview changes without writing +sentry sourcemap inject ./dist --dry-run + +# Only process specific extensions +sentry sourcemap inject ./build --ext .js,.mjs +``` -**Examples:** +### Upload sourcemaps ```bash # Upload sourcemaps from dist/ diff --git a/docs/src/content/docs/commands/span.md b/docs/src/content/docs/commands/span.md index 5e004faa6..916b91fa3 100644 --- a/docs/src/content/docs/commands/span.md +++ b/docs/src/content/docs/commands/span.md @@ -3,46 +3,55 @@ title: span description: Span commands for the Sentry CLI --- -List and inspect spans from Sentry projects or within specific traces. +List and view spans in projects or traces ## Commands -### `sentry span list` +### `sentry span list <org/project/trace-id...>` -List spans in a project or within a specific trace. +List spans in a project or trace -```bash -# Project mode — list spans across the project -sentry span list -sentry span list <org>/<project> -sentry span list <project> +**Arguments:** -# Trace mode — list spans within a specific trace -sentry span list <trace-id> -sentry span list <org>/<project>/<trace-id> -sentry span list <project> <trace-id> -``` +| Argument | Description | +|----------|-------------| +| `<org/project/trace-id...>` | [<org>/<project>] or [<org>/<project>/]<trace-id> (optional) | + +**Options:** + +| Option | Description | +|--------|-------------| +| `-n, --limit <limit>` | Number of spans (<=1000) (default: "25") | +| `-q, --query <query>` | Filter spans (e.g., "op:db", "duration:>100ms", "project:backend") | +| `-s, --sort <sort>` | Sort order: date, duration (default: "date") | +| `-t, --period <period>` | Time period (e.g., "1h", "24h", "7d", "30d") (default: "7d") | +| `-f, --fresh` | Bypass cache, re-detect projects, and fetch fresh data | +| `-c, --cursor <cursor>` | Navigate pages: "next", "prev", "first" (or raw cursor string) | + +### `sentry span view <trace-id/span-id...>` + +View details of specific spans **Arguments:** | Argument | Description | |----------|-------------| -| `<org>/<project>` | Explicit organization and project (project mode) | -| `<project>` | Search for project by name across all accessible organizations | -| `<trace-id>` | 32-character hex trace ID to list spans within (trace mode) | +| `<trace-id/span-id...>` | [<org>/<project>/]<trace-id> <span-id> [<span-id>...] - Trace ID and one or more span IDs (optional) | **Options:** | Option | Description | |--------|-------------| -| `-n, --limit <n>` | Number of spans (max 1000, default: 25) | -| `-q, --query <query>` | Filter spans (e.g., `"op:db"`, `"duration:>100ms"`) | -| `-s, --sort <field>` | Sort order: `date`, `duration` (default: `date`) | -| `--period <period>` | Time period (e.g., `24h`, `7d`; default: `7d`) | -| `-c, --cursor <dir>` | Pagination cursor (`next` or `prev`) | -| `--json` | Output as JSON | +| `--spans <spans>` | Span tree depth limit (number, "all" for unlimited, "no" to disable) (default: "3") | +| `-f, --fresh` | Bypass cache, re-detect projects, and fetch fresh data | + +All commands support `--json` for machine-readable output and `--fields` to select specific JSON fields. + +<!-- GENERATED:END --> + +## Examples -**Examples:** +### List spans ```bash # List recent spans in the current project @@ -56,36 +65,9 @@ sentry span list -q "duration:>100ms" --period 24h # List spans within a specific trace sentry span list abc123def456abc123def456abc12345 - -# Paginate through results -sentry span list -c next -``` - -### `sentry span view` - -View detailed information about one or more spans within a trace. - -```bash -sentry span view <trace-id> <span-id> -sentry span view <org>/<project>/<trace-id> <span-id> -sentry span view <trace-id> <span-id> <span-id> ``` -**Arguments:** - -| Argument | Description | -|----------|-------------| -| `<trace-id>` | The 32-character hexadecimal trace ID (optionally prefixed with `<org>/<project>/`) | -| `<span-id>` | One or more 16-character hexadecimal span IDs | - -**Options:** - -| Option | Description | -|--------|-------------| -| `--spans <depth>` | Span tree depth limit (number, `all` for unlimited, `no` to disable) | -| `--json` | Output as JSON | - -**Examples:** +### View spans ```bash # View a single span diff --git a/docs/src/content/docs/commands/team.md b/docs/src/content/docs/commands/team.md index bf5627932..3e39a254a 100644 --- a/docs/src/content/docs/commands/team.md +++ b/docs/src/content/docs/commands/team.md @@ -3,60 +3,41 @@ title: team description: Team commands for the Sentry CLI --- -Manage Sentry teams. +Work with Sentry teams ## Commands -### `sentry team list` +### `sentry team list <org/project>` -List teams in an organization. - -```bash -# Auto-detect organization or list all -sentry team list - -# List teams in a specific organization -sentry team list <org-slug> - -# Limit results -sentry team list --limit 10 -``` +List teams **Arguments:** | Argument | Description | |----------|-------------| -| `[org-slug]` | Optional organization slug to filter by | +| `<org/project>` | <org>/ (all projects), <org>/<project>, or <project> (search) (optional) | **Options:** | Option | Description | |--------|-------------| -| `-n, --limit <number>` | Maximum number of teams to list (default: 30) | -| `--json` | Output as JSON | +| `-n, --limit <limit>` | Maximum number of teams to list (default: "30") | +| `-f, --fresh` | Bypass cache, re-detect projects, and fetch fresh data | +| `-c, --cursor <cursor>` | Navigate pages: "next", "prev", "first" (or raw cursor string) | -**Example output:** +All commands support `--json` for machine-readable output and `--fields` to select specific JSON fields. -``` -ORG SLUG NAME MEMBERS -my-org backend Backend Team 8 -my-org frontend Frontend Team 5 -my-org mobile Mobile Team 3 -``` +<!-- GENERATED:END --> -**JSON output:** +## Examples ```bash -sentry team list --json -``` +# List teams +sentry team list my-org/ -```json -[ - { - "id": "100", - "slug": "backend", - "name": "Backend Team", - "memberCount": 8 - } -] +# Paginate through teams +sentry team list my-org/ -c next + +# Output as JSON +sentry team list --json ``` diff --git a/docs/src/content/docs/commands/trace.md b/docs/src/content/docs/commands/trace.md index 5c673b6cd..767b31041 100644 --- a/docs/src/content/docs/commands/trace.md +++ b/docs/src/content/docs/commands/trace.md @@ -3,132 +3,106 @@ title: trace description: Trace commands for the Sentry CLI --- -Inspect and browse distributed traces from Sentry projects. +View distributed traces ## Commands -### `sentry trace list` +### `sentry trace list <org/project>` -List recent traces in a project. - -```bash -# Auto-detect from DSN or config -sentry trace list - -# Explicit org and project -sentry trace list <org>/<project> - -# Search for project across all accessible orgs -sentry trace list <project> -``` +List recent traces in a project **Arguments:** | Argument | Description | |----------|-------------| -| `<org>/<project>` | Explicit organization and project (e.g., `my-org/backend`) | -| `<project>` | Search for project by name across all accessible organizations | +| `<org/project>` | <org>/<project> or <project> (search) (optional) | **Options:** | Option | Description | |--------|-------------| -| `-n, --limit <n>` | Number of traces to show (1-1000, default: 20) | +| `-n, --limit <limit>` | Number of traces (1-1000) (default: "20") | | `-q, --query <query>` | Search query (Sentry search syntax) | -| `-s, --sort <field>` | Sort by: `date`, `duration` (default: `date`) | -| `--period <period>` | Time period (e.g., `24h`, `7d`, `14d`; default: `7d`) | -| `-c, --cursor <dir>` | Pagination cursor (`next` or `prev`) | -| `--json` | Output as JSON | - -**Examples:** - -```bash -# List last 20 traces (default) -sentry trace list +| `-s, --sort <sort>` | Sort by: date, duration (default: "date") | +| `-t, --period <period>` | Time period (e.g., "1h", "24h", "7d", "30d") (default: "7d") | +| `-f, --fresh` | Bypass cache, re-detect projects, and fetch fresh data | +| `-c, --cursor <cursor>` | Navigate pages: "next", "prev", "first" (or raw cursor string) | -# Sort by slowest first -sentry trace list --sort duration +### `sentry trace view <org/project/trace-id...>` -# Filter by transaction name, last 24 hours -sentry trace list -q "transaction:GET /api/users" --period 24h +View details of a specific trace -# Paginate through results -sentry trace list my-org/backend -c next -``` +**Arguments:** -### `sentry trace view` +| Argument | Description | +|----------|-------------| +| `<org/project/trace-id...>` | [<org>/<project>/]<trace-id> - Target (optional) and trace ID (required) (optional) | -View details of a specific trace, including a span tree. +**Options:** -```bash -# Auto-detect org from DSN or config -sentry trace view <trace-id> +| Option | Description | +|--------|-------------| +| `-w, --web` | Open in browser | +| `--spans <spans>` | Span tree depth limit (number, "all" for unlimited, "no" to disable) (default: "3") | +| `-f, --fresh` | Bypass cache, re-detect projects, and fetch fresh data | -# Explicit org and project -sentry trace view <org>/<project>/<trace-id> +### `sentry trace logs <org/trace-id...>` -# Search for project across all accessible orgs -sentry trace view <project> <trace-id> -``` +View logs associated with a trace **Arguments:** | Argument | Description | |----------|-------------| -| `<trace-id>` | The 32-character hexadecimal trace ID | -| `<org>/<project>/<trace-id>` | Explicit organization, project, and trace ID | +| `<org/trace-id...>` | [<org>/]<trace-id> - Optional org and required trace ID (optional) | **Options:** | Option | Description | |--------|-------------| -| `-w, --web` | Open in browser | -| `--spans <depth>` | Span tree depth limit (number, `all` for unlimited, `no` to disable) | -| `--json` | Output as JSON | +| `-w, --web` | Open trace in browser | +| `-t, --period <period>` | Time period to search (e.g., "14d", "7d", "24h"). Default: 14d (default: "14d") | +| `-n, --limit <limit>` | Number of log entries (<=1000) (default: "100") | +| `-q, --query <query>` | Additional filter query (Sentry search syntax) | +| `-s, --sort <sort>` | Sort order: "newest" (default) or "oldest" (default: "newest") | +| `-f, --fresh` | Bypass cache, re-detect projects, and fetch fresh data | -**Examples:** +All commands support `--json` for machine-readable output and `--fields` to select specific JSON fields. -```bash -# View trace details with span tree -sentry trace view abc123def456abc123def456abc12345 +<!-- GENERATED:END --> -# Open trace in browser -sentry trace view abc123def456abc123def456abc12345 -w +## Examples -# Auto-recover from an issue short ID -sentry trace view PROJ-123 -``` +### List traces -### `sentry trace logs` +```bash +# List last 20 traces (default) +sentry trace list -View logs associated with a specific trace. +# Sort by slowest first +sentry trace list --sort duration -```bash -# Auto-detect org -sentry trace logs <trace-id> +# Filter by transaction name, last 24 hours +sentry trace list -q "transaction:GET /api/users" --period 24h -# Explicit org -sentry trace logs <org>/<trace-id> +# Paginate through results +sentry trace list my-org/backend -c next ``` -**Arguments:** +### View a trace -| Argument | Description | -|----------|-------------| -| `<trace-id>` | The 32-character hexadecimal trace ID | -| `<org>/<trace-id>` | Explicit organization and trace ID | +```bash +# View trace details with span tree +sentry trace view abc123def456abc123def456abc12345 -**Options:** +# Open trace in browser +sentry trace view abc123def456abc123def456abc12345 -w -| Option | Description | -|--------|-------------| -| `-w, --web` | Open trace in browser | -| `-t, --period <period>` | Time period to search (e.g., `14d`, `7d`, `24h`; default: `14d`) | -| `-n, --limit <n>` | Number of log entries (max 1000, default: 100) | -| `-q, --query <query>` | Additional filter query (Sentry search syntax) | -| `--json` | Output as JSON | +# Auto-recover from an issue short ID +sentry trace view PROJ-123 +``` -**Examples:** +### View trace logs ```bash # View logs for a trace diff --git a/docs/src/content/docs/commands/trial.md b/docs/src/content/docs/commands/trial.md index 45e9a4d58..b658354e6 100644 --- a/docs/src/content/docs/commands/trial.md +++ b/docs/src/content/docs/commands/trial.md @@ -3,68 +3,41 @@ title: trial description: Trial commands for the Sentry CLI --- -View and start product trials for a Sentry organization. +Manage product trials ## Commands -### `sentry trial list` +### `sentry trial list <org>` -List product trials for an organization, including available, active, and expired trials. - -```bash -# Auto-detect org -sentry trial list - -# Explicit org -sentry trial list <org> -``` +List product trials **Arguments:** | Argument | Description | |----------|-------------| -| `<org>` | Organization slug (auto-detected if omitted) | - -**Options:** - -| Option | Description | -|--------|-------------| -| `--json` | Output as JSON | - -**Examples:** - -```bash -# List all trials for the current org -sentry trial list - -# List trials for a specific org -sentry trial list my-org - -# Machine-readable output -sentry trial list --json -``` +| `<org>` | Organization slug (auto-detected if omitted) (optional) | -### `sentry trial start` +### `sentry trial start <name> <org>` -Start a product trial for an organization. - -```bash -sentry trial start <name> -sentry trial start <name> <org> -``` +Start a product trial **Arguments:** | Argument | Description | |----------|-------------| -| `<name>` | Trial name (e.g., `seer`, `replays`, `profiling`, `plan`) | -| `<org>` | Organization slug (auto-detected if omitted) | +| `<name>` | Trial name (seer, replays, performance, spans, profiling, logs, monitors, uptime, plan) | +| `<org>` | Organization slug (auto-detected if omitted) (optional) | + +All commands support `--json` for machine-readable output and `--fields` to select specific JSON fields. -Use `plan` to start a Business plan trial (opens the billing page in a browser). +<!-- GENERATED:END --> -**Examples:** +## Examples ```bash +# List all trials for the current org +sentry trial list + # Start a Seer trial sentry trial start seer diff --git a/package.json b/package.json index f167c28a4..d3d86c6fa 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,9 @@ "test:init-eval": "bun test test/init-eval --timeout 600000 --concurrency 6", "generate:skill": "bun run script/generate-skill.ts", "generate:schema": "bun run script/generate-api-schema.ts", + "generate:command-docs": "bun run script/generate-command-docs.ts", "check:skill": "bun run script/check-skill.ts", + "check:command-docs": "bun run script/check-command-docs.ts", "check:deps": "bun run script/check-no-deps.ts", "check:errors": "bun run script/check-error-patterns.ts" }, diff --git a/plugins/sentry-cli/skills/sentry-cli/references/api.md b/plugins/sentry-cli/skills/sentry-cli/references/api.md index be4783f15..4694e2a72 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/api.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/api.md @@ -26,47 +26,4 @@ Make an authenticated API request - `--verbose - Include full HTTP request and response in the output` - `-n, --dry-run - Show the resolved request without sending it` -**Examples:** - -```bash -sentry api <endpoint> [options] - -# List organizations -sentry api /organizations/ - -# Get a specific organization -sentry api /organizations/my-org/ - -# Get project details -sentry api /projects/my-org/my-project/ - -# Create a new project -sentry api /teams/my-org/my-team/projects/ \ - --method POST \ - --field name="New Project" \ - --field platform=javascript - -# Update an issue status -sentry api /issues/123456789/ \ - --method PUT \ - --field status=resolved - -# Assign an issue -sentry api /issues/123456789/ \ - --method PUT \ - --field assignedTo="user@example.com" - -# Delete a project -sentry api /projects/my-org/my-project/ \ - --method DELETE - -sentry api /organizations/ \ - --header "X-Custom-Header:value" - -sentry api /organizations/ --verbose - -# Get all issues (automatically follows pagination) -sentry api /projects/my-org/my-project/issues/ --paginate -``` - All commands also support `--json`, `--fields`, `--help`, `--log-level`, and `--verbose` flags. diff --git a/plugins/sentry-cli/skills/sentry-cli/references/auth.md b/plugins/sentry-cli/skills/sentry-cli/references/auth.md index d8d26856a..94cb91460 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/auth.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/auth.md @@ -20,30 +20,10 @@ Authenticate with Sentry - `--timeout <value> - Timeout for OAuth flow in seconds (default: 900) - (default: "900")` - `--force - Re-authenticate without prompting` -**Examples:** - -```bash -# OAuth device flow (recommended) -sentry auth login - -# Using an API token -sentry auth login --token YOUR_TOKEN - -SENTRY_URL=https://sentry.example.com SENTRY_CLIENT_ID=your-client-id sentry auth login - -SENTRY_URL=https://sentry.example.com sentry auth login --token YOUR_TOKEN -``` - ### `sentry auth logout` Log out of Sentry -**Examples:** - -```bash -sentry auth logout -``` - ### `sentry auth refresh` Refresh your authentication token @@ -51,12 +31,6 @@ Refresh your authentication token **Flags:** - `--force - Force refresh even if token is still valid` -**Examples:** - -```bash -sentry auth refresh -``` - ### `sentry auth status` View authentication status @@ -65,12 +39,6 @@ View authentication status - `--show-token - Show the stored token (masked by default)` - `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` -**Examples:** - -```bash -sentry auth status -``` - ### `sentry auth token` Print the stored authentication token @@ -82,4 +50,23 @@ Show the currently authenticated user **Flags:** - `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` +**Examples:** + +```bash +# OAuth login (recommended) +sentry auth login + +# Login with an API token +sentry auth login --token YOUR_SENTRY_API_TOKEN + +# Check auth status +sentry auth status + +# Show the raw token +sentry auth status --show-token + +# View current user +sentry auth whoami +``` + All commands also support `--json`, `--fields`, `--help`, `--log-level`, and `--verbose` flags. diff --git a/plugins/sentry-cli/skills/sentry-cli/references/dashboards.md b/plugins/sentry-cli/skills/sentry-cli/references/dashboards.md index df13ab4e2..6e42726ab 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/dashboards.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/dashboards.md @@ -21,23 +21,6 @@ List dashboards - `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` - `-c, --cursor <value> - Navigate pages: "next", "prev", "first" (or raw cursor string)` -**Examples:** - -```bash -# Auto-detect org from config -sentry dashboard list - -# Explicit org -sentry dashboard list my-org/ - -# Explicit org and project -sentry dashboard list my-org/my-project - -sentry dashboard list - -sentry dashboard list -w -``` - ### `sentry dashboard view <args...>` View a dashboard @@ -48,46 +31,10 @@ View a dashboard - `-r, --refresh <value> - Auto-refresh interval in seconds (default: 60, min: 10)` - `-t, --period <value> - Time period override (e.g., "24h", "7d", "14d")` -**Examples:** - -```bash -# By numeric ID -sentry dashboard view <id> - -# By title -sentry dashboard view '<title>' - -# With explicit org -sentry dashboard view <org>/ <id> - -sentry dashboard view 12345 - -sentry dashboard view 'Frontend Performance' - -sentry dashboard view 12345 -w -``` - ### `sentry dashboard create <args...>` Create a dashboard -**Examples:** - -```bash -# Auto-detect org -sentry dashboard create '<title>' - -# Explicit org -sentry dashboard create <org>/ '<title>' - -# Explicit org and project -sentry dashboard create <org>/<project> '<title>' - -sentry dashboard create 'Frontend Performance' - -sentry dashboard widget add 'Frontend Performance' "Error Count" --display big_number --query count -``` - ### `sentry dashboard widget add <args...>` Add a widget to a dashboard diff --git a/plugins/sentry-cli/skills/sentry-cli/references/events.md b/plugins/sentry-cli/skills/sentry-cli/references/events.md index b17ae2a96..3cf9d6086 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/events.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/events.md @@ -20,14 +20,4 @@ View details of a specific event - `--spans <value> - Span tree depth limit (number, "all" for unlimited, "no" to disable) - (default: "3")` - `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` -**Examples:** - -```bash -sentry event view <event-id> - -sentry event view abc123def456 - -sentry event view abc123def456 -w -``` - All commands also support `--json`, `--fields`, `--help`, `--log-level`, and `--verbose` flags. diff --git a/plugins/sentry-cli/skills/sentry-cli/references/issues.md b/plugins/sentry-cli/skills/sentry-cli/references/issues.md index 750878222..5b8bbfe99 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/issues.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/issues.md @@ -48,42 +48,6 @@ List issues in a project | `isUnhandled` | boolean | Whether the issue is unhandled | | `seerFixabilityScore` | number \| null | Seer AI fixability score (0-1) | -**Examples:** - -```bash -# Explicit org and project -sentry issue list <org>/<project> - -# All projects in an organization -sentry issue list <org>/ - -# Search for project across all accessible orgs -sentry issue list <project> - -# Auto-detect from DSN or config -sentry issue list - -# List issues in a specific project -sentry issue list my-org/frontend - -sentry issue list my-org/ - -sentry issue list frontend - -sentry issue list my-org/frontend --query "TypeError" - -sentry issue list my-org/frontend --sort freq --limit 20 - -# Show only unresolved issues -sentry issue list my-org/frontend --query "is:unresolved" - -# Show resolved issues -sentry issue list my-org/frontend --query "is:resolved" - -# Combine with other search terms -sentry issue list my-org/frontend --query "is:unresolved TypeError" -``` - ### `sentry issue explain <issue>` Analyze an issue's root cause using Seer AI @@ -92,24 +56,6 @@ Analyze an issue's root cause using Seer AI - `--force - Force new analysis even if one exists` - `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` -**Examples:** - -```bash -sentry issue explain <issue-id> - -# By numeric issue ID -sentry issue explain 123456789 - -# By short ID with org prefix -sentry issue explain my-org/MYPROJECT-ABC - -# By project-suffix format -sentry issue explain myproject-G - -# Force a fresh analysis -sentry issue explain 123456789 --force -``` - ### `sentry issue plan <issue>` Generate a solution plan using Seer AI @@ -119,24 +65,6 @@ Generate a solution plan using Seer AI - `--force - Force new plan even if one exists` - `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` -**Examples:** - -```bash -sentry issue plan <issue-id> - -# After running explain, create a plan -sentry issue plan 123456789 - -# Specify which root cause to plan for (if multiple were found) -sentry issue plan 123456789 --cause 0 - -# By short ID with org prefix -sentry issue plan my-org/MYPROJECT-ABC --cause 1 - -# By project-suffix format -sentry issue plan myproject-G --cause 0 -``` - ### `sentry issue view <issue>` View details of a specific issue @@ -146,18 +74,4 @@ View details of a specific issue - `--spans <value> - Span tree depth limit (number, "all" for unlimited, "no" to disable) - (default: "3")` - `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` -**Examples:** - -```bash -# By issue ID -sentry issue view <issue-id> - -# By short ID -sentry issue view <short-id> - -sentry issue view FRONT-ABC - -sentry issue view FRONT-ABC -w -``` - All commands also support `--json`, `--fields`, `--help`, `--log-level`, and `--verbose` flags. diff --git a/plugins/sentry-cli/skills/sentry-cli/references/logs.md b/plugins/sentry-cli/skills/sentry-cli/references/logs.md index 4f43f1c59..409ba87dd 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/logs.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/logs.md @@ -34,43 +34,6 @@ List logs from a project | `severity` | string \| null | Severity level (error, warning, info, debug) | | `trace` | string \| null | Trace ID for correlation | -**Examples:** - -```bash -# Auto-detect from DSN or config -sentry log list - -# Explicit org and project -sentry log list <org>/<project> - -# Search for project across all accessible orgs -sentry log list <project> - -# List last 100 logs (default) -sentry log list - -# Stream with default 2-second poll interval -sentry log list -f - -# Stream with custom 5-second poll interval -sentry log list -f 5 - -# Show only error logs -sentry log list -q 'level:error' - -# Filter by message content -sentry log list -q 'database' - -# Show last 50 logs -sentry log list --limit 50 - -# Show last 500 logs -sentry log list -n 500 - -# Stream error logs from a specific project -sentry log list my-org/backend -f -q 'level:error' -``` - ### `sentry log view <args...>` View details of one or more log entries @@ -79,25 +42,4 @@ View details of one or more log entries - `-w, --web - Open in browser` - `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` -**Examples:** - -```bash -# Auto-detect from DSN or config -sentry log view <log-id> - -# Explicit org and project -sentry log view <org>/<project> <log-id> - -# Search for project across all accessible orgs -sentry log view <project> <log-id> - -sentry log view 968c763c740cfda8b6728f27fb9e9b01 - -sentry log view 968c763c740cfda8b6728f27fb9e9b01 -w - -sentry log view my-org/backend 968c763c740cfda8b6728f27fb9e9b01 - -sentry log list --json | jq '.[] | select(.level == "error")' -``` - All commands also support `--json`, `--fields`, `--help`, `--log-level`, and `--verbose` flags. diff --git a/plugins/sentry-cli/skills/sentry-cli/references/organizations.md b/plugins/sentry-cli/skills/sentry-cli/references/organizations.md index 7bf445aed..3ea8cdfd1 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/organizations.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/organizations.md @@ -19,14 +19,6 @@ List organizations - `-n, --limit <value> - Maximum number of organizations to list - (default: "30")` - `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` -**Examples:** - -```bash -sentry org list - -sentry org list --json -``` - ### `sentry org view <org>` View details of an organization @@ -35,14 +27,4 @@ View details of an organization - `-w, --web - Open in browser` - `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` -**Examples:** - -```bash -sentry org view <org-slug> - -sentry org view my-org - -sentry org view my-org -w -``` - All commands also support `--json`, `--fields`, `--help`, `--log-level`, and `--verbose` flags. diff --git a/plugins/sentry-cli/skills/sentry-cli/references/projects.md b/plugins/sentry-cli/skills/sentry-cli/references/projects.md index 3bce54703..23e643c16 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/projects.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/projects.md @@ -38,19 +38,6 @@ List projects - `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` - `-c, --cursor <value> - Navigate pages: "next", "prev", "first" (or raw cursor string)` -**Examples:** - -```bash -# List all projects -sentry project list - -# List projects in a specific organization -sentry project list <org-slug> - -# Filter by platform -sentry project list --platform javascript -``` - ### `sentry project view <org/project>` View details of a project @@ -59,21 +46,4 @@ View details of a project - `-w, --web - Open in browser` - `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` -**Examples:** - -```bash -# Auto-detect from DSN or config -sentry project view - -# Explicit org and project -sentry project view <org>/<project> - -# Find project across all orgs -sentry project view <project> - -sentry project view my-org/frontend - -sentry project view my-org/frontend -w -``` - All commands also support `--json`, `--fields`, `--help`, `--log-level`, and `--verbose` flags. diff --git a/plugins/sentry-cli/skills/sentry-cli/references/teams.md b/plugins/sentry-cli/skills/sentry-cli/references/teams.md index 10acb32d8..05d1deb51 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/teams.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/teams.md @@ -57,19 +57,4 @@ List teams | `teamRole` | string \| null | Your role in the team | | `memberCount` | number | Number of members | -**Examples:** - -```bash -# Auto-detect organization or list all -sentry team list - -# List teams in a specific organization -sentry team list <org-slug> - -# Limit results -sentry team list --limit 10 - -sentry team list --json -``` - All commands also support `--json`, `--fields`, `--help`, `--log-level`, and `--verbose` flags. diff --git a/script/check-command-docs.ts b/script/check-command-docs.ts new file mode 100644 index 000000000..97451b856 --- /dev/null +++ b/script/check-command-docs.ts @@ -0,0 +1,93 @@ +#!/usr/bin/env bun +/** + * Check Command Documentation for Staleness + * + * Compares the auto-generated reference sections of command doc pages + * against freshly generated content. Only the portion above the + * GENERATED:END marker is checked — hand-written custom content below + * the marker is not compared. + * + * Usage: + * bun run script/check-command-docs.ts + * + * Exit codes: + * 0 - All command docs are up to date + * 1 - One or more doc pages have stale reference sections + */ + +import { $ } from "bun"; + +const DOCS_DIR = "docs/src/content/docs/commands"; +const MARKER = "<!-- GENERATED:END -->"; + +/** + * Extract the auto-generated portion of a file (everything up to and + * including the GENERATED:END marker). Returns the full content if + * no marker is found. + */ +function extractGeneratedPortion(content: string): string { + const markerIndex = content.indexOf(MARKER); + if (markerIndex === -1) { + return content; + } + return content.slice(0, markerIndex + MARKER.length); +} + +/** + * Read all command doc files and extract their generated portions. + * Returns a map of filename → generated content. + */ +async function readGeneratedPortions(): Promise<Map<string, string>> { + const files = new Map<string, string>(); + const glob = new Bun.Glob("*.md"); + + for await (const filename of glob.scan({ cwd: DOCS_DIR })) { + const file = Bun.file(`${DOCS_DIR}/${filename}`); + const content = await file.text(); + files.set(filename, extractGeneratedPortion(content)); + } + + return files; +} + +// Snapshot committed generated portions +const committedPortions = await readGeneratedPortions(); + +// Regenerate (preserves custom content below markers) +await $`bun run script/generate-command-docs.ts`.quiet(); + +// Read freshly generated portions +const newPortions = await readGeneratedPortions(); + +// Compare +const staleFiles: string[] = []; + +for (const [filename, newContent] of newPortions) { + const committedContent = committedPortions.get(filename); + if (committedContent !== newContent) { + staleFiles.push(filename); + } +} + +// Check for files that should exist but don't (committed but not generated) +for (const filename of committedPortions.keys()) { + if (!newPortions.has(filename)) { + staleFiles.push(`${filename} (unexpected — not generated)`); + } +} + +if (staleFiles.length === 0) { + console.log("✓ All command docs are up to date"); + process.exit(0); +} + +console.error("✗ Command docs are out of date:"); +for (const file of staleFiles) { + console.error(` - ${file}`); +} +console.error(""); +console.error( + "Run 'bun run generate:command-docs' locally and commit the changes." +); + +process.exit(1); diff --git a/script/generate-command-docs.ts b/script/generate-command-docs.ts new file mode 100644 index 000000000..cc4466bcc --- /dev/null +++ b/script/generate-command-docs.ts @@ -0,0 +1,421 @@ +#!/usr/bin/env bun +/** + * Generate Command Reference Documentation from Stricli Command Metadata + * + * Introspects the CLI's route tree to generate accurate command reference + * pages for the documentation website. Flags, arguments, and aliases are + * extracted directly from source code, preventing documentation drift. + * + * Each page has two sections separated by a marker comment: + * 1. Auto-generated reference (above marker) — flags, args, descriptions + * 2. Hand-written custom content (below marker) — examples, guides, tips + * + * Custom content below the marker is preserved across regeneration. + * + * Usage: + * bun run script/generate-command-docs.ts + * + * Output: + * docs/src/content/docs/commands/{route}.md (one per visible route) + * docs/src/content/docs/commands/index.md (commands overview table) + */ + +import { rmSync } from "node:fs"; +import { routes } from "../src/app.js"; +import type { + CommandInfo, + FlagInfo, + PositionalInfo, + RouteInfo, + RouteMap, +} from "../src/lib/introspect.js"; +import { + buildCommandInfo, + extractRouteGroupCommands, + isCommand, + isRouteMap, +} from "../src/lib/introspect.js"; + +const DOCS_DIR = "docs/src/content/docs/commands"; +const INDEX_PATH = `${DOCS_DIR}/index.md`; + +/** + * Marker comment separating auto-generated reference content from + * hand-written custom content. Everything above this line is regenerated; + * everything below is preserved. + */ +const GENERATED_END_MARKER = "<!-- GENERATED:END -->"; + +/** + * Flag names that are auto-injected by the buildCommand wrapper and + * documented in the global footer rather than per-command. + */ +const GLOBAL_FLAG_NAMES = new Set([ + "json", + "fields", + "help", + "helpAll", + "log-level", +]); + +/** Routes that don't need their own documentation page */ +const SKIP_ROUTES = new Set(["help"]); + +// --------------------------------------------------------------------------- +// Route Introspection +// --------------------------------------------------------------------------- + +/** Walk the route tree and extract metadata for all visible routes */ +function extractVisibleRoutes(topRouteMap: RouteMap): RouteInfo[] { + const result: RouteInfo[] = []; + for (const entry of topRouteMap.getAllEntries()) { + if (entry.hidden || SKIP_ROUTES.has(entry.name.original)) { + continue; + } + const routeName = entry.name.original; + const target = entry.target; + if (isRouteMap(target)) { + result.push({ + name: routeName, + brief: target.brief, + commands: extractRouteGroupCommands(target, routeName), + }); + } else if (isCommand(target)) { + const path = `sentry ${routeName}`; + result.push({ + name: routeName, + brief: target.brief, + commands: [buildCommandInfo(target, path)], + }); + } + } + return result; +} + +// --------------------------------------------------------------------------- +// Markdown Formatting +// --------------------------------------------------------------------------- + +/** + * Get visible, non-global flags for a command. + * Excludes hidden flags and globally-injected flags (--json, --fields, etc.). + */ +function getVisibleFlags(cmd: CommandInfo): FlagInfo[] { + return cmd.flags.filter((f) => !(f.hidden || GLOBAL_FLAG_NAMES.has(f.name))); +} + +/** + * Format a flag as a table row: `| -q, --query <query> | Search query ... |` + * + * Uses the flag name as the value placeholder for readability + * (e.g., `--limit <limit>` instead of `--limit <value>`). + */ +function formatFlagRow( + flag: FlagInfo, + aliases: Record<string, string> +): string { + const alias = Object.entries(aliases).find(([, v]) => v === flag.name)?.[0]; + + let syntax = `--${flag.name}`; + if (alias) { + syntax = `-${alias}, ${syntax}`; + } + if ((flag.kind === "parsed" || flag.kind === "enum") && !flag.variadic) { + syntax += ` <${flag.name}>`; + } else if (flag.variadic) { + syntax += ` <${flag.name}>...`; + } + + let desc = flag.brief; + // Only append default if the brief doesn't already mention it + if ( + flag.default !== undefined && + flag.kind !== "boolean" && + !desc.includes("default:") + ) { + desc += ` (default: ${JSON.stringify(flag.default)})`; + } + + return `| \`${syntax}\` | ${desc} |`; +} + +/** + * Escape angle brackets in text so they render as literal `<` / `>` + * in HTML output rather than being interpreted as HTML tags. + */ +function escapeAngleBrackets(text: string): string { + return text.replace(/</g, "<").replace(/>/g, ">"); +} + +/** Format positional arguments as a markdown table */ +function formatPositionalsTable(positionals: PositionalInfo[]): string { + if (positionals.length === 0) { + return ""; + } + + const lines: string[] = []; + lines.push("**Arguments:**"); + lines.push(""); + lines.push("| Argument | Description |"); + lines.push("|----------|-------------|"); + for (const p of positionals) { + const placeholder = `\`<${p.placeholder}>\``; + const suffix = p.optional ? " (optional)" : ""; + lines.push(`| ${placeholder} | ${escapeAngleBrackets(p.brief)}${suffix} |`); + } + return lines.join("\n"); +} + +/** Format flags as a markdown options table */ +function formatFlagsTable( + flags: FlagInfo[], + aliases: Record<string, string> +): string { + if (flags.length === 0) { + return ""; + } + + const lines: string[] = []; + lines.push("**Options:**"); + lines.push(""); + lines.push("| Option | Description |"); + lines.push("|--------|-------------|"); + for (const flag of flags) { + lines.push(formatFlagRow(flag, aliases)); + } + return lines.join("\n"); +} + +// --------------------------------------------------------------------------- +// Page Generation +// --------------------------------------------------------------------------- + +/** Generate the auto-generated reference section for a single command */ +function generateCommandSection(cmd: CommandInfo): string { + const lines: string[] = []; + + // Command heading + const signature = cmd.positional ? `${cmd.path} ${cmd.positional}` : cmd.path; + lines.push(`### \`${signature}\``); + lines.push(""); + lines.push(cmd.brief); + + // Arguments table + if (cmd.positionals.length > 0) { + lines.push(""); + lines.push(formatPositionalsTable(cmd.positionals)); + } + + // Options table + const visibleFlags = getVisibleFlags(cmd); + if (visibleFlags.length > 0) { + lines.push(""); + lines.push(formatFlagsTable(visibleFlags, cmd.aliases)); + } + + return lines.join("\n"); +} + +/** Determine if a route is a standalone command (not a group with subcommands) */ +function isStandaloneCommand(route: RouteInfo): boolean { + return ( + route.commands.length === 1 && + route.commands[0].path === `sentry ${route.name}` + ); +} + +/** + * Generate the full auto-generated portion of a command doc page. + * + * Includes frontmatter, intro, per-command reference sections, + * and the global flags footer. + */ +function generatePage(route: RouteInfo): string { + const standalone = isStandaloneCommand(route); + const description = standalone + ? `${capitalize(route.name)} command for the Sentry CLI` + : `${capitalize(route.name)} commands for the Sentry CLI`; + + const lines: string[] = []; + + // YAML frontmatter + lines.push("---"); + lines.push(`title: ${route.name}`); + lines.push(`description: ${description}`); + lines.push("---"); + lines.push(""); + + // Intro + lines.push(route.brief); + lines.push(""); + + // Section heading + lines.push(standalone ? "## Usage" : "## Commands"); + lines.push(""); + + // Per-command sections + for (const cmd of route.commands) { + lines.push(generateCommandSection(cmd)); + lines.push(""); + } + + // Global flags footer + lines.push( + "All commands support `--json` for machine-readable output and `--fields` to select specific JSON fields." + ); + lines.push(""); + + // End marker + lines.push(GENERATED_END_MARKER); + + return lines.join("\n"); +} + +/** Known acronyms that should be fully uppercased in titles */ +const ACRONYMS = new Set(["api", "cli"]); + +function capitalize(s: string): string { + if (ACRONYMS.has(s)) { + return s.toUpperCase(); + } + return s.charAt(0).toUpperCase() + s.slice(1); +} + +// --------------------------------------------------------------------------- +// Index Table Generation +// --------------------------------------------------------------------------- + +/** Route display order for the commands index table */ +const INDEX_ORDER = [ + "auth", + "cli", + "org", + "project", + "team", + "issue", + "event", + "log", + "trace", + "span", + "dashboard", + "sourcemap", + "repo", + "trial", + "init", + "schema", + "api", +]; + +/** Generate the commands table for index.md */ +function generateCommandsTable(allRoutes: RouteInfo[]): string { + const sorted = [...allRoutes].sort((a, b) => { + const aIdx = INDEX_ORDER.indexOf(a.name); + const bIdx = INDEX_ORDER.indexOf(b.name); + const aOrder = aIdx === -1 ? 999 : aIdx; + const bOrder = bIdx === -1 ? 999 : bIdx; + return aOrder - bOrder; + }); + + const lines: string[] = []; + lines.push("| Command | Description |"); + lines.push("|---------|-------------|"); + for (const route of sorted) { + lines.push(`| [\`${route.name}\`](./${route.name}/) | ${route.brief} |`); + } + return lines.join("\n"); +} + +// --------------------------------------------------------------------------- +// Custom Content Preservation +// --------------------------------------------------------------------------- + +/** + * Read existing custom content from below the GENERATED:END marker. + * Returns empty string if no marker found or file doesn't exist. + */ +async function readCustomContent(filePath: string): Promise<string> { + try { + const content = await Bun.file(filePath).text(); + const markerIndex = content.indexOf(GENERATED_END_MARKER); + if (markerIndex === -1) { + return ""; + } + return content.slice(markerIndex + GENERATED_END_MARKER.length); + } catch { + return ""; + } +} + +/** + * Read existing index.md and extract content after the commands table. + * Preserves Global Options, JSON Output, and Opening in Browser sections. + */ +async function readIndexCustomContent(): Promise<string> { + try { + const content = await Bun.file(INDEX_PATH).text(); + const markerIndex = content.indexOf(GENERATED_END_MARKER); + if (markerIndex === -1) { + return ""; + } + return content.slice(markerIndex + GENERATED_END_MARKER.length); + } catch { + return ""; + } +} + +// --------------------------------------------------------------------------- +// Main +// --------------------------------------------------------------------------- + +const routeMap = routes as unknown as RouteMap; +const routeInfos = extractVisibleRoutes(routeMap); + +const generatedFiles: string[] = []; + +// Clean up legacy cli/ subdirectory if it exists (we now use cli.md) +try { + rmSync(`${DOCS_DIR}/cli`, { recursive: true, force: true }); +} catch { + // Directory may not exist +} + +// Generate command doc pages +for (const route of routeInfos) { + const filePath = `${DOCS_DIR}/${route.name}.md`; + const pageContent = generatePage(route); + const customContent = await readCustomContent(filePath); + const fullContent = customContent + ? pageContent + customContent + : `${pageContent}\n`; + + await Bun.write(filePath, fullContent); + generatedFiles.push(filePath); +} + +// Update commands/index.md +const indexCustomContent = await readIndexCustomContent(); +const indexLines: string[] = []; +indexLines.push("---"); +indexLines.push("title: Commands"); +indexLines.push("description: Available commands in the Sentry CLI"); +indexLines.push("---"); +indexLines.push(""); +indexLines.push( + "The Sentry CLI provides commands for interacting with various Sentry resources." +); +indexLines.push(""); +indexLines.push("## Available Commands"); +indexLines.push(""); +indexLines.push(generateCommandsTable(routeInfos)); +indexLines.push(""); +indexLines.push(GENERATED_END_MARKER); + +const indexContent = indexCustomContent + ? indexLines.join("\n") + indexCustomContent + : `${indexLines.join("\n")}\n`; + +await Bun.write(INDEX_PATH, indexContent); + +console.log( + `Generated ${generatedFiles.length} command doc pages + ${INDEX_PATH}` +); diff --git a/src/lib/introspect.ts b/src/lib/introspect.ts index 6c4c8a50c..dfd21abd6 100644 --- a/src/lib/introspect.ts +++ b/src/lib/introspect.ts @@ -63,6 +63,14 @@ export type PositionalParams = export type PositionalParam = { brief?: string; placeholder?: string; + optional?: boolean; +}; + +/** Extracted metadata for a single positional argument */ +export type PositionalInfo = { + placeholder: string; + brief: string; + optional: boolean; }; /** Flag definition as stored in Stricli's command parameters */ @@ -87,6 +95,8 @@ export type CommandInfo = { fullDescription?: string; flags: FlagInfo[]; positional: string; + /** Structured positional parameter metadata for documentation generation */ + positionals: PositionalInfo[]; aliases: Record<string, string>; examples: string[]; /** JSON output field metadata extracted from `OutputConfig.schema` */ @@ -191,6 +201,44 @@ export function getPositionalString(params?: PositionalParams): string { return ""; } +/** + * Extract structured positional parameter metadata from a command. + * + * Returns one entry per positional, with placeholder, brief, and whether + * the parameter is optional. Used by documentation generators to build + * argument tables. + * + * @param params - Stricli positional parameter definition + * @returns Array of positional info objects + */ +export function extractPositionals( + params?: PositionalParams +): PositionalInfo[] { + if (!params) { + return []; + } + + if (params.kind === "tuple") { + return params.parameters.map((p, i) => ({ + placeholder: p.placeholder ?? `arg${i}`, + brief: p.brief ?? "", + optional: p.optional ?? false, + })); + } + + if (params.kind === "array") { + return [ + { + placeholder: `${params.parameter.placeholder ?? "args"}...`, + brief: params.parameter.brief ?? "", + optional: true, + }, + ]; + } + + return []; +} + /** * Extract flag metadata from a command's flag definitions. * @@ -237,6 +285,7 @@ export function buildCommandInfo( fullDescription: cmd.fullDescription, flags: extractFlags(cmd.parameters.flags), positional: getPositionalString(cmd.parameters.positional), + positionals: extractPositionals(cmd.parameters.positional), aliases: cmd.parameters.aliases ?? {}, examples, jsonFields: jsonFields?.length ? jsonFields : undefined, From 08fe175753a304f9ccc29b0502aaeff82cca1ac2 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya <byk@sentry.io> Date: Fri, 27 Mar 2026 00:19:57 +0000 Subject: [PATCH 03/10] refactor: reuse extractAllRoutes instead of duplicating route walk logic --- script/generate-command-docs.ts | 42 ++++----------------------------- 1 file changed, 4 insertions(+), 38 deletions(-) diff --git a/script/generate-command-docs.ts b/script/generate-command-docs.ts index cc4466bcc..2b44cf1ea 100644 --- a/script/generate-command-docs.ts +++ b/script/generate-command-docs.ts @@ -29,12 +29,7 @@ import type { RouteInfo, RouteMap, } from "../src/lib/introspect.js"; -import { - buildCommandInfo, - extractRouteGroupCommands, - isCommand, - isRouteMap, -} from "../src/lib/introspect.js"; +import { extractAllRoutes } from "../src/lib/introspect.js"; const DOCS_DIR = "docs/src/content/docs/commands"; const INDEX_PATH = `${DOCS_DIR}/index.md`; @@ -61,37 +56,6 @@ const GLOBAL_FLAG_NAMES = new Set([ /** Routes that don't need their own documentation page */ const SKIP_ROUTES = new Set(["help"]); -// --------------------------------------------------------------------------- -// Route Introspection -// --------------------------------------------------------------------------- - -/** Walk the route tree and extract metadata for all visible routes */ -function extractVisibleRoutes(topRouteMap: RouteMap): RouteInfo[] { - const result: RouteInfo[] = []; - for (const entry of topRouteMap.getAllEntries()) { - if (entry.hidden || SKIP_ROUTES.has(entry.name.original)) { - continue; - } - const routeName = entry.name.original; - const target = entry.target; - if (isRouteMap(target)) { - result.push({ - name: routeName, - brief: target.brief, - commands: extractRouteGroupCommands(target, routeName), - }); - } else if (isCommand(target)) { - const path = `sentry ${routeName}`; - result.push({ - name: routeName, - brief: target.brief, - commands: [buildCommandInfo(target, path)], - }); - } - } - return result; -} - // --------------------------------------------------------------------------- // Markdown Formatting // --------------------------------------------------------------------------- @@ -368,7 +332,9 @@ async function readIndexCustomContent(): Promise<string> { // --------------------------------------------------------------------------- const routeMap = routes as unknown as RouteMap; -const routeInfos = extractVisibleRoutes(routeMap); +const routeInfos = extractAllRoutes(routeMap).filter( + (r) => !SKIP_ROUTES.has(r.name) +); const generatedFiles: string[] = []; From 5a7e3f41894df1cdaaea10443a19025d30a8c1bf Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya <byk@sentry.io> Date: Fri, 27 Mar 2026 00:45:57 +0000 Subject: [PATCH 04/10] fix(docs): restore lost examples and guides, fix args placeholders Restore hand-written content that was lost during the migration to auto-generated reference sections: - dashboard.md: query/sort shorthand tables, detailed widget examples, sample terminal output for list/view/create - cli.md: release channels table, installation detection table, nightly migration note, channel switching examples - auth.md: OAuth flow walkthrough, self-hosted setup, environment variable precedence, auth status sample output - init.md: experimental warning, features table, target syntax table, what the wizard does, supported platforms - api.md: PUT/DELETE examples, verbose mode, API docs link - issue.md: explain/plan multi-format examples, behavioral notes - log.md: full sample output with section dividers, filter examples, jq pipe example - org.md, project.md: sample terminal output - event.md: Context section in output, open-in-browser example Also fix non-descriptive <args...> placeholders by adding descriptive placeholder values to 7 commands (dashboard view/create, widget add/edit/delete, event view, log view). Updates AGENTS.md to explicitly ban 'args' as a placeholder value. --- AGENTS.md | 22 ++- docs/src/content/docs/commands/api.md | 50 ++++++- docs/src/content/docs/commands/auth.md | 53 ++++++- docs/src/content/docs/commands/cli.md | 73 +++++++++- docs/src/content/docs/commands/dashboard.md | 131 +++++++++++++++--- docs/src/content/docs/commands/event.md | 13 +- docs/src/content/docs/commands/init.md | 55 ++++++++ docs/src/content/docs/commands/issue.md | 35 ++++- docs/src/content/docs/commands/log.md | 42 +++++- docs/src/content/docs/commands/org.md | 22 +++ docs/src/content/docs/commands/project.md | 21 ++- docs/src/content/docs/commands/span.md | 3 + docs/src/content/docs/commands/trial.md | 3 + plugins/sentry-cli/skills/sentry-cli/SKILL.md | 14 +- .../skills/sentry-cli/references/auth.md | 7 +- .../sentry-cli/references/dashboards.md | 10 +- .../skills/sentry-cli/references/events.md | 2 +- .../skills/sentry-cli/references/logs.md | 2 +- src/commands/dashboard/create.ts | 1 + src/commands/dashboard/view.ts | 1 + src/commands/dashboard/widget/add.ts | 1 + src/commands/dashboard/widget/delete.ts | 1 + src/commands/dashboard/widget/edit.ts | 1 + src/commands/event/view.ts | 2 +- src/commands/log/view.ts | 2 +- 25 files changed, 487 insertions(+), 80 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index a2de1456f..10878328f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -403,11 +403,11 @@ All normalize to lowercase. Throw `ValidationError` on invalid input. Use `"date"` for timestamp-based sort (not `"time"`). Export sort types from the API layer (e.g., `SpanSortValue` from `api/traces.ts`), import in commands. This matches `issue list`, `trace list`, and `span list`. -### SKILL.md +### SKILL.md and Command Docs -- Run `bun run generate:skill` after changing any command parameters, flags, or docs. -- CI check `bun run check:skill` will fail if SKILL.md is stale. -- Positional `placeholder` values must be descriptive: `"org/project/trace-id"` not `"args"`. +- Run `bun run generate:skill` and `bun run generate:command-docs` after changing any command parameters, flags, or docs. +- CI checks `bun run check:skill` and `bun run check:command-docs` will fail if generated files are stale. +- Positional `placeholder` values must be descriptive: `"org/project/trace-id"` not `"args"`. **Never** use `"args"` as a placeholder — it produces useless `<args...>` in documentation. Use slash-separated entity names that describe what the user passes (e.g., `"org/project/dashboard"`, `"org/project/event-id"`). ### Zod Schemas for Validation @@ -903,10 +903,10 @@ mock.module("./some-module", () => ({ * **Sentry API: events require org+project, issues have legacy global endpoint**: Sentry API scoping: Events require org+project in URL path (\`/projects/{org}/{project}/events/{id}/\`). Issues use legacy global endpoint (\`/api/0/issues/{id}/\`) without org context. Traces need only org (\`/organizations/{org}/trace/{traceId}/\`). Two-step lookup for events: fetch issue → extract org/project from response → fetch event. Cross-project event search possible via Discover endpoint \`/organizations/{org}/events/\` with \`query=id:{eventId}\`. <!-- lore:019cb6ab-ab98-7a9c-a25f-e154a5adbbe1 --> -* **Sentry CLI authenticated fetch architecture with response caching**: \`createAuthenticatedFetch()\` wraps fetch with auth, 30s timeout, retry (max 2), 401 refresh, and span tracing. Response caching via \`http-cache-semantics\` (RFC 7234) with filesystem storage at \`~/.sentry/cache/responses/\`. Fallback TTL tiers: immutable (24hr), stable (5min), volatile (60s), no-cache (0). Only GET 2xx cached. \`--fresh\` and \`SENTRY\_NO\_CACHE=1\` bypass. Cache cleared on login/logout. \`hasServerCacheDirectives(policy)\` distinguishes \`max-age=0\` from missing headers. +* **Sentry CLI authenticated fetch architecture with response caching**: \`createAuthenticatedFetch()\` wraps fetch with auth headers, 30s timeout, retry (max 2), 401 token refresh, and span tracing. Response caching via \`http-cache-semantics\` (RFC 7234) stored at \`~/.sentry/cache/responses/\`. Fallback TTL tiers: immutable (24hr), stable (5min), volatile (60s), no-cache (0). Only GET 2xx cached. \`--fresh\` and \`SENTRY\_NO\_CACHE=1\` bypass cache. Cache cleared on login/logout. <!-- lore:019c8c72-b871-7d5e-a1a4-5214359a5a77 --> -* **Sentry CLI has two distribution channels with different runtimes**: Sentry CLI ships two ways: (1) Standalone binary via \`Bun.build()\` with \`compile: true\`. (2) npm package via esbuild producing CJS \`dist/bin.cjs\` for Node 22+, with Bun API polyfills from \`script/node-polyfills.ts\`. \`Bun.$\` has NO polyfill — use \`execSync\` instead. \`require()\` in ESM is safe (Bun native, esbuild resolves at bundle time). As of PR #474, SDK is \`@sentry/node-core/light\` (not \`@sentry/bun\`), reducing import cost from ~218ms to ~85ms. +* **Sentry CLI has two distribution channels with different runtimes**: Sentry CLI ships two ways: (1) Standalone binary via \`Bun.build()\` with \`compile: true\`. (2) npm package via esbuild producing CJS \`dist/bin.cjs\` for Node 22+, with Bun API polyfills from \`script/node-polyfills.ts\`. \`Bun.$\` has NO polyfill — use \`execSync\` instead. SDK is \`@sentry/node-core/light\` (not \`@sentry/bun\`). <!-- lore:019c8b60-d21a-7d44-8a88-729f74ec7e02 --> * **Sentry CLI resolve-target cascade has 5 priority levels with env var support**: Resolve-target cascade (src/lib/resolve-target.ts) has 5 priority levels: (1) Explicit CLI flags, (2) SENTRY\_ORG/SENTRY\_PROJECT env vars, (3) SQLite config defaults, (4) DSN auto-detection, (5) Directory name inference. SENTRY\_PROJECT supports combo notation \`org/project\` — when used, SENTRY\_ORG is ignored. If combo parse fails (e.g. \`org/\`), the entire value is discarded. The \`resolveFromEnvVars()\` helper is injected into all four resolution functions. @@ -922,13 +922,7 @@ mock.module("./some-module", () => ({ ### Gotcha <!-- lore:019d2548-3e95-7673-8e9b-47811077388a --> -* **Biome noExcessiveCognitiveComplexity max 15 requires extracting helpers from command handlers**: Biome enforces \`noExcessiveCognitiveComplexity\` with max 15. Stricli \`func()\` handlers easily exceed this with fetch loops, pagination, and conditionals. Fix: extract logic into standalone helper functions — this also improves testability since \`func()\` handlers require full context setup. Keep \`func()\` as a thin orchestrator calling exported helpers. Property-based tests on extracted functions drove coverage from 78% to 97%. Split further if a helper still exceeds 15. - -<!-- lore:019d2548-3ea0-7802-8390-aac4749d6ca6 --> -* **Biome prefers .at(-1) over arr\[arr.length - 1] indexing**: Biome's \`useAtIndex\` rule flags \`arr\[arr.length - 1]\` patterns. Use \`arr.at(-1)\` instead. This applies throughout the codebase — the lint check will fail CI otherwise. - -<!-- lore:019d2548-3ea3-7a9b-b5bb-13bf595fd509 --> -* **Biome requires block statements — no single-line if/break/return**: Biome's \`useBlockStatements\` rule rejects braceless control flow like \`if (match) return match.id;\` or \`if (!nextCursor) break;\`. Always wrap in braces: \`if (match) { return match.id; }\`. Similarly, nested ternaries are banned (\`noNestedTernary\`) — use if/else chains or extract into a variable with sequential assignments. +* **Biome noExcessiveCognitiveComplexity max 15 requires extracting helpers from command handlers**: Biome lint rules that frequently trip developers in this codebase: (1) \`noExcessiveCognitiveComplexity\` max 15 — extract helpers from Stricli \`func()\` handlers to stay under limit; improves testability too. (2) \`useBlockStatements\` — always use braces, no braceless \`if/return/break\`. Nested ternaries banned (\`noNestedTernary\`) — use if/else or sequential assignments. (3) \`useAtIndex\` — use \`arr.at(-1)\` not \`arr\[arr.length - 1]\`. (4) \`noStaticOnlyClass\` — use branded instances instead of static-only classes. <!-- lore:019c8ee1-affd-7198-8d01-54aa164cde35 --> * **brew is not in VALID\_METHODS but Homebrew formula passes --method brew**: Homebrew install: \`isHomebrewInstall()\` detects via Cellar realpath (checked before stored install info). Upgrade command tells users \`brew upgrade getsentry/tools/sentry\`. Formula runs \`sentry cli setup --method brew --no-modify-path\` as post\_install. Version pinning throws 'unsupported\_operation'. Uses .gz artifacts. Tap at getsentry/tools. @@ -963,7 +957,7 @@ mock.module("./some-module", () => ({ * **Non-essential DB cache writes should be guarded with try-catch**: Non-essential DB cache writes (e.g., \`setUserInfo()\`) must be wrapped in try-catch so a broken DB doesn't crash a command whose primary operation succeeded. In login.ts, \`getCurrentUser()\` failure after token save must not block auth — log warning, continue. Exception: \`getUserRegions()\` failure should \`clearAuth()\` and fail hard (indicates invalid token). <!-- lore:019d2c91-bc3d-7be6-ac74-ce926182526d --> -* **Sentry CLI command docs are auto-generated from Stricli route tree with CI freshness check**: Command reference docs in \`docs/src/content/docs/commands/\*.md\` are auto-generated by \`script/generate-command-docs.ts\` using Stricli route tree introspection (\`src/lib/introspect.ts\`). Content between \`\<!-- GENERATED:START -->\` and \`\<!-- GENERATED:END -->\` markers is regenerated; hand-written examples go below the end marker. Run \`bun run generate:command-docs\` after changing command parameters/flags/docs. CI check \`bun run check:command-docs\` fails if docs are stale (runs in same job as \`check:skill\`). The \`cli/\` subdirectory was flattened into a single \`cli.md\`. Skill reference files under \`plugins/sentry-cli/\` are also regenerated separately via \`generate:skill\`. +* **Sentry CLI command docs are auto-generated from Stricli route tree with CI freshness check**: Command docs in \`docs/src/content/docs/commands/\*.md\` and SKILL.md are auto-generated from Stricli route tree introspection (\`src/lib/introspect.ts\`). Content between \`\<!-- GENERATED:START/END -->\` markers is regenerated; hand-written examples go below. Run \`bun run generate:command-docs\` and \`bun run generate:skill\` after changing command parameters/flags/docs. CI checks \`check:command-docs\` and \`check:skill\` fail if stale. <!-- lore:019ce2c5-c9a8-7219-bdb8-154ead871d27 --> * **Stricli buildCommand output config injects json flag into func params**: When a Stricli command uses \`output: { json: true, human: formatFn }\`, \`--json\` and \`--fields\` flags are auto-injected. The \`func\` handler receives these in its first parameter — type explicitly (e.g., \`flags: { json?: boolean }\`) to access them. Commands with interactive side effects (browser prompts, QR codes) should check \`flags.json\` and skip them when true. diff --git a/docs/src/content/docs/commands/api.md b/docs/src/content/docs/commands/api.md index 0ec460911..e47064d1a 100644 --- a/docs/src/content/docs/commands/api.md +++ b/docs/src/content/docs/commands/api.md @@ -37,22 +37,60 @@ All commands support `--json` for machine-readable output and `--fields` to sele ## Examples +### GET requests + ```bash -# GET request (default) +# List organizations sentry api /api/0/organizations/ -# POST with JSON body -sentry api /api/0/organizations/my-org/issues/ -X POST -d '{"status": "resolved"}' +# Get a specific issue +sentry api /api/0/issues/123456789/ +``` + +### POST requests + +```bash +# Create a release +sentry api /api/0/organizations/my-org/releases/ \ + -X POST -F version=1.0.0 + +# With inline JSON body +sentry api /api/0/organizations/my-org/issues/ \ + -X POST -d '{"status": "resolved"}' +``` -# Pass individual fields (auto-encoded as JSON body) -sentry api /api/0/projects/my-org/my-project/ -X PUT -F name=new-name +### PUT requests +```bash +# Update an issue status +sentry api /issues/123456789/ \ + -X PUT -F status=resolved + +# Assign an issue +sentry api /issues/123456789/ \ + -X PUT --field assignedTo="user@example.com" +``` + +### DELETE requests + +```bash +sentry api /projects/my-org/my-project/ -X DELETE +``` + +### Advanced usage + +```bash # Add custom headers sentry api /api/0/organizations/ -H "X-Custom: value" # Read body from a file -sentry api /api/0/projects/my-org/my-project/releases/ -X POST -i release.json +sentry api /api/0/projects/my-org/my-project/releases/ -X POST --input release.json + +# Verbose mode (shows full HTTP request/response) +sentry api /api/0/organizations/ --verbose # Preview the request without sending sentry api /api/0/organizations/ --dry-run ``` + +For full API documentation, see the [Sentry API Reference](https://docs.sentry.io/api/). diff --git a/docs/src/content/docs/commands/auth.md b/docs/src/content/docs/commands/auth.md index 8ed8b7622..7549b9d3f 100644 --- a/docs/src/content/docs/commands/auth.md +++ b/docs/src/content/docs/commands/auth.md @@ -64,16 +64,51 @@ All commands support `--json` for machine-readable output and `--fields` to sele ## Examples +### OAuth login (recommended) + ```bash -# OAuth login (recommended) sentry auth login +``` + +1. A URL and device code will be displayed +2. Open the URL in your browser +3. Enter the code when prompted +4. Authorize the application +5. The CLI automatically receives your token + +### Token login -# Login with an API token +```bash sentry auth login --token YOUR_SENTRY_API_TOKEN +``` + +### Self-hosted Sentry + +```bash +SENTRY_URL=https://sentry.example.com sentry auth login +``` + +For token-based auth with self-hosted: + +```bash +SENTRY_URL=https://sentry.example.com sentry auth login --token YOUR_TOKEN +``` + +See [Self-Hosted Sentry](../self-hosted/) for details. -# Check auth status +### Check auth status + +```bash sentry auth status +``` +``` +Authenticated as: username +Organization: my-org +Token expires: 2024-12-31 +``` + +```bash # Show the raw token sentry auth status --show-token @@ -83,4 +118,14 @@ sentry auth whoami ## Credential Storage -Auth tokens are stored securely in a local SQLite database at `~/.sentry/config.db`. +Auth tokens are stored in a SQLite database at `~/.sentry/config.db` with restricted file permissions. + +## Environment Variable Precedence + +The CLI checks for auth tokens in the following order, using the first one found: + +1. `SENTRY_AUTH_TOKEN` environment variable (legacy) +2. `SENTRY_TOKEN` environment variable +3. The stored token in the SQLite database + +When a token comes from an environment variable, the CLI skips expiry checks and automatic refresh. diff --git a/docs/src/content/docs/commands/cli.md b/docs/src/content/docs/commands/cli.md index 1b6e756b1..dc64f9c73 100644 --- a/docs/src/content/docs/commands/cli.md +++ b/docs/src/content/docs/commands/cli.md @@ -68,16 +68,79 @@ All commands support `--json` for machine-readable output and `--fields` to sele ## Examples +### Check for updates + ```bash -# Check for updates sentry cli upgrade --check +``` + +``` +Installation method: curl +Current version: 0.4.0 +Channel: stable +Latest version: 0.5.0 -# Upgrade to the latest version +Run 'sentry cli upgrade' to update. +``` + +### Upgrade + +```bash +# Upgrade to latest stable sentry cli upgrade -# Send feedback -sentry cli feedback "Great CLI!" +# Upgrade to a specific version +sentry cli upgrade 0.5.0 + +# Force re-download +sentry cli upgrade --force +``` + +### Release Channels + +```bash +# Switch to nightly builds +sentry cli upgrade nightly + +# Switch back to stable +sentry cli upgrade stable +``` -# Fix configuration issues +After switching, bare `sentry cli upgrade` will continue tracking that channel. + +| Channel | Description | +|---------|-------------| +| `stable` | Latest stable release (default) | +| `nightly` | Built from `main`, updated on every commit | + +### Installation Detection + +The CLI detects how it was installed and uses the appropriate upgrade method: + +| Method | Detection | +|--------|-----------| +| curl | Binary in `~/.sentry/bin` (installed via cli.sentry.dev) | +| brew | Binary in a Homebrew Cellar (`brew install getsentry/tools/sentry`) | +| npm | Globally installed via `npm install -g sentry` | +| pnpm | Globally installed via `pnpm add -g sentry` | +| bun | Globally installed via `bun install -g sentry` | + +Nightly builds are only available as standalone binaries (via the curl install method). Switching to nightly from a package manager install will automatically migrate to a standalone binary. + +### Send feedback + +```bash +# Send positive feedback +sentry cli feedback i love this tool + +# Report an issue +sentry cli feedback the issue view is confusing +``` + +Feedback is sent via Sentry's telemetry system. If telemetry is disabled (`SENTRY_CLI_NO_TELEMETRY=1`), feedback cannot be sent. + +### Fix configuration issues + +```bash sentry cli fix ``` diff --git a/docs/src/content/docs/commands/dashboard.md b/docs/src/content/docs/commands/dashboard.md index 15f376b1f..39b43eef1 100644 --- a/docs/src/content/docs/commands/dashboard.md +++ b/docs/src/content/docs/commands/dashboard.md @@ -26,7 +26,7 @@ List dashboards | `-f, --fresh` | Bypass cache, re-detect projects, and fetch fresh data | | `-c, --cursor <cursor>` | Navigate pages: "next", "prev", "first" (or raw cursor string) | -### `sentry dashboard view <args...>` +### `sentry dashboard view <org/project/dashboard...>` View a dashboard @@ -34,7 +34,7 @@ View a dashboard | Argument | Description | |----------|-------------| -| `<args...>` | [<org/project>] <dashboard-id-or-title> (optional) | +| `<org/project/dashboard...>` | [<org/project>] <dashboard-id-or-title> (optional) | **Options:** @@ -45,7 +45,7 @@ View a dashboard | `-r, --refresh <refresh>` | Auto-refresh interval in seconds (default: 60, min: 10) | | `-t, --period <period>` | Time period override (e.g., "24h", "7d", "14d") | -### `sentry dashboard create <args...>` +### `sentry dashboard create <org/project/title...>` Create a dashboard @@ -53,9 +53,9 @@ Create a dashboard | Argument | Description | |----------|-------------| -| `<args...>` | [<org/project>] <title> (optional) | +| `<org/project/title...>` | [<org/project>] <title> (optional) | -### `sentry dashboard widget add <args...>` +### `sentry dashboard widget add <org/project/dashboard/title...>` Add a widget to a dashboard @@ -63,7 +63,7 @@ Add a widget to a dashboard | Argument | Description | |----------|-------------| -| `<args...>` | [<org/project>] <dashboard> <title> (optional) | +| `<org/project/dashboard/title...>` | [<org/project>] <dashboard> <title> (optional) | **Options:** @@ -77,7 +77,7 @@ Add a widget to a dashboard | `-s, --sort <sort>` | Order by (prefix - for desc, e.g. -count) | | `-n, --limit <limit>` | Result limit | -### `sentry dashboard widget edit <args...>` +### `sentry dashboard widget edit <org/project/dashboard...>` Edit a widget in a dashboard @@ -85,7 +85,7 @@ Edit a widget in a dashboard | Argument | Description | |----------|-------------| -| `<args...>` | [<org/project>] <dashboard-id-or-title> (optional) | +| `<org/project/dashboard...>` | [<org/project>] <dashboard-id-or-title> (optional) | **Options:** @@ -102,7 +102,7 @@ Edit a widget in a dashboard | `-s, --sort <sort>` | Order by (prefix - for desc, e.g. -count) | | `-n, --limit <limit>` | Result limit | -### `sentry dashboard widget delete <args...>` +### `sentry dashboard widget delete <org/project/dashboard...>` Delete a widget from a dashboard @@ -110,7 +110,7 @@ Delete a widget from a dashboard | Argument | Description | |----------|-------------| -| `<args...>` | [<org/project>] <dashboard-id-or-title> (optional) | +| `<org/project/dashboard...>` | [<org/project>] <dashboard-id-or-title> (optional) | **Options:** @@ -131,35 +131,120 @@ All commands support `--json` for machine-readable output and `--fields` to sele # List all dashboards sentry dashboard list -# Open in browser +# Filter by name pattern +sentry dashboard list "Backend*" + +# Open dashboard list in browser sentry dashboard list -w +``` -# Filter by name -sentry dashboard list "Backend*" +``` +ID TITLE WIDGETS CREATED +12345 General 4 2024-01-15 +12346 Frontend Performance 6 2024-02-20 +12347 Backend Errors 3 2024-03-10 ``` ### View a dashboard ```bash -# View with live data -sentry dashboard view "Backend Performance" +# View by title +sentry dashboard view 'Frontend Performance' + +# View by ID +sentry dashboard view 12345 # Auto-refresh every 30 seconds sentry dashboard view "Backend Performance" --refresh 30 # Open in browser -sentry dashboard view "Backend Performance" -w +sentry dashboard view 12345 -w +``` + +``` +Dashboard: Frontend Performance (ID: 12345) +URL: https://my-org.sentry.io/dashboard/12345/ + +Widgets: + #0 Error Count big_number count() + #1 Errors Over Time line count() + #2 Errors by Browser bar count() group by browser.name + #3 Top Endpoints table count(), p95(span.duration) group by transaction ``` -### Manage widgets +### Create a dashboard ```bash -# Add a widget -sentry dashboard widget add "My Dashboard" -t "Error Count" -d line -q "count()" +sentry dashboard create 'Frontend Performance' +``` + +``` +Created dashboard: Frontend Performance (ID: 12348) +URL: https://my-org.sentry.io/dashboard/12348/ +``` -# Edit a widget -sentry dashboard widget edit "My Dashboard" -i 0 --new-title "Updated Title" +### Add widgets -# Delete a widget -sentry dashboard widget delete "My Dashboard" -i 0 +```bash +# Simple counter widget +sentry dashboard widget add 'My Dashboard' "Error Count" \ + --display big_number --query count + +# Line chart with group-by +sentry dashboard widget add 'My Dashboard' "Errors by Browser" \ + --display line --query count --group-by browser.name + +# Table with multiple aggregates, sorted descending +sentry dashboard widget add 'My Dashboard' "Top Endpoints" \ + --display table \ + --query count --query p95:span.duration \ + --group-by transaction \ + --sort -count --limit 10 + +# With search filter +sentry dashboard widget add 'My Dashboard' "Slow Requests" \ + --display bar --query p95:span.duration \ + --where "span.op:http.client" \ + --group-by span.description ``` + +### Edit widgets + +```bash +# Change display type +sentry dashboard widget edit 12345 --title 'Error Count' --display bar + +# Rename a widget +sentry dashboard widget edit 'My Dashboard' --index 0 --new-title 'Total Errors' + +# Change the query +sentry dashboard widget edit 12345 --title 'Error Rate' --query p95:span.duration +``` + +### Delete widgets + +```bash +# Delete by title +sentry dashboard widget delete 'My Dashboard' --title 'Error Count' + +# Delete by index +sentry dashboard widget delete 12345 --index 2 +``` + +## Query Shorthand + +The `--query` flag supports shorthand for aggregate functions: + +| Input | Expands to | +|-------|-----------| +| `count` | `count()` | +| `p95:span.duration` | `p95(span.duration)` | +| `avg:span.duration` | `avg(span.duration)` | +| `count()` | `count()` (passthrough) | + +## Sort Shorthand + +| Input | Meaning | +|-------|---------| +| `count` | Sort by `count()` ascending | +| `-count` | Sort by `count()` descending | diff --git a/docs/src/content/docs/commands/event.md b/docs/src/content/docs/commands/event.md index 3d0e1cf5a..4eadf926e 100644 --- a/docs/src/content/docs/commands/event.md +++ b/docs/src/content/docs/commands/event.md @@ -7,7 +7,7 @@ View Sentry events ## Commands -### `sentry event view <args...>` +### `sentry event view <org/project/event-id...>` View details of a specific event @@ -15,7 +15,7 @@ View details of a specific event | Argument | Description | |----------|-------------| -| `<args...>` | [<org>/<project>] <event-id> - Target (optional) and event ID (required) (optional) | +| `<org/project/event-id...>` | [<org>/<project>] <event-id> - Target (optional) and event ID (required) (optional) | **Options:** @@ -51,6 +51,15 @@ Tags: os: Windows 10 environment: production release: 1.2.3 + +Context: + url: https://example.com/app + user_id: 12345 +``` + +```bash +# Open in browser +sentry event view abc123def456 -w ``` ## Finding Event IDs diff --git a/docs/src/content/docs/commands/init.md b/docs/src/content/docs/commands/init.md index 47ffcb719..1be28a6e7 100644 --- a/docs/src/content/docs/commands/init.md +++ b/docs/src/content/docs/commands/init.md @@ -31,6 +31,10 @@ All commands support `--json` for machine-readable output and `--fields` to sele <!-- GENERATED:END --> +> **Experimental:** `sentry init` is experimental and may modify your source files. Always review changes before committing. + +**Prerequisites:** You must be authenticated first. Run `sentry auth login` if you haven't already. + ## Examples ```bash @@ -43,6 +47,57 @@ sentry init -y # Dry run to preview changes sentry init --dry-run +# Target a subdirectory +sentry init ./my-app + +# Use a specific org (auto-detect project) +sentry init acme/ + +# Use a specific org and project +sentry init acme/my-app + +# Assign a team when creating a new project +sentry init acme/ --team backend + # Enable specific features sentry init --features profiling,replays ``` + +## Target Syntax + +| Syntax | Meaning | +|--------|---------| +| _(omitted)_ | Auto-detect org and project | +| `acme/` | Use org `acme`, auto-detect or create project | +| `acme/my-app` | Use org `acme` and project `my-app` | +| `my-app` | Search for project `my-app` across all accessible orgs | + +Path-like arguments (starting with `.`, `/`, or `~`) are always treated as the directory. The order of target and directory can be swapped — the CLI will auto-correct with a warning. + +## Available Features + +| Feature | Description | +|---------|-------------| +| `errors` | Error monitoring | +| `tracing` | Performance tracing | +| `logs` | Log integration | +| `replay` | Session replay | +| `metrics` | Custom metrics | +| `profiling` | Profiling | +| `sourcemaps` | Source map uploads | +| `crons` | Cron job monitoring | +| `ai-monitoring` | AI/LLM monitoring | +| `user-feedback` | User feedback widget | + +## What the Wizard Does + +1. **Detects your framework** — scans your project files to identify the platform and framework +2. **Installs the SDK** — adds the appropriate Sentry SDK package to your project +3. **Instruments your code** — configures error monitoring, tracing, and any selected features + +### Supported Platforms + +- **JavaScript / TypeScript** — Next.js, Express, SvelteKit, React +- **Python** — Flask, FastAPI + +More platforms and frameworks are coming soon. diff --git a/docs/src/content/docs/commands/issue.md b/docs/src/content/docs/commands/issue.md index 2d2608780..712eab835 100644 --- a/docs/src/content/docs/commands/issue.md +++ b/docs/src/content/docs/commands/issue.md @@ -93,6 +93,12 @@ All commands support `--json` for machine-readable output and `--fields` to sele ```bash # List issues in a specific project sentry issue list my-org/frontend + +# All projects in an org +sentry issue list my-org/ + +# Search for a project across organizations +sentry issue list frontend ``` ``` @@ -135,12 +141,33 @@ Latest event: URL: https://example.com/app ``` -### Seer AI Requirements +```bash +# Open in browser +sentry issue view FRONT-ABC -w +``` + +### Explain and plan with Seer AI + +```bash +# Analyze root cause (may take a few minutes for new issues) +sentry issue explain 123456789 -The `explain` and `plan` commands require: +# By short ID with org prefix +sentry issue explain my-org/MYPROJECT-ABC + +# Force a fresh analysis +sentry issue explain 123456789 --force + +# Generate a fix plan (requires explain to be run first) +sentry issue plan 123456789 + +# Specify which root cause to plan for +sentry issue plan 123456789 --cause 0 +``` + +**Requirements:** - Seer AI enabled for your organization - GitHub integration configured with repository access - Code mappings set up to link stack frames to source files - -Root cause analysis must be completed (`sentry issue explain`) before generating a plan (`sentry issue plan`). +- Root cause analysis must be completed (`sentry issue explain`) before generating a plan diff --git a/docs/src/content/docs/commands/log.md b/docs/src/content/docs/commands/log.md index 0ec6f6ca9..af547c89c 100644 --- a/docs/src/content/docs/commands/log.md +++ b/docs/src/content/docs/commands/log.md @@ -28,7 +28,7 @@ List logs from a project | `-s, --sort <sort>` | Sort order: "newest" (default) or "oldest" (default: "newest") | | `--fresh` | Bypass cache, re-detect projects, and fetch fresh data | -### `sentry log view <args...>` +### `sentry log view <org/project/log-id...>` View details of one or more log entries @@ -36,7 +36,7 @@ View details of one or more log entries | Argument | Description | |----------|-------------| -| `<args...>` | [<org>/<project>] <log-id> [<log-id>...] - Target (optional) and one or more log IDs (optional) | +| `<org/project/log-id...>` | [<org>/<project>] <log-id> [<log-id>...] - Target (optional) and one or more log IDs (optional) | **Options:** @@ -54,6 +54,7 @@ All commands support `--json` for machine-readable output and `--fields` to sele ### List logs ```bash +# List last 100 logs (default) sentry log list ``` @@ -67,6 +68,19 @@ TIMESTAMP LEVEL MESSAGE Showing 4 logs. ``` +**Filter logs:** + +```bash +# Show only error logs +sentry log list -q 'level:error' + +# Filter by message content +sentry log list -q 'database' + +# Limit results +sentry log list --limit 50 +``` + ### Stream logs in real-time ```bash @@ -88,6 +102,7 @@ sentry log view 968c763c740cfda8b6728f27fb9e9b01 ``` Log 968c763c740c... +════════════════════ ID: 968c763c740cfda8b6728f27fb9e9b01 Timestamp: 2024-01-20 14:22:05 @@ -96,12 +111,29 @@ Severity: ERROR Message: Database connection timeout after 30s +─── Context ─── + Project: backend Environment: production Release: 1.2.3 +─── Trace ─── + Trace ID: abc123def456abc123def456abc12345 Span ID: 1234567890abcdef + +─── Source Location ─── + +Function: connect_to_database +File: src/db/connection.py:142 +``` + +```bash +# With explicit project +sentry log view my-org/backend 968c763c740cfda8b6728f27fb9e9b01 + +# Open in browser +sentry log view 968c763c740cfda8b6728f27fb9e9b01 -w ``` ## Finding Log IDs @@ -114,4 +146,10 @@ Log IDs can be found: ## JSON Output +Use `--json` for machine-readable output: + +```bash +sentry log list --json | jq '.[] | select(.level == "error")' +``` + In streaming mode with `--json`, each log entry is output as a separate JSON object (newline-delimited JSON), making it suitable for piping to other tools. diff --git a/docs/src/content/docs/commands/org.md b/docs/src/content/docs/commands/org.md index 54f164008..568f42cda 100644 --- a/docs/src/content/docs/commands/org.md +++ b/docs/src/content/docs/commands/org.md @@ -44,10 +44,32 @@ All commands support `--json` for machine-readable output and `--fields` to sele ```bash # List organizations sentry org list +``` + +``` +SLUG NAME ROLE +my-org My Organization owner +another-org Another Org member +``` +```bash # View organization details sentry org view my-org +``` +``` +Organization: My Organization +Slug: my-org +Role: owner +Projects: 5 +Teams: 3 +Members: 12 +``` + +```bash # Open in browser sentry org view my-org -w + +# JSON output +sentry org list --json ``` diff --git a/docs/src/content/docs/commands/project.md b/docs/src/content/docs/commands/project.md index 4f414b611..b30eb3e33 100644 --- a/docs/src/content/docs/commands/project.md +++ b/docs/src/content/docs/commands/project.md @@ -86,15 +86,34 @@ All commands support `--json` for machine-readable output and `--fields` to sele ## Examples ```bash -# List all projects +# List all projects in an org sentry project list my-org/ +``` +``` +ORG SLUG PLATFORM TEAM +my-org frontend javascript web-team +my-org backend python api-team +my-org mobile-ios cocoa mobile-team +``` + +```bash # Filter by platform sentry project list my-org/ --platform javascript # View project details sentry project view my-org/frontend +``` +``` +Project: frontend +Organization: my-org +Platform: javascript +Team: web-team +DSN: https://abc123@sentry.io/123456 +``` + +```bash # Open project in browser sentry project view my-org/frontend -w ``` diff --git a/docs/src/content/docs/commands/span.md b/docs/src/content/docs/commands/span.md index 916b91fa3..ff7c1e01b 100644 --- a/docs/src/content/docs/commands/span.md +++ b/docs/src/content/docs/commands/span.md @@ -65,6 +65,9 @@ sentry span list -q "duration:>100ms" --period 24h # List spans within a specific trace sentry span list abc123def456abc123def456abc12345 + +# Paginate through results +sentry span list -c next ``` ### View spans diff --git a/docs/src/content/docs/commands/trial.md b/docs/src/content/docs/commands/trial.md index b658354e6..fa22cd8f4 100644 --- a/docs/src/content/docs/commands/trial.md +++ b/docs/src/content/docs/commands/trial.md @@ -38,6 +38,9 @@ All commands support `--json` for machine-readable output and `--fields` to sele # List all trials for the current org sentry trial list +# List trials for a specific org +sentry trial list my-org + # Start a Seer trial sentry trial start seer diff --git a/plugins/sentry-cli/skills/sentry-cli/SKILL.md b/plugins/sentry-cli/skills/sentry-cli/SKILL.md index f0c4c3103..294d512c6 100644 --- a/plugins/sentry-cli/skills/sentry-cli/SKILL.md +++ b/plugins/sentry-cli/skills/sentry-cli/SKILL.md @@ -243,7 +243,7 @@ Manage Sentry issues View Sentry events -- `sentry event view <args...>` — View details of a specific event +- `sentry event view <org/project/event-id...>` — View details of a specific event → Full flags and examples: `references/events.md` @@ -271,11 +271,11 @@ CLI-related commands Manage Sentry dashboards - `sentry dashboard list <org/title-filter...>` — List dashboards -- `sentry dashboard view <args...>` — View a dashboard -- `sentry dashboard create <args...>` — Create a dashboard -- `sentry dashboard widget add <args...>` — Add a widget to a dashboard -- `sentry dashboard widget edit <args...>` — Edit a widget in a dashboard -- `sentry dashboard widget delete <args...>` — Delete a widget from a dashboard +- `sentry dashboard view <org/project/dashboard...>` — View a dashboard +- `sentry dashboard create <org/project/title...>` — Create a dashboard +- `sentry dashboard widget add <org/project/dashboard/title...>` — Add a widget to a dashboard +- `sentry dashboard widget edit <org/project/dashboard...>` — Edit a widget in a dashboard +- `sentry dashboard widget delete <org/project/dashboard...>` — Delete a widget from a dashboard → Full flags and examples: `references/dashboards.md` @@ -300,7 +300,7 @@ Work with Sentry teams View Sentry logs - `sentry log list <org/project-or-trace-id...>` — List logs from a project -- `sentry log view <args...>` — View details of one or more log entries +- `sentry log view <org/project/log-id...>` — View details of one or more log entries → Full flags and examples: `references/logs.md` diff --git a/plugins/sentry-cli/skills/sentry-cli/references/auth.md b/plugins/sentry-cli/skills/sentry-cli/references/auth.md index 94cb91460..88146e14c 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/auth.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/auth.md @@ -53,13 +53,14 @@ Show the currently authenticated user **Examples:** ```bash -# OAuth login (recommended) sentry auth login -# Login with an API token sentry auth login --token YOUR_SENTRY_API_TOKEN -# Check auth status +SENTRY_URL=https://sentry.example.com sentry auth login + +SENTRY_URL=https://sentry.example.com sentry auth login --token YOUR_TOKEN + sentry auth status # Show the raw token diff --git a/plugins/sentry-cli/skills/sentry-cli/references/dashboards.md b/plugins/sentry-cli/skills/sentry-cli/references/dashboards.md index 6e42726ab..b68f59b28 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/dashboards.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/dashboards.md @@ -21,7 +21,7 @@ List dashboards - `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` - `-c, --cursor <value> - Navigate pages: "next", "prev", "first" (or raw cursor string)` -### `sentry dashboard view <args...>` +### `sentry dashboard view <org/project/dashboard...>` View a dashboard @@ -31,11 +31,11 @@ View a dashboard - `-r, --refresh <value> - Auto-refresh interval in seconds (default: 60, min: 10)` - `-t, --period <value> - Time period override (e.g., "24h", "7d", "14d")` -### `sentry dashboard create <args...>` +### `sentry dashboard create <org/project/title...>` Create a dashboard -### `sentry dashboard widget add <args...>` +### `sentry dashboard widget add <org/project/dashboard/title...>` Add a widget to a dashboard @@ -48,7 +48,7 @@ Add a widget to a dashboard - `-s, --sort <value> - Order by (prefix - for desc, e.g. -count)` - `-n, --limit <value> - Result limit` -### `sentry dashboard widget edit <args...>` +### `sentry dashboard widget edit <org/project/dashboard...>` Edit a widget in a dashboard @@ -64,7 +64,7 @@ Edit a widget in a dashboard - `-s, --sort <value> - Order by (prefix - for desc, e.g. -count)` - `-n, --limit <value> - Result limit` -### `sentry dashboard widget delete <args...>` +### `sentry dashboard widget delete <org/project/dashboard...>` Delete a widget from a dashboard diff --git a/plugins/sentry-cli/skills/sentry-cli/references/events.md b/plugins/sentry-cli/skills/sentry-cli/references/events.md index 3cf9d6086..2a7a0eca6 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/events.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/events.md @@ -11,7 +11,7 @@ requires: View Sentry events -### `sentry event view <args...>` +### `sentry event view <org/project/event-id...>` View details of a specific event diff --git a/plugins/sentry-cli/skills/sentry-cli/references/logs.md b/plugins/sentry-cli/skills/sentry-cli/references/logs.md index 409ba87dd..53a774b8d 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/logs.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/logs.md @@ -34,7 +34,7 @@ List logs from a project | `severity` | string \| null | Severity level (error, warning, info, debug) | | `trace` | string \| null | Trace ID for correlation | -### `sentry log view <args...>` +### `sentry log view <org/project/log-id...>` View details of one or more log entries diff --git a/src/commands/dashboard/create.ts b/src/commands/dashboard/create.ts index 3b6c0a5d8..a28c7648c 100644 --- a/src/commands/dashboard/create.ts +++ b/src/commands/dashboard/create.ts @@ -152,6 +152,7 @@ export const createCommand = buildCommand({ positional: { kind: "array", parameter: { + placeholder: "org/project/title", brief: "[<org/project>] <title>", parse: String, }, diff --git a/src/commands/dashboard/view.ts b/src/commands/dashboard/view.ts index 2763ec166..40524f50d 100644 --- a/src/commands/dashboard/view.ts +++ b/src/commands/dashboard/view.ts @@ -149,6 +149,7 @@ export const viewCommand = buildCommand({ positional: { kind: "array", parameter: { + placeholder: "org/project/dashboard", brief: "[<org/project>] <dashboard-id-or-title>", parse: String, }, diff --git a/src/commands/dashboard/widget/add.ts b/src/commands/dashboard/widget/add.ts index 8938d3cb4..42cce6355 100644 --- a/src/commands/dashboard/widget/add.ts +++ b/src/commands/dashboard/widget/add.ts @@ -97,6 +97,7 @@ export const addCommand = buildCommand({ positional: { kind: "array", parameter: { + placeholder: "org/project/dashboard/title", brief: "[<org/project>] <dashboard> <title>", parse: String, }, diff --git a/src/commands/dashboard/widget/delete.ts b/src/commands/dashboard/widget/delete.ts index 329eeb2f1..7af2917dc 100644 --- a/src/commands/dashboard/widget/delete.ts +++ b/src/commands/dashboard/widget/delete.ts @@ -54,6 +54,7 @@ export const deleteCommand = buildCommand({ positional: { kind: "array", parameter: { + placeholder: "org/project/dashboard", brief: "[<org/project>] <dashboard-id-or-title>", parse: String, }, diff --git a/src/commands/dashboard/widget/edit.ts b/src/commands/dashboard/widget/edit.ts index 760e1d442..ff071557f 100644 --- a/src/commands/dashboard/widget/edit.ts +++ b/src/commands/dashboard/widget/edit.ts @@ -141,6 +141,7 @@ export const editCommand = buildCommand({ positional: { kind: "array", parameter: { + placeholder: "org/project/dashboard", brief: "[<org/project>] <dashboard-id-or-title>", parse: String, }, diff --git a/src/commands/event/view.ts b/src/commands/event/view.ts index ef2b325f1..2764f800d 100644 --- a/src/commands/event/view.ts +++ b/src/commands/event/view.ts @@ -655,7 +655,7 @@ export const viewCommand = buildCommand({ positional: { kind: "array", parameter: { - placeholder: "args", + placeholder: "org/project/event-id", brief: "[<org>/<project>] <event-id> - Target (optional) and event ID (required)", parse: String, diff --git a/src/commands/log/view.ts b/src/commands/log/view.ts index ab8fee1ff..8bf5f63de 100644 --- a/src/commands/log/view.ts +++ b/src/commands/log/view.ts @@ -333,7 +333,7 @@ export const viewCommand = buildCommand({ positional: { kind: "array", parameter: { - placeholder: "args", + placeholder: "org/project/log-id", brief: "[<org>/<project>] <log-id> [<log-id>...] - Target (optional) and one or more log IDs", parse: String, From b028de238adc64ea33281f2165be954983d878b6 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya <byk@sentry.io> Date: Fri, 27 Mar 2026 00:50:25 +0000 Subject: [PATCH 05/10] fix: add dashboard view/create to ORG_PROJECT_COMMANDS completion set The placeholder fix surfaced these commands to the drift detection test since they now have org-containing placeholders. --- src/lib/complete.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/complete.ts b/src/lib/complete.ts index f9de11258..85cb29f06 100644 --- a/src/lib/complete.ts +++ b/src/lib/complete.ts @@ -105,6 +105,8 @@ export const ORG_PROJECT_COMMANDS = new Set([ "log list", "log view", "dashboard list", + "dashboard view", + "dashboard create", ]); /** From 6f319fb9ee0a713c8584b938971c0fbafd846ac8 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya <byk@sentry.io> Date: Fri, 27 Mar 2026 00:55:01 +0000 Subject: [PATCH 06/10] refactor: remove redundant readIndexCustomContent, reuse readCustomContent --- script/generate-command-docs.ts | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/script/generate-command-docs.ts b/script/generate-command-docs.ts index 2b44cf1ea..ca1beeaef 100644 --- a/script/generate-command-docs.ts +++ b/script/generate-command-docs.ts @@ -310,23 +310,6 @@ async function readCustomContent(filePath: string): Promise<string> { } } -/** - * Read existing index.md and extract content after the commands table. - * Preserves Global Options, JSON Output, and Opening in Browser sections. - */ -async function readIndexCustomContent(): Promise<string> { - try { - const content = await Bun.file(INDEX_PATH).text(); - const markerIndex = content.indexOf(GENERATED_END_MARKER); - if (markerIndex === -1) { - return ""; - } - return content.slice(markerIndex + GENERATED_END_MARKER.length); - } catch { - return ""; - } -} - // --------------------------------------------------------------------------- // Main // --------------------------------------------------------------------------- @@ -359,7 +342,7 @@ for (const route of routeInfos) { } // Update commands/index.md -const indexCustomContent = await readIndexCustomContent(); +const indexCustomContent = await readCustomContent(INDEX_PATH); const indexLines: string[] = []; indexLines.push("---"); indexLines.push("title: Commands"); From fef20216d17d23addc3f351e1bed86119bce1f80 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya <byk@sentry.io> Date: Fri, 27 Mar 2026 01:12:07 +0000 Subject: [PATCH 07/10] fix(docs): fix internal inconsistencies in command examples - api.md: remove /api/0/ prefix from all examples (endpoints are relative to /api/0/ as documented in the arguments table) - event.md: use full 32-char hex event ID in examples (was 12 chars) - init.md: fix feature name 'replays' -> 'replay' (singular) - log.md: fix jq example to use .data[] envelope and .severity field (not .level), fix misleading 'trace IDs in brackets' text --- docs/src/content/docs/commands/api.md | 24 +++++++++++++----------- docs/src/content/docs/commands/event.md | 6 +++--- docs/src/content/docs/commands/init.md | 2 +- docs/src/content/docs/commands/log.md | 4 ++-- 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/docs/src/content/docs/commands/api.md b/docs/src/content/docs/commands/api.md index e47064d1a..9a1f943f2 100644 --- a/docs/src/content/docs/commands/api.md +++ b/docs/src/content/docs/commands/api.md @@ -37,25 +37,27 @@ All commands support `--json` for machine-readable output and `--fields` to sele ## Examples +Endpoints are relative to `/api/0/` — the prefix is added automatically. + ### GET requests ```bash # List organizations -sentry api /api/0/organizations/ +sentry api organizations/ # Get a specific issue -sentry api /api/0/issues/123456789/ +sentry api issues/123456789/ ``` ### POST requests ```bash # Create a release -sentry api /api/0/organizations/my-org/releases/ \ +sentry api organizations/my-org/releases/ \ -X POST -F version=1.0.0 # With inline JSON body -sentry api /api/0/organizations/my-org/issues/ \ +sentry api issues/123456789/ \ -X POST -d '{"status": "resolved"}' ``` @@ -63,34 +65,34 @@ sentry api /api/0/organizations/my-org/issues/ \ ```bash # Update an issue status -sentry api /issues/123456789/ \ +sentry api issues/123456789/ \ -X PUT -F status=resolved # Assign an issue -sentry api /issues/123456789/ \ +sentry api issues/123456789/ \ -X PUT --field assignedTo="user@example.com" ``` ### DELETE requests ```bash -sentry api /projects/my-org/my-project/ -X DELETE +sentry api projects/my-org/my-project/ -X DELETE ``` ### Advanced usage ```bash # Add custom headers -sentry api /api/0/organizations/ -H "X-Custom: value" +sentry api organizations/ -H "X-Custom: value" # Read body from a file -sentry api /api/0/projects/my-org/my-project/releases/ -X POST --input release.json +sentry api projects/my-org/my-project/releases/ -X POST --input release.json # Verbose mode (shows full HTTP request/response) -sentry api /api/0/organizations/ --verbose +sentry api organizations/ --verbose # Preview the request without sending -sentry api /api/0/organizations/ --dry-run +sentry api organizations/ --dry-run ``` For full API documentation, see the [Sentry API Reference](https://docs.sentry.io/api/). diff --git a/docs/src/content/docs/commands/event.md b/docs/src/content/docs/commands/event.md index 4eadf926e..938705813 100644 --- a/docs/src/content/docs/commands/event.md +++ b/docs/src/content/docs/commands/event.md @@ -32,11 +32,11 @@ All commands support `--json` for machine-readable output and `--fields` to sele ## Examples ```bash -sentry event view abc123def456 +sentry event view abc123def456abc123def456abc12345 ``` ``` -Event: abc123def456 +Event: abc123def456abc123def456abc12345 Issue: FRONT-ABC Timestamp: 2024-01-20 14:22:00 @@ -59,7 +59,7 @@ Context: ```bash # Open in browser -sentry event view abc123def456 -w +sentry event view abc123def456abc123def456abc12345 -w ``` ## Finding Event IDs diff --git a/docs/src/content/docs/commands/init.md b/docs/src/content/docs/commands/init.md index 1be28a6e7..d17558c5c 100644 --- a/docs/src/content/docs/commands/init.md +++ b/docs/src/content/docs/commands/init.md @@ -60,7 +60,7 @@ sentry init acme/my-app sentry init acme/ --team backend # Enable specific features -sentry init --features profiling,replays +sentry init --features profiling,replay ``` ## Target Syntax diff --git a/docs/src/content/docs/commands/log.md b/docs/src/content/docs/commands/log.md index af547c89c..53a636c65 100644 --- a/docs/src/content/docs/commands/log.md +++ b/docs/src/content/docs/commands/log.md @@ -140,7 +140,7 @@ sentry log view 968c763c740cfda8b6728f27fb9e9b01 -w Log IDs can be found: -1. In the output of `sentry log list` (shown as trace IDs in brackets) +1. In the output of `sentry log list` (the ID column) 2. In the Sentry UI when viewing log entries 3. In the `sentry.item_id` field of JSON output @@ -149,7 +149,7 @@ Log IDs can be found: Use `--json` for machine-readable output: ```bash -sentry log list --json | jq '.[] | select(.level == "error")' +sentry log list --json | jq '.data[] | select(.severity == "error")' ``` In streaming mode with `--json`, each log entry is output as a separate JSON object (newline-delimited JSON), making it suitable for piping to other tools. From 5713d1f18bc07a5a3f7b1b785d9c9a2a32a74c7d Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya <byk@sentry.io> Date: Fri, 27 Mar 2026 01:21:36 +0000 Subject: [PATCH 08/10] fix(docs): remove contradictory (optional) suffix from array positional args The brief text from source code already communicates optionality (e.g., 'Target (optional) and trace ID (required)'). Appending a blanket '(optional)' suffix to all array positionals produced contradictions like 'trace ID (required) (optional)'. --- docs/src/content/docs/commands/cli.md | 4 ++-- docs/src/content/docs/commands/dashboard.md | 12 ++++++------ docs/src/content/docs/commands/event.md | 2 +- docs/src/content/docs/commands/init.md | 4 ++-- docs/src/content/docs/commands/issue.md | 2 +- docs/src/content/docs/commands/log.md | 4 ++-- docs/src/content/docs/commands/org.md | 2 +- docs/src/content/docs/commands/project.md | 8 ++++---- docs/src/content/docs/commands/repo.md | 2 +- docs/src/content/docs/commands/schema.md | 2 +- docs/src/content/docs/commands/span.md | 4 ++-- docs/src/content/docs/commands/team.md | 2 +- docs/src/content/docs/commands/trace.md | 6 +++--- docs/src/content/docs/commands/trial.md | 4 ++-- script/generate-command-docs.ts | 3 +-- 15 files changed, 30 insertions(+), 31 deletions(-) diff --git a/docs/src/content/docs/commands/cli.md b/docs/src/content/docs/commands/cli.md index dc64f9c73..731b91a6c 100644 --- a/docs/src/content/docs/commands/cli.md +++ b/docs/src/content/docs/commands/cli.md @@ -15,7 +15,7 @@ Send feedback about the CLI | Argument | Description | |----------|-------------| -| `<message...>` | Your feedback message (optional) | +| `<message...>` | Your feedback message | ### `sentry cli fix` @@ -51,7 +51,7 @@ Update the Sentry CLI to the latest version | Argument | Description | |----------|-------------| -| `<version>` | Specific version (e.g. 0.5.0), or "nightly"/"stable" to switch channel; omit to update within current channel (optional) | +| `<version>` | Specific version (e.g. 0.5.0), or "nightly"/"stable" to switch channel; omit to update within current channel | **Options:** diff --git a/docs/src/content/docs/commands/dashboard.md b/docs/src/content/docs/commands/dashboard.md index 39b43eef1..a21f17f6e 100644 --- a/docs/src/content/docs/commands/dashboard.md +++ b/docs/src/content/docs/commands/dashboard.md @@ -15,7 +15,7 @@ List dashboards | Argument | Description | |----------|-------------| -| `<org/title-filter...>` | [<org/project>] [<name-glob>] (optional) | +| `<org/title-filter...>` | [<org/project>] [<name-glob>] | **Options:** @@ -34,7 +34,7 @@ View a dashboard | Argument | Description | |----------|-------------| -| `<org/project/dashboard...>` | [<org/project>] <dashboard-id-or-title> (optional) | +| `<org/project/dashboard...>` | [<org/project>] <dashboard-id-or-title> | **Options:** @@ -53,7 +53,7 @@ Create a dashboard | Argument | Description | |----------|-------------| -| `<org/project/title...>` | [<org/project>] <title> (optional) | +| `<org/project/title...>` | [<org/project>] <title> | ### `sentry dashboard widget add <org/project/dashboard/title...>` @@ -63,7 +63,7 @@ Add a widget to a dashboard | Argument | Description | |----------|-------------| -| `<org/project/dashboard/title...>` | [<org/project>] <dashboard> <title> (optional) | +| `<org/project/dashboard/title...>` | [<org/project>] <dashboard> <title> | **Options:** @@ -85,7 +85,7 @@ Edit a widget in a dashboard | Argument | Description | |----------|-------------| -| `<org/project/dashboard...>` | [<org/project>] <dashboard-id-or-title> (optional) | +| `<org/project/dashboard...>` | [<org/project>] <dashboard-id-or-title> | **Options:** @@ -110,7 +110,7 @@ Delete a widget from a dashboard | Argument | Description | |----------|-------------| -| `<org/project/dashboard...>` | [<org/project>] <dashboard-id-or-title> (optional) | +| `<org/project/dashboard...>` | [<org/project>] <dashboard-id-or-title> | **Options:** diff --git a/docs/src/content/docs/commands/event.md b/docs/src/content/docs/commands/event.md index 938705813..488b46267 100644 --- a/docs/src/content/docs/commands/event.md +++ b/docs/src/content/docs/commands/event.md @@ -15,7 +15,7 @@ View details of a specific event | Argument | Description | |----------|-------------| -| `<org/project/event-id...>` | [<org>/<project>] <event-id> - Target (optional) and event ID (required) (optional) | +| `<org/project/event-id...>` | [<org>/<project>] <event-id> - Target (optional) and event ID (required) | **Options:** diff --git a/docs/src/content/docs/commands/init.md b/docs/src/content/docs/commands/init.md index d17558c5c..097e9a703 100644 --- a/docs/src/content/docs/commands/init.md +++ b/docs/src/content/docs/commands/init.md @@ -15,8 +15,8 @@ Initialize Sentry in your project (experimental) | Argument | Description | |----------|-------------| -| `<target>` | <org>/<project>, <org>/, <project>, or a directory path (optional) | -| `<directory>` | Project directory (default: current directory) (optional) | +| `<target>` | <org>/<project>, <org>/, <project>, or a directory path | +| `<directory>` | Project directory (default: current directory) | **Options:** diff --git a/docs/src/content/docs/commands/issue.md b/docs/src/content/docs/commands/issue.md index 712eab835..2d08599f3 100644 --- a/docs/src/content/docs/commands/issue.md +++ b/docs/src/content/docs/commands/issue.md @@ -15,7 +15,7 @@ List issues in a project | Argument | Description | |----------|-------------| -| `<org/project>` | <org>/ (all projects), <org>/<project>, or <project> (search) (optional) | +| `<org/project>` | <org>/ (all projects), <org>/<project>, or <project> (search) | **Options:** diff --git a/docs/src/content/docs/commands/log.md b/docs/src/content/docs/commands/log.md index 53a636c65..7b7b651d2 100644 --- a/docs/src/content/docs/commands/log.md +++ b/docs/src/content/docs/commands/log.md @@ -15,7 +15,7 @@ List logs from a project | Argument | Description | |----------|-------------| -| `<org/project-or-trace-id...>` | [<org>/[<project>/]]<trace-id>, <org>/<project>, or <project> (optional) | +| `<org/project-or-trace-id...>` | [<org>/[<project>/]]<trace-id>, <org>/<project>, or <project> | **Options:** @@ -36,7 +36,7 @@ View details of one or more log entries | Argument | Description | |----------|-------------| -| `<org/project/log-id...>` | [<org>/<project>] <log-id> [<log-id>...] - Target (optional) and one or more log IDs (optional) | +| `<org/project/log-id...>` | [<org>/<project>] <log-id> [<log-id>...] - Target (optional) and one or more log IDs | **Options:** diff --git a/docs/src/content/docs/commands/org.md b/docs/src/content/docs/commands/org.md index 568f42cda..d27997a0b 100644 --- a/docs/src/content/docs/commands/org.md +++ b/docs/src/content/docs/commands/org.md @@ -26,7 +26,7 @@ View details of an organization | Argument | Description | |----------|-------------| -| `<org>` | Organization slug (optional if auto-detected) (optional) | +| `<org>` | Organization slug (optional if auto-detected) | **Options:** diff --git a/docs/src/content/docs/commands/project.md b/docs/src/content/docs/commands/project.md index b30eb3e33..ac5876fa0 100644 --- a/docs/src/content/docs/commands/project.md +++ b/docs/src/content/docs/commands/project.md @@ -15,8 +15,8 @@ Create a new project | Argument | Description | |----------|-------------| -| `<name>` | Project name (supports org/name syntax) (optional) | -| `<platform>` | Project platform (e.g., node, python, javascript-nextjs) (optional) | +| `<name>` | Project name (supports org/name syntax) | +| `<platform>` | Project platform (e.g., node, python, javascript-nextjs) | **Options:** @@ -51,7 +51,7 @@ List projects | Argument | Description | |----------|-------------| -| `<org/project>` | <org>/ (all projects), <org>/<project>, or <project> (search) (optional) | +| `<org/project>` | <org>/ (all projects), <org>/<project>, or <project> (search) | **Options:** @@ -70,7 +70,7 @@ View details of a project | Argument | Description | |----------|-------------| -| `<org/project>` | <org>/<project>, <project> (search), or omit for auto-detect (optional) | +| `<org/project>` | <org>/<project>, <project> (search), or omit for auto-detect | **Options:** diff --git a/docs/src/content/docs/commands/repo.md b/docs/src/content/docs/commands/repo.md index cad81d5be..65d888273 100644 --- a/docs/src/content/docs/commands/repo.md +++ b/docs/src/content/docs/commands/repo.md @@ -15,7 +15,7 @@ List repositories | Argument | Description | |----------|-------------| -| `<org/project>` | <org>/ (all projects), <org>/<project>, or <project> (search) (optional) | +| `<org/project>` | <org>/ (all projects), <org>/<project>, or <project> (search) | **Options:** diff --git a/docs/src/content/docs/commands/schema.md b/docs/src/content/docs/commands/schema.md index 9475836f8..caa3cdc0e 100644 --- a/docs/src/content/docs/commands/schema.md +++ b/docs/src/content/docs/commands/schema.md @@ -15,7 +15,7 @@ Browse the Sentry API schema | Argument | Description | |----------|-------------| -| `<resource...>` | Resource name and optional operation (optional) | +| `<resource...>` | Resource name and optional operation | **Options:** diff --git a/docs/src/content/docs/commands/span.md b/docs/src/content/docs/commands/span.md index ff7c1e01b..f86025d0e 100644 --- a/docs/src/content/docs/commands/span.md +++ b/docs/src/content/docs/commands/span.md @@ -15,7 +15,7 @@ List spans in a project or trace | Argument | Description | |----------|-------------| -| `<org/project/trace-id...>` | [<org>/<project>] or [<org>/<project>/]<trace-id> (optional) | +| `<org/project/trace-id...>` | [<org>/<project>] or [<org>/<project>/]<trace-id> | **Options:** @@ -36,7 +36,7 @@ View details of specific spans | Argument | Description | |----------|-------------| -| `<trace-id/span-id...>` | [<org>/<project>/]<trace-id> <span-id> [<span-id>...] - Trace ID and one or more span IDs (optional) | +| `<trace-id/span-id...>` | [<org>/<project>/]<trace-id> <span-id> [<span-id>...] - Trace ID and one or more span IDs | **Options:** diff --git a/docs/src/content/docs/commands/team.md b/docs/src/content/docs/commands/team.md index 3e39a254a..39bfdea49 100644 --- a/docs/src/content/docs/commands/team.md +++ b/docs/src/content/docs/commands/team.md @@ -15,7 +15,7 @@ List teams | Argument | Description | |----------|-------------| -| `<org/project>` | <org>/ (all projects), <org>/<project>, or <project> (search) (optional) | +| `<org/project>` | <org>/ (all projects), <org>/<project>, or <project> (search) | **Options:** diff --git a/docs/src/content/docs/commands/trace.md b/docs/src/content/docs/commands/trace.md index 767b31041..0ef172e56 100644 --- a/docs/src/content/docs/commands/trace.md +++ b/docs/src/content/docs/commands/trace.md @@ -15,7 +15,7 @@ List recent traces in a project | Argument | Description | |----------|-------------| -| `<org/project>` | <org>/<project> or <project> (search) (optional) | +| `<org/project>` | <org>/<project> or <project> (search) | **Options:** @@ -36,7 +36,7 @@ View details of a specific trace | Argument | Description | |----------|-------------| -| `<org/project/trace-id...>` | [<org>/<project>/]<trace-id> - Target (optional) and trace ID (required) (optional) | +| `<org/project/trace-id...>` | [<org>/<project>/]<trace-id> - Target (optional) and trace ID (required) | **Options:** @@ -54,7 +54,7 @@ View logs associated with a trace | Argument | Description | |----------|-------------| -| `<org/trace-id...>` | [<org>/]<trace-id> - Optional org and required trace ID (optional) | +| `<org/trace-id...>` | [<org>/]<trace-id> - Optional org and required trace ID | **Options:** diff --git a/docs/src/content/docs/commands/trial.md b/docs/src/content/docs/commands/trial.md index fa22cd8f4..8eaa739b0 100644 --- a/docs/src/content/docs/commands/trial.md +++ b/docs/src/content/docs/commands/trial.md @@ -15,7 +15,7 @@ List product trials | Argument | Description | |----------|-------------| -| `<org>` | Organization slug (auto-detected if omitted) (optional) | +| `<org>` | Organization slug (auto-detected if omitted) | ### `sentry trial start <name> <org>` @@ -26,7 +26,7 @@ Start a product trial | Argument | Description | |----------|-------------| | `<name>` | Trial name (seer, replays, performance, spans, profiling, logs, monitors, uptime, plan) | -| `<org>` | Organization slug (auto-detected if omitted) (optional) | +| `<org>` | Organization slug (auto-detected if omitted) | All commands support `--json` for machine-readable output and `--fields` to select specific JSON fields. diff --git a/script/generate-command-docs.ts b/script/generate-command-docs.ts index ca1beeaef..06664c34a 100644 --- a/script/generate-command-docs.ts +++ b/script/generate-command-docs.ts @@ -124,8 +124,7 @@ function formatPositionalsTable(positionals: PositionalInfo[]): string { lines.push("|----------|-------------|"); for (const p of positionals) { const placeholder = `\`<${p.placeholder}>\``; - const suffix = p.optional ? " (optional)" : ""; - lines.push(`| ${placeholder} | ${escapeAngleBrackets(p.brief)}${suffix} |`); + lines.push(`| ${placeholder} | ${escapeAngleBrackets(p.brief)} |`); } return lines.join("\n"); } From 05436f62f780895df2ae88d518866848f58d1339 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya <byk@sentry.io> Date: Fri, 27 Mar 2026 01:33:22 +0000 Subject: [PATCH 09/10] fix: restore examples to skill reference files, derive index order from route tree Two root causes for missing skill examples: 1. COMMAND_SECTION_REGEX used \S+ which matched <placeholder> text, causing command paths like 'sentry api <endpoint>' instead of 'sentry api'. Fixed with [^\s<]+ to stop at angle brackets. 2. The regex only matched up to 2 words after 'sentry', missing 3-word paths like 'sentry dashboard widget add'. Fixed with {1,3} quantifier. 3. extractSectionExamples only registered command paths when code blocks existed in the section. Fixed to always register paths so extractLooseExamples can match custom-section examples. Also replaced the manual INDEX_ORDER constant in generate-command-docs.ts with the natural order from extractAllRoutes() (preserves insertion order from app.ts's buildRouteMap). --- docs/src/content/docs/commands/index.md | 10 +- .../skills/sentry-cli/references/api.md | 40 +++++++ .../sentry-cli/references/dashboards.md | 63 ++++++++++ .../skills/sentry-cli/references/events.md | 9 ++ .../skills/sentry-cli/references/issues.md | 42 +++++++ .../skills/sentry-cli/references/logs.md | 35 ++++++ .../sentry-cli/references/organizations.md | 16 +++ .../skills/sentry-cli/references/projects.md | 16 +++ .../skills/sentry-cli/references/setup.md | 76 ++++++++++++ .../skills/sentry-cli/references/sourcemap.md | 22 ++++ .../skills/sentry-cli/references/teams.md | 26 ++++ .../skills/sentry-cli/references/traces.md | 62 ++++++++++ .../skills/sentry-cli/references/trials.md | 19 +++ script/generate-command-docs.ts | 37 +----- script/generate-skill.ts | 112 +++++++++++++++--- 15 files changed, 533 insertions(+), 52 deletions(-) diff --git a/docs/src/content/docs/commands/index.md b/docs/src/content/docs/commands/index.md index f2047f036..f688a0482 100644 --- a/docs/src/content/docs/commands/index.md +++ b/docs/src/content/docs/commands/index.md @@ -11,21 +11,21 @@ The Sentry CLI provides commands for interacting with various Sentry resources. |---------|-------------| | [`auth`](./auth/) | Authenticate with Sentry | | [`cli`](./cli/) | CLI-related commands | +| [`dashboard`](./dashboard/) | Manage Sentry dashboards | | [`org`](./org/) | Work with Sentry organizations | | [`project`](./project/) | Work with Sentry projects | +| [`repo`](./repo/) | Work with Sentry repositories | | [`team`](./team/) | Work with Sentry teams | | [`issue`](./issue/) | Manage Sentry issues | | [`event`](./event/) | View Sentry events | | [`log`](./log/) | View Sentry logs | -| [`trace`](./trace/) | View distributed traces | -| [`span`](./span/) | List and view spans in projects or traces | -| [`dashboard`](./dashboard/) | Manage Sentry dashboards | | [`sourcemap`](./sourcemap/) | Manage sourcemaps | -| [`repo`](./repo/) | Work with Sentry repositories | +| [`span`](./span/) | List and view spans in projects or traces | +| [`trace`](./trace/) | View distributed traces | | [`trial`](./trial/) | Manage product trials | | [`init`](./init/) | Initialize Sentry in your project (experimental) | -| [`schema`](./schema/) | Browse the Sentry API schema | | [`api`](./api/) | Make an authenticated API request | +| [`schema`](./schema/) | Browse the Sentry API schema | <!-- GENERATED:END --> diff --git a/plugins/sentry-cli/skills/sentry-cli/references/api.md b/plugins/sentry-cli/skills/sentry-cli/references/api.md index 4694e2a72..0577d86aa 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/api.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/api.md @@ -26,4 +26,44 @@ Make an authenticated API request - `--verbose - Include full HTTP request and response in the output` - `-n, --dry-run - Show the resolved request without sending it` +**Examples:** + +```bash +# List organizations +sentry api organizations/ + +# Get a specific issue +sentry api issues/123456789/ + +# Create a release +sentry api organizations/my-org/releases/ \ + -X POST -F version=1.0.0 + +# With inline JSON body +sentry api issues/123456789/ \ + -X POST -d '{"status": "resolved"}' + +# Update an issue status +sentry api issues/123456789/ \ + -X PUT -F status=resolved + +# Assign an issue +sentry api issues/123456789/ \ + -X PUT --field assignedTo="user@example.com" + +sentry api projects/my-org/my-project/ -X DELETE + +# Add custom headers +sentry api organizations/ -H "X-Custom: value" + +# Read body from a file +sentry api projects/my-org/my-project/releases/ -X POST --input release.json + +# Verbose mode (shows full HTTP request/response) +sentry api organizations/ --verbose + +# Preview the request without sending +sentry api organizations/ --dry-run +``` + All commands also support `--json`, `--fields`, `--help`, `--log-level`, and `--verbose` flags. diff --git a/plugins/sentry-cli/skills/sentry-cli/references/dashboards.md b/plugins/sentry-cli/skills/sentry-cli/references/dashboards.md index b68f59b28..28c9b3df8 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/dashboards.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/dashboards.md @@ -72,4 +72,67 @@ Delete a widget from a dashboard - `-i, --index <value> - Widget index (0-based)` - `-t, --title <value> - Widget title to match` +**Examples:** + +```bash +# List all dashboards +sentry dashboard list + +# Filter by name pattern +sentry dashboard list "Backend*" + +# Open dashboard list in browser +sentry dashboard list -w + +# View by title +sentry dashboard view 'Frontend Performance' + +# View by ID +sentry dashboard view 12345 + +# Auto-refresh every 30 seconds +sentry dashboard view "Backend Performance" --refresh 30 + +# Open in browser +sentry dashboard view 12345 -w + +sentry dashboard create 'Frontend Performance' + +# Simple counter widget +sentry dashboard widget add 'My Dashboard' "Error Count" \ + --display big_number --query count + +# Line chart with group-by +sentry dashboard widget add 'My Dashboard' "Errors by Browser" \ + --display line --query count --group-by browser.name + +# Table with multiple aggregates, sorted descending +sentry dashboard widget add 'My Dashboard' "Top Endpoints" \ + --display table \ + --query count --query p95:span.duration \ + --group-by transaction \ + --sort -count --limit 10 + +# With search filter +sentry dashboard widget add 'My Dashboard' "Slow Requests" \ + --display bar --query p95:span.duration \ + --where "span.op:http.client" \ + --group-by span.description + +# Change display type +sentry dashboard widget edit 12345 --title 'Error Count' --display bar + +# Rename a widget +sentry dashboard widget edit 'My Dashboard' --index 0 --new-title 'Total Errors' + +# Change the query +sentry dashboard widget edit 12345 --title 'Error Rate' --query p95:span.duration + +# Delete by title +sentry dashboard widget delete 'My Dashboard' --title 'Error Count' + +# Delete by index +sentry dashboard widget delete 12345 --index 2 +``` + All commands also support `--json`, `--fields`, `--help`, `--log-level`, and `--verbose` flags. diff --git a/plugins/sentry-cli/skills/sentry-cli/references/events.md b/plugins/sentry-cli/skills/sentry-cli/references/events.md index 2a7a0eca6..f44f3bbf7 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/events.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/events.md @@ -20,4 +20,13 @@ View details of a specific event - `--spans <value> - Span tree depth limit (number, "all" for unlimited, "no" to disable) - (default: "3")` - `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` +**Examples:** + +```bash +sentry event view abc123def456abc123def456abc12345 + +# Open in browser +sentry event view abc123def456abc123def456abc12345 -w +``` + All commands also support `--json`, `--fields`, `--help`, `--log-level`, and `--verbose` flags. diff --git a/plugins/sentry-cli/skills/sentry-cli/references/issues.md b/plugins/sentry-cli/skills/sentry-cli/references/issues.md index 5b8bbfe99..8b078ca59 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/issues.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/issues.md @@ -74,4 +74,46 @@ View details of a specific issue - `--spans <value> - Span tree depth limit (number, "all" for unlimited, "no" to disable) - (default: "3")` - `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` +**Examples:** + +```bash +# List issues in a specific project +sentry issue list my-org/frontend + +# All projects in an org +sentry issue list my-org/ + +# Search for a project across organizations +sentry issue list frontend + +# Show only unresolved issues +sentry issue list my-org/frontend --query "is:unresolved" + +# Show resolved issues +sentry issue list my-org/frontend --query "is:resolved" + +# Sort by frequency +sentry issue list my-org/frontend --sort freq --limit 20 + +sentry issue view FRONT-ABC + +# Open in browser +sentry issue view FRONT-ABC -w + +# Analyze root cause (may take a few minutes for new issues) +sentry issue explain 123456789 + +# By short ID with org prefix +sentry issue explain my-org/MYPROJECT-ABC + +# Force a fresh analysis +sentry issue explain 123456789 --force + +# Generate a fix plan (requires explain to be run first) +sentry issue plan 123456789 + +# Specify which root cause to plan for +sentry issue plan 123456789 --cause 0 +``` + All commands also support `--json`, `--fields`, `--help`, `--log-level`, and `--verbose` flags. diff --git a/plugins/sentry-cli/skills/sentry-cli/references/logs.md b/plugins/sentry-cli/skills/sentry-cli/references/logs.md index 53a774b8d..dad8141f3 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/logs.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/logs.md @@ -42,4 +42,39 @@ View details of one or more log entries - `-w, --web - Open in browser` - `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` +**Examples:** + +```bash +# List last 100 logs (default) +sentry log list + +# Show only error logs +sentry log list -q 'level:error' + +# Filter by message content +sentry log list -q 'database' + +# Limit results +sentry log list --limit 50 + +# Stream with default 2-second poll interval +sentry log list -f + +# Stream with custom 5-second poll interval +sentry log list -f 5 + +# Stream error logs from a specific project +sentry log list my-org/backend -f -q 'level:error' + +sentry log view 968c763c740cfda8b6728f27fb9e9b01 + +# With explicit project +sentry log view my-org/backend 968c763c740cfda8b6728f27fb9e9b01 + +# Open in browser +sentry log view 968c763c740cfda8b6728f27fb9e9b01 -w + +sentry log list --json | jq '.data[] | select(.severity == "error")' +``` + All commands also support `--json`, `--fields`, `--help`, `--log-level`, and `--verbose` flags. diff --git a/plugins/sentry-cli/skills/sentry-cli/references/organizations.md b/plugins/sentry-cli/skills/sentry-cli/references/organizations.md index 3ea8cdfd1..4c5effc3e 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/organizations.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/organizations.md @@ -27,4 +27,20 @@ View details of an organization - `-w, --web - Open in browser` - `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` +**Examples:** + +```bash +# List organizations +sentry org list + +# View organization details +sentry org view my-org + +# Open in browser +sentry org view my-org -w + +# JSON output +sentry org list --json +``` + All commands also support `--json`, `--fields`, `--help`, `--log-level`, and `--verbose` flags. diff --git a/plugins/sentry-cli/skills/sentry-cli/references/projects.md b/plugins/sentry-cli/skills/sentry-cli/references/projects.md index 23e643c16..8159570c0 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/projects.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/projects.md @@ -46,4 +46,20 @@ View details of a project - `-w, --web - Open in browser` - `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` +**Examples:** + +```bash +# List all projects in an org +sentry project list my-org/ + +# Filter by platform +sentry project list my-org/ --platform javascript + +# View project details +sentry project view my-org/frontend + +# Open project in browser +sentry project view my-org/frontend -w +``` + All commands also support `--json`, `--fields`, `--help`, `--log-level`, and `--verbose` flags. diff --git a/plugins/sentry-cli/skills/sentry-cli/references/setup.md b/plugins/sentry-cli/skills/sentry-cli/references/setup.md index cc0171237..c7661e7f3 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/setup.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/setup.md @@ -49,6 +49,35 @@ Update the Sentry CLI to the latest version - `--offline - Upgrade using only cached version info and patches (no network)` - `--method <value> - Installation method to use (curl, brew, npm, pnpm, bun, yarn)` +**Examples:** + +```bash +sentry cli upgrade --check + +# Upgrade to latest stable +sentry cli upgrade + +# Upgrade to a specific version +sentry cli upgrade 0.5.0 + +# Force re-download +sentry cli upgrade --force + +# Switch to nightly builds +sentry cli upgrade nightly + +# Switch back to stable +sentry cli upgrade stable + +# Send positive feedback +sentry cli feedback i love this tool + +# Report an issue +sentry cli feedback the issue view is confusing + +sentry cli fix +``` + ### `sentry init <target> <directory>` Initialize Sentry in your project (experimental) @@ -59,6 +88,34 @@ Initialize Sentry in your project (experimental) - `--features <value>... - Features to enable: errors,tracing,logs,replay,metrics,profiling,sourcemaps,crons,ai-monitoring,user-feedback` - `-t, --team <value> - Team slug to create the project under` +**Examples:** + +```bash +# Interactive setup +sentry init + +# Non-interactive with auto-yes +sentry init -y + +# Dry run to preview changes +sentry init --dry-run + +# Target a subdirectory +sentry init ./my-app + +# Use a specific org (auto-detect project) +sentry init acme/ + +# Use a specific org and project +sentry init acme/my-app + +# Assign a team when creating a new project +sentry init acme/ --team backend + +# Enable specific features +sentry init --features profiling,replay +``` + ### `sentry schema <resource...>` Browse the Sentry API schema @@ -67,4 +124,23 @@ Browse the Sentry API schema - `--all - Show all endpoints in a flat list` - `-q, --search <value> - Search endpoints by keyword` +**Examples:** + +```bash +# List all API resources +sentry schema + +# Browse issue endpoints +sentry schema issues + +# View details for a specific operation +sentry schema issues list + +# Search for monitoring-related endpoints +sentry schema --search monitor + +# Flat list of every endpoint +sentry schema --all +``` + All commands also support `--json`, `--fields`, `--help`, `--log-level`, and `--verbose` flags. diff --git a/plugins/sentry-cli/skills/sentry-cli/references/sourcemap.md b/plugins/sentry-cli/skills/sentry-cli/references/sourcemap.md index 1c6bc3227..d87d5eac2 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/sourcemap.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/sourcemap.md @@ -27,4 +27,26 @@ Upload sourcemaps to Sentry - `--release <value> - Release version to associate with the upload` - `--url-prefix <value> - URL prefix for uploaded files (default: ~/) - (default: "~/")` +**Examples:** + +```bash +# Inject debug IDs into all JS files in dist/ +sentry sourcemap inject ./dist + +# Preview changes without writing +sentry sourcemap inject ./dist --dry-run + +# Only process specific extensions +sentry sourcemap inject ./build --ext .js,.mjs + +# Upload sourcemaps from dist/ +sentry sourcemap upload ./dist + +# Associate with a release +sentry sourcemap upload ./dist --release 1.0.0 + +# Set a custom URL prefix +sentry sourcemap upload ./dist --url-prefix '~/static/js/' +``` + All commands also support `--json`, `--fields`, `--help`, `--log-level`, and `--verbose` flags. diff --git a/plugins/sentry-cli/skills/sentry-cli/references/teams.md b/plugins/sentry-cli/skills/sentry-cli/references/teams.md index 05d1deb51..af3c4186d 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/teams.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/teams.md @@ -36,6 +36,19 @@ List repositories | `externalSlug` | string \| null | External slug (e.g. org/repo) | | `externalId` | string \| null | External ID | +**Examples:** + +```bash +# List repositories (auto-detect org) +sentry repo list + +# List repos in a specific org with pagination +sentry repo list my-org/ -c next + +# Output as JSON +sentry repo list --json +``` + ### `sentry team list <org/project>` List teams @@ -57,4 +70,17 @@ List teams | `teamRole` | string \| null | Your role in the team | | `memberCount` | number | Number of members | +**Examples:** + +```bash +# List teams +sentry team list my-org/ + +# Paginate through teams +sentry team list my-org/ -c next + +# Output as JSON +sentry team list --json +``` + All commands also support `--json`, `--fields`, `--help`, `--log-level`, and `--verbose` flags. diff --git a/plugins/sentry-cli/skills/sentry-cli/references/traces.md b/plugins/sentry-cli/skills/sentry-cli/references/traces.md index b1a68c2b5..682f34ec8 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/traces.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/traces.md @@ -47,6 +47,34 @@ View details of specific spans - `--spans <value> - Span tree depth limit (number, "all" for unlimited, "no" to disable) - (default: "3")` - `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` +**Examples:** + +```bash +# List recent spans in the current project +sentry span list + +# Find all DB spans +sentry span list -q "op:db" + +# Slow spans in the last 24 hours +sentry span list -q "duration:>100ms" --period 24h + +# List spans within a specific trace +sentry span list abc123def456abc123def456abc12345 + +# Paginate through results +sentry span list -c next + +# View a single span +sentry span view abc123def456abc123def456abc12345 a1b2c3d4e5f67890 + +# View multiple spans at once +sentry span view abc123def456abc123def456abc12345 a1b2c3d4e5f67890 b2c3d4e5f6789012 + +# With explicit org/project +sentry span view my-org/backend/abc123def456abc123def456abc12345 a1b2c3d4e5f67890 +``` + ### `sentry trace list <org/project>` List recent traces in a project @@ -91,4 +119,38 @@ View logs associated with a trace - `-s, --sort <value> - Sort order: "newest" (default) or "oldest" - (default: "newest")` - `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` +**Examples:** + +```bash +# List last 20 traces (default) +sentry trace list + +# Sort by slowest first +sentry trace list --sort duration + +# Filter by transaction name, last 24 hours +sentry trace list -q "transaction:GET /api/users" --period 24h + +# Paginate through results +sentry trace list my-org/backend -c next + +# View trace details with span tree +sentry trace view abc123def456abc123def456abc12345 + +# Open trace in browser +sentry trace view abc123def456abc123def456abc12345 -w + +# Auto-recover from an issue short ID +sentry trace view PROJ-123 + +# View logs for a trace +sentry trace logs abc123def456abc123def456abc12345 + +# Search with a longer time window +sentry trace logs --period 30d abc123def456abc123def456abc12345 + +# Filter logs within a trace +sentry trace logs -q 'level:error' abc123def456abc123def456abc12345 +``` + All commands also support `--json`, `--fields`, `--help`, `--log-level`, and `--verbose` flags. diff --git a/plugins/sentry-cli/skills/sentry-cli/references/trials.md b/plugins/sentry-cli/skills/sentry-cli/references/trials.md index 070ec9971..9513c755d 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/trials.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/trials.md @@ -30,4 +30,23 @@ List product trials Start a product trial +**Examples:** + +```bash +# List all trials for the current org +sentry trial list + +# List trials for a specific org +sentry trial list my-org + +# Start a Seer trial +sentry trial start seer + +# Start a trial for a specific org +sentry trial start replays my-org + +# Start a Business plan trial (opens browser) +sentry trial start plan +``` + All commands also support `--json`, `--fields`, `--help`, `--log-level`, and `--verbose` flags. diff --git a/script/generate-command-docs.ts b/script/generate-command-docs.ts index 06664c34a..d658e4160 100644 --- a/script/generate-command-docs.ts +++ b/script/generate-command-docs.ts @@ -248,41 +248,16 @@ function capitalize(s: string): string { // Index Table Generation // --------------------------------------------------------------------------- -/** Route display order for the commands index table */ -const INDEX_ORDER = [ - "auth", - "cli", - "org", - "project", - "team", - "issue", - "event", - "log", - "trace", - "span", - "dashboard", - "sourcemap", - "repo", - "trial", - "init", - "schema", - "api", -]; - -/** Generate the commands table for index.md */ +/** + * Generate the commands table for index.md. + * Uses the route order from extractAllRoutes() (which preserves the + * insertion order from app.ts's buildRouteMap) — no manual constant needed. + */ function generateCommandsTable(allRoutes: RouteInfo[]): string { - const sorted = [...allRoutes].sort((a, b) => { - const aIdx = INDEX_ORDER.indexOf(a.name); - const bIdx = INDEX_ORDER.indexOf(b.name); - const aOrder = aIdx === -1 ? 999 : aIdx; - const bOrder = bIdx === -1 ? 999 : bIdx; - return aOrder - bOrder; - }); - const lines: string[] = []; lines.push("| Command | Description |"); lines.push("|---------|-------------|"); - for (const route of sorted) { + for (const route of allRoutes) { lines.push(`| [\`${route.name}\`](./${route.name}/) | ${route.brief} |`); } return lines.join("\n"); diff --git a/script/generate-skill.ts b/script/generate-skill.ts index b868cee45..ed02455c9 100644 --- a/script/generate-skill.ts +++ b/script/generate-skill.ts @@ -328,19 +328,24 @@ sentry auth status \`\`\``; } -/** Regex to match command sections in docs (### `sentry ...`) */ +/** + * Regex to match command sections in docs (### `sentry ...`). + * Captures the command path (e.g., "sentry issue list") while allowing + * optional positional placeholders before the closing backtick + * (e.g., `sentry issue list <org/project>`). + * + * Uses `[^\s<]+` instead of `\S+` so the capture stops at `<` + * (the start of positional placeholders like `<org/project>`). + */ const COMMAND_SECTION_REGEX = - /###\s+`(sentry\s+\S+(?:\s+\S+)?)`\s*\n([\s\S]*?)(?=###\s+`|$)/g; + /###\s+`(sentry(?:\s+[^\s<]+){1,3})[^`]*`\s*\n([\s\S]*?)(?=###\s+`|$)/g; -/** Load examples for a specific command from docs */ -async function loadCommandExamples( - commandGroup: string -): Promise<Map<string, string[]>> { - const docContent = await loadDoc(`commands/${commandGroup}.md`); +/** + * Extract examples from `### \`sentry ...\`` command sections in markdown. + * Returns a map of command path → code block contents. + */ +function extractSectionExamples(docContent: string): Map<string, string[]> { const examples = new Map<string, string[]>(); - if (!docContent) { - return examples; - } const commandPattern = new RegExp( COMMAND_SECTION_REGEX.source, COMMAND_SECTION_REGEX.flags @@ -350,17 +355,92 @@ async function loadCommandExamples( const commandPath = match[1]; const sectionContent = match[2]; const codeBlocks = extractCodeBlocks(sectionContent, "bash"); - if (codeBlocks.length > 0) { - examples.set( - commandPath, - codeBlocks.map((b) => b.code) - ); - } + // Always register the command path so extractLooseExamples can + // match custom-section code blocks to specific subcommands. + examples.set( + commandPath, + codeBlocks.map((b) => b.code) + ); match = commandPattern.exec(docContent); } return examples; } +/** Append a code block to a map entry, creating the array if needed */ +function appendExample( + map: Map<string, string[]>, + key: string, + code: string +): void { + const list = map.get(key) ?? []; + list.push(code); + map.set(key, list); +} + +/** + * Find the first command path that appears in a code block's content. + * Returns undefined if no match is found. + */ +function matchCommandPath(code: string, paths: string[]): string | undefined { + return paths.find((p) => code.includes(p)); +} + +/** + * Scan all bash code blocks in a document and match them to commands + * by looking for `sentry <group> <subcommand>` in the code content. + * + * Handles the case where examples live in a separate custom section + * (below a GENERATED:END marker) rather than inline within command + * reference headings. + */ +function extractLooseExamples( + docContent: string, + commandGroup: string, + existing: Map<string, string[]> +): void { + const commandPaths = Array.from(existing.keys()); + const allBashBlocks = extractCodeBlocks(docContent, "bash"); + + if (commandPaths.length === 0) { + const prefix = `sentry ${commandGroup}`; + for (const block of allBashBlocks) { + if (block.code.includes(prefix)) { + appendExample(existing, prefix, block.code); + } + } + return; + } + + const capturedCode = new Set(Array.from(existing.values()).flat()); + for (const block of allBashBlocks) { + if (capturedCode.has(block.code)) { + continue; + } + const matched = matchCommandPath(block.code, commandPaths); + if (matched) { + appendExample(existing, matched, block.code); + } + } +} + +/** + * Load examples for a specific command group from docs. + * + * Uses two strategies: (1) extract bash blocks from `### \`sentry ...\`` + * sections, (2) scan loose bash blocks and match by command path in content. + */ +async function loadCommandExamples( + commandGroup: string +): Promise<Map<string, string[]>> { + const docContent = await loadDoc(`commands/${commandGroup}.md`); + if (!docContent) { + return new Map(); + } + const examples = extractSectionExamples(docContent); + extractLooseExamples(docContent, commandGroup, examples); + return examples; +} + /** Load supplementary content from commands/index.md */ async function loadCommandsOverview(): Promise<{ globalOptions: string; From 5d5097225f6377b45a507cc9fa26aa077fd50592 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya <byk@sentry.io> Date: Fri, 27 Mar 2026 01:40:54 +0000 Subject: [PATCH 10/10] refactor: use marked AST parser for example extraction, add examples check Replace fragile regex-based markdown parsing in generate-skill.ts with marked.lexer() AST walking for robust command heading detection and code block association. The old COMMAND_SECTION_REGEX was brittle with positional placeholders in headings and couldn't handle the split between auto-generated reference sections and hand-written custom sections. The new approach: 1. Parses the full document into an AST via marked.lexer() 2. Collects command paths from ### `sentry ...` headings 3. Walks tokens sequentially, associating bash code blocks with commands by heading context or content matching Also adds an examples completeness check to check-skill.ts that verifies every skill reference file contains at least one Examples section. This catches cases where doc pages are missing bash code blocks that the skill generator needs. --- .../skills/sentry-cli/references/auth.md | 42 ++--- .../sentry-cli/references/dashboards.md | 114 ++++++++------ .../skills/sentry-cli/references/issues.md | 66 ++++---- .../skills/sentry-cli/references/logs.md | 24 +-- .../skills/sentry-cli/references/setup.md | 24 ++- .../skills/sentry-cli/references/sourcemap.md | 20 ++- .../skills/sentry-cli/references/traces.md | 70 +++++---- script/check-skill.ts | 48 +++++- script/generate-skill.ts | 143 +++++++++--------- 9 files changed, 324 insertions(+), 227 deletions(-) diff --git a/plugins/sentry-cli/skills/sentry-cli/references/auth.md b/plugins/sentry-cli/skills/sentry-cli/references/auth.md index 88146e14c..33bdf31ed 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/auth.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/auth.md @@ -20,6 +20,18 @@ Authenticate with Sentry - `--timeout <value> - Timeout for OAuth flow in seconds (default: 900) - (default: "900")` - `--force - Re-authenticate without prompting` +**Examples:** + +```bash +sentry auth login + +sentry auth login --token YOUR_SENTRY_API_TOKEN + +SENTRY_URL=https://sentry.example.com sentry auth login + +SENTRY_URL=https://sentry.example.com sentry auth login --token YOUR_TOKEN +``` + ### `sentry auth logout` Log out of Sentry @@ -39,28 +51,9 @@ View authentication status - `--show-token - Show the stored token (masked by default)` - `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` -### `sentry auth token` - -Print the stored authentication token - -### `sentry auth whoami` - -Show the currently authenticated user - -**Flags:** -- `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` - **Examples:** ```bash -sentry auth login - -sentry auth login --token YOUR_SENTRY_API_TOKEN - -SENTRY_URL=https://sentry.example.com sentry auth login - -SENTRY_URL=https://sentry.example.com sentry auth login --token YOUR_TOKEN - sentry auth status # Show the raw token @@ -70,4 +63,15 @@ sentry auth status --show-token sentry auth whoami ``` +### `sentry auth token` + +Print the stored authentication token + +### `sentry auth whoami` + +Show the currently authenticated user + +**Flags:** +- `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` + All commands also support `--json`, `--fields`, `--help`, `--log-level`, and `--verbose` flags. diff --git a/plugins/sentry-cli/skills/sentry-cli/references/dashboards.md b/plugins/sentry-cli/skills/sentry-cli/references/dashboards.md index 28c9b3df8..c565b83d5 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/dashboards.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/dashboards.md @@ -21,6 +21,19 @@ List dashboards - `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` - `-c, --cursor <value> - Navigate pages: "next", "prev", "first" (or raw cursor string)` +**Examples:** + +```bash +# List all dashboards +sentry dashboard list + +# Filter by name pattern +sentry dashboard list "Backend*" + +# Open dashboard list in browser +sentry dashboard list -w +``` + ### `sentry dashboard view <org/project/dashboard...>` View a dashboard @@ -31,31 +44,37 @@ View a dashboard - `-r, --refresh <value> - Auto-refresh interval in seconds (default: 60, min: 10)` - `-t, --period <value> - Time period override (e.g., "24h", "7d", "14d")` +**Examples:** + +```bash +# View by title +sentry dashboard view 'Frontend Performance' + +# View by ID +sentry dashboard view 12345 + +# Auto-refresh every 30 seconds +sentry dashboard view "Backend Performance" --refresh 30 + +# Open in browser +sentry dashboard view 12345 -w +``` + ### `sentry dashboard create <org/project/title...>` Create a dashboard -### `sentry dashboard widget add <org/project/dashboard/title...>` - -Add a widget to a dashboard +**Examples:** -**Flags:** -- `-d, --display <value> - Display type (big_number, line, area, bar, table, stacked_area, top_n, text, categorical_bar, details, wheel, rage_and_dead_clicks, server_tree, agents_traces_table)` -- `--dataset <value> - Widget dataset (default: spans)` -- `-q, --query <value>... - Aggregate expression (e.g. count, p95:span.duration)` -- `-w, --where <value> - Search conditions filter (e.g. is:unresolved)` -- `-g, --group-by <value>... - Group-by column (repeatable)` -- `-s, --sort <value> - Order by (prefix - for desc, e.g. -count)` -- `-n, --limit <value> - Result limit` +```bash +sentry dashboard create 'Frontend Performance' +``` -### `sentry dashboard widget edit <org/project/dashboard...>` +### `sentry dashboard widget add <org/project/dashboard/title...>` -Edit a widget in a dashboard +Add a widget to a dashboard **Flags:** -- `-i, --index <value> - Widget index (0-based)` -- `-t, --title <value> - Widget title to match` -- `--new-title <value> - New widget title` - `-d, --display <value> - Display type (big_number, line, area, bar, table, stacked_area, top_n, text, categorical_bar, details, wheel, rage_and_dead_clicks, server_tree, agents_traces_table)` - `--dataset <value> - Widget dataset (default: spans)` - `-q, --query <value>... - Aggregate expression (e.g. count, p95:span.duration)` @@ -64,40 +83,9 @@ Edit a widget in a dashboard - `-s, --sort <value> - Order by (prefix - for desc, e.g. -count)` - `-n, --limit <value> - Result limit` -### `sentry dashboard widget delete <org/project/dashboard...>` - -Delete a widget from a dashboard - -**Flags:** -- `-i, --index <value> - Widget index (0-based)` -- `-t, --title <value> - Widget title to match` - **Examples:** ```bash -# List all dashboards -sentry dashboard list - -# Filter by name pattern -sentry dashboard list "Backend*" - -# Open dashboard list in browser -sentry dashboard list -w - -# View by title -sentry dashboard view 'Frontend Performance' - -# View by ID -sentry dashboard view 12345 - -# Auto-refresh every 30 seconds -sentry dashboard view "Backend Performance" --refresh 30 - -# Open in browser -sentry dashboard view 12345 -w - -sentry dashboard create 'Frontend Performance' - # Simple counter widget sentry dashboard widget add 'My Dashboard' "Error Count" \ --display big_number --query count @@ -118,7 +106,27 @@ sentry dashboard widget add 'My Dashboard' "Slow Requests" \ --display bar --query p95:span.duration \ --where "span.op:http.client" \ --group-by span.description +``` +### `sentry dashboard widget edit <org/project/dashboard...>` + +Edit a widget in a dashboard + +**Flags:** +- `-i, --index <value> - Widget index (0-based)` +- `-t, --title <value> - Widget title to match` +- `--new-title <value> - New widget title` +- `-d, --display <value> - Display type (big_number, line, area, bar, table, stacked_area, top_n, text, categorical_bar, details, wheel, rage_and_dead_clicks, server_tree, agents_traces_table)` +- `--dataset <value> - Widget dataset (default: spans)` +- `-q, --query <value>... - Aggregate expression (e.g. count, p95:span.duration)` +- `-w, --where <value> - Search conditions filter (e.g. is:unresolved)` +- `-g, --group-by <value>... - Group-by column (repeatable)` +- `-s, --sort <value> - Order by (prefix - for desc, e.g. -count)` +- `-n, --limit <value> - Result limit` + +**Examples:** + +```bash # Change display type sentry dashboard widget edit 12345 --title 'Error Count' --display bar @@ -127,7 +135,19 @@ sentry dashboard widget edit 'My Dashboard' --index 0 --new-title 'Total Errors' # Change the query sentry dashboard widget edit 12345 --title 'Error Rate' --query p95:span.duration +``` + +### `sentry dashboard widget delete <org/project/dashboard...>` + +Delete a widget from a dashboard +**Flags:** +- `-i, --index <value> - Widget index (0-based)` +- `-t, --title <value> - Widget title to match` + +**Examples:** + +```bash # Delete by title sentry dashboard widget delete 'My Dashboard' --title 'Error Count' diff --git a/plugins/sentry-cli/skills/sentry-cli/references/issues.md b/plugins/sentry-cli/skills/sentry-cli/references/issues.md index 8b078ca59..55048ce6d 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/issues.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/issues.md @@ -48,32 +48,6 @@ List issues in a project | `isUnhandled` | boolean | Whether the issue is unhandled | | `seerFixabilityScore` | number \| null | Seer AI fixability score (0-1) | -### `sentry issue explain <issue>` - -Analyze an issue's root cause using Seer AI - -**Flags:** -- `--force - Force new analysis even if one exists` -- `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` - -### `sentry issue plan <issue>` - -Generate a solution plan using Seer AI - -**Flags:** -- `--cause <value> - Root cause ID to plan (required if multiple causes exist)` -- `--force - Force new plan even if one exists` -- `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` - -### `sentry issue view <issue>` - -View details of a specific issue - -**Flags:** -- `-w, --web - Open in browser` -- `--spans <value> - Span tree depth limit (number, "all" for unlimited, "no" to disable) - (default: "3")` -- `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` - **Examples:** ```bash @@ -94,12 +68,19 @@ sentry issue list my-org/frontend --query "is:resolved" # Sort by frequency sentry issue list my-org/frontend --sort freq --limit 20 +``` -sentry issue view FRONT-ABC +### `sentry issue explain <issue>` -# Open in browser -sentry issue view FRONT-ABC -w +Analyze an issue's root cause using Seer AI + +**Flags:** +- `--force - Force new analysis even if one exists` +- `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` + +**Examples:** +```bash # Analyze root cause (may take a few minutes for new issues) sentry issue explain 123456789 @@ -116,4 +97,31 @@ sentry issue plan 123456789 sentry issue plan 123456789 --cause 0 ``` +### `sentry issue plan <issue>` + +Generate a solution plan using Seer AI + +**Flags:** +- `--cause <value> - Root cause ID to plan (required if multiple causes exist)` +- `--force - Force new plan even if one exists` +- `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` + +### `sentry issue view <issue>` + +View details of a specific issue + +**Flags:** +- `-w, --web - Open in browser` +- `--spans <value> - Span tree depth limit (number, "all" for unlimited, "no" to disable) - (default: "3")` +- `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` + +**Examples:** + +```bash +sentry issue view FRONT-ABC + +# Open in browser +sentry issue view FRONT-ABC -w +``` + All commands also support `--json`, `--fields`, `--help`, `--log-level`, and `--verbose` flags. diff --git a/plugins/sentry-cli/skills/sentry-cli/references/logs.md b/plugins/sentry-cli/skills/sentry-cli/references/logs.md index dad8141f3..3d08e7c26 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/logs.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/logs.md @@ -34,14 +34,6 @@ List logs from a project | `severity` | string \| null | Severity level (error, warning, info, debug) | | `trace` | string \| null | Trace ID for correlation | -### `sentry log view <org/project/log-id...>` - -View details of one or more log entries - -**Flags:** -- `-w, --web - Open in browser` -- `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` - **Examples:** ```bash @@ -66,6 +58,20 @@ sentry log list -f 5 # Stream error logs from a specific project sentry log list my-org/backend -f -q 'level:error' +sentry log list --json | jq '.data[] | select(.severity == "error")' +``` + +### `sentry log view <org/project/log-id...>` + +View details of one or more log entries + +**Flags:** +- `-w, --web - Open in browser` +- `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` + +**Examples:** + +```bash sentry log view 968c763c740cfda8b6728f27fb9e9b01 # With explicit project @@ -73,8 +79,6 @@ sentry log view my-org/backend 968c763c740cfda8b6728f27fb9e9b01 # Open in browser sentry log view 968c763c740cfda8b6728f27fb9e9b01 -w - -sentry log list --json | jq '.data[] | select(.severity == "error")' ``` All commands also support `--json`, `--fields`, `--help`, `--log-level`, and `--verbose` flags. diff --git a/plugins/sentry-cli/skills/sentry-cli/references/setup.md b/plugins/sentry-cli/skills/sentry-cli/references/setup.md index c7661e7f3..c5d009b16 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/setup.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/setup.md @@ -19,6 +19,16 @@ Browse the Sentry API schema Send feedback about the CLI +**Examples:** + +```bash +# Send positive feedback +sentry cli feedback i love this tool + +# Report an issue +sentry cli feedback the issue view is confusing +``` + ### `sentry cli fix` Diagnose and repair CLI database issues @@ -26,6 +36,12 @@ Diagnose and repair CLI database issues **Flags:** - `--dry-run - Show what would be fixed without making changes` +**Examples:** + +```bash +sentry cli fix +``` + ### `sentry cli setup` Configure shell integration @@ -68,14 +84,6 @@ sentry cli upgrade nightly # Switch back to stable sentry cli upgrade stable - -# Send positive feedback -sentry cli feedback i love this tool - -# Report an issue -sentry cli feedback the issue view is confusing - -sentry cli fix ``` ### `sentry init <target> <directory>` diff --git a/plugins/sentry-cli/skills/sentry-cli/references/sourcemap.md b/plugins/sentry-cli/skills/sentry-cli/references/sourcemap.md index d87d5eac2..ae7b97165 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/sourcemap.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/sourcemap.md @@ -19,14 +19,6 @@ Inject debug IDs into JavaScript files and sourcemaps - `--ext <value> - Comma-separated file extensions to process (default: .js,.cjs,.mjs)` - `--dry-run - Show what would be modified without writing` -### `sentry sourcemap upload <directory>` - -Upload sourcemaps to Sentry - -**Flags:** -- `--release <value> - Release version to associate with the upload` -- `--url-prefix <value> - URL prefix for uploaded files (default: ~/) - (default: "~/")` - **Examples:** ```bash @@ -38,7 +30,19 @@ sentry sourcemap inject ./dist --dry-run # Only process specific extensions sentry sourcemap inject ./build --ext .js,.mjs +``` + +### `sentry sourcemap upload <directory>` + +Upload sourcemaps to Sentry + +**Flags:** +- `--release <value> - Release version to associate with the upload` +- `--url-prefix <value> - URL prefix for uploaded files (default: ~/) - (default: "~/")` +**Examples:** + +```bash # Upload sourcemaps from dist/ sentry sourcemap upload ./dist diff --git a/plugins/sentry-cli/skills/sentry-cli/references/traces.md b/plugins/sentry-cli/skills/sentry-cli/references/traces.md index 682f34ec8..e7ad58594 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/traces.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/traces.md @@ -39,14 +39,6 @@ List spans in a project or trace | `transaction` | string \| null | Transaction name | | `trace` | string | Trace ID | -### `sentry span view <trace-id/span-id...>` - -View details of specific spans - -**Flags:** -- `--spans <value> - Span tree depth limit (number, "all" for unlimited, "no" to disable) - (default: "3")` -- `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` - **Examples:** ```bash @@ -64,7 +56,19 @@ sentry span list abc123def456abc123def456abc12345 # Paginate through results sentry span list -c next +``` +### `sentry span view <trace-id/span-id...>` + +View details of specific spans + +**Flags:** +- `--spans <value> - Span tree depth limit (number, "all" for unlimited, "no" to disable) - (default: "3")` +- `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` + +**Examples:** + +```bash # View a single span sentry span view abc123def456abc123def456abc12345 a1b2c3d4e5f67890 @@ -98,27 +102,6 @@ List recent traces in a project | `transaction.duration` | number | Duration (ms) | | `project` | string | Project slug | -### `sentry trace view <org/project/trace-id...>` - -View details of a specific trace - -**Flags:** -- `-w, --web - Open in browser` -- `--spans <value> - Span tree depth limit (number, "all" for unlimited, "no" to disable) - (default: "3")` -- `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` - -### `sentry trace logs <org/trace-id...>` - -View logs associated with a trace - -**Flags:** -- `-w, --web - Open trace in browser` -- `-t, --period <value> - Time period to search (e.g., "14d", "7d", "24h"). Default: 14d - (default: "14d")` -- `-n, --limit <value> - Number of log entries (<=1000) - (default: "100")` -- `-q, --query <value> - Additional filter query (Sentry search syntax)` -- `-s, --sort <value> - Sort order: "newest" (default) or "oldest" - (default: "newest")` -- `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` - **Examples:** ```bash @@ -133,7 +116,20 @@ sentry trace list -q "transaction:GET /api/users" --period 24h # Paginate through results sentry trace list my-org/backend -c next +``` + +### `sentry trace view <org/project/trace-id...>` + +View details of a specific trace + +**Flags:** +- `-w, --web - Open in browser` +- `--spans <value> - Span tree depth limit (number, "all" for unlimited, "no" to disable) - (default: "3")` +- `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` + +**Examples:** +```bash # View trace details with span tree sentry trace view abc123def456abc123def456abc12345 @@ -142,7 +138,23 @@ sentry trace view abc123def456abc123def456abc12345 -w # Auto-recover from an issue short ID sentry trace view PROJ-123 +``` +### `sentry trace logs <org/trace-id...>` + +View logs associated with a trace + +**Flags:** +- `-w, --web - Open trace in browser` +- `-t, --period <value> - Time period to search (e.g., "14d", "7d", "24h"). Default: 14d - (default: "14d")` +- `-n, --limit <value> - Number of log entries (<=1000) - (default: "100")` +- `-q, --query <value> - Additional filter query (Sentry search syntax)` +- `-s, --sort <value> - Sort order: "newest" (default) or "oldest" - (default: "newest")` +- `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` + +**Examples:** + +```bash # View logs for a trace sentry trace logs abc123def456abc123def456abc12345 diff --git a/script/check-skill.ts b/script/check-skill.ts index 4edc93001..6a7c11c50 100644 --- a/script/check-skill.ts +++ b/script/check-skill.ts @@ -74,16 +74,52 @@ for (const path of committedFiles.keys()) { } } -if (staleFiles.length === 0) { +// Check that every reference file contains at least one **Examples:** section. +// This catches cases where doc pages are missing bash code blocks that the +// skill generator needs to populate examples for AI agents. +const missingExamples: string[] = []; +for (const [path, content] of newFiles) { + if (!path.startsWith("references/")) { + continue; + } + if (!content.includes("**Examples:**")) { + missingExamples.push(path); + } +} + +const issues: string[] = []; + +if (staleFiles.length > 0) { + issues.push("Skill files are out of date:"); + for (const file of staleFiles) { + issues.push(` - ${file}`); + } + issues.push(""); + issues.push("Run 'bun run generate:skill' locally and commit the changes."); +} + +if (missingExamples.length > 0) { + if (issues.length > 0) { + issues.push(""); + } + issues.push("Skill reference files missing examples:"); + for (const file of missingExamples) { + issues.push(` - ${file}`); + } + issues.push(""); + issues.push( + "Add bash code blocks to the matching docs/src/content/docs/commands/ pages" + ); + issues.push("and re-run 'bun run generate:skill' to populate examples."); +} + +if (issues.length === 0) { console.log("✓ All skill files are up to date"); process.exit(0); } -console.error("✗ Skill files are out of date:"); -for (const file of staleFiles) { - console.error(` - ${file}`); +for (const line of issues) { + console.error(line.startsWith(" ") ? line : `✗ ${line}`); } -console.error(""); -console.error("Run 'bun run generate:skill' locally and commit the changes."); process.exit(1); diff --git a/script/generate-skill.ts b/script/generate-skill.ts index ed02455c9..5d16ab683 100644 --- a/script/generate-skill.ts +++ b/script/generate-skill.ts @@ -20,6 +20,8 @@ */ import { rmSync } from "node:fs"; +import type { Token } from "marked"; +import { marked } from "marked"; import { routes } from "../src/app.js"; import type { CommandInfo, @@ -329,42 +331,10 @@ sentry auth status } /** - * Regex to match command sections in docs (### `sentry ...`). - * Captures the command path (e.g., "sentry issue list") while allowing - * optional positional placeholders before the closing backtick - * (e.g., `sentry issue list <org/project>`). - * - * Uses `[^\s<]+` instead of `\S+` so the capture stops at `<` - * (the start of positional placeholders like `<org/project>`). + * Regex to extract the command path from a heading like `` `sentry issue list <org/project>` ``. + * Captures the words between `sentry` and the first `<` or closing backtick. */ -const COMMAND_SECTION_REGEX = - /###\s+`(sentry(?:\s+[^\s<]+){1,3})[^`]*`\s*\n([\s\S]*?)(?=###\s+`|$)/g; - -/** - * Extract examples from `### \`sentry ...\`` command sections in markdown. - * Returns a map of command path → code block contents. - */ -function extractSectionExamples(docContent: string): Map<string, string[]> { - const examples = new Map<string, string[]>(); - const commandPattern = new RegExp( - COMMAND_SECTION_REGEX.source, - COMMAND_SECTION_REGEX.flags - ); - let match = commandPattern.exec(docContent); - while (match !== null) { - const commandPath = match[1]; - const sectionContent = match[2]; - const codeBlocks = extractCodeBlocks(sectionContent, "bash"); - // Always register the command path so extractLooseExamples can - // match custom-section code blocks to specific subcommands. - examples.set( - commandPath, - codeBlocks.map((b) => b.code) - ); - match = commandPattern.exec(docContent); - } - return examples; -} +const CMD_HEADING_RE = /^`sentry\s+(.*?)\s*(?:<[^>]*>.*)?`$/; /** Append a code block to a map entry, creating the array if needed */ function appendExample( @@ -378,56 +348,84 @@ function appendExample( } /** - * Find the first command path that appears in a code block's content. - * Returns undefined if no match is found. + * Collect all command paths from `### \`sentry ...\`` headings in a token list. + * Initializes each path with an empty array in the examples map. */ -function matchCommandPath(code: string, paths: string[]): string | undefined { - return paths.find((p) => code.includes(p)); +function collectCommandPaths( + tokens: Token[], + examples: Map<string, string[]> +): string[] { + const paths: string[] = []; + for (const token of tokens) { + if (token.type !== "heading" || token.depth !== 3) { + continue; + } + const m = CMD_HEADING_RE.exec(token.text); + if (m) { + const cmdPath = `sentry ${m[1]}`; + paths.push(cmdPath); + if (!examples.has(cmdPath)) { + examples.set(cmdPath, []); + } + } + } + return paths; +} + +/** Find the best command path match for a loose code block by content */ +function matchCodeToCommand( + code: string, + commandPaths: string[], + groupFallback: string +): string | undefined { + return ( + commandPaths.find((p) => code.includes(p)) ?? + (code.includes(groupFallback) ? groupFallback : undefined) + ); } /** - * Scan all bash code blocks in a document and match them to commands - * by looking for `sentry <group> <subcommand>` in the code content. - * - * Handles the case where examples live in a separate custom section - * (below a GENERATED:END marker) rather than inline within command - * reference headings. + * Walk tokens sequentially and associate each bash code block with + * the appropriate command path — either by heading context or content matching. */ -function extractLooseExamples( - docContent: string, +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: sequential token walk with type narrowing +function associateCodeBlocks( + tokens: Token[], + commandPaths: string[], commandGroup: string, - existing: Map<string, string[]> + examples: Map<string, string[]> ): void { - const commandPaths = Array.from(existing.keys()); - const allBashBlocks = extractCodeBlocks(docContent, "bash"); - - if (commandPaths.length === 0) { - const prefix = `sentry ${commandGroup}`; - for (const block of allBashBlocks) { - if (block.code.includes(prefix)) { - appendExample(existing, prefix, block.code); - } - } - return; - } + const groupFallback = `sentry ${commandGroup}`; + let currentCmd: string | null = null; - const capturedCode = new Set(Array.from(existing.values()).flat()); - for (const block of allBashBlocks) { - if (capturedCode.has(block.code)) { + for (const token of tokens) { + if (token.type === "heading" && token.depth === 3) { + const m = CMD_HEADING_RE.exec(token.text); + currentCmd = m ? `sentry ${m[1]}` : null; + } + if (token.type !== "code" || token.lang !== "bash") { continue; } - const matched = matchCommandPath(block.code, commandPaths); - if (matched) { - appendExample(existing, matched, block.code); + const code = token.text.trim(); + if (currentCmd && examples.has(currentCmd)) { + appendExample(examples, currentCmd, code); + } else { + const target = matchCodeToCommand(code, commandPaths, groupFallback); + if (target) { + appendExample(examples, target, code); + } } } } /** - * Load examples for a specific command group from docs. + * Load examples for a specific command group from docs using the `marked` + * AST parser. Walks the token tree to find command headings and associate + * bash code blocks with each command. * - * Uses two strategies: (1) extract bash blocks from `### \`sentry ...\`` - * sections, (2) scan loose bash blocks and match by command path in content. + * Handles both auto-generated reference sections (`### \`sentry ...\`` headings) + * and hand-written custom sections (`## Examples` with descriptive headings) + * by matching code blocks to commands via heading context or content analysis. */ async function loadCommandExamples( commandGroup: string @@ -436,8 +434,11 @@ async function loadCommandExamples( if (!docContent) { return new Map(); } - const examples = extractSectionExamples(docContent); - extractLooseExamples(docContent, commandGroup, examples); + + const tokens = marked.lexer(docContent); + const examples = new Map<string, string[]>(); + const commandPaths = collectCommandPaths(tokens, examples); + associateCodeBlocks(tokens, commandPaths, commandGroup, examples); return examples; }