Dashboard › cli › Session 06nSIoYMqqXG
06nSIoYMqqXG8Q5idRead-only exploration in /home/byk/Code/getsentry/cli-pr-1558. Do not modify files. Review the current uncommitted implementation for mapping docs.customUsage[0] to PositionalInfo.syntax in packages/cli/src/lib/introspect.ts and rendering it in script/generate-skill-markdown.ts. Find all customUsage definitions and assess whether using the full canonical usage as a single argument-table row is correct for every current command, including project create and agent-conversation view. Identify concrete defects only, with file:line evidence and a minimal recommendation. Also inspect whether any customUsage command has zero or multiple extracted positional rows, which would bypass or misuse the mapping. Return PASS if no defects.
The required repo-setup skill is not available in this session, so I will apply the checked-in repository instructions directly and keep the review read-only.
<path>/home/byk/Code/getsentry/cli-pr-1558</path> <type>directory</type> <entries> .craft.yml .git .github/ .gitignore .lore.md .nojekyll .npmrc AGENTS.md apps/ CHANGELOG.md codemods/ docs/ LICENSE.md node_modules/ package.json packages/ pnpm-lock.yaml pnpm-workspace.yaml README.md (19 entries) </entries>
/home/byk/Code/getsentry/cli-pr-1558/AGENTS.md /home/byk/Code/getsentry/cli-pr-1558/packages/cli/AGENTS.md
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/CONTRIBUTING.md
<path>/home/byk/Code/getsentry/cli-pr-1558/AGENTS.md</path> <type>file</type> <content> 1: # Jared (Outpost agent) 2: 3: Autonomous GitHub coding agent. Work in `/workspace/repo`. 4: 5: ## Model tiers 6: 7: The primary model is chosen per event (see `src/agents/models.ts`): heavy for 8: code-producing situations, cheaper for lightweight ones. 9: 10: | Role | Subagent | Model | 11: | --- | --- | --- | 12: | Triage / plan / review (heavy) | (primary Jared) | Claude Opus 4.8 | 13: | Triage / plan / review (light) | (primary Jared) | xAI Grok 4.3 | 14: | Explore | `explore` | OpenAI gpt-5-mini | 15: | Implement | `implement` | Moonshot kimi-k2.7-code | 16: | Ship (commit/push/PR) | `ship` | xAI Grok (`grok-build-0.1`) | 17: 18: Pipeline: triage → explore → plan → implement → review → ship. 19: (`worker` is a deprecated alias of `implement`.) 20: 21: Operators also talk to Jared directly from the Outpost dashboard. ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/AGENTS.md</path> <type>file</type> <content> 1: # AGENTS.md 2: 3: Guidelines for AI agents working in this codebase. 4: 5: ## Project Overview 6: 7: **Sentry CLI** is a command-line interface for [Sentry](https://sentry.io), built with Node.js, [pnpm](https://pnpm.io), and [Stricli](https://bloomberg.github.io/stricli/). It lives in `packages/cli` of a pnpm workspace; the docs site lives in `apps/cli-docs`. 8: 9: ### Goals 10: 11: - **Zero-config experience** - Auto-detect project context from DSNs in source code and env files 12: - **AI-powered debugging** - Integrate Seer AI for root cause analysis and fix plans 13: - **Developer-friendly** - Follow `gh` CLI conventions for intuitive UX 14: - **Agent-friendly** - JSON output and predictable behavior for AI coding agents 15: - **Fast** - Native binaries via Node SEA (fossilize), SQLite caching for API responses 16: 17: ### Key Features 18: 19: - **DSN Auto-Detection** - ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/CONTRIBUTING.md</path> <type>file</type> <content> 1: # Contributing to Sentry CLI 2: 3: This guide documents the patterns and conventions used in this CLI for consistency. 4: 5: ## Command Patterns 6: 7: We follow [gh CLI](https://cli.github.com/) conventions for best-in-class developer experience. 8: 9: ### List Commands 10: 11: List commands use **optional positional arguments** for context with smart auto-detection. 12: 13: ```bash 14: sentry org list [--limit N] [--json] 15: sentry project list [org] [--limit N] [--json] 16: sentry issue list [<org>/<project>] [--json] 17: ``` 18: 19: **Target syntax**: 20: - `<org>/<project>` - Explicit organization and project (e.g., `my-org/frontend`) 21: - `<org>/` - All projects in the specified organization 22: - `<project>` - Search for project by name across all accessible organizations 23: - *(omit)* - Auto-detect from DSN or config 24: 25: **Rationale**: Positional ...
No files found
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/package.json</path>
<type>file</type>
<content>
1: {
2: "name": "sentry",
3: "version": "0.45.0-dev.0",
4: "description": "Sentry CLI - A command-line interface for using Sentry built by robots and humans for robots and humans",
5: "repository": {
6: "type": "git",
7: "url": "git+https://github.com/getsentry/cli.git"
8: },
9: "main": "./dist/index.cjs",
10: "type": "module",
11: "types": "./dist/index.d.cts",
12: "exports": {
13: ".": {
14: "import": {
15: "types": "./dist/index.d.mts",
16: "default": "./dist/index.mjs"
17: },
18: "require": {
19: "types": "./dist/index.d.cts",
20: "default": "./dist/index.cjs"
21: }
22: }
23: },
24: "bin": {
25: "sentry": "./dist/bin.cjs"
26: },
27: "files": [
28: "dist/bin.cjs",
29: "dist/index.cjs",
30: "dist/index.mjs",
31: "dist/index.d.cts",
32: "dist/index.d.mts",
33: ...
M packages/cli/script/generate-command-docs.ts M packages/cli/script/generate-skill-markdown.ts M packages/cli/src/lib/introspect.ts M packages/cli/test/lib/introspect.property.test.ts M packages/cli/test/lib/introspect.test.ts M packages/cli/test/script/generate-skill-markdown.test.ts
diff --git a/packages/cli/script/generate-command-docs.ts b/packages/cli/script/generate-command-docs.ts
index ac02d200b..291b4efa0 100644
--- a/packages/cli/script/generate-command-docs.ts
+++ b/packages/cli/script/generate-command-docs.ts
@@ -25,7 +25,10 @@
import { mkdirSync, rmSync } from "node:fs";
import { access, readFile, writeFile } from "node:fs/promises";
-import { formatCommandExamples } from "./generate-skill-markdown.js";
+import {
+ formatCommandArguments,
+ formatCommandExamples,
+} from "./generate-skill-markdown.js";
import { DOCS_CONTENT, DOCS_FRAGMENTS } from "./paths.js";
// Ensure src/generated/skill-content.ts exists before importing the route tree.
@@ -50,7 +53,6 @@ import type { EnvVarEntry } from "../src/lib/env-registry.js";
import type {
CommandInfo,
FlagInfo,
- PositionalInfo,
RouteInfo,
RouteMap,
} from "../src/lib/introspect.js";
@@ -135,34 +137,6 @@ function formatFlagRow(
return `| \`${syntax}\` | ${desc} |`;
}
-/**
- * ...
Found 5 matches /home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/lib/command.test.ts: Line 186: customUsage: ["<name>:<kind>..."], /home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/lib/command.ts: Line 107: * `customUsage` is present, its first line is the canonical signature suffix; Line 466: const primaryUsage = docs.customUsage?.[0]; /home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/project/create.ts: Line 609: customUsage: ["[<org>/]<name>:<platform>..."], /home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/agent-conversation/view.ts: Line 75: customUsage: [USAGE],
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/lib/introspect.ts</path>
<type>file</type>
<content>
1: /**
2: * Route Tree Introspection
3: *
4: * Shared module for extracting structured metadata from Stricli's route tree.
5: * Used at runtime by `sentry help --json` and at build time by `generate-skill.ts`.
6: *
7: * While @stricli/core exports RouteMap and Command types, they require complex
8: * generic parameters (CommandContext) and don't export internal types like
9: * RouteMapEntry or FlagParameter. These simplified types are purpose-built
10: * for introspection and documentation generation.
11: */
12:
13: import type { CommandExample } from "./command.js";
14: import {
15: extractSchemaFields,
16: type SchemaFieldInfo,
17: } from "./formatters/output.js";
18: import { fuzzyMatch } from "./fuzzy.js";
19:
20: // ---------------------------------------------------------------------------
21: // Stricli Runtime Types (simplified for introspection)
22: ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/script/generate-skill-markdown.ts</path>
<type>file</type>
<content>
1: /**
2: * Markdown parsing helpers shared by the skill generator and its tests.
3: */
4:
5: import type { PositionalInfo } from "../src/lib/introspect.js";
6:
7: /** Matches a generated command heading and stops before positional usage. */
8: const COMMAND_HEADING_RE =
9: /^`sentry\s+([^<[`\s]+(?:\s+[^<[`\s]+)*)(?:\s*(?:<|\[)[^`]*)?`$/;
10:
11: /** Extract the literal command path from a generated command heading. */
12: export function extractCommandPathFromHeading(
13: heading: string
14: ): string | undefined {
15: const match = COMMAND_HEADING_RE.exec(heading);
16: return match?.[1] ? `sentry ${match[1]}` : undefined;
17: }
18:
19: /** Find the command whose literal path appears in a loose example block. ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/script/generate-command-docs.ts</path>
<type>file</type>
<content>
1: #!/usr/bin/env tsx
2: /**
3: * Generate Command Reference & Configuration Documentation
4: *
5: * Introspects the CLI's route tree and env var registry to generate
6: * accurate reference pages for the documentation website. Flags, arguments,
7: * aliases, and environment variables are extracted directly from source code,
8: * preventing documentation drift.
9: *
10: * Each generated page combines:
11: * 1. Auto-generated reference and examples from CLI metadata or env registry
12: * 2. Hand-written guides and tips from docs/src/fragments/
13: *
14: * The generated output is gitignored. Fragment files are the committed
15: * source of truth for content that cannot live in command definitions.
16: *
17: * Usage:
18: * tsx script/generate-command-docs.ts
19: *
20: * Output:
21: * docs/src/content/docs/commands/{route}.md (one per ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/project/create.ts</path>
<type>file</type>
<content>
560: teamSource = team.source;
561: projectDetails = await createProjectWithErrors({
562: orgSlug,
563: teamSlug,
564: name,
565: platform,
566: detectedFrom,
567: });
568: } catch (error) {
569: // 403 means the user lacks permission to create or access teams, or to
570: // create projects on the resolved team. Fall back to the org-scoped endpoint
571: // which requires only project:read and auto-creates a personal team.
572: // Skip the fallback when --team was explicit: the 403 is meaningful there.
573: if (!(error instanceof ApiError && error.status === 403) || flags.team) {
574: throw error;
575: }
576: // Policy 403: org has disabled member project creation. The org-scoped
577: // endpoint enforces the same flag — re-throw to avoid a wasted round-trip.
578: if ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/agent-conversation/view.ts</path>
<type>file</type>
<content>
1: /**
2: * sentry agent-conversation view
3: *
4: * View the transcript of a specific agent conversation.
5: */
6:
7: import type { SentryContext } from "../../context.js";
8: import { getConversationSpans } from "../../lib/api-client.js";
9: import { buildCommand } from "../../lib/command.js";
10: import { ContextError, validationError } from "../../lib/errors.js";
11: import {
12: buildTranscriptResult,
13: formatTranscriptResult,
14: type TranscriptResult,
15: } from "../../lib/formatters/conversation.js";
16: import { CommandOutput } from "../../lib/formatters/output.js";
17: import {
18: applyFreshFlag,
19: FRESH_ALIASES,
20: FRESH_FLAG,
21: } from "../../lib/list-command.js";
22: import { withProgress } from "../../lib/polling.js";
23: import { resolveOrg } from "../../lib/resolve-target.js";
24:
25: type ViewFlags = {
26: ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/lib/command.ts</path> <type>file</type> <content> 70: /** 71: * Parse a string input as a number. 72: * Re-exported from Stricli for convenience. 73: */ 74: export const numberParser = stricliNumberParser; 75: 76: /** Base flags type from Stricli */ 77: type BaseFlags = Readonly<Partial<Record<string, unknown>>>; 78: 79: /** Base args type from Stricli */ 80: type BaseArgs = readonly unknown[]; 81: 82: /** 83: * Type-erased Stricli builder arguments. 84: * 85: * At the `stricliCommand()` call site we've modified both `parameters` 86: * (injected hidden flags) and `func` (wrapped with telemetry/output 87: * logic), which breaks the original `FLAGS`/`ARGS` generic alignment 88: * that Stricli's `CommandBuilderArguments` enforces via `NoInfer`. ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/lib/command.ts</path>
<type>file</type>
<content>
430: return docs;
431: }
432: const jsonFieldsDoc = formatSchemaForHelp(schemaFields);
433: const baseFull = docs.fullDescription ?? docs.brief;
434: return {
435: ...docs,
436: fullDescription: `${baseFull}\n\n${jsonFieldsDoc}`,
437: };
438: }
439:
440: /** Convert extended command docs into native Stricli help documentation. */
441: function prepareNativeDocs(
442: docs: CommandDocumentation
443: ): StricliBuilderArgs<CommandContext>["docs"] {
444: const { examples, ...nativeDocs } = docs;
445: if (!examples?.length) {
446: return nativeDocs;
447: }
448:
449: const renderedExamples = examples
450: .map(({ description, command }) => ` ${command} # ${description}`)
451: .join("\n");
452: return {
453: ...nativeDocs,
454: fullDescription: `${nativeDocs.fullDescription ?? ...
Found 35 matches /home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/lib/command.test.ts: Line 186: customUsage: ["<name>:<kind>..."], /home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/lib/command.ts: Line 107: * `customUsage` is present, its first line is the canonical signature suffix; Line 466: const primaryUsage = docs.customUsage?.[0]; /home/byk/Code/getsentry/cli-pr-1558/packages/cli/coverage/lcov-report/cli/src/lib/command.ts.html: Line 1992: * `customUsage` is present, its first line is the canonical signature suffix; Line 2351: const primaryUsage = docs.customUsage?.[0]; /home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/project/create.ts: Line 609: customUsage: ["[<org>/]<name>:<platform>..."], /home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/agent-conversation/view.ts: Line 75: customUsage: ...
Found 9 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/script/generate-skill-markdown.test.ts:
Line 47: (listCommand as unknown as { __primaryUsage?: string }).__primaryUsage
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/lib/introspect.test.ts:
Line 328: __primaryUsage: "<name>:<kind>...",
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/lib/command.test.ts:
Line 200: (command as unknown as { __primaryUsage?: string }).__primaryUsage
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/lib/introspect.ts:
Line 62: __primaryUsage?: string;
Line 311: if (cmd.__primaryUsage && positional && positionals.length === 1) {
Line 312: positionals[0] = { ...positional, syntax: cmd.__primaryUsage };
Line 321: cmd.__primaryUsage ?? getPositionalString(cmd.parameters.positional),
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/lib/command.ts:
Line 470: metadata.__primaryUsage = ...
Found 10 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/script/generate-command-docs.ts:
Line 29: formatCommandArguments,
Line 175: if (cmd.positionals.length > 0) {
Line 177: lines.push(formatCommandArguments(cmd.positionals));
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/script/generate-skill-markdown.ts:
Line 53: export function formatCommandArguments(
Line 54: positionals: readonly PositionalInfo[]
Line 56: if (positionals.length === 0) {
Line 66: for (const positional of positionals) {
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/script/generate-sdk.ts:
Line 380: positionalExpr = `positionals(${args})`;
Line 583: // Required flags make params required even with variadic positionals
Line 690: "function positionals(...values: (string | undefined)[]): string[] {",
/home/byk/Code/getsentry/cli-pr-1558/apps/cli-docs/src/fragments/commands/agent-conversation.md /home/byk/Code/getsentry/cli-pr-1558/apps/cli-docs/src/fragments/commands/project.md
Found 2 matches /home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/lib/command.ts: Line 459: function attachDocumentationMetadata( Line 894: attachDocumentationMetadata(cmd, builderArgs.docs);
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/lib/command.ts</path>
<type>file</type>
<content>
850: const finalHint = returned ? appendCacheHint(returned.hint) : undefined;
851: await withTracing("render", "cli.command.render", () => {
852: writeFinalization(stdout, finalHint, cleanFlags.json, renderer);
853: });
854: } catch (err) {
855: // Finalize before error handling to close streaming state
856: // (e.g., table footer). No hint since the generator didn't
857: // complete. Only in human mode — JSON must not be corrupted.
858: if (!cleanFlags.json) {
859: writeFinalization(stdout, undefined, false, renderer);
860: }
861:
862: // If a positional arg was "help" and the command failed with a
863: // resolution/validation error, the user likely meant --help.
864: // Show help as recovery instead of the confusing error. ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/lib/introspect.ts</path>
<type>file</type>
<content>
292: }
293:
294: /**
295: * Build a {@link CommandInfo} from a Stricli Command.
296: *
297: * @param cmd - The Stricli command to introspect
298: * @param path - Full command path (e.g. "sentry issue list")
299: * @param examples - Optional usage examples
300: */
301: export function buildCommandInfo(
302: cmd: Command,
303: path: string,
304: examples: string[] = []
305: ): CommandInfo {
306: const jsonFields = cmd.__jsonSchema
307: ? extractSchemaFields(cmd.__jsonSchema)
308: : undefined;
309: const positionals = extractPositionals(cmd.parameters.positional);
310: const [positional] = positionals;
311: if (cmd.__primaryUsage && positional && positionals.length === 1) {
312: positionals[0] = { ...positional, syntax: cmd.__primaryUsage };
313: }
314:
315: return {
316: path,
317: brief: cmd.brief,
318: fullDescription: ...
Found 2 matches /home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/project/create.ts: Line 609: customUsage: ["[<org>/]<name>:<platform>..."], /home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/agent-conversation/view.ts: Line 75: customUsage: [USAGE],
diff --git a/packages/cli/script/generate-command-docs.ts b/packages/cli/script/generate-command-docs.ts
index ac02d200b..291b4efa0 100644
--- a/packages/cli/script/generate-command-docs.ts
+++ b/packages/cli/script/generate-command-docs.ts
@@ -25,7 +25,10 @@
import { mkdirSync, rmSync } from "node:fs";
import { access, readFile, writeFile } from "node:fs/promises";
-import { formatCommandExamples } from "./generate-skill-markdown.js";
+import {
+ formatCommandArguments,
+ formatCommandExamples,
+} from "./generate-skill-markdown.js";
import { DOCS_CONTENT, DOCS_FRAGMENTS } from "./paths.js";
// Ensure src/generated/skill-content.ts exists before importing the route tree.
@@ -50,7 +53,6 @@ import type { EnvVarEntry } from "../src/lib/env-registry.js";
import type {
CommandInfo,
FlagInfo,
- PositionalInfo,
RouteInfo,
RouteMap,
} from "../src/lib/introspect.js";
@@ -135,34 +137,6 @@ function formatFlagRow(
return `| \`${syntax}\` | ${desc} |`;
}
-/**
- * ...
Found 34 matches /home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/help.ts: Line 36: kind: "array", /home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/lib/introspect.ts: Line 71: kind: "array"; /home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/event/view.ts: Line 1082: kind: "array", /home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/event/send.ts: Line 142: kind: "array", /home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/docs/query.ts: Line 40: kind: "array", /home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/docs/list.ts: Line 54: kind: "array", /home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/debug-files/upload.ts: Line 567: kind: "array", /home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/trace/view.ts: Line 484: kind: "array", /home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/trace/logs.ts: Line ...
Found 4 matches /home/byk/Code/getsentry/cli-pr-1558/node_modules/.pnpm/@stricli+core@1.2.8_patch_hash=892258f886d48063b409e0ac6141260023c396d1ed4f915231701f6a34edffcc/node_modules/@stricli/core/dist/index.d.ts: Line 1033: readonly kind: "array"; Line 1035: readonly minimum?: number; Line 1300: readonly limit?: [minimum: number, count: number]; Line 1301: constructor(placeholder: Placeholder, limit?: [minimum: number, count: number]);
<path>/home/byk/Code/getsentry/cli-pr-1558/node_modules/.pnpm/@stricli+core@1.2.8_patch_hash=892258f886d48063b409e0ac6141260023c396d1ed4f915231701f6a34edffcc/node_modules/@stricli/core/dist/index.d.ts</path>
<type>file</type>
<content>
1000: * In-line documentation for this parameter.
1001: */
1002: readonly brief: string;
1003: /**
1004: * String that serves as placeholder for the value in the generated usage line.
1005: * Defaults to "argN" where N is the index of this parameter.
1006: */
1007: readonly placeholder?: string;
1008: /**
1009: * Default input value if one is not provided at runtime.
1010: */
1011: readonly default?: string;
1012: readonly optional?: boolean;
1013: }
1014: interface RequiredPositionalParameter<T, CONTEXT extends CommandContext> extends BasePositionalParameter<T, CONTEXT> {
1015: /**
1016: * Parameter is required and cannot be set as optional.
1017: */
1018: readonly optional?: ...
Found 2 matches
/home/byk/Code/getsentry/cli-pr-1558/node_modules/.pnpm/@stricli+core@1.2.8_patch_hash=892258f886d48063b409e0ac6141260023c396d1ed4f915231701f6a34edffcc/node_modules/@stricli/core/dist/index.js:
Line 821: if (typeof positional.minimum === "number" && positionalIndex < positional.minimum) {
Line 824: positional.minimum,
<path>/home/byk/Code/getsentry/cli-pr-1558/node_modules/.pnpm/@stricli+core@1.2.8_patch_hash=892258f886d48063b409e0ac6141260023c396d1ed4f915231701f6a34edffcc/node_modules/@stricli/core/dist/index.js</path>
<type>file</type>
<content>
790: } else if (nextFlags.length > 1) {
791: const nextFlagExpectingArg = nextFlags.find((nextFlag) => !isNiladic(nextFlag));
792: const externalFlagName = asExternal(nextFlagExpectingArg.namedFlag[0], config.caseStyle);
793: throw new UnsatisfiedFlagError(externalFlagName);
794: } else {
795: activeFlag = nextFlags[0].namedFlag;
796: }
797: return;
798: }
799: }
800: if (activeFlag) {
801: storeInput(flagInputs, config.caseStyle, activeFlag, input);
802: activeFlag = void 0;
803: } else {
804: if (positional.kind === "tuple") {
805: if (positionalIndex >= positional.parameters.length) {
806: throw ...
Found 2 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/project/create.ts:
Line 465: function parseProjectSpecs(rawSpecs: readonly string[]): {
Line 658: const { explicitOrg, parsed } = parseProjectSpecs(args);
Resume your exhaustive audit of all 33 kind: "array" positional declarations in getsentry/cli after the server restart. Do not edit files. Inspect each command's parser declaration, runtime validation, docs/custom usage, and tests. Return a complete table with file:line, whether zero values are valid, the minimum parser cardinality that preserves runtime behavior, and whether an explicit minimum should be added. Pay special attention to issue merge (one positional plus --into must remain valid), project create (zero specs invalid), event send, schema, and help (zero values valid). Identify every command that requires a positive minimum, not just known failures. Report evidence and any ambiguous contracts. Finish with exact recommended edits.
I’ll re-enumerate the current worktree, then trace each array parameter through its command function, usage metadata, and focused tests.
M packages/cli/script/generate-command-docs.ts M packages/cli/script/generate-skill-markdown.ts M packages/cli/src/lib/introspect.ts M packages/cli/test/lib/introspect.property.test.ts M packages/cli/test/lib/introspect.test.ts M packages/cli/test/script/generate-skill-markdown.test.ts
Found 34 matches /home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/lib/introspect.ts: Line 71: kind: "array"; /home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/trace/view.ts: Line 484: kind: "array", /home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/trace/logs.ts: Line 130: kind: "array", /home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/span/view.ts: Line 384: kind: "array", /home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/span/list.ts: Line 575: kind: "array", /home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/send-envelope.ts: Line 26: kind: "array", /home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/schema.ts: Line 324: kind: "array", /home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/replay/view.ts: Line 360: kind: "array", /home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/react-native/xcode.ts: ...
<skill_content name="ast-grep"> # Skill: ast-grep # ast-grep Code Search ## Overview This skill helps translate natural language queries into ast-grep rules for structural code search. ast-grep uses Abstract Syntax Tree (AST) patterns to match code based on its structure rather than just text, enabling powerful and precise code search across large codebases. ## When to Use This Skill Use this skill when users: - Need to search for code patterns using structural matching (e.g., "find all async functions that don't have error handling") - Want to locate specific language constructs (e.g., "find all function calls with specific parameters") - Request searches that require understanding code structure rather than just text - Ask to search for code with particular AST characteristics - Need to perform complex code queries that traditional text search cannot handle ## General Workflow Follow this process to help users write effective ast-grep rules: ### Step 1: Understand the ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/help.ts</path>
<type>file</type>
<content>
1: /**
2: * Help Command
3: *
4: * Provides help information for the CLI.
5: * - `sentry help` or `sentry` (no args): Shows branded help with banner
6: * - `sentry help <command>`: Shows detailed help for that command
7: * - `sentry help --json`: Emits full command tree as structured JSON
8: * - `sentry help --json <command>`: Emits specific command/group metadata as JSON
9: */
10:
11: import type { SentryContext } from "../context.js";
12: import { buildCommand } from "../lib/command.js";
13: import { OutputError } from "../lib/errors.js";
14: import { CommandOutput } from "../lib/formatters/output.js";
15: import {
16: formatHelpHuman,
17: introspectAllCommands,
18: introspectCommand,
19: } from "../lib/help.js";
20:
21: export const helpCommand = buildCommand({
22: auth: false,
23: docs: {
24: brief: "Display help for a command",
25: ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/schema.ts</path>
<type>file</type>
<content>
260: // Resource exists but the operation didn't match: show its endpoints so
261: // the user can pick a valid operation. This is scoped to the resource,
262: // not the full list, so it isn't misleading.
263: const resourceEndpoints = getEndpointsByResource(resource);
264: if (resourceEndpoints.length > 0) {
265: throw new OutputError({
266: kind: "endpoints",
267: endpoints: resourceEndpoints,
268: } satisfies SchemaResult);
269: }
270: throw noResourceMatchError(resource);
271: }
272:
273: // Resource only: show all endpoints for that resource
274: const endpoints = getEndpointsByResource(resource);
275: if (endpoints.length === 0) {
276: throw noResourceMatchError(resource);
277: }
278: return { kind: "endpoints", endpoints };
279: }
280:
281: // ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/event/send.ts</path>
<type>file</type>
<content>
90:
91: export const sendCommand = buildCommand({
92: docs: {
93: brief: "Send a Sentry event",
94: fullDescription: `\
95: Send a Sentry event to the ingest pipeline using DSN-based authentication.
96:
97: No login required — provide a DSN via --dsn or the SENTRY_DSN environment variable.
98:
99: ## Building an event from flags
100:
101: \`\`\`
102: sentry event send -m "Something went wrong" -l error --tag env:prod
103: \`\`\`
104:
105: ## Sending from a JSON file
106:
107: The JSON file must be a valid serialized Sentry Event object:
108:
109: \`\`\`
110: sentry event send ./event.json
111: \`\`\`
112:
113: Use --raw to skip JSON parsing and send the file bytes directly to the ingest endpoint.
114: This also supports sending pre-built Sentry envelope files. ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/event/send.ts</path>
<type>file</type>
<content>
276: async *func(
277: this: SentryContext,
278: flags: SendEventFlags & {
279: dsn?: string;
280: raw?: boolean;
281: json?: boolean;
282: },
283: ...files: string[]
284: ) {
285: const dsn = requireDsn(flags);
286: let dsnComponents: ReturnType<typeof makeDsn>;
287: try {
288: dsnComponents = makeDsn(dsn);
289: } catch (err) {
290: log.debug("makeDsn threw for DSN input", err);
291: dsnComponents = undefined;
292: }
293: if (!dsnComponents) {
294: throw new ValidationError(`Invalid DSN: ${dsn}`, "dsn");
295: }
296:
297: if (files.length > 0) {
298: for (const file of files) {
299: const { body, eventId } = await buildFilePayload(
300: file,
301: flags.raw ?? ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/issue/merge.ts</path>
<type>file</type>
<content>
205: );
206: if (direct) {
207: return [direct, ...issues.filter((i) => i !== direct)];
208: }
209:
210: // Fallback: resolve `into` through the same pipeline as positional args
211: // (handles project-alias suffixes like `f-g`, URLs, @selectors, etc).
212: // This adds a second API round trip in the alias-only case, but avoids
213: // reimplementing the alias lookup logic here.
214: //
215: // Only a clean "not found" (ResolutionError, or ApiError with status 404)
216: // is swallowed — real errors (auth, 5xx, network, ContextError) propagate
217: // so the user sees a proper diagnostic instead of the misleading
218: // "did not match any of the provided issues". ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/send-envelope.ts</path>
<type>file</type>
<content>
1: /**
2: * `sentry send-envelope` — Deprecated. Suggests `sentry event send --raw`.
3: *
4: * Kept as a hidden backward-compat alias that prints a deprecation notice
5: * and forwards to `sentry event send --raw`.
6: */
7:
8: import type { SentryContext } from "../context.js";
9: import { buildCommand } from "../lib/command.js";
10: import { CliError, EXIT } from "../lib/errors.js";
11:
12: export const sendEnvelopeCommand = buildCommand({
13: docs: {
14: brief: "Send a Sentry envelope file (deprecated)",
15: fullDescription:
16: "This command has been replaced by `sentry event send --raw <file>`.\n\n" +
17: "Use `sentry event send --raw ./captured.envelope` instead.",
18: },
19: auth: false,
20: skipRcUrlCheck: true,
21: output: {
22: human: () => "",
23: },
24: parameters: {
25: positional: {
26: kind: ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/docs/query.ts</path>
<type>file</type>
<content>
1: import type { SentryContext } from "../../context.js";
2: import { buildCommand } from "../../lib/command.js";
3: import { detectDocsContext } from "../../lib/docs-context.js";
4: import { queryDocs } from "../../lib/docs-service.js";
5: import { ValidationError } from "../../lib/errors.js";
6: import { CommandOutput } from "../../lib/formatters/output.js";
7: import { withProgress } from "../../lib/polling.js";
8:
9: type QueryFlags = { readonly fields?: string[]; readonly json: boolean };
10: type QueryOutput = {
11: answer: string;
12: detectedContext: Awaited<ReturnType<typeof detectDocsContext>>;
13: sources: string[];
14: };
15:
16: /** Friendly wait messages for a docs-MCP request without measurable stages. ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/docs/list.ts</path>
<type>file</type>
<content>
1: import type { SentryContext } from "../../context.js";
2: import { validateLimit } from "../../lib/arg-parsing.js";
3: import { buildCommand } from "../../lib/command.js";
4: import { type DocsListResponse, listDocs } from "../../lib/docs-service.js";
5: import { ValidationError } from "../../lib/errors.js";
6: import { muted } from "../../lib/formatters/colors.js";
7: import { CommandOutput } from "../../lib/formatters/output.js";
8: import { formatTable } from "../../lib/formatters/table.js";
9:
10: type ListFlags = {
11: readonly fields?: string[];
12: readonly json: boolean;
13: readonly limit: number;
14: };
15:
16: function parseLimit(value: string): number {
17: return validateLimit(value, 1, 20);
18: }
19:
20: function formatListHuman(data: DocsListResponse): string {
21: if (data.results.length === 0) {
22: return muted("No documentation ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/cli/feedback.ts</path>
<type>file</type>
<content>
1: /**
2: * Feedback Command
3: *
4: * Allows users to submit feedback about the CLI.
5: * All arguments after 'feedback' are joined into a single message.
6: *
7: * @example sentry cli feedback i love this tool
8: * @example sentry cli feedback the issue view is confusing
9: */
10:
11: import { isatty } from "node:tty";
12: // biome-ignore lint/performance/noNamespaceImport: Sentry SDK recommends namespace import
13: import * as Sentry from "@sentry/node-core/light";
14: import type { SentryContext } from "../../context.js";
15: import { buildCommand } from "../../lib/command.js";
16: import { ConfigError, ValidationError } from "../../lib/errors.js";
17: import { formatFeedbackResult } from "../../lib/formatters/human.js";
18: import { CommandOutput } from "../../lib/formatters/output.js";
19: import { logger } from "../../lib/logger.js";
20:
21: /** ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/cli/defaults.ts</path>
<type>file</type>
<content>
260: };
261:
262: // ---------------------------------------------------------------------------
263: // Command
264: // ---------------------------------------------------------------------------
265:
266: const log = logger.withTag("defaults");
267:
268: export const defaultsCommand = buildCommand({
269: auth: false,
270: docs: {
271: brief: "View and manage default settings",
272: fullDescription:
273: "View and manage persistent CLI default settings.\n\n" +
274: "With no arguments, shows all current defaults. Pass a key and value\n" +
275: "to set a default, or use `--clear` to remove defaults.\n\n" +
276: "## Examples\n\n" +
277: "```\n" +
278: "sentry cli defaults # Show all defaults\n" +
279: "sentry cli defaults org my-org # Set default organization\n" +
280: "sentry cli ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/trace/view.ts</path>
<type>file</type>
<content>
405: const resolved = await resolveOrg({ cwd });
406: if (!resolved) {
407: throw new ContextError("Organization", `sentry issue view ${issueShortId}`);
408: }
409: const org = resolved.org;
410:
411: const issue = await getIssueByShortId(org, issueShortId);
412: let project: string | undefined;
413: if (issue.project?.slug) {
414: setOrgProjectContext([org], [issue.project.slug]);
415: project = issue.project.slug;
416: }
417:
418: const event = await getLatestEvent(org, issue.id);
419: const traceId = event?.contexts?.trace?.trace_id;
420: if (!traceId) {
421: throw new ValidationError(
422: `Could not find a trace for issue '${issueShortId}'. The latest event has no trace context.\n\n` +
423: `Try: sentry issue view ${issueShortId}`
424: );
425: }
426:
427: return { traceId, org, project };
428: }
429: ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/trace/logs.ts</path>
<type>file</type>
<content>
70: /** Format trace log results as human-readable table output. */
71: function formatTraceLogsHuman(data: TraceLogsData): string {
72: if (data.logs.length === 0) {
73: return data.emptyMessage ?? "No logs found.";
74: }
75: const parts = [formatLogTable(data.logs, false)];
76: const countText = `Showing ${data.logs.length} log${data.logs.length === 1 ? "" : "s"} for trace ${data.traceId}.`;
77: const tip = data.hasMore ? " Use --limit to show more." : "";
78: parts.push(formatFooter(`${countText}${tip}`));
79: return parts.join("").trimEnd();
80: }
81:
82: /**
83: * Default time period for the trace-logs API.
84: * The API requires statsPeriod — without it the response may be empty even
85: * when logs exist for the trace. ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/span/view.ts</path>
<type>file</type>
<content>
315: * custom attributes are appended after the standard fields.
316: * Multiple spans are separated by `---`.
317: */
318: function formatSpanViewHuman(data: SpanViewData): string {
319: const parts: string[] = [];
320: for (let i = 0; i < data.results.length; i++) {
321: if (i > 0) {
322: parts.push("\n---\n");
323: }
324: const result = data.results[i];
325: if (!result) {
326: continue;
327: }
328:
329: // Standard span details (KV table + ancestor chain)
330: const detail = data.details?.get(result.spanId);
331: parts.push(
332: formatSpanDetails(result.span, result.ancestors, data.traceId, detail)
333: );
334:
335: // Show child tree if --spans > 0 and the span has children
336: const children = result.span.children ?? [];
337: if (data.spansDepth > 0 && children.length > 0) {
338: ...
Found 10 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/span/view.ts:
Line 54: const USAGE_HINT =
Line 139: throw new ContextError("Trace ID", USAGE_HINT, [
Line 151: export function parsePositionalArgs(args: string[]): SpanViewArgs {
Line 152: if (args.length === 0) {
Line 153: throw new ContextError("Trace ID and span ID", USAGE_HINT, []);
Line 158: throw new ContextError("Trace ID and span ID", USAGE_HINT, []);
Line 167: if (args.length === 1) {
Line 177: if (args.length === 1 && !first.includes("/")) {
Line 180: throw new ContextError("Trace ID and span ID", USAGE_HINT, [
Line 190: throw new ContextError("Span ID", USAGE_HINT, [
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/span/view.ts</path>
<type>file</type>
<content>
45:
46: type ViewFlags = {
47: readonly json: boolean;
48: readonly spans: number;
49: readonly fresh: boolean;
50: readonly fields?: string[];
51: };
52:
53: /** Usage hint for ContextError messages */
54: const USAGE_HINT =
55: "sentry span view [<org>/<project>/]<trace-id> <span-id> [<span-id>...]";
56:
57: /** Result of the initial positional-arg parse for `span view`. */
58: type SpanViewArgs =
59: | {
60: /** Args are already resolved (auto-split `<trace-id>/<span-id>`). */
61: kind: "resolved";
62: traceTarget: ReturnType<typeof parseSlashSeparatedTraceTarget>;
63: rawSpanIds: string[];
64: }
65: | {
66: /**
67: * First arg is the raw trace target (needs async recovery); the rest
68: * are raw span IDs. Command layer calls `parseTraceTargetWithRecovery`. ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/span/list.ts</path>
<type>file</type>
<content>
515: } else if (flatSpans.length > 0) {
516: const countText = `Showing ${flatSpans.length} span${flatSpans.length === 1 ? "" : "s"}.`;
517: hint = nav
518: ? `${countText} ${nav}`
519: : `${countText} Use 'sentry span view <trace-id> <span-id>' to view span details.`;
520: }
521:
522: return {
523: output: {
524: flatSpans,
525: hasMore,
526: hasPrev,
527: nextCursor,
528: org,
529: project,
530: extraAttributes: extraApiFields,
531: },
532: hint,
533: };
534: }
535:
536: // ---------------------------------------------------------------------------
537: // Command definition
538: // ---------------------------------------------------------------------------
539:
540: export const listCommand = buildListCommand("span", {
541: docs: {
542: brief: "List spans in a project or ...
Found 2 matches /home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/span/list.ts: Line 194: export function parseSpanListArgs( Line 614: const parsed = parseSpanListArgs(args);
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/span/list.ts</path> <type>file</type> <content> 150: const DEFAULT_SORT: SpanSortValue = "date"; 151: 152: /** Default time period for span queries */ 153: const DEFAULT_PERIOD = "7d"; 154: 155: /** Pagination storage key for trace-scoped span listing */ 156: export const PAGINATION_KEY = "span-list"; 157: 158: /** Pagination storage key for project-scoped span listing */ 159: export const PROJECT_PAGINATION_KEY = "span-search"; 160: 161: /** Command name used in resolver error messages (project mode) */ 162: const COMMAND_NAME = "span list"; 163: 164: /** Usage hint for trace-mode ContextError messages */ 165: const TRACE_USAGE_HINT = "sentry span list [<org>/<project>/]<trace-id>"; 166: 167: /** 168: * Parse --limit flag, delegating range validation to shared utility. ...
Found 1 matches /home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/lib/trace-target.ts: Line 604: export function parseDualModeArgs(
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/lib/trace-target.ts</path>
<type>file</type>
<content>
560: const _exhaustive: never = parsed;
561: throw new ValidationError(`Unexpected target type: ${_exhaustive}`);
562: }
563: }
564: }
565:
566: // ---------------------------------------------------------------------------
567: // Dual-mode argument disambiguation (project vs trace)
568: // ---------------------------------------------------------------------------
569:
570: /**
571: * Result from dual-mode argument disambiguation.
572: *
573: * Used by commands that support both project-scoped listing (no trace ID)
574: * and trace-scoped listing (trace ID provided), like `span list` and
575: * `log list`. ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/event/view.ts</path>
<type>file</type>
<content>
1020: * when agents paste dozens of IDs.
1021: *
1022: * When all fetches fail, re-throws the error from the primary (first) event.
1023: */
1024: export async function fetchMultipleEvents(
1025: options: FetchMultipleOptions
1026: ): Promise<SentryEvent[]> {
1027: const { eventIds, org, project, prefetchedEvent, primaryId } = options;
1028: const log = logger.withTag("event.view");
1029: const limit = pLimit(ORG_FANOUT_CONCURRENCY);
1030:
1031: const results = await Promise.allSettled(
1032: eventIds.map((id) =>
1033: limit(() =>
1034: fetchEventWithContext(
1035: id === primaryId ? prefetchedEvent : null,
1036: org,
1037: project,
1038: id
1039: )
1040: )
1041: )
1042: );
1043:
1044: const events: SentryEvent[] = [];
1045: for (let i = 0; i < results.length; i++) {
1046: ...
Found 15 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/event/view.ts:
Line 32: ContextError,
Line 169: /** Usage hint for ContextError messages */
Line 202: * ContextError for single-slash args like "org/SHORT-ID", which looks like
Line 208: // which throws ContextError for single-slash args.
Line 239: throw new ContextError("Issue ID", BARE_LATEST_HINT, [
Line 354: export function parsePositionalArgs(args: string[]): ParsedPositionalArgs {
Line 355: if (args.length === 0) {
Line 356: throw new ContextError("Event ID", USAGE_HINT, []);
Line 361: throw new ContextError("Event ID", USAGE_HINT, []);
Line 384: throw new ContextError("Event ID", USAGE_HINT, [
Line 440: throw new ContextError("Issue ID", BARE_LATEST_HINT, [
Line 589: * Throws a ContextError if the event is not found in the given org, with a
Line 879: throw new ContextError("Organization", `sentry event view ${issueId}`);
Line ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/event/view.ts</path>
<type>file</type>
<content>
150: }
151: return data.events.map(transform);
152: }
153:
154: /**
155: * Build a CLI-native replay hint when the event is linked to a replay.
156: */
157: function replayHint(org: string, event: SentryEvent): string | undefined {
158: const replayId = getReplayIdFromEvent(event);
159: return replayId
160: ? `Related replay: sentry replay view ${org}/${replayId}`
161: : undefined;
162: }
163:
164: function joinHintParts(parts: Array<string | undefined>): string | undefined {
165: const hints = parts.filter((part): part is string => Boolean(part));
166: return hints.length > 0 ? hints.join(" | ") : undefined;
167: }
168:
169: /** Usage hint for ContextError messages */
170: const USAGE_HINT = "sentry event view <org>/<project> <event-id>";
171:
172: /**
173: * Expand positional args by splitting each on newlines. ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/replay/view.ts</path>
<type>file</type>
<content>
310: async function enrichReplayView(
311: org: string,
312: replay: ReplayDetails
313: ): Promise<
314: Pick<ReplayViewData, "activity" | "relatedIssues" | "relatedTraces">
315: > {
316: const [activity, relatedIssues, relatedTraces] = await Promise.all([
317: fetchReplayActivity(org, replay),
318: fetchRelatedReplayIssues(org, replay),
319: fetchRelatedReplayTraces(org, replay),
320: ]);
321:
322: return { activity, relatedIssues, relatedTraces };
323: }
324:
325: export const viewCommand = buildCommand({
326: docs: {
327: brief: "View a Session Replay",
328: fullDescription:
329: "View detailed information about a Session Replay.\n\n" +
330: "Replay ID formats:\n" +
331: " <replay-id> - auto-detect org from config or DSN\n" +
332: " <org>/<replay-id> - explicit organization\n" +
333: ...
Found 13 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/replay/view.ts:
Line 23: ContextError,
Line 88: throw new ContextError("Replay ID", USAGE_HINT, []);
Line 102: throw new ContextError("Replay ID", USAGE_HINT, []);
Line 125: export function parsePositionalArgs(args: string[]): ParsedPositionalArgs {
Line 126: if (args.length === 0) {
Line 127: throw new ContextError("Replay ID", USAGE_HINT, []);
Line 129: if (args.length > 2) {
Line 131: `Too many positional arguments (got ${args.length}, expected at most 2).\n\nUsage: ${USAGE_HINT}`,
Line 138: throw new ContextError("Replay ID", USAGE_HINT, []);
Line 147: throw new ContextError("Replay ID", USAGE_HINT, [
Line 152: if (args.length === 1) {
Line 158: throw new ContextError("Replay ID", USAGE_HINT, []);
Line 162: args.length === 2 ? detectSwappedViewArgs(first, second) : null;
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/replay/view.ts</path>
<type>file</type>
<content>
50: ReplayDetails,
51: ReplayRelatedIssue,
52: ReplayRelatedTrace,
53: } from "../../types/index.js";
54: import { ReplayViewOutputSchema } from "../../types/index.js";
55:
56: type ViewFlags = {
57: readonly json: boolean;
58: readonly web: boolean;
59: readonly fresh: boolean;
60: readonly fields?: string[];
61: };
62:
63: type ParsedPositionalArgs = {
64: replayId: string;
65: targetArg: string | undefined;
66: warning?: string;
67: };
68:
69: const USAGE_HINT =
70: "sentry replay view [<org>/<project>/]<replay-id> | <replay-url>";
71: const MAX_ACTIVITY_EVENTS = 6;
72: const MAX_RELATED_ERRORS = 3;
73: const MAX_RELATED_TRACES = 2;
74:
75: const log = logger.withTag("replay.view");
76:
77: /**
78: * Parse a single positional argument as a replay target. ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/log/view.ts</path>
<type>file</type>
<content>
440: hint,
441: idList.map((id) => `ID: ${id}`)
442: );
443: }
444:
445: /**
446: * Data returned by the log view command.
447: * Used by both JSON and human output paths.
448: */
449: type LogViewData = {
450: /** Retrieved log entries */
451: logs: DetailedSentryLog[];
452: /** Org slug — needed by human formatter for trace URLs, also useful context in JSON */
453: orgSlug: string;
454: /** Full attribute sets from the trace-items detail endpoint (index matches logs) */
455: details?: (TraceItemDetail | undefined)[];
456: /** --fields filter: limits which custom attributes are shown in human output */
457: extraFields?: string[];
458: };
459:
460: /**
461: * Format log view data as human-readable output.
462: *
463: * Each log entry is formatted with full details. Multiple entries
464: * are separated by horizontal rules. ...
Found 16 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/log/view.ts:
Line 23: ContextError,
Line 69: /** Usage hint for ContextError messages */
Line 78: * throws `ContextError` for any single-slash arg, treating it as `org/project`
Line 113: * @throws {ContextError} If no arguments provided
Line 116: export function parsePositionalArgs(args: string[]): {
Line 122: if (args.length === 0) {
Line 123: throw new ContextError("Log ID", USAGE_HINT, []);
Line 128: throw new ContextError("Log ID", USAGE_HINT, []);
Line 135: // throws ContextError for "org/logId" thinking it's "org/project" with no ID. ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/log/view.ts</path>
<type>file</type>
<content>
60: const LOG_DETAIL_CONCURRENCY = 15;
61:
62: type ViewFlags = {
63: readonly json: boolean;
64: readonly web: boolean;
65: readonly fresh: boolean;
66: readonly fields?: string[];
67: };
68:
69: /** Usage hint for ContextError messages */
70: const USAGE_HINT = "sentry log view <org>/<project> <log-id> [<log-id>...]";
71:
72: /**
73: * Resolve a single-slash positional arg (`before/after`) as `org/log-id`, or
74: * return `null` when `after` is not a valid 32-char hex log ID and should fall
75: * through to `parseSlashSeparatedArg`.
76: *
77: * This guard must run before `parseSlashSeparatedArg` because that function
78: * throws `ContextError` for any single-slash arg, treating it as `org/project`
79: * with a missing log ID (CLI-1AK). ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/log/list.ts</path>
<type>file</type>
<content>
660: }
661: }
662:
663: return text;
664: },
665: };
666: }
667:
668: /**
669: * Transform log output into the JSON shape.
670: *
671: * Discriminates between {@link LogListResult} (single-fetch) and bare
672: * {@link LogLike} items (follow mode). Single-fetch yields a JSON envelope
673: * with `data` and `hasMore`; follow mode yields one JSON object per line (JSONL).
674: */
675: function jsonTransformLogOutput(data: LogOutput, fields?: string[]): unknown {
676: if (isLogListResult(data)) {
677: // Batch (single-fetch): return envelope with data + hasMore
678: const logList = data;
679: const items =
680: fields && fields.length > 0
681: ? logList.logs.map((log) => filterFields(log, fields))
682: : logList.logs;
683: return { data: items, hasMore: logList.hasMore };
684: }
685: // Single item ...
Found 2 matches /home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/log/list.ts: Line 163: function parseLogListArgs( Line 785: const parsed = parseLogListArgs(args);
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/log/list.ts</path>
<type>file</type>
<content>
135: }
136:
137: /**
138: * Extends the base {@link BaseLogLike} from formatters with the
139: * `timestamp_precise` field needed for follow-mode dedup tracking.
140: */
141: type LogLike = BaseLogLike & {
142: /** Nanosecond-precision timestamp used for dedup in follow mode.
143: * Optional because TraceLog may omit it when the API response doesn't include it. */
144: timestamp_precise?: number;
145: };
146:
147: /** Result from a single fetch: logs to yield + hint for the footer. */
148: type FetchResult = {
149: result: LogListResult;
150: hint: string;
151: };
152:
153: // ---------------------------------------------------------------------------
154: // Positional argument disambiguation
155: // ---------------------------------------------------------------------------
156:
157: /**
158: * Disambiguate log list positional arguments. ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/dashboard/create.ts</path>
<type>file</type>
<content>
100: return { orgSlug: parsed.org, projectIds: [] };
101:
102: case "project-search": {
103: const found = await resolveProjectBySlug(
104: parsed.projectSlug,
105: "sentry dashboard create <org>/<project> <title>",
106: undefined,
107: parsed.originalSlug
108: );
109: const pid = toNumericId(found.projectData.id);
110: return {
111: orgSlug: found.org,
112: projectIds: pid !== undefined ? [pid] : [],
113: };
114: }
115: case "auto-detect": {
116: const result = await resolveAllTargets({ cwd });
117: if (result.targets.length === 0) {
118: const resolved = await resolveOrg({ cwd });
119: if (!resolved) {
120: throw new ContextError(
121: "Organization",
122: "sentry dashboard create <org>/ <title>"
123: ...
Found 5 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/dashboard/create.ts:
Line 14: import { ContextError, ValidationError } from "../../lib/errors.js";
Line 43: function parsePositionalArgs(args: string[]): {
Line 47: if (args.length === 0) {
Line 50: if (args.length === 1) {
Line 120: throw new ContextError(
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/dashboard/create.ts</path>
<type>file</type>
<content>
30: readonly json: boolean;
31: readonly fields?: string[];
32: };
33:
34: type CreateResult = DashboardDetail & { url: string };
35:
36: /**
37: * Parse array positional args for `dashboard create`.
38: *
39: * Handles:
40: * - `<title>` — title only (auto-detect org/project)
41: * - `<target> <title>` — explicit target + title
42: */
43: function parsePositionalArgs(args: string[]): {
44: title: string;
45: targetArg: string | undefined;
46: } {
47: if (args.length === 0) {
48: throw new ValidationError("Dashboard title is required.", "title");
49: }
50: if (args.length === 1) {
51: return { title: args[0] as string, targetArg: undefined };
52: }
53: // Two args: first is target, second is title
54: return { title: args[1] as string, targetArg: args[0] as string };
55: }
56:
57: /** Result of resolving org + project IDs from ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/dashboard/list.ts</path>
<type>file</type>
<content>
335:
336: /**
337: * Build the footer hint for the dashboard list command.
338: *
339: * Shows pagination navigation hints (`-c next` / `-c prev`) when applicable,
340: * plus a link to the dashboards page in Sentry.
341: */
342: function buildHint(
343: result: DashboardListResult,
344: orgSlug: string
345: ): string | undefined {
346: const filterArg = result.titleFilter ? ` '${result.titleFilter}'` : "";
347: const navRaw = paginationHint({
348: hasPrev: !!result.hasPrev,
349: hasMore: !!result.hasMore,
350: prevHint: `sentry dashboard list ${orgSlug}/${filterArg} -c prev`,
351: nextHint: `sentry dashboard list ${orgSlug}/${filterArg} -c next`,
352: });
353: const nav = navRaw ? ` ${navRaw}` : "";
354: const url = buildDashboardsListUrl(orgSlug);
355:
356: if (result.dashboards.length === 0) {
357: // Empty results — ...
No files found
Found 3 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/dashboard/resolve.ts:
Line 253: export function parseDashboardListArgs(args: string[]): ListArgResult {
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/dashboard/list.ts:
Line 42: parseDashboardListArgs,
Line 411: const { targetArg, titleFilter } = parseDashboardListArgs(args);
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/dashboard/resolve.ts</path>
<type>file</type>
<content>
215: };
216:
217: /**
218: * Try to extract org context from a Sentry URL in dashboard list args.
219: *
220: * When the URL contains a dashboard ID, throws a helpful error suggesting
221: * `sentry dashboard view` instead. When only an org is present, extracts
222: * it as the target.
223: */
224: function tryExtractListUrl(
225: first: string,
226: remaining: string[]
227: ): ListArgResult | null {
228: const urlParsed = parseSentryUrl(first);
229: if (!urlParsed) {
230: return null;
231: }
232: applySentryUrlContext(urlParsed.baseUrl);
233: if (urlParsed.dashboardId) {
234: const orgPrefix = urlParsed.org ? `${urlParsed.org}/ ` : "";
235: const orgSuffix = urlParsed.org ? ` ${urlParsed.org}/` : "";
236: const orgNote = urlParsed.org ? ` in '${urlParsed.org}'` : "";
237: throw new ValidationError(
238: "This looks ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/dashboard/restore.ts</path>
<type>file</type>
<content>
1: /**
2: * sentry dashboard restore
3: *
4: * Restore a dashboard to a previous revision.
5: */
6:
7: import type { SentryContext } from "../../context.js";
8: import { restoreDashboardRevision } from "../../lib/api-client.js";
9: import { parseOrgProjectArg } from "../../lib/arg-parsing.js";
10: import { buildCommand } from "../../lib/command.js";
11: import { ValidationError } from "../../lib/errors.js";
12: import { colorTag, escapeMarkdownCell } from "../../lib/formatters/markdown.js";
13: import { CommandOutput } from "../../lib/formatters/output.js";
14: import { formatRelativeTime } from "../../lib/formatters/time-utils.js";
15: import { withProgress } from "../../lib/polling.js";
16: import { buildDashboardUrl } from "../../lib/sentry-urls.js";
17: import type { DashboardDetail } from "../../types/dashboard.js";
18: import {
19: ...
Found 1 matches /home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/dashboard/resolve.ts: Line 159: export function parseDashboardPositionalArgs(
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/dashboard/resolve.ts</path>
<type>file</type>
<content>
135: "Dashboard ID or title is required.\n\n" +
136: "The URL provided contains an org but no dashboard ID.\n" +
137: `Try: sentry dashboard <command> ${urlParsed.org}/ <id-or-title>`,
138: "dashboard"
139: );
140: }
141: return null;
142: }
143:
144: /**
145: * Parse a dashboard reference and optional target from array positional args.
146: *
147: * Handles:
148: * - `<id-or-title>` — single arg (auto-detect org)
149: * - `<target> <id-or-title>` — explicit target + dashboard ref
150: * - Full Sentry dashboard URL — extracts org + dashboard ID
151: *
152: * When two args are provided and the first is a bare slug (no `/`), it is
153: * normalized to `slug/` so `parseOrgProjectArg` treats it as an org-all
154: * target. Dashboards are org-scoped so the project component is irrelevant. ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/dashboard/view.ts</path>
<type>file</type>
<content>
135: | string
136: | undefined,
137: layout: w.layout,
138: queries: w.queries,
139: data: widgetResults.get(i) ?? {
140: type: "error" as const,
141: message: "No data returned",
142: },
143: })),
144: };
145: }
146:
147: /**
148: * Resolve the effective time range for a dashboard view.
149: *
150: * Priority: explicit --period flag > dashboard's saved period > 24h default.
151: * Dashboard period is a raw string from the API that needs parsing.
152: */
153: function resolveViewTimeRange(
154: flagPeriod: TimeRange | undefined,
155: dashboardPeriod: string | null | undefined
156: ): TimeRange {
157: if (flagPeriod) {
158: return flagPeriod;
159: }
160: return dashboardPeriod ? ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/dashboard/revisions.ts</path>
<type>file</type>
<content>
80:
81: const columns: Column<RevisionRow>[] = [
82: { header: "ID", value: (r) => r.id },
83: { header: "TITLE", value: (r) => r.title },
84: { header: "AUTHOR", value: (r) => r.author },
85: { header: "CREATED", value: (r) => r.created },
86: ];
87:
88: const parts: string[] = [];
89: const buffer: Writer = { write: (s: string) => parts.push(s) };
90: writeTable(buffer, rows, columns);
91:
92: return parts.join("").trimEnd();
93: }
94:
95: function jsonTransformRevisions(
96: result: RevisionsResult,
97: fields?: string[]
98: ): unknown {
99: const items =
100: fields && fields.length > 0
101: ? result.revisions.map((r) => filterFields(r, fields))
102: : result.revisions;
103:
104: const envelope: Record<string, unknown> = {
105: data: items,
106: hasMore: result.hasMore,
107: hasPrev: ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/dashboard/widget/add.ts</path>
<type>file</type>
<content>
50: /**
51: * Parse positional args for widget add.
52: * Last arg is widget title, rest go to dashboard resolution.
53: */
54: function parseAddPositionalArgs(args: string[]): {
55: dashboardArgs: string[];
56: title: string;
57: } {
58: if (args.length < 2) {
59: throw new ValidationError(
60: "Widget title is required as a positional argument.\n\n" +
61: "Example:\n" +
62: ' sentry dashboard widget add <dashboard> "My Widget" --display line --query count',
63: "title"
64: );
65: }
66: if (args.length > 3) {
67: throw new ValidationError(
68: `Too many positional arguments (got ${args.length}, expected at most 3).\n\n` +
69: "Usage: sentry dashboard widget add [<org/project>] <dashboard> <title>",
70: "positional"
71: );
72: }
73:
74: const title = args.at(-1) as string;
75: ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/dashboard/widget/edit.ts</path>
<type>file</type>
<content>
145: const orderby = mergedQueries?.[0]?.orderby ?? existing.queries?.[0]?.orderby;
146: const aggregates =
147: mergedQueries?.[0]?.aggregates ?? existing.queries?.[0]?.aggregates ?? [];
148: if (orderby && aggregates.length > 0) {
149: validateSortReferencesAggregate(orderby, aggregates);
150: }
151: }
152:
153: /** Build the replacement widget object by merging flags over existing */
154: function buildReplacement(
155: flags: EditFlags,
156: existing: DashboardWidget
157: ): DashboardWidget {
158: const mergedQueries = mergeQueries(flags, existing.queries?.[0]);
159: const baseLimit = flags.limit !== undefined ? flags.limit : existing.limit;
160: const columns =
161: mergedQueries?.[0]?.columns ?? existing.queries?.[0]?.columns ?? ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/dashboard/widget/edit.ts</path>
<type>file</type>
<content>
309: aliases: {
310: i: "index",
311: t: "title",
312: d: "display",
313: q: "query",
314: w: "where",
315: g: "group-by",
316: s: "sort",
317: n: "limit",
318: x: "col",
319: y: "row",
320: },
321: },
322: async *func(this: SentryContext, flags: EditFlags, ...args: string[]) {
323: const { cwd } = this;
324:
325: if (flags.index === undefined && !flags.title) {
326: throw new ValidationError(
327: "Specify --index or --title to identify the widget to edit.\n\n" +
328: "Example:\n" +
329: " sentry dashboard widget edit <dashboard> --title 'My Widget' --display bar",
330: "index"
331: );
332: }
333:
334: // Resolve dataset aliases (e.g. "errors" → "error-events") once, up front.
335: // Replace flags.dataset with the ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/dashboard/widget/delete.ts</path>
<type>file</type>
<content>
1: /**
2: * sentry dashboard widget delete
3: *
4: * Remove a widget from an existing dashboard.
5: *
6: * Uses `buildDeleteCommand` — auto-injects `--yes`/`--force`/`--dry-run`
7: * flags. Non-interactive guard is disabled (`noNonInteractiveGuard`) because
8: * widget deletion is reversible (re-add the widget). `--yes`/`--force` are
9: * accepted but have no effect today (no confirmation prompt); `--dry-run`
10: * shows which widget would be removed without modifying the dashboard.
11: */
12:
13: import type { SentryContext } from "../../../context.js";
14: import { getDashboard, updateDashboard } from "../../../lib/api-client.js";
15: import { parseOrgProjectArg } from "../../../lib/arg-parsing.js";
16: import { numberParser } from "../../../lib/command.js";
17: import { ValidationError } from "../../../lib/errors.js";
18: import { ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/debug-files/find.ts</path>
<type>file</type>
<content>
75: throw new ValidationError(
76: `Unknown debug file type '${type}'. Valid types: ${FIND_DIF_TYPES.join(
77: ", "
78: )}`,
79: "type"
80: );
81: }
82: }
83: return types;
84: }
85:
86: /** Build the ordered, de-duplicated list of directories to search. */
87: async function resolveSearchPaths(
88: flags: FindFlags,
89: types: string[],
90: cwd: string
91: ): Promise<string[]> {
92: const paths: string[] = [];
93: // dSYMs live in Xcode DerivedData; only search it when dSYMs are wanted.
94: if (!flags["no-well-known"] && types.includes("dsym")) {
95: const derived = join(homedir(), DERIVED_DATA);
96: const info = await stat(derived).catch(() => null);
97: if (info?.isDirectory()) {
98: paths.push(derived);
99: }
100: }
101: if (!flags["no-cwd"]) {
102: ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/debug-files/upload.ts</path>
<type>file</type>
<content>
490: setExitCode(1);
491: const details = failures
492: .map(
493: (r) =>
494: `${r.debugId ?? r.name}: ${r.state}${r.detail ? ` (${r.detail})` : ""}`
495: )
496: .join("; ");
497: return {
498: hint: `${failures.length === 1 ? "1 file" : `${failures.length} files`} had failures: ${details}.${scanOversize}${requireAllNote}`,
499: };
500: }
501:
502: if (params.oversizedCount > 0) {
503: setExitCode(1);
504: return {
505: hint: `Uploaded ${results.length} debug file(s) to ${params.org}/${params.project}, but ${params.oversizedCount} file(s) were skipped for exceeding the maximum file size (${params.maxFileSize} bytes).${requireAllNote}`,
506: };
507: }
508:
509: if (params.missingRequestedIds.length > 0 && params.requireAll) {
510: setExitCode(1);
511: return {
512: ...
Found 2 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/debug-files/upload.ts:
Line 81: function collectScanPaths(paths: string[], derivedData: boolean): string[] {
Line 664: const scanTargets = collectScanPaths(paths, Boolean(flags["derived-data"]));
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/debug-files/upload.ts</path>
<type>file</type>
<content>
55: renderMarkdown,
56: } from "../../lib/formatters/markdown.js";
57: import { CommandOutput } from "../../lib/formatters/output.js";
58: import { logger } from "../../lib/logger.js";
59: import { resolveOrgAndProject } from "../../lib/resolve-target.js";
60:
61: const log = logger.withTag("debug-files.upload");
62:
63: const USAGE_HINT = "sentry debug-files upload <path>...";
64:
65: /** Relative path to Xcode's DerivedData folder under the user's home dir. */
66: const DERIVED_DATA_SUBPATH = "Library/Developer/Xcode/DerivedData";
67:
68: /**
69: * Resolve the effective scan paths, optionally appending Xcode's DerivedData
70: * folder when `--derived-data` is set.
71: *
72: * DerivedData only exists on macOS; on other platforms the flag is a no-op
73: * (with a warning). ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/build/upload.ts</path>
<type>file</type>
<content>
115: throw new ValidationError(`Path does not exist: ${path}`, "path");
116: }
117:
118: const plugin = parsePluginFromPipeline(ctx.env.SENTRY_PIPELINE);
119:
120: // Normalize into a wrapper ZIP on disk (streamed, so peak memory does not
121: // scale with the build size), then upload it via the file-based chunk path.
122: const workDir = await mkdtemp(join(tmpdir(), "sentry-build-"));
123: const outPath = join(workDir, "normalized.zip");
124: try {
125: // An XCArchive is a directory; validate its structure, then zip it. The
126: // validation refuses arbitrary directories so a stray
127: // `sentry build upload ./` can't sweep up source, .git/, or secrets.
128: if (info.isDirectory()) {
129: validateXcarchiveDirectory(path);
130: await normalizeBuildDirectory(path, outPath, plugin);
131: } else {
132: // ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/react-native/xcode.ts</path>
<type>file</type>
<content>
430: "block until the server finishes processing the upload.",
431: },
432: auth: false,
433: output: {
434: human: formatResult,
435: },
436: parameters: {
437: flags: {
438: force: {
439: kind: "boolean",
440: brief: "Run even in a debug configuration",
441: optional: true,
442: },
443: "allow-fetch": {
444: kind: "boolean",
445: brief: "Fetch sourcemaps from the packager on simulator builds",
446: optional: true,
447: },
448: "fetch-from": {
449: kind: "parsed",
450: parse: String,
451: brief: `Packager URL to fetch from (default: ${DEFAULT_PACKAGER_URL})`,
452: optional: true,
453: },
454: "build-script": {
455: kind: "parsed",
456: parse: String,
457: brief: "Path to the ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/react-native/xcode.ts</path>
<type>file</type>
<content>
375: hint: string;
376: exitCode?: number;
377: }
378: | { kind: "pair"; mode: "fetch" | "wrap"; pair: BundlePair };
379:
380: /** Resolve the bundle/sourcemap pair via the packager (fetch) or a wrapped build. */
381: async function preparePair(
382: ctx: SentryContext,
383: script: string,
384: scriptArgs: string[],
385: fetchUrl: string | undefined
386: ): Promise<PrepareResult> {
387: const tempDir = mkdtempSync(join(tmpdir(), "sentry-rn-xcode-"));
388: if (fetchUrl) {
389: log.info(`Fetching sourcemaps from ${fetchUrl}`);
390: return {
391: kind: "pair",
392: mode: "fetch",
393: pair: await fetchFromPackager(fetchUrl, tempDir),
394: };
395: }
396: const result = runWrappedBuild(script, scriptArgs, ctx, tempDir);
397: // A failed build must not publish artifacts (matches the legacy CLI, ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/proguard/upload.ts</path>
<type>file</type>
<content>
115: );
116: }
117: if (content.length === 0) {
118: throw new ValidationError(
119: `ProGuard mapping file '${path}' is empty.`,
120: "path"
121: );
122: }
123: return content;
124: }
125:
126: /**
127: * Deduplicate mappings with identical content (same UUID = same content).
128: * Logs a warning for each skipped duplicate.
129: */
130: function deduplicateMappings(mappings: ProguardMapping[]): ProguardMapping[] {
131: const seen = new Map<string, string>();
132: const unique: ProguardMapping[] = [];
133: for (const m of mappings) {
134: const existing = seen.get(m.uuid);
135: if (existing) {
136: log.warn(
137: `Skipping '${m.path}': identical content as '${existing}' (UUID ${m.uuid})`
138: );
139: continue;
140: }
141: seen.set(m.uuid, m.path);
142: unique.push(m);
143: ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/monitor/run.ts</path>
<type>file</type>
<content>
125: timer = setTimeout(
126: reject,
127: CHECKIN_SEND_TIMEOUT_MS,
128: new Error("Check-in send timed out")
129: );
130: });
131: try {
132: await Promise.race([send, timeout]);
133: } finally {
134: clearTimeout(timer);
135: }
136: } catch (err) {
137: log.warn(
138: `Failed to send ${phase} check-in: ${err instanceof Error ? err.message : String(err)}`
139: );
140: log.debug("Continuing despite check-in failure...");
141: }
142: }
143:
144: export const runCommand = buildCommand({
145: docs: {
146: brief: "Wrap a command with cron monitor check-ins",
147: fullDescription: `\
148: Run a command and report its execution to a Sentry cron monitor. ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/src/commands/local/run.ts</path>
<type>file</type>
<content>
300: " - go.mod (Go)",
301: " - docker-compose.yml / compose.yml (Docker Compose)",
302: ].join("\n");
303:
304: /** Build the env vars for the child process. */
305: function buildChildEnv(
306: spotlightUrl: string,
307: commandSource: string,
308: cwd: string
309: ): Record<string, string | undefined> {
310: const clientSpotlightVars = Object.fromEntries(
311: CLIENT_SPOTLIGHT_PREFIXES.map((prefix) => [
312: `${prefix}SENTRY_SPOTLIGHT`,
313: spotlightUrl,
314: ])
315: );
316: let env: Record<string, string | undefined> = {
317: ...process.env,
318: ...clientSpotlightVars,
319: SENTRY_SPOTLIGHT: spotlightUrl,
320: SENTRY_TRACES_SAMPLE_RATE: process.env.SENTRY_TRACES_SAMPLE_RATE ?? "1",
321: SENTRY_RELEASE: process.env.SENTRY_RELEASE ?? ...
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/types/dashboard.test.ts /home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/types/dashboard.property.test.ts /home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/lib/help-positional.test.ts /home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/lib/trace-target.test.ts /home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/lib/trace-log-schema.property.test.ts /home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/lib/trace-id.test.ts /home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/lib/security/login-token-rc-poison.test.ts /home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/lib/security/auto-login-host-guard.test.ts /home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/lib/replay-search.test.ts /home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/lib/replay-duration.test.ts /home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/lib/proguard.property.test.ts /home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/l...
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/alert/rule-resolve.test.ts /home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/alert/mutation-utils.test.ts /home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/agent-conversation/view.test.ts /home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/agent-conversation/list.test.ts /home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/alert/metrics/view.test.ts /home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/alert/metrics/list.test.ts /home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/alert/metrics/edit.test.ts /home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/alert/metrics/delete.test.ts /home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/alert/metrics/create.test.ts /home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/trial/start.test.ts /home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/alert/issues/view...
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/local/ui.test.ts /home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/local/server.test.ts /home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/local/run.test.ts /home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/local/agent-fixture.test.ts /home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/monitor/run.test.ts /home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/log/view.test.ts /home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/log/view.property.test.ts /home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/log/view.func.test.ts /home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/log/list.test.ts
Found 45 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/issue/merge.func.test.ts:
Line 5: * rejection, --into parent selection, and API call shape.
Line 91: test("rejects when fewer than 2 issues are provided (0 positionals, no --into)", async () => {
Line 99: expect(err.message).toContain("needs at least 2 issue IDs");
Line 103: test("rejects when 1 positional is given without --into (shows --into hint)", async () => {
Line 111: expect(err.message).toContain("needs at least 2 issue IDs");
Line 112: expect(err.message).toContain("--into");
Line 116: test("rejects when 0 positionals + --into (still needs at least 1 positional)", async () => {
Line 124: expect(err.message).toContain("needs at least 2 issue IDs");
Line 128: test("accepts 1 positional + --into as a valid 2-issue merge (CLI-1AE fix)", async () => {
Line 138: // Sentry honors the --into preference in this case
Line 144: // sentry ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/issue/merge.func.test.ts</path>
<type>file</type>
<content>
75: }
76:
77: describe("mergeCommand.func()", () => {
78: let resolveIssueSpy: ReturnType<typeof spyOn>;
79: let mergeSpy: ReturnType<typeof spyOn>;
80:
81: beforeEach(() => {
82: resolveIssueSpy = vi.spyOn(issueUtils, "resolveIssue");
83: mergeSpy = vi.spyOn(apiClient, "mergeIssues");
84: });
85:
86: afterEach(() => {
87: resolveIssueSpy.mockRestore();
88: mergeSpy.mockRestore();
89: });
90:
91: test("rejects when fewer than 2 issues are provided (0 positionals, no --into)", async () => {
92: const { context } = createMockContext();
93: const func = await mergeCommand.loader();
94: const err = await func
95: .call(context, { json: false })
96: .catch((e: Error) => e);
97:
98: expect(err).toBeInstanceOf(Error);
99: expect(err.message).toContain("needs at least 2 issue IDs");
100: ...
Found 1 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/trace/view.test.ts:
Line 79: test("returns empty args unchanged", () => {
Found 5 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/trace/view.func.test.ts:
Line 103: test("returns only summary when spanTreeLines is empty", () => {
Line 315: test("calls getDetailedTrace without project for org-scoped target", async () => {
Line 336: test("throws ContextError when auto-detect cannot resolve a target", async () => {
Line 574: test("returns empty array for empty input", () => {
Line 619: test("handles spans with empty children array", () => {
Found 3 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/trace/logs.test.ts:
Line 193: test("outputs empty JSON envelope when no logs found with --json", async () => {
Line 218: test("shows message about no logs when empty", async () => {
Line 241: test("includes period in empty result message", async () => {
Found 13 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/span/view.test.ts:
Line 77: test("throws for empty string", () => {
Line 140: describe("auto-split traceId/spanId single-arg format", () => {
Line 141: test("auto-splits traceId/spanId single-arg format (resolved path)", () => {
Line 154: test("auto-splits with uppercase hex IDs", () => {
Line 166: test("does not auto-split org/traceId format (two args) — defers to command", () => {
Line 167: // org/traceId has a non-hex org slug, so it shouldn't trigger the auto-split
Line 180: test("does not auto-split when left is not a valid trace ID", () => {
Line 181: // Auto-split requires hex-on-both-sides. When left is non-hex,
Line 190: test("does not auto-split when right is not a valid span ID", () => {
Line 192: // auto-split heuristic rejects it. ...
Found 19 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/span/list.test.ts:
Line 8: * - listCommand.func (project mode): new project-scoped behavior
Line 90: test("throws for empty string", () => {
Line 100: test("no args → project mode", () => {
Line 105: test("org/project → project mode with target", () => {
Line 113: test("bare project name → project mode with target", () => {
Line 141: test("short non-hex string → project mode", () => {
Line 149: test("32-char non-hex string → project mode", () => {
Line 492: // listCommand.func — project mode (new)
Line 495: describe("listCommand.func (project mode)", () => {
Line 531: // and fall back to a default for auto-detect (no target). ...
Found 1 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/event/send.test.ts:
Line 48: test("inline message sends an envelope and prints event ID", async () => {
Found 13 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/event/view.test.ts:
Line 93: describe("single argument (event ID only)", () => {
Line 94: test("parses single arg as event ID", () => {
Line 233: test("throws ContextError for empty args", () => {
Line 271: test("bare 'latest' (single arg) throws ContextError", () => {
Line 296: describe("slash-separated org/project/eventId (single arg)", () => {
Line 348: test("handles empty string event ID in two-arg case", () => {
Line 377: test("single arg with newlines goes through single-arg path after expansion", () => {
Line 463: test("self-hosted event URL extracts eventId, passes org, sets SENTRY_URL (requires matching token host)", () => {
Line 525: // Message says "not found", not "is required"
Line 702: // Message says "not found", not "is required"
Line 1520: test("handles empty array", () => {
Line 1547: test("returns only ...
No files found
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/replay/view.test.ts</path>
<type>file</type>
<content>
1: /**
2: * Replay View Command Tests
3: */
4:
5: import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
6: import {
7: parsePositionalArgs,
8: viewCommand,
9: } from "../../../src/commands/replay/view.js";
10:
11: vi.mock("../../../src/lib/api-client.js", async (importOriginal) => {
12: const actual =
13: await importOriginal<typeof import("../../../src/lib/api-client.js")>();
14: return Object.fromEntries(
15: Object.entries(actual).map(([k, v]) => [
16: k,
17: typeof v === "function" ? vi.fn(v) : v,
18: ])
19: );
20: });
21:
22: // biome-ignore lint/performance/noNamespaceImport: needed for spyOn mocking
23: import * as apiClient from "../../../src/lib/api-client.js";
24:
25: vi.mock("../../../src/lib/browser.js", async (importOriginal) => {
26: const actual =
27: await importOriginal<typeof ...
Found 6 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/log/view.test.ts:
Line 129: describe("single argument (log ID only)", () => {
Line 164: test("splits newline-separated IDs in a single argument", () => {
Line 198: test("throws ContextError for empty args", () => {
Line 242: describe("slash-separated org/project/logId (single arg)", () => {
Line 304: test("newline-delimited log IDs as a single arg with target", () => {
Line 353: // Message says "not found", not "is required"
Found 2 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/log/list.test.ts:
Line 794: test("non-hex string triggers project mode", async () => {
Line 812: test("org/project (non-hex) triggers project mode", async () => {
Found 42 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/log/list.test.ts:
Line 370: await func.call(context, BATCH_FLAGS, `${ORG}/${PROJECT}`);
Line 388: await func.call(context, BATCH_FLAGS, `${ORG}/${PROJECT}`);
Line 423: await func.call(context, HUMAN_FLAGS, `${ORG}/${PROJECT}`);
Line 435: await func.call(context, HUMAN_FLAGS, `${ORG}/${PROJECT}`);
Line 449: await func.call(context, HUMAN_FLAGS, `${ORG}/${PROJECT}`);
Line 462: await func.call(context, { json: false, limit: 3 }, `${ORG}/${PROJECT}`);
Line 474: await func.call(context, HUMAN_FLAGS, `${ORG}/${PROJECT}`);
Line 540: await func.call(context, { json: true, limit: 3 }, `${ORG}/${PROJECT}`);
Line 553: await func.call(context, BATCH_FLAGS, `${ORG}/${PROJECT}`);
Line 595: await func.call(context, BATCH_FLAGS, TRACE_ID);
Line 616: func.call(context, { ...BATCH_FLAGS, query: "bad:::query" }, TRACE_ID)
Line 629: ...
Found 4 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/docs.test.ts:
Line 19: import { listCommand } from "../../src/commands/docs/list.js";
Line 20: import { queryCommand } from "../../src/commands/docs/query.js";
Line 81: const func = await queryCommand.loader();
Line 137: const func = await listCommand.loader();
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/docs.test.ts</path>
<type>file</type>
<content>
60: sentryConfigured: true,
61: });
62: listDocs.mockResolvedValue({
63: results: [
64: {
65: description: "Configure tracing.",
66: title: "Tracing",
67: url: "https://docs.sentry.io/platforms/javascript/tracing/",
68: },
69: ],
70: });
71: queryDocs.mockResolvedValue({
72: answer:
73: "Use [tracing](https://docs.sentry.io/platforms/javascript/tracing/).\n\n## Sources\n\n- <https://docs.sentry.io/platforms/javascript/tracing/>",
74: sources: ["https://docs.sentry.io/platforms/javascript/tracing/"],
75: });
76: });
77:
78: describe("docs commands", () => {
79: test("queries docs with automatic safe context and returns it in JSON", async () => {
80: const { context, stdoutWrite } = createContext();
81: const func = await queryCommand.loader();
82:
83: await func.call(context, { json: ...
No files found
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/help.test.ts</path>
<type>file</type>
<content>
1: /**
2: * Tests for the Help Command
3: *
4: * Tests `sentry help --json` output for full tree, specific groups,
5: * specific commands, and not-found cases.
6: */
7:
8: import { run } from "@stricli/core";
9: import { describe, expect, test } from "vitest";
10: import { app } from "../../src/app.js";
11: import type { SentryContext } from "../../src/context.js";
12:
13: /**
14: * Run a help command and capture stdout output.
15: */
16: async function runHelp(args: string[]): Promise<string> {
17: let output = "";
18: const mockContext: SentryContext = {
19: process,
20: env: process.env,
21: cwd: process.cwd(),
22: homeDir: "/tmp",
23: configDir: "/tmp",
24: stdout: {
25: write(data: string | Uint8Array) {
26: output +=
27: typeof data === "string" ? data : new TextDecoder().decode(data);
28: ...
Found 1 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/schema.test.ts:
Line 85: test("glob pattern matching resources returns their endpoints", () => {
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/schema.test.ts</path>
<type>file</type>
<content>
1: /**
2: * Schema Command Tests
3: *
4: * Covers resolveResourceQuery — in particular the no-match paths that used to
5: * dump the full resource list (byte-identical to a successful browse) instead
6: * of reporting that nothing matched. See getsentry/cli#1424.
7: */
8:
9: import { describe, expect, test } from "vitest";
10: import { resolveResourceQuery } from "../../src/commands/schema.js";
11: import { OutputError, ResolutionError } from "../../src/lib/errors.js";
12:
13: describe("resolveResourceQuery", () => {
14: test("returns endpoints for a known resource", () => {
15: const result = resolveResourceQuery("issues");
16: expect(result.kind).toBe("endpoints");
17: if (result.kind === "endpoints") {
18: expect(result.endpoints.length).toBeGreaterThan(0);
19: for (const ep of result.endpoints) {
20: ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/send-envelope.test.ts</path>
<type>file</type>
<content>
1: /**
2: * Tests for `sentry send-envelope` deprecation shim.
3: */
4:
5: import { beforeEach, describe, expect, test, vi } from "vitest";
6: import { sendEnvelopeCommand } from "../../src/commands/send-envelope.js";
7: import { CliError } from "../../src/lib/errors.js";
8: import { useTestConfigDir } from "../helpers.js";
9:
10: useTestConfigDir("send-envelope-");
11:
12: function makeContext() {
13: return {
14: stdout: { write: vi.fn(() => true) },
15: stderr: { write: vi.fn(() => true) },
16: cwd: "/tmp",
17: };
18: }
19:
20: describe("sendEnvelopeCommand (deprecation shim)", () => {
21: let func: Awaited<ReturnType<typeof sendEnvelopeCommand.loader>>;
22:
23: beforeEach(async () => {
24: func = await sendEnvelopeCommand.loader();
25: });
26:
27: test("throws CliError suggesting event send --raw", async () => {
28: ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/event/send.test.ts</path>
<type>file</type>
<content>
1: /**
2: * Tests for `sentry event send` command func().
3: */
4:
5: import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
6: import { sendCommand } from "../../../src/commands/event/send.js";
7: // biome-ignore lint/performance/noNamespaceImport: needed for spyOn
8: import * as transport from "../../../src/lib/envelope/transport.js";
9: import { ValidationError } from "../../../src/lib/errors.js";
10: import { useTestConfigDir } from "../../helpers.js";
11:
12: useTestConfigDir("send-event-");
13:
14: const SAAS_DSN = "https://abc123@o1.ingest.us.sentry.io/999";
15:
16: function makeContext() {
17: const writes: string[] = [];
18: return {
19: ctx: {
20: stdout: {
21: write: (s: string) => {
22: writes.push(s);
23: return true;
24: },
25: },
26: stderr: { write: vi.fn(() ...
Found 6 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/project/create.test.ts:
Line 774: expect(err.message).toContain("Project specification is required");
Line 783: ])("rejects an empty project name argument (%j)", async (name) => {
Line 791: expect(err.message).toContain("Project name cannot be empty");
Line 806: expect(err.message).toContain("Platform is required");
Line 1101: test("dry-run: multi-project empty org previews one shared team", async () => {
Line 1221: test("falls back to a later project's slug when the first name slugifies to empty", async () => {
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/project/create.test.ts</path>
<type>file</type>
<content>
748: const func = await createCommand.loader();
749: await func.call(context, { json: false }, "my-app:node");
750:
751: const output = stdoutWrite.mock.calls.map((c) => c[0]).join("");
752: // Plain mode renders code spans as plain text without padding
753: expect(output).toContain("Slug my-app-0g was assigned");
754: expect(output).toContain("my-app is already taken");
755: });
756:
757: test("does not show slug note when slug matches name", async () => {
758: const { context, stdoutWrite } = createMockContext();
759: const func = await createCommand.loader();
760: await func.call(context, { json: false }, "my-app:node");
761:
762: const output = stdoutWrite.mock.calls.map((c) => c[0]).join("");
763: expect(output).not.toContain("was assigned");
764: });
765:
766: test("shows helpful error when name is ...
Found 4 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/proguard/upload.test.ts:
Line 22: "require-one"?: boolean;
Line 79: test("no paths with --require-one: throws ValidationError", async () => {
Line 82: await func.call(ctx, { "require-one": true });
Line 86: expect((err as Error).message).toContain("--require-one");
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/proguard/upload.test.ts</path>
<type>file</type>
<content>
55:
56: afterEach(() => {
57: rmSync(dir, { recursive: true, force: true });
58: for (const [k, v] of Object.entries(savedEnv)) {
59: if (v === undefined) {
60: delete process.env[k];
61: } else {
62: process.env[k] = v;
63: }
64: }
65: });
66:
67: // ── Input validation ─────────────────────────────────────────────
68:
69: test("no paths: throws ContextError", async () => {
70: const ctx = makeContext();
71: try {
72: await func.call(ctx, {});
73: expect.unreachable("should have thrown");
74: } catch (err) {
75: expect(err).toBeInstanceOf(ContextError);
76: }
77: });
78:
79: test("no paths with --require-one: throws ValidationError", async () => {
80: const ctx = makeContext();
81: try {
82: await func.call(ctx, { "require-one": true });
83: ...
No files found
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/monitor/run.test.ts</path>
<type>file</type>
<content>
1: /**
2: * Tests for `sentry monitor run` command func().
3: *
4: * Uses a real child process (`node -e ...`) to verify exit-code propagation,
5: * the `SENTRY_MONITOR_SLUG` env var, and that check-in send failures do not
6: * abort the wrapped command. The envelope transport is mocked.
7: */
8:
9: import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
10: import { runCommand } from "../../../src/commands/monitor/run.js";
11: // biome-ignore lint/performance/noNamespaceImport: needed for spyOn
12: import * as transport from "../../../src/lib/envelope/transport.js";
13: import { CliError, ValidationError } from "../../../src/lib/errors.js";
14: import { useTestConfigDir } from "../../helpers.js";
15:
16: useTestConfigDir("monitor-run-");
17:
18: const SAAS_DSN = "https://abc123@o1.ingest.us.sentry.io/999";
19:
20: const NODE = ...
Found 6 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/local/run.test.ts:
Line 5: * exit code propagation, auto-detection, --verify, --timeout, and error cases.
Line 103: test("throws ValidationError when no command and no auto-detect", async () => {
Line 117: "No command provided and could not auto-detect"
Line 137: test("auto-detects dev command from package.json", async () => {
Line 146: // No args provided — should auto-detect and run "echo hello"
Line 153: // If we get here without throwing, auto-detection worked and
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/local/run.test.ts</path>
<type>file</type>
<content>
85: }
86: });
87:
88: function makeContext(cwd?: string) {
89: return {
90: stdout: { write: vi.fn(() => true) },
91: stderr: { write: vi.fn(() => true) },
92: cwd: cwd ?? tmpDir,
93: };
94: }
95:
96: describe("sentry local run", () => {
97: beforeEach(() => {
98: spawnCapture.args = undefined;
99: spawnCapture.env = undefined;
100: spawnCapture.stdio = undefined;
101: });
102:
103: test("throws ValidationError when no command and no auto-detect", async () => {
104: const func = (await runCommand.loader()) as unknown as RunFunc;
105: const ctx = makeContext();
106: try {
107: await func.call(ctx, {
108: port: 0,
109: host: "localhost",
110: verify: false,
111: timeout: 0,
112: });
113: expect.unreachable("should have thrown");
114: } catch (err) {
115: ...
No files found
Found 3 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/react-native/xcode.test.ts:
Line 48: Awaited<ReturnType<typeof xcodeCommand.loader>>
Line 69: const func = await xcodeCommand.loader();
Line 70: await func.call(createContext(env), { "build-script": script, ...flags });
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/react-native/xcode.test.ts</path>
<type>file</type>
<content>
35: const spawnMock = vi.mocked(spawnSync);
36:
37: let dir: string;
38: let script: string;
39:
40: function createContext(env: NodeJS.ProcessEnv) {
41: return {
42: stdout: { write: () => true },
43: stderr: { write: () => true },
44: cwd: dir,
45: env,
46: process: { ...process, execPath: "/usr/bin/sentry", exitCode: undefined },
47: } as unknown as Parameters<
48: Awaited<ReturnType<typeof xcodeCommand.loader>>
49: >[0];
50: }
51:
52: beforeEach(() => {
53: dir = mkdtempSync(join(tmpdir(), "rn-xcode-"));
54: script = join(dir, "react-native-xcode.sh");
55: writeFileSync(script, "#!/bin/sh\ntrue\n");
56: spawnMock.mockClear();
57: vi.spyOn(resolveTarget, "resolveOrgAndProject").mockResolvedValue({
58: org: "acme",
59: project: "mobile",
60: });
61: vi.spyOn(sourcemaps, ...
Found 3 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/debug-files/find.test.ts:
Line 11: import { join } from "node:path";
Line 70: "--path",
Line 87: test("exits successfully when there is nothing to find (no ids)", async () => {
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/debug-files/find.test.ts</path>
<type>file</type>
<content>
60: }
61:
62: describe("sentry debug-files find", () => {
63: test("finds a breakpad file but still reports the id as missing (exit 1)", async () => {
64: await writeFile(join(tempDir, "example.sym"), BREAKPAD_FIXTURE);
65:
66: const { output, exitCode } = await runFind([
67: BREAKPAD_ID,
68: "--no-well-known",
69: "--no-cwd",
70: "--path",
71: tempDir,
72: "--json",
73: ]);
74: const parsed = JSON.parse(output);
75: expect(parsed.matches).toHaveLength(1);
76: expect(parsed.matches[0]).toMatchObject({
77: type: "breakpad",
78: id: BREAKPAD_ID,
79: });
80: // A breakpad match does not satisfy the request.
81: expect(parsed.missing.map((m: { id: string }) => m.id)).toContain(
82: BREAKPAD_ID
83: );
84: expect(exitCode).toBe(1);
85: });
86:
87: ...
Found 6 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/debug-files/upload.test.ts:
Line 154: test("no paths exits non-zero", async () => {
Line 182: // ── --derived-data ───────────────────────────────────────────────
Line 184: test("--derived-data is additive: explicit paths still scan", async () => {
Line 188: "--derived-data",
Line 199: "--derived-data alone on non-macOS exits non-zero (no scan targets)",
Line 201: const { exitCode } = await runUpload(["--derived-data", "--no-upload"]);
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/debug-files/upload.test.ts</path>
<type>file</type>
<content>
135: },
136: },
137: stderr: {
138: write(data: string | Uint8Array) {
139: error +=
140: typeof data === "string" ? data : new TextDecoder().decode(data);
141: return true;
142: },
143: },
144: stdin: process.stdin,
145: };
146:
147: await run(app, ["debug-files", "upload", ...args], mockContext);
148: return { output, error, exitCode: mockContext.process.exitCode };
149: }
150:
151: describe("sentry debug-files upload", () => {
152: // ── Input validation ─────────────────────────────────────────────
153:
154: test("no paths exits non-zero", async () => {
155: const { exitCode } = await runUpload([]);
156: expect(exitCode).not.toBe(0);
157: });
158:
159: test("--wait and --wait-for together exits non-zero", async () => {
160: const path = await ...
Found 1 matches /home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/build/upload.test.ts: Line 250: // without `optional: true`, Stricli treats it as required and the common
Found 16 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/build/upload.test.ts:
Line 112: const func = await uploadCommand.loader();
Line 114: await func.call(harness.context, {}, apk);
Line 127: const func = await uploadCommand.loader();
Line 129: await func.call(
Line 148: const func = await uploadCommand.loader();
Line 151: await func.call(
Line 172: const func = await uploadCommand.loader();
Line 174: await func.call(harness.context, {}, bad);
Line 195: const func = await uploadCommand.loader();
Line 197: await func.call(harness.context, {}, dir);
Line 209: const func = await uploadCommand.loader();
Line 211: await func.call(harness.context, {}, dir);
Line 228: const func = await uploadCommand.loader();
Line 230: await func.call(harness.context, {}, ipa);
Line 241: const func = await uploadCommand.loader();
Line 243: await func.call(harness.context, ...
Found 1 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/dashboard/create.test.ts:
Line 141: expect(err.message).toContain("Dashboard title is required");
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/dashboard/create.test.ts</path>
<type>file</type>
<content>
120: expect(parsed.url).toContain("dashboard/123");
121: });
122:
123: test("human output contains 'Created dashboard' and title", async () => {
124: const { context, stdoutWrite } = createMockContext();
125: const func = await createCommand.loader();
126: await func.call(context, { json: false }, "My Dashboard");
127:
128: const output = stdoutWrite.mock.calls.map((c) => c[0]).join("");
129: expect(output).toContain("Created dashboard");
130: expect(output).toContain("My Dashboard");
131: });
132:
133: test("throws ValidationError when title is missing", async () => {
134: const { context } = createMockContext();
135: const func = await createCommand.loader();
136:
137: const err = await func
138: .call(context, { json: false })
139: .catch((e: Error) => e);
140: ...
Found 2 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/dashboard/list.test.ts:
Line 262: test("shows empty state message when no dashboards exist", async () => {
Line 626: test("decodes empty string to all undefined", () => {
Found 6 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/dashboard/resolve.test.ts:
Line 77: test("throws ValidationError for empty args", () => {
Line 156: test("empty args returns undefined for both", () => {
Line 516: test("auto-detect with null resolveOrg throws ContextError", async () => {
Line 525: test("auto-detect delegates to resolveOrg", async () => {
Line 781: test("returns undefined for undefined input", () => {
Line 866: test("returns undefined for ungrouped widgets with no limit", () => {
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/dashboard/resolve.test.ts</path>
<type>file</type>
<content>
55: // biome-ignore lint/performance/noNamespaceImport: needed for spyOn mocking
56: import * as region from "../../../src/lib/region.js";
57:
58: vi.mock("../../../src/lib/resolve-target.js", async (importOriginal) => {
59: const actual =
60: await importOriginal<typeof import("../../../src/lib/resolve-target.js")>();
61: return Object.fromEntries(
62: Object.entries(actual).map(([k, v]) => [
63: k,
64: typeof v === "function" ? vi.fn(v) : v,
65: ])
66: );
67: });
68:
69: // biome-ignore lint/performance/noNamespaceImport: needed for spyOn mocking
70: import * as resolveTarget from "../../../src/lib/resolve-target.js";
71:
72: // ---------------------------------------------------------------------------
73: // parseDashboardPositionalArgs
74: // ...
Found 9 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/dashboard/widget/add.test.ts:
Line 66: title: "My Dashboard",
Line 69: title: "Error Count",
Line 84: title: "Slow Spans",
Line 146: title: "My Dashboard",
Line 148: expect.objectContaining({ title: "New Widget", displayType: "line" }),
Line 171: expect(parsed.widget.title).toBe("My Counter");
Line 175: test("human output contains 'Added widget' and title", async () => {
Line 190: test("throws ValidationError when title is missing (less than 2 positional args)", async () => {
Line 198: expect(err.message).toContain("Widget title is required");
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/dashboard/widget/add.test.ts</path>
<type>file</type>
<content>
175: test("human output contains 'Added widget' and title", async () => {
176: const { context, stdoutWrite } = createMockContext();
177: const func = await addCommand.loader();
178: await func.call(
179: context,
180: { json: false, display: "line", query: ["count"] },
181: "123",
182: "Error Rate"
183: );
184:
185: const output = stdoutWrite.mock.calls.map((c) => c[0]).join("");
186: expect(output).toContain("Added widget");
187: expect(output).toContain("Error Rate");
188: });
189:
190: test("throws ValidationError when title is missing (less than 2 positional args)", async () => {
191: const { context } = createMockContext();
192: const func = await addCommand.loader();
193:
194: const err = await func
195: .call(context, { json: false, display: "line" }, "123")
196: ...
No files found
No files found
Found 100 matches (more matches available)
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/lib/command.test.ts:
Line 34: } from "../../src/lib/interactive-prompts.js";
Line 83: test("derives prompt availability from parsed flags instead of ambiguous aliases", async () => {
Line 86: const promptStates: boolean[] = [];
Line 97: promptStates.push(interactivePromptsAllowed());
Line 122: promptStates.push(interactivePromptsAllowed());
Line 145: expect(promptStates.at(-1)).toBe(testCase.expected);
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/lib/version-check.test.ts:
Line 104: test("does not suppress for cli feedback", () => {
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/lib/telemetry.test.ts:
Line 181: // subsequent test files (e.g. feedbackCommand checks it). ...
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/e2e/feedback.test.ts</path>
<type>file</type>
<content>
1: /**
2: * Feedback command E2E tests.
3: *
4: * Exercises the real command router and generated API client against a mock
5: * Sentry API, including the mandatory issue-category and status filters.
6: */
7:
8: import {
9: afterAll,
10: afterEach,
11: beforeAll,
12: beforeEach,
13: describe,
14: expect,
15: test,
16: } from "vitest";
17: import { EXIT } from "../../src/lib/errors.js";
18: import { createE2EContext, type E2EContext } from "../fixture.js";
19: import { cleanupTestDir, createTestConfigDir } from "../helpers.js";
20: import {
21: createSentryMockServer,
22: TEST_FEEDBACK_ID,
23: TEST_FEEDBACK_LATEST_ORG,
24: TEST_FEEDBACK_SHORT_ID,
25: TEST_ORG,
26: TEST_PROJECT,
27: TEST_TOKEN,
28: } from "../mocks/routes.js";
29: import type { MockServer } from "../mocks/server.js";
30:
31: let testConfigDir: string;
32: let mockServer: ...
Found 6 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/lib/telemetry.test.ts:
Line 181: // subsequent test files (e.g. feedbackCommand checks it).
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/cli.test.ts:
Line 12: import { feedbackCommand } from "../../src/commands/cli/feedback.js";
Line 65: describe("feedbackCommand.func", () => {
Line 68: const func = await feedbackCommand.loader();
Line 80: const func = await feedbackCommand.loader();
Line 92: const func = await feedbackCommand.loader();
<path>/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/cli.test.ts</path>
<type>file</type>
<content>
55: context,
56: getStderr: () => stderrChunks.join(""),
57: getStdout: () => stdoutChunks.join(""),
58: errors,
59: restore: () => {
60: process.stderr.write = origWrite;
61: },
62: };
63: }
64:
65: describe("feedbackCommand.func", () => {
66: test("throws ValidationError for empty message", async () => {
67: // Access func through loader
68: const func = await feedbackCommand.loader();
69: const mockContext = {
70: stdout: { write: vi.fn(() => true) },
71: stderr: { write: vi.fn(() => true) },
72: };
73:
74: await expect(func.call(mockContext, {}, "")).rejects.toThrow(
75: "Please provide a feedback message."
76: );
77: });
78:
79: test("throws ValidationError for whitespace-only message", async () => {
80: const func = await feedbackCommand.loader();
81: const mockContext = ...
Found 2 matches
/home/byk/Code/getsentry/cli-pr-1558/packages/cli/test/commands/cli/defaults.test.ts:
Line 181: describe("empty string validation", () => {
Line 393: test("show action with empty defaults", () => {
Date: September 10, 2026 * 🔴 [requested-review] (14:34) User requested read-only review of the current uncommitted implementation in `/home/byk/Code/getsentry/cli-pr-1558`; files must not be modified. * 🟡 (14:34) User asked to review mapping `docs.customUsage[0]` to `PositionalInfo.syntax` in `packages/cli/src/lib/introspect.ts` and rendering it in `script/generate-skill-markdown.ts`. * 🟡 (14:…