Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -686,7 +686,7 @@ mock.module("./some-module", () => ({
* **Shared pagination infrastructure: buildPaginationContextKey and parseCursorFlag**: List commands with cursor pagination use \`buildPaginationContextKey(type, identifier, flags)\` for composite context keys and \`parseCursorFlag(value)\` accepting \`"last"\` magic value. Critical: \`resolveCursor()\` must be called inside the \`org-all\` override closure, not before \`dispatchOrgScopedList\` — otherwise cursor validation errors fire before the correct mode-specific error.

<!-- lore:019cbd5f-ec35-7e2d-8386-6d3a67adf0cf -->
* **Telemetry instrumentation pattern: withTracingSpan + captureException for handled errors**: For graceful-fallback operations, use \`withTracingSpan\` from \`src/lib/telemetry.ts\` for child spans and \`captureException\` from \`@sentry/bun\` (named import — Biome forbids namespace imports) with \`level: 'warning'\` for non-fatal errors. \`withTracingSpan\` uses \`onlyIfParent: true\` so it's a no-op without active transaction. When returning \`withTracingSpan(...)\` directly, drop \`async\` and use \`Promise.resolve(null)\` for early returns. User-visible fallbacks should use \`log.warn()\` not \`log.debug()\` — debug is invisible at default level. Also: several commands bypass telemetry by importing \`buildCommand\` from \`@stricli/core\` directly instead of \`../../lib/command.js\`. Affected: trace/list, trace/view, log/view, api.ts, help.ts.
* **Telemetry instrumentation pattern: withTracingSpan + captureException for handled errors**: For graceful-fallback operations, use \`withTracingSpan\` from \`src/lib/telemetry.ts\` for child spans and \`captureException\` from \`@sentry/bun\` (named import — Biome forbids namespace imports) with \`level: 'warning'\` for non-fatal errors. \`withTracingSpan\` uses \`onlyIfParent: true\` so it's a no-op without active transaction. When returning \`withTracingSpan(...)\` directly, drop \`async\` and use \`Promise.resolve(null)\` for early returns. User-visible fallbacks should use \`log.warn()\` not \`log.debug()\` — debug is invisible at default level.

### Preference

Expand Down
28 changes: 28 additions & 0 deletions biome.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,23 @@
"javascript": {
"globals": ["Bun"]
},
"linter": {
"rules": {
"style": {
"noRestrictedImports": {
"level": "error",
"options": {
"paths": {
"@stricli/core": {
"importNames": ["buildCommand"],
"message": "Import buildCommand from '../lib/command.js' instead. The wrapper injects telemetry, --log-level, and --verbose."
}
}
}
}
}
}
},
"overrides": [
{
"includes": ["test/**/*.ts"],
Expand Down Expand Up @@ -47,6 +64,17 @@
}
}
}
},
{
// command.ts is the canonical wrapper — it must import buildCommand from @stricli/core
"includes": ["src/lib/command.ts"],
"linter": {
"rules": {
"style": {
"noRestrictedImports": "off"
}
}
}
}
]
}
2 changes: 2 additions & 0 deletions docs/src/content/docs/commands/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ All commands support the following global options:

- `--help` - Show help for the command
- `--version` - Show CLI version
- `--log-level <level>` - Set log verbosity (`error`, `warn`, `log`, `info`, `debug`, `trace`). Overrides `SENTRY_LOG_LEVEL`
- `--verbose` - Shorthand for `--log-level debug`

## JSON Output

Expand Down
39 changes: 39 additions & 0 deletions docs/src/content/docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,18 @@ Disable CLI telemetry (error tracking for the CLI itself). The CLI sends anonymi
export SENTRY_CLI_NO_TELEMETRY=1
```

### `SENTRY_LOG_LEVEL`

Controls the verbosity of diagnostic output. Defaults to `info`.

Valid values: `error`, `warn`, `log`, `info`, `debug`, `trace`

```bash
export SENTRY_LOG_LEVEL=debug
```

Equivalent to passing `--log-level debug` on the command line. CLI flags take precedence over the environment variable.

### `SENTRY_CLI_NO_UPDATE_CHECK`

Disable the automatic update check that runs periodically in the background.
Expand All @@ -97,6 +109,33 @@ Disable the automatic update check that runs periodically in the background.
export SENTRY_CLI_NO_UPDATE_CHECK=1
```

## Global Options

These flags are accepted by every command. They are not shown in individual command `--help` output, but are always available.

### `--log-level <level>`

Set the log verbosity level. Accepts: `error`, `warn`, `log`, `info`, `debug`, `trace`.

```bash
sentry issue list --log-level debug
sentry --log-level=trace cli upgrade
```

Overrides `SENTRY_LOG_LEVEL` when both are set.

### `--verbose`

Shorthand for `--log-level debug`. Enables debug-level diagnostic output.

```bash
sentry issue list --verbose
```

:::note
The `sentry api` command also uses `--verbose` to show full HTTP request/response details. When used with `sentry api`, it serves both purposes (debug logging + HTTP output).
:::

## Credential Storage

Credentials are stored in a SQLite database at `~/.sentry/` (or the path set by `SENTRY_CONFIG_DIR`) with restricted file permissions (mode 600) for security. The database also caches:
Expand Down
9 changes: 9 additions & 0 deletions plugins/sentry-cli/skills/sentry-cli/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,15 @@ Show the currently authenticated user
**Flags:**
- `--json - Output as JSON`

## Global Options

All commands support the following global options:

- `--help` - Show help for the command
- `--version` - Show CLI version
- `--log-level <level>` - Set log verbosity (`error`, `warn`, `log`, `info`, `debug`, `trace`). Overrides `SENTRY_LOG_LEVEL`
- `--verbose` - Shorthand for `--log-level debug`

## Output Formats

### JSON Output
Expand Down
28 changes: 22 additions & 6 deletions script/generate-skill.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ type FlagDef = {
optional?: boolean;
variadic?: boolean;
placeholder?: string;
hidden?: boolean;
};

// ─────────────────────────────────────────────────────────────────────────────
Expand Down Expand Up @@ -376,6 +377,7 @@ async function loadCommandExamples(
* Load supplementary content from commands/index.md
*/
async function loadCommandsOverview(): Promise<{
globalOptions: string;
jsonOutput: string;
webFlag: string;
} | null> {
Expand All @@ -385,10 +387,12 @@ async function loadCommandsOverview(): Promise<{
return null;
}

const globalSection = extractSection(content, "Global Options");
const jsonSection = extractSection(content, "JSON Output");
const webSection = extractSection(content, "Opening in Browser");

return {
globalOptions: globalSection || "",
jsonOutput: jsonSection || "",
webFlag: webSection || "",
};
Expand Down Expand Up @@ -423,6 +427,7 @@ type FlagInfo = {
default?: unknown;
optional: boolean;
variadic: boolean;
hidden: boolean;
};

type RouteInfo = {
Expand Down Expand Up @@ -468,6 +473,7 @@ function extractFlags(flags: Record<string, FlagDef> | undefined): FlagInfo[] {
default: def.default,
optional: def.optional ?? def.kind === "boolean",
variadic: def.variadic ?? false,
hidden: def.hidden ?? false,
}));
}

Expand Down Expand Up @@ -616,9 +622,9 @@ function generateCommandDoc(cmd: CommandInfo): string {
lines.push("");
lines.push(cmd.brief);

// Flags section
// Flags section — exclude help flags and hidden global flags (e.g. --log-level, --verbose)
const visibleFlags = cmd.flags.filter(
(f) => f.name !== "help" && f.name !== "helpAll"
(f) => !f.hidden && f.name !== "help" && f.name !== "helpAll"
);

if (visibleFlags.length > 0) {
Expand Down Expand Up @@ -707,12 +713,22 @@ function generateCommandsSection(routeInfos: RouteInfo[]): string {
}

/**
* Generate the Output Formats section from docs
* Generate supplementary sections (Global Options, Output Formats) from docs
*/
async function generateOutputFormatsSection(): Promise<string> {
async function generateSupplementarySections(): Promise<string> {
const overview = await loadCommandsOverview();

const lines: string[] = [];

// Global Options section
if (overview?.globalOptions) {
lines.push("## Global Options");
lines.push("");
lines.push(overview.globalOptions);
lines.push("");
}

// Output Formats section
lines.push("## Output Formats");
lines.push("");

Expand Down Expand Up @@ -747,7 +763,7 @@ async function generateOutputFormatsSection(): Promise<string> {
async function generateSkillMarkdown(routeMap: RouteMap): Promise<string> {
const routeInfos = await extractRoutes(routeMap);
const prerequisites = await loadPrerequisites();
const outputFormats = await generateOutputFormatsSection();
const supplementary = await generateSupplementarySections();

const sections = [
generateFrontMatter(),
Expand All @@ -759,7 +775,7 @@ async function generateSkillMarkdown(routeMap: RouteMap): Promise<string> {
prerequisites,
"",
generateCommandsSection(routeInfos),
outputFormats,
supplementary,
"",
];

Expand Down
20 changes: 4 additions & 16 deletions src/bin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,7 @@ import { buildContext } from "./context.js";
import { AuthError, formatError, getExitCode } from "./lib/errors.js";
import { error } from "./lib/formatters/colors.js";
import { runInteractiveLogin } from "./lib/interactive-login.js";
import {
extractLogLevelFromArgs,
getEnvLogLevel,
setLogLevel,
} from "./lib/logger.js";
import { getEnvLogLevel, setLogLevel } from "./lib/logger.js";
import { withTelemetry } from "./lib/telemetry.js";
import { startCleanupOldBinary } from "./lib/upgrade.js";
import {
Expand Down Expand Up @@ -94,22 +90,14 @@ async function main(): Promise<void> {

const args = process.argv.slice(2);

// Apply SENTRY_LOG_LEVEL env var first (lazy read, not at module load time).
// CLI flags below override this if present.
// Apply SENTRY_LOG_LEVEL env var early (lazy read, not at module load time).
// CLI flags (--log-level, --verbose) are handled by Stricli via
// buildCommand and take priority when present.
const envLogLevel = getEnvLogLevel();
if (envLogLevel !== null) {
setLogLevel(envLogLevel);
}

// Extract global log-level flags before Stricli parses args.
// --log-level is consumed (removed); --verbose is read but left in place
// because some commands (e.g., `api`) define their own --verbose flag.
// CLI flags take priority over SENTRY_LOG_LEVEL env var.
const logLevel = extractLogLevelFromArgs(args);
if (logLevel !== null) {
setLogLevel(logLevel);
}

const suppressNotification = shouldSuppressNotification(args);

// Start background update check (non-blocking)
Expand Down
3 changes: 2 additions & 1 deletion src/commands/help.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
* - `sentry help <command>`: Shows Stricli's detailed help (--helpAll) for that command
*/

import { buildCommand, run } from "@stricli/core";
import { run } from "@stricli/core";
import type { SentryContext } from "../context.js";
import { buildCommand } from "../lib/command.js";
import { printCustomHelp } from "../lib/help.js";

export const helpCommand = buildCommand({
Expand Down
Loading