Skip to content

Commit be6b1cb

Browse files
committed
Merge remote-tracking branch 'origin/main' into feat/dashboard-widget-commands
# Conflicts: # plugins/sentry-cli/skills/sentry-cli/SKILL.md
2 parents 15c9230 + 0cf6f36 commit be6b1cb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+2073
-1230
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../../plugins/sentry-cli/skills/sentry-cli/references

.github/workflows/ci.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ jobs:
8585
echo "Nightly version: ${VERSION}"
8686
8787
check-skill:
88-
name: Check SKILL.md
88+
name: Check skill files
8989
needs: [changes]
9090
if: needs.changes.outputs.skill == 'true'
9191
runs-on: ubuntu-latest
@@ -112,22 +112,22 @@ jobs:
112112
run: bun install --frozen-lockfile
113113
- name: Generate API Schema
114114
run: bun run generate:schema
115-
- name: Check SKILL.md
115+
- name: Check skill files
116116
id: check
117117
run: bun run check:skill
118118
continue-on-error: true
119-
- name: Auto-commit regenerated SKILL.md
119+
- name: Auto-commit regenerated skill files
120120
if: steps.check.outcome == 'failure' && steps.token.outcome == 'success'
121121
run: |
122122
git config user.name "github-actions[bot]"
123123
git config user.email "github-actions[bot]@users.noreply.github.com"
124-
git add plugins/sentry-cli/skills/sentry-cli/SKILL.md
125-
git commit -m "chore: regenerate SKILL.md"
124+
git add plugins/sentry-cli/skills/sentry-cli/ docs/public/.well-known/skills/index.json
125+
git commit -m "chore: regenerate skill files"
126126
git push
127-
- name: Fail for fork PRs with stale SKILL.md
127+
- name: Fail for fork PRs with stale skill files
128128
if: steps.check.outcome == 'failure' && steps.token.outcome != 'success'
129129
run: |
130-
echo "::error::SKILL.md is out of date. Run 'bun run generate:skill' locally and commit the result."
130+
echo "::error::Skill files are out of date. Run 'bun run generate:skill' locally and commit the result."
131131
exit 1
132132
133133
lint:

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ coverage-isolated
1717
*.lcov
1818

1919
# test artifacts
20-
.test-tmp
2120
*.junit.xml
2221

2322
# logs

AGENTS.md

Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -781,62 +781,4 @@ mock.module("./some-module", () => ({
781781
| Add documentation | `docs/src/content/docs/` |
782782
783783
<!-- This section is maintained by the coding agent via lore (https://github.com/BYK/opencode-lore) -->
784-
## Long-term Knowledge
785-
786-
### Architecture
787-
788-
<!-- lore:019cafbb-24ad-75a3-b037-5efbe6a1e85d -->
789-
* **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\`.
790-
791-
<!-- lore:019cb38b-e327-7ec5-8fb0-9e635b2bac48 -->
792-
* **GHCR versioned nightly tags for delta upgrade support**: GHCR nightly distribution uses three tag types: \`:nightly\` (rolling), \`:nightly-\<version>\` (immutable), \`:patch-\<version>\` (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.
793-
794-
<!-- lore:a1f33ceb-6116-4d29-b6d0-0dc9678e4341 -->
795-
* **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.
796-
797-
<!-- lore:019cb950-9b7b-731a-9832-b7f6cfb6a6a2 -->
798-
* **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.
799-
800-
<!-- lore:019ca9c3-989c-7c8d-bcd0-9f308fd2c3d7 -->
801-
* **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()\`.
802-
803-
<!-- lore:019cd2b7-bb98-730e-a0d3-ec25bfa6cf4c -->
804-
* **Sentry issue stats field: time-series controlled by groupStatsPeriod**: The \`stats\` field on issues is \`{ '24h': \[\[ts, count], ...] }\`. Key depends on \`groupStatsPeriod\` param (\`""\`, \`"14d"\`, \`"24h"\`, \`"auto"\`). \`statsPeriod\` controls time window; \`groupStatsPeriod\` controls stats key. \*\*Critical\*\*: \`count\` is period-scoped — \`lifetime.count\` is the true lifetime total. Issue list table uses \`groupStatsPeriod: 'auto'\` for sparkline data. Column order: SHORT ID, ISSUE, SEEN, AGE, TREND, EVENTS, USERS, TRIAGE. TREND auto-hidden when terminal < 100 cols. \`--compact\` tri-state: explicit overrides; \`undefined\` triggers \`shouldAutoCompact(rowCount)\` — compact if \`3N + 3 > termHeight\`, false for non-TTY. Height is \`3N + 3\` (not \`3N + 4\`) because last data row has no trailing separator.
805-
806-
<!-- lore:019ca9c3-98a2-7a81-9db7-d36c2e71237c -->
807-
* **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.
808-
809-
<!-- lore:019cbf3f-6dc2-727d-8dca-228555e9603f -->
810-
* **withAuthGuard returns discriminated Result type, not fallback+onError**: \`withAuthGuard\<T>(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.
811-
812-
### Gotcha
813-
814-
<!-- lore:019c9994-d161-783e-8b3e-79457cd62f42 -->
815-
* **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.
816-
817-
<!-- lore:019c8c31-f52f-7230-9252-cceb907f3e87 -->
818-
* **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.
819-
820-
<!-- lore:019cc3e6-0cdd-7a53-9eb7-a284a3b4eb78 -->
821-
* **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.
822-
823-
### Pattern
824-
825-
<!-- lore:dbd63348-2049-42b3-bb99-d6a3d64369c7 -->
826-
* **Branch naming and commit message conventions for Sentry CLI**: Branch naming: \`feat/\<short-description>\` or \`fix/\<issue-number>-\<short-description>\` (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.
827-
828-
<!-- lore:019cc3e6-0cf5-720d-beb7-97c9c9901295 -->
829-
* **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.
830-
831-
<!-- lore:019c90f5-913b-7995-8bac-84289cf5d6d9 -->
832-
* **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"\`.
833-
834-
<!-- lore:019c8a8a-64ee-703c-8c1e-ed32ae8a90a7 -->
835-
* **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.
836-
837-
<!-- lore:019cdd9b-330a-784f-9487-0abf7b80be3c -->
838-
* **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.
839-
840-
<!-- lore:019cc325-d322-7e6e-86cc-93010b71abee -->
841-
* **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.
842784
<!-- End lore-managed section -->

docs/public/.well-known/skills/index.json

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,21 @@
33
{
44
"name": "sentry-cli",
55
"description": "Guide for using the Sentry CLI to interact with Sentry from the command line. Use when the user asks about viewing issues, events, projects, organizations, making API calls, or authenticating with Sentry via CLI.",
6-
"files": ["SKILL.md"]
6+
"files": [
7+
"SKILL.md",
8+
"references/api.md",
9+
"references/auth.md",
10+
"references/dashboards.md",
11+
"references/events.md",
12+
"references/issues.md",
13+
"references/logs.md",
14+
"references/organizations.md",
15+
"references/projects.md",
16+
"references/setup.md",
17+
"references/teams.md",
18+
"references/traces.md",
19+
"references/trials.md"
20+
]
721
}
822
]
923
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../../../../plugins/sentry-cli/skills/sentry-cli/references
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
---
2+
title: Agent Guidance
3+
description: Operational guidance for AI coding agents using the Sentry CLI
4+
---
5+
6+
Best practices and operational guidance for AI coding agents using the Sentry CLI.
7+
8+
## Design Principles
9+
10+
The `sentry` CLI follows conventions from well-known tools — if you're familiar with them, that knowledge transfers directly:
11+
12+
- **`gh` (GitHub CLI) conventions**: The `sentry` CLI uses the same `<noun> <verb>` command pattern (e.g., `sentry issue list`, `sentry org view`). Flags follow `gh` conventions: `--json` for machine-readable output, `--fields` to select specific fields, `-w`/`--web` to open in browser, `-q`/`--query` for filtering, `-n`/`--limit` for result count.
13+
- **`sentry api` mimics `curl`**: The `sentry api` command provides direct API access with a `curl`-like interface — `--method` for HTTP method, `--data` for request body, `--header` for custom headers. It handles authentication automatically. If you know how to call a REST API with `curl`, the same patterns apply.
14+
15+
## Context Window Tips
16+
17+
- Use `--fields id,title,status` on list commands to reduce output size
18+
- Use `--json` when piping output between commands or processing programmatically
19+
- Use `--limit` to cap the number of results (default is usually 10–100)
20+
- Prefer `sentry issue view PROJECT-123` over listing and filtering manually
21+
- Use `sentry api` for endpoints not covered by dedicated commands
22+
23+
## Safety Rules
24+
25+
- Always confirm with the user before running destructive commands: `project delete`, `trial start`
26+
- Verify the org/project context is correct before mutations — use `sentry auth status` to check defaults
27+
- Never store or log authentication tokens — use `sentry auth login` and let the CLI manage credentials
28+
- When in doubt about the target org/project, use explicit `<org>/<project>` arguments instead of auto-detection
29+
30+
## Workflow Patterns
31+
32+
### Investigate an Issue
33+
34+
```bash
35+
# 1. Find the issue
36+
sentry issue list my-org/my-project --query "is:unresolved" --limit 5
37+
38+
# 2. Get details
39+
sentry issue view PROJECT-123
40+
41+
# 3. Get AI root cause analysis
42+
sentry issue explain PROJECT-123
43+
44+
# 4. Get a fix plan
45+
sentry issue plan PROJECT-123
46+
```
47+
48+
### Explore Traces and Performance
49+
50+
```bash
51+
# 1. List recent traces
52+
sentry trace list my-org/my-project --limit 5
53+
54+
# 2. View a specific trace with span tree
55+
sentry trace view my-org/my-project/abc123def456...
56+
57+
# 3. View spans for a trace
58+
sentry span list my-org/my-project/abc123def456...
59+
60+
# 4. View logs associated with a trace
61+
sentry trace logs my-org/abc123def456...
62+
```
63+
64+
### Stream Logs
65+
66+
```bash
67+
# Stream logs in real-time
68+
sentry log list my-org/my-project --follow
69+
70+
# Filter logs by severity
71+
sentry log list my-org/my-project --query "severity:error"
72+
```
73+
74+
### Arbitrary API Access
75+
76+
```bash
77+
# GET request (default)
78+
sentry api /api/0/organizations/my-org/
79+
80+
# POST request with data
81+
sentry api /api/0/organizations/my-org/projects/ --method POST --data '{"name":"new-project","platform":"python"}'
82+
```
83+
84+
## Common Mistakes
85+
86+
- **Wrong issue ID format**: Use `PROJECT-123` (short ID), not the numeric ID `123456789`. The short ID includes the project prefix.
87+
- **Forgetting authentication**: Run `sentry auth login` before any other command. Check with `sentry auth status`.
88+
- **Missing `--json` for piping**: Human-readable output includes formatting. Use `--json` when parsing output programmatically.
89+
- **Org/project ambiguity**: Auto-detection scans for DSNs in `.env` files and source code. If the project is ambiguous, specify explicitly: `sentry issue list my-org/my-project`.
90+
- **Confusing `--query` syntax**: The `--query` flag uses Sentry search syntax (e.g., `is:unresolved`, `assigned:me`), not free text search.
91+
- **Not using `--web`**: View commands support `-w`/`--web` to open the resource in the browser — useful for sharing links.

0 commit comments

Comments
 (0)