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..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 `` 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 @@ -893,82 +893,83 @@ 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 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. - -* **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. SDK is \`@sentry/node-core/light\` (not \`@sentry/bun\`). - -* **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 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. - -* **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. + +* **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. - -* **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. + +* **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). -### Gotcha + +* **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. - -* **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. + +* **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. - -* **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. + +* **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\`. - -* **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. + +* **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\`). - -* **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. + +* **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. -### Pattern + +* **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. - -* **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. + +* **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 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 \`\\` 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. - -* **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..9a1f943f2 100644 --- a/docs/src/content/docs/commands/api.md +++ b/docs/src/content/docs/commands/api.md @@ -1,114 +1,98 @@ --- 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 | +| `-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 | + +All commands support `--json` for machine-readable output and `--fields` to select specific JSON fields. + + ## Examples -### GET Request +Endpoints are relative to `/api/0/` — the prefix is added automatically. + +### GET requests ```bash # List organizations -sentry api /organizations/ - -# Get a specific organization -sentry api /organizations/my-org/ +sentry api organizations/ -# Get project details -sentry api /projects/my-org/my-project/ +# Get a specific issue +sentry api issues/123456789/ ``` -### POST Request +### POST requests ```bash -# Create a new project -sentry api /teams/my-org/my-team/projects/ \ - --method POST \ - --field name="New Project" \ - --field platform=javascript +# 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"}' ``` -### PUT Request +### PUT requests ```bash # Update an issue status -sentry api /issues/123456789/ \ - --method PUT \ - --field status=resolved +sentry api issues/123456789/ \ + -X PUT -F status=resolved # Assign an issue -sentry api /issues/123456789/ \ - --method PUT \ - --field assignedTo="user@example.com" -``` - -### DELETE Request - -```bash -# Delete a project -sentry api /projects/my-org/my-project/ \ - --method DELETE +sentry api issues/123456789/ \ + -X PUT --field assignedTo="user@example.com" ``` -### With Headers +### DELETE requests ```bash -sentry api /organizations/ \ - --header "X-Custom-Header:value" +sentry api projects/my-org/my-project/ -X DELETE ``` -### Verbose Mode +### Advanced usage ```bash -sentry api /organizations/ --verbose -``` +# Add custom headers +sentry api organizations/ -H "X-Custom: value" -Request and response metadata is logged to stderr: +# Read body from a file +sentry api projects/my-org/my-project/releases/ -X POST --input release.json -``` -> GET /api/0/organizations/ -> -< HTTP 200 -< content-type: application/json -< -[{"slug": "my-org", ...}] -``` - -### Pagination +# Verbose mode (shows full HTTP request/response) +sentry api organizations/ --verbose -```bash -# Get all issues (automatically follows pagination) -sentry api /projects/my-org/my-project/issues/ --paginate +# Preview the request without sending +sentry api organizations/ --dry-run ``` -## 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..7549b9d3f 100644 --- a/docs/src/content/docs/commands/auth.md +++ b/docs/src/content/docs/commands/auth.md @@ -1,96 +1,126 @@ --- 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. +Authenticate with Sentry -```bash -# OAuth device flow (recommended) -sentry auth login +**Options:** -# Using an API token -sentry auth login --token YOUR_TOKEN -``` +| Option | Description | +|--------|-------------| +| `--token ` | Authenticate using an API token instead of OAuth | +| `--timeout ` | Timeout for OAuth flow in seconds (default: 900) | +| `--force` | Re-authenticate without prompting | + +### `sentry auth logout` + +Log out of Sentry + +### `sentry auth refresh` + +Refresh your authentication token + +**Options:** + +| Option | Description | +|--------|-------------| +| `--force` | Force refresh even if token is still valid | + +### `sentry auth status` + +View authentication status + +**Options:** + +| Option | Description | +|--------|-------------| +| `--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 **Options:** | Option | Description | |--------|-------------| -| `--token ` | Use an API token instead of OAuth | +| `-f, --fresh` | Bypass cache, re-detect projects, and fetch fresh data | -**OAuth Flow:** +All commands support `--json` for machine-readable output and `--fields` to select specific JSON fields. -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 + -**Self-Hosted Sentry (26.1.0+):** +## Examples -For self-hosted instances, set `SENTRY_URL` and `SENTRY_CLIENT_ID` (from a public OAuth application you create on your instance): +### OAuth login (recommended) ```bash -SENTRY_URL=https://sentry.example.com SENTRY_CLIENT_ID=your-client-id sentry auth login +sentry auth login ``` -On older versions or without an OAuth application, use an API token instead: +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 ```bash -SENTRY_URL=https://sentry.example.com sentry auth login --token YOUR_TOKEN +sentry auth login --token YOUR_SENTRY_API_TOKEN ``` -See [Self-Hosted Sentry](../self-hosted/) for full setup details. +### Self-hosted Sentry -### `sentry auth logout` +```bash +SENTRY_URL=https://sentry.example.com sentry auth login +``` -Remove stored credentials. +For token-based auth with self-hosted: ```bash -sentry auth logout +SENTRY_URL=https://sentry.example.com sentry auth login --token YOUR_TOKEN ``` -### `sentry auth status` +See [Self-Hosted Sentry](../self-hosted/) for details. -Check your authentication status. +### Check auth status ```bash sentry auth status ``` -**Output:** - ``` Authenticated as: username Organization: my-org Token expires: 2024-12-31 ``` -### `sentry auth refresh` - -Refresh your OAuth token. - ```bash -sentry auth refresh -``` +# Show the raw token +sentry auth status --show-token -This is typically handled automatically when tokens expire. +# View current user +sentry auth whoami +``` ## Credential Storage -Credentials are stored in a SQLite database at `~/.sentry/cli.db` with restricted file permissions (mode 600). - -Use `sentry auth token` to retrieve your current access token, or `sentry auth status` to check authentication state. +Auth tokens are stored in a SQLite database at `~/.sentry/config.db` with restricted file permissions. -### Environment Variable Precedence +## Environment Variable Precedence The CLI checks for auth tokens in the following order, using the first one found: diff --git a/docs/src/content/docs/commands/cli.md b/docs/src/content/docs/commands/cli.md new file mode 100644 index 000000000..731b91a6c --- /dev/null +++ b/docs/src/content/docs/commands/cli.md @@ -0,0 +1,146 @@ +--- +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 | + +### `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 | + +**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 + +### 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 + +```bash +# 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 +``` + +### Release Channels + +```bash +# Switch to nightly builds +sentry cli upgrade nightly + +# Switch back to stable +sentry cli upgrade stable +``` + +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/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..a21f17f6e 100644 --- a/docs/src/content/docs/commands/dashboard.md +++ b/docs/src/content/docs/commands/dashboard.md @@ -3,229 +3,204 @@ 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>] | **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 | +| `-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) | -**Examples:** +### `sentry dashboard view ` -```bash -sentry dashboard list -``` +View a dashboard -``` -ID TITLE WIDGETS CREATED -12345 General 4 2024-01-15 -12346 Frontend Performance 6 2024-02-20 -12347 Backend Errors 3 2024-03-10 -``` +**Arguments:** -**Open dashboard list in browser:** +| Argument | Description | +|----------|-------------| +| `` | [<org/project>] <dashboard-id-or-title> | -```bash -sentry dashboard list -w -``` +**Options:** -### `sentry dashboard view` +| Option | Description | +|--------|-------------| +| `-w, --web` | Open in browser | +| `-f, --fresh` | Bypass cache, re-detect projects, and fetch fresh data | +| `-r, --refresh ` | Auto-refresh interval in seconds (default: 60, min: 10) | +| `-t, --period ` | Time period override (e.g., "24h", "7d", "14d") | -View details of a specific dashboard, including its widgets. +### `sentry dashboard create ` -```bash -# By numeric ID -sentry dashboard view +Create a dashboard -# By title -sentry dashboard view '' +**Arguments:** -# With explicit org -sentry dashboard view <org>/ <id> -``` +| Argument | Description | +|----------|-------------| +| `<org/project/title...>` | [<org/project>] <title> | + +### `sentry dashboard widget add <org/project/dashboard/title...>` + +Add a widget to a dashboard **Arguments:** | Argument | Description | |----------|-------------| -| `<id>` or `<title>` | Dashboard ID (numeric) or title (case-insensitive) | -| `<org>/` | Organization slug (optional) | +| `<org/project/dashboard/title...>` | [<org/project>] <dashboard> <title> | **Options:** | Option | Description | |--------|-------------| -| `-w, --web` | Open in browser | -| `-f, --fresh` | Bypass cache and fetch fresh data | -| `--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 | -**Examples:** +### `sentry dashboard widget edit <org/project/dashboard...>` -```bash -sentry dashboard view 12345 -``` +Edit a widget in a dashboard -``` -Dashboard: Frontend Performance (ID: 12345) -URL: https://my-org.sentry.io/dashboard/12345/ +**Arguments:** -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 -``` +| Argument | Description | +|----------|-------------| +| `<org/project/dashboard...>` | [<org/project>] <dashboard-id-or-title> | -**View by title:** +**Options:** -```bash -sentry dashboard view 'Frontend Performance' -``` +| 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 | -**Open in browser:** +### `sentry dashboard widget delete <org/project/dashboard...>` -```bash -sentry dashboard view 12345 -w -``` +Delete a widget from a dashboard -### `sentry dashboard create` +**Arguments:** -Create a new dashboard. +| Argument | Description | +|----------|-------------| +| `<org/project/dashboard...>` | [<org/project>] <dashboard-id-or-title> | -```bash -# Auto-detect org -sentry dashboard create '<title>' +**Options:** -# Explicit org -sentry dashboard create <org>/ '<title>' +| Option | Description | +|--------|-------------| +| `-i, --index <index>` | Widget index (0-based) | +| `-t, --title <title>` | Widget title to match | -# Explicit org and project -sentry dashboard create <org>/<project> '<title>' -``` +All commands support `--json` for machine-readable output and `--fields` to select specific JSON fields. -**Arguments:** +<!-- GENERATED:END --> -| Argument | Description | -|----------|-------------| -| `<title>` | Dashboard title | -| `<org>/` or `<org>/<project>` | Organization and optional project (auto-detected if omitted) | +## Examples -**Examples:** +### List dashboards ```bash -sentry dashboard create 'Frontend Performance' +# List all dashboards +sentry dashboard list + +# Filter by name pattern +sentry dashboard list "Backend*" + +# Open dashboard list in browser +sentry dashboard list -w ``` ``` -Created dashboard: Frontend Performance (ID: 12348) -URL: https://my-org.sentry.io/dashboard/12348/ +ID TITLE WIDGETS CREATED +12345 General 4 2024-01-15 +12346 Frontend Performance 6 2024-02-20 +12347 Backend Errors 3 2024-03-10 ``` -**Add widgets after creation:** +### View a dashboard ```bash -sentry dashboard widget add 'Frontend Performance' "Error Count" --display big_number --query count -``` +# View by title +sentry dashboard view 'Frontend Performance' -### `sentry dashboard widget add` +# View by ID +sentry dashboard view 12345 -Add a widget to an existing dashboard. +# Auto-refresh every 30 seconds +sentry dashboard view "Backend Performance" --refresh 30 -```bash -sentry dashboard widget add <dashboard> '<widget-title>' --display <type> [options] +# Open in browser +sentry dashboard view 12345 -w ``` -**Arguments:** - -| Argument | Description | -|----------|-------------| -| `<dashboard>` | Dashboard ID (numeric) or title | -| `<widget-title>` | Title for the new widget | -| `<org>/` | Organization slug (optional, prepend before dashboard) | - -**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 | - -**Query shorthand:** +``` +Dashboard: Frontend Performance (ID: 12345) +URL: https://my-org.sentry.io/dashboard/12345/ -The `--query` flag supports shorthand for aggregate functions: +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 +``` -| Input | Expands to | -|-------|-----------| -| `count` | `count()` | -| `p95:span.duration` | `p95(span.duration)` | -| `avg:span.duration` | `avg(span.duration)` | -| `count()` | `count()` (passthrough) | +### Create a dashboard -**Sort shorthand:** +```bash +sentry dashboard create 'Frontend Performance' +``` -| Input | Meaning | -|-------|---------| -| `count` | Sort by `count()` ascending | -| `-count` | Sort by `count()` descending | +``` +Created dashboard: Frontend Performance (ID: 12348) +URL: https://my-org.sentry.io/dashboard/12348/ +``` -**Examples:** +### Add widgets ```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 -``` -```bash # With search filter sentry dashboard widget add 'My Dashboard' "Slow Requests" \ --display bar --query p95:span.duration \ @@ -233,93 +208,43 @@ sentry dashboard widget add 'My Dashboard' "Slow Requests" \ --group-by span.description ``` -### `sentry dashboard widget edit` - -Edit an existing widget in a dashboard. Only provided flags are changed — omitted values are preserved. - -```bash -# Identify widget by title -sentry dashboard widget edit <dashboard> --title '<widget-title>' [options] - -# Identify widget by index (0-based) -sentry dashboard widget edit <dashboard> --index <n> [options] -``` - -**Arguments:** - -| Argument | Description | -|----------|-------------| -| `<dashboard>` | Dashboard ID (numeric) or title | -| `<org>/` | Organization slug (optional, prepend before dashboard) | - -**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:** +### Edit widgets ```bash # Change display type sentry dashboard widget edit 12345 --title 'Error Count' --display bar -``` -```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 ``` -### `sentry dashboard widget delete` - -Remove a widget from a dashboard. +### Delete widgets ```bash # Delete by title -sentry dashboard widget delete <dashboard> --title '<widget-title>' +sentry dashboard widget delete 'My Dashboard' --title 'Error Count' -# Delete by index (0-based) -sentry dashboard widget delete <dashboard> --index <n> +# Delete by index +sentry dashboard widget delete 12345 --index 2 ``` -**Arguments:** - -| Argument | Description | -|----------|-------------| -| `<dashboard>` | Dashboard ID (numeric) or title | -| `<org>/` | Organization slug (optional, prepend before dashboard) | - -**Options:** +## Query Shorthand -| Option | Description | -|--------|-------------| -| `-i, --index <n>` | Widget index (0-based) | -| `-t, --title <title>` | Match widget by title (case-insensitive) | -| `--json` | Output as JSON | +The `--query` flag supports shorthand for aggregate functions: -**Examples:** +| Input | Expands to | +|-------|-----------| +| `count` | `count()` | +| `p95:span.duration` | `p95(span.duration)` | +| `avg:span.duration` | `avg(span.duration)` | +| `count()` | `count()` (passthrough) | -```bash -# Delete by title -sentry dashboard widget delete 'My Dashboard' --title 'Error Count' -``` +## Sort Shorthand -```bash -# Delete by index -sentry dashboard widget delete 12345 --index 2 -``` +| 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 9042b5c10..488b46267 100644 --- a/docs/src/content/docs/commands/event.md +++ b/docs/src/content/docs/commands/event.md @@ -3,39 +3,40 @@ title: event description: Event commands for the Sentry CLI --- -Inspect Sentry events. +View Sentry events ## Commands -### `sentry event view` +### `sentry event view <org/project/event-id...>` -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 | +| `<org/project/event-id...>` | [<org>/<project>] <event-id> - Target (optional) and event ID (required) | **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 | -**Example:** +All commands support `--json` for machine-readable output and `--fields` to select specific JSON fields. + +<!-- GENERATED:END --> + +## Examples ```bash -sentry event view abc123def456 +sentry event view abc123def456abc123def456abc12345 ``` ``` -Event: abc123def456 +Event: abc123def456abc123def456abc12345 Issue: FRONT-ABC Timestamp: 2024-01-20 14:22:00 @@ -56,10 +57,9 @@ Context: user_id: 12345 ``` -**Open in browser:** - ```bash -sentry event view abc123def456 -w +# Open in browser +sentry event view abc123def456abc123def456abc12345 -w ``` ## Finding Event IDs diff --git a/docs/src/content/docs/commands/index.md b/docs/src/content/docs/commands/index.md index 20452e259..f688a0482 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,15 +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 | -| [`api`](./api/) | Direct API access | +| [`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 | +| [`sourcemap`](./sourcemap/) | Manage sourcemaps | +| [`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) | +| [`api`](./api/) | Make an authenticated API request | +| [`schema`](./schema/) | Browse the Sentry API schema | + +<!-- GENERATED:END --> ## Global Options diff --git a/docs/src/content/docs/commands/init.md b/docs/src/content/docs/commands/init.md index d669e46a6..097e9a703 100644 --- a/docs/src/content/docs/commands/init.md +++ b/docs/src/content/docs/commands/init.md @@ -1,42 +1,69 @@ --- 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 | +| `<directory>` | Project directory (default: current directory) | **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 | +| `--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 | + +All commands support `--json` for machine-readable output and `--fields` to select specific JSON fields. + +<!-- 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 +# 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 -## Target syntax +# Enable specific features +sentry init --features profiling,replay +``` -The optional `[target]` argument lets you specify which Sentry org and project to use: +## Target Syntax | Syntax | Meaning | |--------|---------| @@ -45,11 +72,9 @@ The optional `[target]` argument lets you specify which Sentry org and project t | `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 +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. -Pass a comma-separated list to `--features` to control which integrations are configured: +## Available Features | Feature | Description | |---------|-------------| @@ -64,46 +89,13 @@ Pass a comma-separated list to `--features` to control which integrations are co | `ai-monitoring` | AI/LLM monitoring | | `user-feedback` | User feedback widget | -## Examples - -```bash -# Run the wizard in the current directory -sentry init - -# 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 - -# Use a specific org and project in a subdirectory -sentry init acme/my-app ./my-app - -# Preview what changes would be made -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 -``` - -## What the wizard does +## 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: +### Supported Platforms - **JavaScript / TypeScript** — Next.js, Express, SvelteKit, React - **Python** — Flask, FastAPI diff --git a/docs/src/content/docs/commands/issue.md b/docs/src/content/docs/commands/issue.md index 735db6970..2d08599f3 100644 --- a/docs/src/content/docs/commands/issue.md +++ b/docs/src/content/docs/commands/issue.md @@ -3,121 +3,124 @@ 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) | -# 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:** - -```bash -# List issues in a specific project -sentry issue list my-org/frontend -``` +### `sentry issue plan <issue>` -``` -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 -``` +Generate a solution plan using Seer AI -**List issues from all projects in an org:** +**Arguments:** -```bash -sentry issue list my-org/ -``` +| Argument | Description | +|----------|-------------| +| `<issue>` | Issue: @latest, @most_frequent, <org>/ID, <project>-suffix, ID, or suffix | -**Search for a project across organizations:** +**Options:** -```bash -sentry issue list frontend -``` +| 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 | -**With search query:** +### `sentry issue view <issue>` -```bash -sentry issue list my-org/frontend --query "TypeError" -``` +View details of a specific issue -**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 + +# All projects in an org +sentry issue list my-org/ -# By short ID -sentry issue view <short-id> +# Search for a project across organizations +sentry issue list frontend ``` -**Arguments:** +``` +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 +``` -| Argument | Description | -|----------|-------------| -| `<issue-id>` | The issue ID (numeric) or short ID (e.g., PROJ-ABC) | +**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 | -| `--json` | Output as JSON | +# 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 +``` -**Example:** +### View an issue ```bash sentry issue view FRONT-ABC @@ -138,103 +141,33 @@ Latest event: URL: https://example.com/app ``` -**Open in browser:** - ```bash +# Open in browser sentry issue view FRONT-ABC -w ``` -### `sentry issue explain` - -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:** +### Explain and plan with Seer AI ```bash -# By numeric issue ID +# 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 -# By project-suffix format -sentry issue explain myproject-G - # Force a fresh analysis sentry issue explain 123456789 --force -``` - -**Requirements:** - -- 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 +# Generate a fix plan (requires explain to be run first) sentry issue plan 123456789 -# Specify which root cause to plan for (if multiple were found) +# Specify which root cause to plan for 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 +- 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 diff --git a/docs/src/content/docs/commands/log.md b/docs/src/content/docs/commands/log.md index 58a730f04..7b7b651d2 100644 --- a/docs/src/content/docs/commands/log.md +++ b/docs/src/content/docs/commands/log.md @@ -3,44 +3,55 @@ 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> | -# 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 <org/project/log-id...>` + +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 | +| `<org/project/log-id...>` | [<org>/<project>] <log-id> [<log-id>...] - Target (optional) and one or more log IDs | **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) @@ -57,16 +68,6 @@ TIMESTAMP LEVEL MESSAGE Showing 4 logs. ``` -**Stream logs in real-time:** - -```bash -# Stream with default 2-second poll interval -sentry log list -f - -# Stream with custom 5-second poll interval -sentry log list -f 5 -``` - **Filter logs:** ```bash @@ -75,56 +76,25 @@ sentry log list -q 'level:error' # Filter by message content sentry log list -q 'database' -``` - -**Limit results:** -```bash -# Show last 50 logs +# Limit results sentry log list --limit 50 - -# Show last 500 logs -sentry log list -n 500 ``` -**Combine options:** +### Stream logs in real-time ```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> +# Stream with default 2-second poll interval +sentry log list -f -# Explicit org and project -sentry log view <org>/<project> <log-id> +# Stream with custom 5-second poll interval +sentry log list -f 5 -# Search for project across all accessible orgs -sentry log view <project> <log-id> +# Stream error logs from a specific project +sentry log list my-org/backend -f -q 'level:error' ``` -**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 @@ -147,15 +117,10 @@ 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 ─── @@ -163,23 +128,19 @@ Function: connect_to_database File: src/db/connection.py:142 ``` -**Open in browser:** - -```bash -sentry log view 968c763c740cfda8b6728f27fb9e9b01 -w -``` - -**With explicit project:** - ```bash +# With explicit project sentry log view my-org/backend 968c763c740cfda8b6728f27fb9e9b01 + +# Open in browser +sentry log view 968c763c740cfda8b6728f27fb9e9b01 -w ``` ## Finding Log IDs 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 @@ -188,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. diff --git a/docs/src/content/docs/commands/org.md b/docs/src/content/docs/commands/org.md index eb9a2b76e..d27997a0b 100644 --- a/docs/src/content/docs/commands/org.md +++ b/docs/src/content/docs/commands/org.md @@ -1,74 +1,59 @@ --- 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) | **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 --> + +## Examples + +```bash +# List organizations +sentry org list +``` -**Example:** +``` +SLUG NAME ROLE +my-org My Organization owner +another-org Another Org member +``` ```bash +# View organization details sentry org view my-org ``` @@ -81,8 +66,10 @@ Teams: 3 Members: 12 ``` -**Open in browser:** - ```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 e8e37a668..ac5876fa0 100644 --- a/docs/src/content/docs/commands/project.md +++ b/docs/src/content/docs/commands/project.md @@ -3,78 +3,105 @@ 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) | +| `<platform>` | Project platform (e.g., node, python, javascript-nextjs) | -# 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 -### `sentry project view` +**Arguments:** + +| Argument | Description | +|----------|-------------| +| `<org/project>` | <org>/ (all projects), <org>/<project>, or <project> (search) | -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 | **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. + +<!-- GENERATED:END --> + +## Examples ```bash +# 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 ``` @@ -86,8 +113,7 @@ Team: web-team DSN: https://abc123@sentry.io/123456 ``` -**Open in browser:** - ```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 new file mode 100644 index 000000000..65d888273 --- /dev/null +++ b/docs/src/content/docs/commands/repo.md @@ -0,0 +1,43 @@ +--- +title: repo +description: Repo commands for the Sentry CLI +--- + +Work with Sentry repositories + +## Commands + +### `sentry repo list <org/project>` + +List repositories + +**Arguments:** + +| Argument | Description | +|----------|-------------| +| `<org/project>` | <org>/ (all projects), <org>/<project>, or <project> (search) | + +**Options:** + +| Option | Description | +|--------|-------------| +| `-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 + +```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..caa3cdc0e --- /dev/null +++ b/docs/src/content/docs/commands/schema.md @@ -0,0 +1,48 @@ +--- +title: schema +description: Schema command for the Sentry CLI +--- + +Browse the Sentry API schema + +## Usage + +### `sentry schema <resource...>` + +Browse the Sentry API schema + +**Arguments:** + +| Argument | Description | +|----------|-------------| +| `<resource...>` | Resource name and optional operation | + +**Options:** + +| Option | Description | +|--------|-------------| +| `--all` | Show all endpoints in a flat list | +| `-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 + +```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..2a1c25674 --- /dev/null +++ b/docs/src/content/docs/commands/sourcemap.md @@ -0,0 +1,74 @@ +--- +title: sourcemap +description: Sourcemap commands for the Sentry CLI +--- + +Manage sourcemaps + +## Commands + +### `sentry sourcemap inject <directory>` + +Inject debug IDs into JavaScript files and sourcemaps + +**Arguments:** + +| Argument | Description | +|----------|-------------| +| `<directory>` | Directory to scan for JS + sourcemap pairs | + +**Options:** + +| Option | Description | +|--------|-------------| +| `--ext <ext>` | 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 + +**Arguments:** + +| Argument | Description | +|----------|-------------| +| `<directory>` | Directory containing sourcemaps | + +**Options:** + +| Option | Description | +|--------|-------------| +| `--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 +``` + +### Upload sourcemaps + +```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..f86025d0e --- /dev/null +++ b/docs/src/content/docs/commands/span.md @@ -0,0 +1,84 @@ +--- +title: span +description: Span commands for the Sentry CLI +--- + +List and view spans in projects or traces + +## Commands + +### `sentry span list <org/project/trace-id...>` + +List spans in a project or trace + +**Arguments:** + +| Argument | Description | +|----------|-------------| +| `<org/project/trace-id...>` | [<org>/<project>] or [<org>/<project>/]<trace-id> | + +**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 | +|----------|-------------| +| `<trace-id/span-id...>` | [<org>/<project>/]<trace-id> <span-id> [<span-id>...] - Trace ID and one or more span IDs | + +**Options:** + +| Option | Description | +|--------|-------------| +| `--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 + +### List spans + +```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 spans + +```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/team.md b/docs/src/content/docs/commands/team.md index bf5627932..39bfdea49 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) | **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 new file mode 100644 index 000000000..0ef172e56 --- /dev/null +++ b/docs/src/content/docs/commands/trace.md @@ -0,0 +1,116 @@ +--- +title: trace +description: Trace commands for the Sentry CLI +--- + +View distributed traces + +## Commands + +### `sentry trace list <org/project>` + +List recent traces in a project + +**Arguments:** + +| Argument | Description | +|----------|-------------| +| `<org/project>` | <org>/<project> or <project> (search) | + +**Options:** + +| Option | Description | +|--------|-------------| +| `-n, --limit <limit>` | Number of traces (1-1000) (default: "20") | +| `-q, --query <query>` | Search query (Sentry search syntax) | +| `-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) | + +### `sentry trace view <org/project/trace-id...>` + +View details of a specific trace + +**Arguments:** + +| Argument | Description | +|----------|-------------| +| `<org/project/trace-id...>` | [<org>/<project>/]<trace-id> - Target (optional) and trace ID (required) | + +**Options:** + +| 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 | + +### `sentry trace logs <org/trace-id...>` + +View logs associated with a trace + +**Arguments:** + +| Argument | Description | +|----------|-------------| +| `<org/trace-id...>` | [<org>/]<trace-id> - Optional org and required trace ID | + +**Options:** + +| Option | Description | +|--------|-------------| +| `-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 | + +All commands support `--json` for machine-readable output and `--fields` to select specific JSON fields. + +<!-- GENERATED:END --> + +## Examples + +### List traces + +```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 a trace + +```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 +``` + +### View trace logs + +```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..8eaa739b0 --- /dev/null +++ b/docs/src/content/docs/commands/trial.md @@ -0,0 +1,52 @@ +--- +title: trial +description: Trial commands for the Sentry CLI +--- + +Manage product trials + +## Commands + +### `sentry trial list <org>` + +List product trials + +**Arguments:** + +| Argument | Description | +|----------|-------------| +| `<org>` | Organization slug (auto-detected if omitted) | + +### `sentry trial start <name> <org>` + +Start a product trial + +**Arguments:** + +| Argument | Description | +|----------|-------------| +| `<name>` | Trial name (seer, replays, performance, spans, profiling, logs, monitors, uptime, plan) | +| `<org>` | Organization slug (auto-detected if omitted) | + +All commands support `--json` for machine-readable output and `--fields` to select specific JSON fields. + +<!-- GENERATED:END --> + +## 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 +``` 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/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/api.md b/plugins/sentry-cli/skills/sentry-cli/references/api.md index be4783f15..0577d86aa 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/api.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/api.md @@ -29,44 +29,41 @@ Make an authenticated API request **Examples:** ```bash -sentry api <endpoint> [options] - # List organizations -sentry api /organizations/ +sentry api organizations/ -# Get a specific organization -sentry api /organizations/my-org/ +# Get a specific issue +sentry api issues/123456789/ -# Get project details -sentry api /projects/my-org/my-project/ +# Create a release +sentry api organizations/my-org/releases/ \ + -X POST -F version=1.0.0 -# Create a new project -sentry api /teams/my-org/my-team/projects/ \ - --method POST \ - --field name="New Project" \ - --field platform=javascript +# With inline JSON body +sentry api issues/123456789/ \ + -X POST -d '{"status": "resolved"}' # Update an issue status -sentry api /issues/123456789/ \ - --method PUT \ - --field status=resolved +sentry api issues/123456789/ \ + -X PUT -F status=resolved # Assign an issue -sentry api /issues/123456789/ \ - --method PUT \ - --field assignedTo="user@example.com" +sentry api issues/123456789/ \ + -X PUT --field assignedTo="user@example.com" + +sentry api projects/my-org/my-project/ -X DELETE -# Delete a project -sentry api /projects/my-org/my-project/ \ - --method DELETE +# Add custom headers +sentry api organizations/ -H "X-Custom: value" -sentry api /organizations/ \ - --header "X-Custom-Header:value" +# Read body from a file +sentry api projects/my-org/my-project/releases/ -X POST --input release.json -sentry api /organizations/ --verbose +# Verbose mode (shows full HTTP request/response) +sentry api organizations/ --verbose -# Get all issues (automatically follows pagination) -sentry api /projects/my-org/my-project/issues/ --paginate +# 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/auth.md b/plugins/sentry-cli/skills/sentry-cli/references/auth.md index d8d26856a..33bdf31ed 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/auth.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/auth.md @@ -23,13 +23,11 @@ Authenticate with Sentry **Examples:** ```bash -# OAuth device flow (recommended) sentry auth login -# Using an API token -sentry auth login --token YOUR_TOKEN +sentry auth login --token YOUR_SENTRY_API_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 SENTRY_URL=https://sentry.example.com sentry auth login --token YOUR_TOKEN ``` @@ -38,12 +36,6 @@ SENTRY_URL=https://sentry.example.com sentry auth login --token YOUR_TOKEN Log out of Sentry -**Examples:** - -```bash -sentry auth logout -``` - ### `sentry auth refresh` Refresh your authentication token @@ -51,12 +43,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 @@ -69,6 +55,12 @@ View authentication status ```bash sentry auth status + +# Show the raw token +sentry auth status --show-token + +# View current user +sentry auth whoami ``` ### `sentry auth token` diff --git a/plugins/sentry-cli/skills/sentry-cli/references/dashboards.md b/plugins/sentry-cli/skills/sentry-cli/references/dashboards.md index df13ab4e2..c565b83d5 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/dashboards.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/dashboards.md @@ -24,21 +24,17 @@ List dashboards **Examples:** ```bash -# Auto-detect org from config +# List all dashboards sentry dashboard list -# Explicit org -sentry dashboard list my-org/ - -# Explicit org and project -sentry dashboard list my-org/my-project - -sentry dashboard list +# Filter by name pattern +sentry dashboard list "Backend*" +# Open dashboard list in browser sentry dashboard list -w ``` -### `sentry dashboard view <args...>` +### `sentry dashboard view <org/project/dashboard...>` View a dashboard @@ -51,44 +47,30 @@ View a dashboard **Examples:** ```bash -# By numeric ID -sentry dashboard view <id> - -# By title -sentry dashboard view '<title>' - -# With explicit org -sentry dashboard view <org>/ <id> +# View by title +sentry dashboard view 'Frontend Performance' +# View by ID sentry dashboard view 12345 -sentry dashboard view 'Frontend Performance' +# Auto-refresh every 30 seconds +sentry dashboard view "Backend Performance" --refresh 30 +# Open in browser sentry dashboard view 12345 -w ``` -### `sentry dashboard create <args...>` +### `sentry dashboard create <org/project/title...>` 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...>` +### `sentry dashboard widget add <org/project/dashboard/title...>` Add a widget to a dashboard @@ -101,7 +83,32 @@ 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...>` +**Examples:** + +```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 +``` + +### `sentry dashboard widget edit <org/project/dashboard...>` Edit a widget in a dashboard @@ -117,7 +124,20 @@ 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...>` +**Examples:** + +```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 +``` + +### `sentry dashboard widget delete <org/project/dashboard...>` Delete a widget from a dashboard @@ -125,4 +145,14 @@ Delete a widget from a dashboard - `-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' + +# 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 b17ae2a96..f44f3bbf7 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 @@ -23,11 +23,10 @@ View details of a specific event **Examples:** ```bash -sentry event view <event-id> +sentry event view abc123def456abc123def456abc12345 -sentry event view abc123def456 - -sentry event view abc123def456 -w +# 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 750878222..55048ce6d 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/issues.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/issues.md @@ -51,37 +51,23 @@ List issues in a project **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 +# All projects in an org sentry issue list my-org/ +# Search for a project across organizations 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" +# Sort by frequency +sentry issue list my-org/frontend --sort freq --limit 20 ``` ### `sentry issue explain <issue>` @@ -95,19 +81,20 @@ Analyze an issue's root cause using Seer AI **Examples:** ```bash -sentry issue explain <issue-id> - -# By numeric issue ID +# 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 -# By project-suffix format -sentry issue explain myproject-G - # 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 ``` ### `sentry issue plan <issue>` @@ -119,24 +106,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 @@ -149,14 +118,9 @@ View details of a specific issue **Examples:** ```bash -# By issue ID -sentry issue view <issue-id> - -# By short ID -sentry issue view <short-id> - sentry issue view FRONT-ABC +# Open in browser sentry issue view FRONT-ABC -w ``` diff --git a/plugins/sentry-cli/skills/sentry-cli/references/logs.md b/plugins/sentry-cli/skills/sentry-cli/references/logs.md index 4f43f1c59..3d08e7c26 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/logs.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/logs.md @@ -37,41 +37,31 @@ List logs from a project **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 +# Limit results sentry log list --limit 50 -# Show last 500 logs -sentry log list -n 500 +# 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 list --json | jq '.data[] | select(.severity == "error")' ``` -### `sentry log view <args...>` +### `sentry log view <org/project/log-id...>` View details of one or more log entries @@ -82,22 +72,13 @@ View details of one or more log entries **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 - +# With explicit project sentry log view my-org/backend 968c763c740cfda8b6728f27fb9e9b01 -sentry log list --json | jq '.[] | select(.level == "error")' +# Open in browser +sentry log view 968c763c740cfda8b6728f27fb9e9b01 -w ``` 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..4c5effc3e 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 @@ -38,11 +30,17 @@ View details of an organization **Examples:** ```bash -sentry org view <org-slug> +# 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 3bce54703..8159570c0 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 @@ -62,17 +49,16 @@ View details of a project **Examples:** ```bash -# Auto-detect from DSN or config -sentry project view +# List all projects in an org +sentry project list my-org/ -# Explicit org and project -sentry project view <org>/<project> - -# Find project across all orgs -sentry project view <project> +# 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 ``` diff --git a/plugins/sentry-cli/skills/sentry-cli/references/setup.md b/plugins/sentry-cli/skills/sentry-cli/references/setup.md index cc0171237..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 @@ -49,6 +65,27 @@ 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 +``` + ### `sentry init <target> <directory>` Initialize Sentry in your project (experimental) @@ -59,6 +96,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 +132,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..ae7b97165 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/sourcemap.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/sourcemap.md @@ -19,6 +19,19 @@ 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` +**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 <directory>` Upload sourcemaps to Sentry @@ -27,4 +40,17 @@ 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 +# 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 10acb32d8..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 @@ -60,15 +73,13 @@ List teams **Examples:** ```bash -# Auto-detect organization or list all -sentry team list - -# List teams in a specific organization -sentry team list <org-slug> +# List teams +sentry team list my-org/ -# Limit results -sentry team list --limit 10 +# Paginate through teams +sentry team list my-org/ -c next +# Output as JSON sentry team list --json ``` diff --git a/plugins/sentry-cli/skills/sentry-cli/references/traces.md b/plugins/sentry-cli/skills/sentry-cli/references/traces.md index b1a68c2b5..e7ad58594 100644 --- a/plugins/sentry-cli/skills/sentry-cli/references/traces.md +++ b/plugins/sentry-cli/skills/sentry-cli/references/traces.md @@ -39,6 +39,25 @@ List spans in a project or trace | `transaction` | string \| null | Transaction name | | `trace` | string | Trace ID | +**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 <trace-id/span-id...>` View details of specific spans @@ -47,6 +66,19 @@ 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 +# 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 @@ -70,6 +102,22 @@ List recent traces in a project | `transaction.duration` | number | Duration (ms) | | `project` | string | Project slug | +**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 <org/project/trace-id...>` View details of a specific trace @@ -79,6 +127,19 @@ View details of a specific trace - `--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 + +# Open trace in browser +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 @@ -91,4 +152,17 @@ 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 +# 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/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/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-command-docs.ts b/script/generate-command-docs.ts new file mode 100644 index 000000000..d658e4160 --- /dev/null +++ b/script/generate-command-docs.ts @@ -0,0 +1,344 @@ +#!/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 { extractAllRoutes } 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"]); + +// --------------------------------------------------------------------------- +// 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}>\``; + lines.push(`| ${placeholder} | ${escapeAngleBrackets(p.brief)} |`); + } + 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 +// --------------------------------------------------------------------------- + +/** + * 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 lines: string[] = []; + lines.push("| Command | Description |"); + lines.push("|---------|-------------|"); + for (const route of allRoutes) { + 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 ""; + } +} + +// --------------------------------------------------------------------------- +// Main +// --------------------------------------------------------------------------- + +const routeMap = routes as unknown as RouteMap; +const routeInfos = extractAllRoutes(routeMap).filter( + (r) => !SKIP_ROUTES.has(r.name) +); + +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 readCustomContent(INDEX_PATH); +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/script/generate-skill.ts b/script/generate-skill.ts index b868cee45..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, @@ -328,36 +330,115 @@ sentry auth status \`\`\``; } -/** Regex to match command sections in docs (### `sentry ...`) */ -const COMMAND_SECTION_REGEX = - /###\s+`(sentry\s+\S+(?:\s+\S+)?)`\s*\n([\s\S]*?)(?=###\s+`|$)/g; +/** + * 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 CMD_HEADING_RE = /^`sentry\s+(.*?)\s*(?:<[^>]*>.*)?`$/; + +/** 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); +} + +/** + * Collect all command paths from `### \`sentry ...\`` headings in a token list. + * Initializes each path with an empty array in the examples map. + */ +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) + ); +} + +/** + * Walk tokens sequentially and associate each bash code block with + * the appropriate command path — either by heading context or content matching. + */ +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: sequential token walk with type narrowing +function associateCodeBlocks( + tokens: Token[], + commandPaths: string[], + commandGroup: string, + examples: Map<string, string[]> +): void { + const groupFallback = `sentry ${commandGroup}`; + let currentCmd: string | null = null; + + 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 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 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. + * + * 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 ): Promise<Map<string, string[]>> { const docContent = await loadDoc(`commands/${commandGroup}.md`); - const examples = new Map<string, string[]>(); if (!docContent) { - return examples; - } - 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"); - if (codeBlocks.length > 0) { - examples.set( - commandPath, - codeBlocks.map((b) => b.code) - ); - } - match = commandPattern.exec(docContent); + return new Map(); } + + const tokens = marked.lexer(docContent); + const examples = new Map<string, string[]>(); + const commandPaths = collectCommandPaths(tokens, examples); + associateCodeBlocks(tokens, commandPaths, commandGroup, examples); return examples; } 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, 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", ]); /** 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,