Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
4d6ddde
feat(init): add init command for guided Sentry project setup
betegon Feb 17, 2026
8146d8b
feat(init): pass tracing options to Mastra workflow runs
betegon Feb 17, 2026
57f902f
feat(init): generate unique trace ID for each wizard run
betegon Feb 17, 2026
0c5e440
fix(init): flatten nested workflow spans with shared parent span ID
betegon Feb 17, 2026
d60e3b2
fix(init): remove unnecessary parentSpanId from tracing options
betegon Feb 18, 2026
3d39f61
feat(init): show ASCII banner and make error monitoring required
betegon Feb 18, 2026
11cdf6c
fix(init): improve wizard UX for already-installed case, feature prom…
betegon Feb 18, 2026
049fc95
feat(init): add AI transparency note and review reminder to wizard
betegon Feb 18, 2026
1e76a55
fix: added auth headers in the mastra client (#264)
MathurAditya724 Feb 19, 2026
077119a
fix(init): update MASTRA_API_URL to production worker endpoint
betegon Feb 23, 2026
350530f
feat(init): add eval test dependencies and biome config
betegon Feb 23, 2026
4e1269f
feat(init): add init-eval test suite
betegon Feb 23, 2026
476bcbc
ci: add workflow_dispatch CI job for init-eval tests
betegon Feb 23, 2026
193a467
fix(init): use .md URL conversion in eval docs-fetcher
betegon Feb 23, 2026
bcb10f2
feat(init): add flask and python profiling doc URLs
betegon Feb 23, 2026
129e7b7
feat(init): add nextjs doc URLs for eval ground truth
betegon Feb 23, 2026
b6c10b7
feat(init): add sveltekit doc URLs for eval ground truth
betegon Feb 23, 2026
a8156c0
feat(init): add react-vite doc URLs for eval ground truth
betegon Feb 23, 2026
1d29ebd
fix(init): use venv for flask build check and remove opencode-lore dep
betegon Feb 23, 2026
ce9614f
feat(init): add python-fastapi eval test and gitignore package-lock
betegon Feb 23, 2026
3227619
style(init): fix lint formatting in eval test files
betegon Feb 23, 2026
04ae63d
ci(init): add minimal permissions to init-eval workflow
betegon Feb 23, 2026
4d7787c
fix(init): update sveltekit template and use python3 in eval tests
betegon Feb 24, 2026
102baa6
ci(init): run init-eval on PRs and main pushes
betegon Feb 24, 2026
51f8968
Revert "ci(init): run init-eval on PRs and main pushes"
betegon Feb 24, 2026
d5d0b22
ci(init): remove init-eval workflow for now
betegon Feb 24, 2026
1308035
feat(init): enforce --dry-run flag in local operations
betegon Feb 25, 2026
00417d6
fix(init): use HTTPS for default API URL
betegon Feb 25, 2026
d41cbb8
fix(init): add @clack/prompts as direct dependency
betegon Feb 25, 2026
2dd7f47
feat(init): add command execution guardrails to local-ops
betegon Feb 25, 2026
a8a10a4
docs(init): add init command page to cli.sentry.dev
betegon Feb 25, 2026
b8cddd5
refactor(init): extract magic values into named constants
betegon Feb 26, 2026
b20089e
Merge remote-tracking branch 'origin/main' into claude/funny-jang
betegon Feb 27, 2026
441ea88
fix: resolve lint and format errors in local-ops
betegon Feb 27, 2026
184dff6
test(init): add comprehensive tests for init wizard coverage
betegon Feb 27, 2026
9fb739d
merge: resolve conflicts with main branch
betegon Mar 2, 2026
20a4431
Merge branch 'feat/init-command' of https://github.com/getsentry/cli …
betegon Mar 2, 2026
068663d
test(init): improve patch coverage by including isolated tests in CI …
betegon Mar 2, 2026
7488e86
fix(ci): run isolated tests separately to avoid mock.module() leakage
betegon Mar 2, 2026
2124e99
fix(test): move init-command test out of isolated to avoid mock leakage
betegon Mar 2, 2026
0f0f61a
fix(test): run each isolated test file in its own bun process
betegon Mar 2, 2026
07905aa
fix(test): merge duplicate LCOV entries from per-file isolated runs
betegon Mar 2, 2026
864fef6
refactor(test): replace mock.module() with spyOn() for init tests
betegon Mar 2, 2026
8cfa8f5
fix(test): keep wizard-runner isolated (spyOn fails on local ESM in CI)
betegon Mar 2, 2026
241eb0c
fix: close file descriptor on readSync failure in readFiles
betegon Mar 2, 2026
a1a1629
fix: block redirection/background metacharacters and use cross-platfo…
betegon Mar 2, 2026
b5cce8e
fix: validate remote-supplied cwd against project directory
betegon Mar 2, 2026
6ca341e
fix: set process.exitCode on wizard failure paths
betegon Mar 2, 2026
b6b4525
fix: harden wizard runner error handling and command validation
betegon Mar 2, 2026
dee9c53
fix: block subshell bypass via parentheses and set exitCode on missin…
betegon Mar 3, 2026
b5bc811
Merge remote-tracking branch 'origin/main' into feat/init-command
betegon Mar 3, 2026
c1461d3
refactor: split skill docs into reference files and improve skill loader
betegon Mar 3, 2026
037382b
Revert "refactor: split skill docs into reference files and improve s…
betegon Mar 3, 2026
89e98ca
refactor: remove merge-lcov and simplify test/CI coverage pipeline
betegon Mar 3, 2026
cae38bb
fix: reset process.exitCode in test resetAllMocks to prevent CI exit …
betegon Mar 3, 2026
b5a8c8f
test: add wizard-runner unit tests to improve patch coverage to >= 80%
betegon Mar 3, 2026
39e4b5a
fix: lint errors in wizard-runner test and imports
betegon Mar 3, 2026
bc4ca1d
fix: address PR review issues in interactive and local-ops
betegon Mar 3, 2026
6ffca44
fix: block env var injection in commands and fix resume step ID mismatch
betegon Mar 3, 2026
aa04148
refactor: add DirEntry type and precomputeDirListing returning DirEnt…
betegon Mar 3, 2026
d1b5fc8
Revert "refactor: add DirEntry type and precomputeDirListing returnin…
betegon Mar 3, 2026
5313a92
perf(init): pre-compute dir listing and send _prevPhases for cross-ph…
betegon Mar 3, 2026
be2e9ad
fix(init): address PR review comments — block # metachar, document fi…
betegon Mar 3, 2026
c69da8b
refactor(init): add typed interfaces, validate-all-then-execute, and …
betegon Mar 3, 2026
914995f
fix(init): add symlink bypass protection, API timeout, and cleanup
betegon Mar 3, 2026
af67578
fix(init): restore production API URL and validate-all-then-execute f…
betegon Mar 3, 2026
ba6bd73
Merge branch 'main' into feat/init-command
betegon Mar 4, 2026
30eb4e8
feat(init): add create-sentry-project local op with org resolution fa…
betegon Mar 4, 2026
4803bbf
fix: use org-as-subdomain pattern for SaaS, path-based for self-hoste…
betegon Mar 5, 2026
1313877
refactor(init): remove add-example-trigger step (#357)
betegon Mar 5, 2026
6bdb9ff
fix(init): reject unknown patch actions in both dry-run and real patc…
betegon Mar 5, 2026
32cb8bd
fix(init): use "Error" spinner label for non-cancellation failures
betegon Mar 5, 2026
4ab3d5f
Merge remote-tracking branch 'origin/main' into feat/init-command
betegon Mar 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# dependencies (bun install)
node_modules
package-lock.json

# output
out
Expand Down Expand Up @@ -36,6 +37,7 @@ report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
.cache
*.tsbuildinfo
.turbo
.mastra

# docs
docs/dist
Expand Down
2 changes: 1 addition & 1 deletion biome.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
"extends": ["ultracite/core"],
"files": {
"includes": ["!docs"]
"includes": ["!docs", "!test/init-eval/templates"]
},
"javascript": {
"globals": ["Bun"]
Expand Down
440 changes: 438 additions & 2 deletions bun.lock

Large diffs are not rendered by default.

63 changes: 63 additions & 0 deletions docs/src/content/docs/commands/init.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
---
title: init
description: AI-powered project setup wizard for the Sentry CLI
---

Set up Sentry in your project with an AI-powered wizard. The `init` command detects your platform and framework, installs the Sentry SDK, and instruments your code for error monitoring, tracing, and more.

**Prerequisites:** You must be authenticated first. Run `sentry auth login` if you haven't already.

## Usage

```bash
sentry init [directory]
```

**Arguments:**

| Argument | Description |
|----------|-------------|
| `[directory]` | Project directory (default: current directory) |

**Options:**

| Option | Description |
|--------|-------------|
| `--force` | Continue even if Sentry is already installed |
| `-y, --yes` | Non-interactive mode (accept defaults) |
| `--dry-run` | Preview changes without applying them |
| `--features <list>` | Comma-separated features: `errors`, `tracing`, `logs`, `replay`, `metrics` |

## Examples

```bash
# Run the wizard in the current directory
sentry init

# Target a subdirectory
sentry init ./my-app

# Preview what changes would be made
sentry init --dry-run

# Select specific features
sentry init --features errors,tracing,logs

# Non-interactive mode (accept all defaults)
sentry init --yes
```

## What the wizard does

1. **Detects your framework** — scans your project files to identify the platform and framework
2. **Installs the SDK** — adds the appropriate Sentry SDK package to your project
3. **Instruments your code** — configures error monitoring, tracing, and any selected features

## Supported platforms

The wizard currently supports:

- **JavaScript / TypeScript** — Next.js, Express, SvelteKit, React
- **Python** — Flask, FastAPI

More platforms and frameworks are coming soon.
1 change: 1 addition & 0 deletions docs/src/content/docs/getting-started.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ Credentials are stored in a SQLite database at `~/.sentry/` with restricted file

Once authenticated, you can start using the CLI:

- [Initialize Sentry](../commands/init/) - Set up Sentry in your project with the guided wizard
- [Organization commands](../commands/org/) - List and view organizations
- [Project commands](../commands/project/) - Manage projects
- [Issue commands](../commands/issue/) - Track and manage issues
Expand Down
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
"url": "git+https://github.com/getsentry/cli.git"
},
"devDependencies": {
"@anthropic-ai/sdk": "^0.39.0",
"@biomejs/biome": "2.3.8",
"@clack/prompts": "^0.11.0",
"@mastra/client-js": "^1.4.0",
"@sentry/api": "^0.21.0",
"@sentry/bun": "10.39.0",
"@sentry/esbuild-plugin": "^2.23.0",
Expand All @@ -25,6 +28,7 @@
"fast-check": "^4.5.3",
"ignore": "^7.0.5",
"marked": "^15",
"openai": "^6.22.0",
"p-limit": "^7.2.0",
"pretty-ms": "^9.3.0",
"qrcode-terminal": "^0.12.0",
Expand Down Expand Up @@ -64,6 +68,7 @@
"test:unit": "bun test test/lib test/commands test/types --coverage --coverage-reporter=lcov",
"test:isolated": "bun test test/isolated",
"test:e2e": "bun test test/e2e",
"test:init-eval": "bun test test/init-eval --timeout 600000 --concurrency 6",
"generate:skill": "bun run script/generate-skill.ts",
"check:skill": "bun run script/check-skill.ts",
"check:deps": "bun run script/check-no-deps.ts"
Expand Down
14 changes: 14 additions & 0 deletions plugins/sentry-cli/skills/sentry-cli/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,20 @@ View logs associated with a trace
- `-n, --limit <value> - Number of log entries (1-1000) - (default: "100")`
- `-q, --query <value> - Additional filter query (Sentry search syntax)`

### Init

Initialize Sentry in your project

#### `sentry init <directory>`

Initialize Sentry in your project

**Flags:**
- `--force - Continue even if Sentry is already installed`
- `-y, --yes - Non-interactive mode (accept defaults)`
- `--dry-run - Preview changes without applying them`
- `--features <value> - Comma-separated features: errors,tracing,logs,replay,metrics`

### Issues

List issues in a project
Expand Down
2 changes: 2 additions & 0 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { whoamiCommand } from "./commands/auth/whoami.js";
import { cliRoute } from "./commands/cli/index.js";
import { eventRoute } from "./commands/event/index.js";
import { helpCommand } from "./commands/help.js";
import { initCommand } from "./commands/init.js";
import { issueRoute } from "./commands/issue/index.js";
import { listCommand as issueListCommand } from "./commands/issue/list.js";
import { logRoute } from "./commands/log/index.js";
Expand Down Expand Up @@ -64,6 +65,7 @@ export const routes = buildRouteMap({
event: eventRoute,
log: logRoute,
trace: traceRoute,
init: initCommand,
api: apiCommand,
issues: issueListCommand,
orgs: orgListCommand,
Expand Down
84 changes: 84 additions & 0 deletions src/commands/init.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/**
* sentry init
*
* Initialize Sentry in a project using the remote wizard workflow.
* Communicates with the Mastra API via suspend/resume to perform
* local filesystem operations and interactive prompts.
*/

import path from "node:path";
import type { SentryContext } from "../context.js";
import { buildCommand } from "../lib/command.js";
import { runWizard } from "../lib/init/wizard-runner.js";

type InitFlags = {
readonly force: boolean;
readonly yes: boolean;
readonly "dry-run": boolean;
readonly features?: string;
};

export const initCommand = buildCommand<InitFlags, [string?], SentryContext>({
docs: {
brief: "Initialize Sentry in your project",
fullDescription:
"Runs the Sentry setup wizard to detect your project's framework, " +
"install the SDK, and configure error monitoring. Uses a remote " +
"workflow that coordinates local file operations through the CLI.",
},
parameters: {
positional: {
kind: "tuple",
parameters: [
{
placeholder: "directory",
brief: "Project directory (default: current directory)",
parse: String,
optional: true,
},
],
},
flags: {
force: {
kind: "boolean",
brief: "Continue even if Sentry is already installed",
default: false,
},
yes: {
kind: "boolean",
brief: "Non-interactive mode (accept defaults)",
default: false,
},
"dry-run": {
kind: "boolean",
brief: "Preview changes without applying them",
default: false,
},
features: {
kind: "parsed",
parse: String,
brief: "Comma-separated features: errors,tracing,logs,replay,metrics",
optional: true,
placeholder: "list",
},
},
aliases: {
y: "yes",
},
},
async func(this: SentryContext, flags: InitFlags, directory?: string) {
const targetDir = directory ? path.resolve(this.cwd, directory) : this.cwd;
const featuresList = flags.features
?.split(",")
.map((f) => f.trim())
.filter(Boolean);

await runWizard({
directory: targetDir,
force: flags.force,
yes: flags.yes,
dryRun: flags["dry-run"],
features: featuresList,
});
},
});
20 changes: 1 addition & 19 deletions src/commands/project/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {
resolveOrCreateTeam,
} from "../../lib/resolve-team.js";
import { buildProjectUrl } from "../../lib/sentry-urls.js";
import { slugify } from "../../lib/utils.js";
import type { SentryProject, SentryTeam, Writer } from "../../types/index.js";

/** Usage hint template — base command without positionals */
Expand Down Expand Up @@ -107,25 +108,6 @@ function normalizePlatform(platform: string, stderr: Writer): string {
return corrected;
}

/**
* Convert a project name to its expected Sentry slug.
* Aligned with Sentry's canonical implementation:
* https://github.com/getsentry/sentry/blob/master/static/app/utils/slugify.tsx
*
* @example slugify("My Cool App") // "my-cool-app"
* @example slugify("my-app") // "my-app"
* @example slugify("Café Project") // "cafe-project"
* @example slugify("my_app") // "my_app"
*/
function slugify(name: string): string {
return name
.normalize("NFKD")
.toLowerCase()
.replace(/[^a-z0-9_\s-]/g, "")
.replace(/[-\s]+/g, "-")
.replace(/^-|-$/g, "");
}

/**
* Check whether an API error is about an invalid platform value.
* Relies on Sentry's error message wording — may need updating if the API changes.
Expand Down
39 changes: 39 additions & 0 deletions src/lib/banner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* Banner Formatting
*
* Standalone module for the Sentry ASCII banner.
* Extracted to avoid circular imports (wizard-runner → help → app → init → wizard-runner).
*/

import chalk from "chalk";

/** ASCII art banner rows for gradient coloring */
const BANNER_ROWS = [
" ███████╗███████╗███╗ ██╗████████╗██████╗ ██╗ ██╗",
" ██╔════╝██╔════╝████╗ ██║╚══██╔══╝██╔══██╗╚██╗ ██╔╝",
" ███████╗█████╗ ██╔██╗ ██║ ██║ ██████╔╝ ╚████╔╝ ",
" ╚════██║██╔══╝ ██║╚██╗██║ ██║ ██╔══██╗ ╚██╔╝ ",
" ███████║███████╗██║ ╚████║ ██║ ██║ ██║ ██║ ",
" ╚══════╝╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ",
];

/** Purple gradient colors from bright to dark (Sentry brand-inspired) */
const BANNER_GRADIENT = [
"#B4A4DE",
"#9C84D4",
"#8468C8",
"#6C4EBA",
"#5538A8",
"#432B8A",
];

/**
* Format the banner with a vertical gradient effect.
* Each row gets progressively darker purple.
*/
export function formatBanner(): string {
return BANNER_ROWS.map((row, i) => {
const color = BANNER_GRADIENT[i] ?? "#B4A4DE";
return chalk.hex(color)(row);
}).join("\n");
}
33 changes: 1 addition & 32 deletions src/lib/help.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,43 +6,12 @@
* Commands are auto-generated from Stricli's route structure.
*/

import chalk from "chalk";
import { routes } from "../app.js";
import type { Writer } from "../types/index.js";
import { formatBanner } from "./banner.js";
import { isAuthenticated } from "./db/auth.js";
import { cyan, magenta, muted } from "./formatters/colors.js";

/** ASCII art banner rows for gradient coloring */
const BANNER_ROWS = [
" ███████╗███████╗███╗ ██╗████████╗██████╗ ██╗ ██╗",
" ██╔════╝██╔════╝████╗ ██║╚══██╔══╝██╔══██╗╚██╗ ██╔╝",
" ███████╗█████╗ ██╔██╗ ██║ ██║ ██████╔╝ ╚████╔╝ ",
" ╚════██║██╔══╝ ██║╚██╗██║ ██║ ██╔══██╗ ╚██╔╝ ",
" ███████║███████╗██║ ╚████║ ██║ ██║ ██║ ██║ ",
" ╚══════╝╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ",
];

/** Purple gradient colors from bright to dark (Sentry brand-inspired) */
const BANNER_GRADIENT = [
"#B4A4DE",
"#9C84D4",
"#8468C8",
"#6C4EBA",
"#5538A8",
"#432B8A",
];

/**
* Format the banner with a vertical gradient effect.
* Each row gets progressively darker purple.
*/
function formatBanner(): string {
return BANNER_ROWS.map((row, i) => {
const color = BANNER_GRADIENT[i] ?? "#B4A4DE";
return chalk.hex(color)(row);
}).join("\n");
}

const TAGLINE = "The command-line interface for Sentry";

type HelpCommand = {
Expand Down
Loading
Loading