Skip to content

feat(init): add init command for guided Sentry project setup#283

Merged
betegon merged 81 commits intomainfrom
feat/init-command
Mar 9, 2026
Merged

feat(init): add init command for guided Sentry project setup#283
betegon merged 81 commits intomainfrom
feat/init-command

Conversation

@betegon
Copy link
Member

@betegon betegon commented Feb 23, 2026

Summary

Adds sentry init — an AI-powered wizard that walks users through adding Sentry to their project. It detects the platform, installs the SDK, instruments the code, and configures error monitoring, tracing, and session replay.

Changes

Core wizard

  • New init command backed by a Mastra AI workflow (hosted at getsentry/cli-init-api) that handles platform detection, SDK installation, and code instrumentation
  • ASCII banner, AI transparency note, and review reminder in the wizard UX
  • Tracing: unique trace IDs per wizard run with flattened span hierarchy
  • Python platforms use venv for isolated dependency installation
  • Magic values extracted into named constants (constants.ts)
  • Docs page added to cli.sentry.dev

Security hardening

  • Shell metacharacter blocklist: () subshell bypass, > < & redirection/background, $ ' " \ expansion/escaping, { } * ? glob/brace expansion, # shell comment
  • Environment variable injection blocking (VAR=value cmd pattern)
  • Remote-supplied cwd validation against project directory
  • Dangerous executable blocklist and path-traversal prevention
  • File descriptor cleanup on readSync failure
  • Cross-platform shell execution ({ shell: true } instead of hardcoded sh)

Performance

Testing & CI

  • Wizard-runner unit tests (coverage 5.94% → 99.42%)
  • Banner extracted to src/lib/banner.ts to break circular import
  • Mock isolation fixes (spyOn instead of mock.module where possible)
  • Simplified coverage pipeline (removed merge-lcov workaround)

Eval suite

The eval suite validates that the wizard produces correct, buildable Sentry instrumentation for each supported platform. It uses a 3-phase test architecture:

Phase 1: Wizard run

Each test scaffolds a fresh project from a platform template, then runs the full sentry init wizard against it. The wizard output (exit code, stdout/stderr, git diff, new files) is captured for the next phases.

Phase 2: Hard assertions (deterministic)

Five code-based pass/fail checks that run without any LLM:

  1. exit-code — wizard exits 0
  2. sdk-installed — the Sentry SDK package appears in the dependency file (package.json / requirements.txt)
  3. init-presentSentry.init (or sentry_sdk.init) appears in changed or new files
  4. no-placeholder-dsn — no leftover placeholder DSNs (___PUBLIC_DSN___, YOUR_DSN_HERE, etc.)
  5. build-succeedsnpm run build / equivalent passes after the wizard's changes

Phase 3: LLM judge (per-feature)

For each feature (errors, tracing, replay, logs, profiling, etc.), an LLM judge scores correctness:

  • Official Sentry docs are fetched as ground truth (URLs mapped in feature-docs.json)
  • GPT-4o evaluates the wizard's diff + new files against the docs on 4 criteria: feature-initialized, correct-imports, no-syntax-errors, follows-docs
  • Each criterion is scored pass/fail/unknown; the overall feature score must be >= 0.5

Platforms

6 platform templates are covered:

Platform Template SDK
Express express/ @sentry/node
Next.js nextjs/ @sentry/nextjs
SvelteKit sveltekit/ @sentry/sveltekit
React + Vite react-vite/ @sentry/react
Flask python-flask/ sentry-sdk
FastAPI python-fastapi/ sentry-sdk

Running

bun run test:init-eval          # all platforms

Requires SENTRY_AUTH_TOKEN, SENTRY_ORG, SENTRY_PROJECT, and optionally OPENAI_API_KEY (LLM judge is skipped without it).

Test Plan

  • All init unit tests pass (124 tests across 7 files)
  • bun run lint and bun run typecheck pass
  • CI passes (unit tests, e2e, lint, typecheck, build)
  • CI workflow for eval is tracked separately in Run init evals on CI #290

🤖 Generated with Claude Code

betegon and others added 21 commits February 17, 2026 20:48
Adds `sentry init` wizard that walks users through project setup via
the Mastra API, handling DSN configuration, SDK installation prompts,
and local file operations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sends tags and metadata (CLI version, OS, arch, node version) with
startAsync and resumeAsync calls so workflow runs are visible and
filterable in Mastra Studio.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Import randomBytes and generate a hex trace ID so all
suspend/resume calls within a single wizard run share one trace.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a synthetic parentSpanId to tracingOptions so all workflow run
spans become siblings under the same parent instead of nesting by
timestamp containment.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The parentSpanId was creating artificial nesting - let the workflow
engine handle span hierarchy naturally.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Display the branded SENTRY ASCII banner before the intro line for visual
consistency with `sentry --help`. Make the "errors" feature always enabled
in the feature multi-select so users cannot deselect error monitoring.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…pt, and source maps hint

Route success-with-exitCode results to formatError so the --force hint
is shown when Sentry is already installed. Fold the "Error Monitoring is
always included" note into the multiselect prompt. Use a more approachable
Source Maps hint.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Show a non-blocking info note about AI usage with a docs link before
the first network call, and a review reminder before the success outro.
Extract SENTRY_DOCS_URL constant to share between wizard-runner and
clack-utils cancel message.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add @anthropic-ai/sdk and openai as devDependencies for the LLM-as-judge
eval framework. Add opencode-lore dependency. Exclude test/init-eval/templates
from biome linting since they are fixture apps, not source code.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add LLM-as-judge eval tests for the init wizard across all five
platforms (Express, Next.js, Flask, React+Vite, SvelteKit). Each test
runs the wizard end-to-end and asserts on SDK installation, Sentry.init
presence, build success, and documentation accuracy via an LLM judge.

Includes template apps, helper utilities (assertions, doc-fetcher,
judge, platform configs), and feature-docs.json mapping.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a separate workflow for running init-eval tests on demand. Supports
running a single platform or all platforms via matrix. Uses the init-eval
GitHub environment for MASTRA_API_URL and OPENAI_API_KEY secrets.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Store python-fastapi doc URLs as base paths (with trailing slash) like
other platforms, and convert to .md at fetch time. This mirrors the
pattern in cli-init-api and lets us return clean markdown directly
instead of stripping HTML tags.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Sentry doc URLs for python-flask (getting-started, errors, tracing,
logs, profiling) and add the shared python/profiling page to both flask
and fastapi profiling entries.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Sentry doc URLs for all nextjs features: getting-started, errors,
logs, tracing, session replay, metrics, and profiling (browser + node).
Sourcemaps left empty for now.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Sentry doc URLs for sveltekit features and add missing logs,
metrics, and profiling features to the platform entry.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Sentry doc URLs for react-vite features and add missing logs,
metrics, and profiling features to the platform entry.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Flask eval was using bare `pip install` which fails when pip isn't on
PATH. Use the same venv pattern as fastapi. Also remove accidental
opencode-lore runtime dependency.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions
Copy link
Contributor

github-actions bot commented Feb 23, 2026

Semver Impact of This PR

🟡 Minor (new features)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


New Features ✨

  • (init) Add init command for guided Sentry project setup by betegon in #283
  • Input hardening against agent hallucinations by BYK in #370
  • Add response caching for read-only API calls by BYK in #330

Bug Fixes 🐛

  • (docs) Remove double borders and fix column alignment on landing page tables by betegon in #369

🤖 This preview updates automatically when you update the PR.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 23, 2026

Codecov Results 📊

104 passed | Total: 104 | Pass Rate: 100% | Execution Time: 0ms

📊 Comparison with Base Branch

Metric Change
Total Tests
Passed Tests
Failed Tests
Skipped Tests

✨ No test changes detected

All tests are passing successfully.

✅ Patch coverage is 95.72%. Project has 4049 uncovered lines.
✅ Project coverage is 81.98%. Comparing base (base) to head (head).

Files with missing lines (7)
File Patch % Lines
local-ops.ts 92.89% ⚠️ 35 Missing
sentry-url-parser.ts 76.19% ⚠️ 25 Missing
app.ts 81.36% ⚠️ 22 Missing
create.ts 93.98% ⚠️ 15 Missing
wizard-runner.ts 95.42% ⚠️ 12 Missing
help.ts 96.81% ⚠️ 3 Missing
utils.ts 88.00% ⚠️ 3 Missing
Coverage diff
@@            Coverage Diff             @@
##          main       #PR       +/-##
==========================================
+ Coverage    80.79%    81.98%    +1.19%
==========================================
  Files          132       140        +8
  Lines        21382     22473     +1091
  Branches         0         0         —
==========================================
+ Hits         17274     18424     +1150
- Misses        4108      4049       -59
- Partials         0         0         —

Generated by Codecov Action

betegon and others added 3 commits February 23, 2026 22:16
Restrict GITHUB_TOKEN to contents:read as flagged by CodeQL.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update SvelteKit template with working deps (adapter-node, latest
svelte/vite) and add required src files (app.d.ts, app.html). Use
python3 instead of python for venv creation in Flask/FastAPI platforms.
Add --concurrency 6 to init-eval test runner.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add push/pull_request triggers so the eval runs automatically alongside
other CI checks. Keep workflow_dispatch for manual single-platform runs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…llback (#333)

## Summary

Adds the `create-sentry-project` local operation so the remote workflow
can ask the CLI to create a Sentry project. Resolves the org via local
config / env vars first, falling back to listing orgs from the API
(auto-selects if only one, prompts interactively if multiple).

## Changes

- New `createSentryProject` handler in `local-ops.ts` with extracted
`resolveOrgSlug` helper that handles all org resolution paths (config,
single-org auto-select, multi-org interactive prompt, `--yes` guard)
- `CreateSentryProjectPayload` type added to `types.ts`
- Test suite covering success, single-org fallback, no-orgs, multi-org
`--yes`, interactive select, user cancel, API error, and missing DSN
paths
- Downstream mock setup extracted into `mockDownstreamSuccess` helper to
reduce test duplication

## Test Plan

```bash
bun test test/lib/init/local-ops.create-sentry-project.test.ts  # 8 pass
bun run lint  # clean
```

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
#354)

## Summary
- Add `getOrgBaseUrl()` helper that builds org-scoped subdomain URLs for
SaaS (e.g. `https://my-org.sentry.io`) while returning the base URL
unchanged for self-hosted instances
- Update all 8 URL builder functions in `sentry-urls.ts` to branch on
SaaS vs self-hosted:
  - **SaaS**: subdomain pattern (`https://my-org.sentry.io/issues/...`)
- **Self-hosted**: path-based pattern
(`https://sentry.company.com/organizations/my-org/issues/...`)
- Add `isSaaS()` private helper that checks the current base URL against
`isSentrySaasUrl()`
- Add self-hosted test coverage verifying all builders produce
path-based URLs with no subdomain prepended

## How this affected our `sentry init` command
- before:
`https://sentry.io/settings/bete-dev/projects/project-created/`
- after: `https://bete-dev.sentry.io/settings/projects/project-created/`

## Test plan
- [x] `bun run typecheck` passes
- [x] `bun run lint` passes
- [x] `bun test test/lib/sentry-urls.property.test.ts` passes (45 tests,
including 10 new self-hosted tests)
- [x] SaaS URLs still use `{org}.sentry.io` subdomain pattern
- [x] Self-hosted URLs use `/organizations/{org}/` or `/settings/{org}/`
path patterns
## Summary

Removes `add-example-trigger` references from the CLI to match the API
repo, where this step was already removed. Cleans up the step label,
confirm handler logic, `purpose` field on `ConfirmPayload`, and 5
related test cases.

## Changes

- Removed `"add-example-trigger"` from `STEP_LABELS` in `clack-utils.ts`
- Removed `addExample` / `isExample` logic from `handleConfirm` in
`interactive.ts`
- Removed optional `purpose` field from `ConfirmPayload` in `types.ts`
- Removed 5 test cases covering example-trigger confirm behavior

## Test plan

- `bun run lint` passes
- `bun test test/lib/init/interactive.test.ts` — remaining confirm tests
pass
- `git grep "addExample\|add-example-trigger\|add-example" -- src/
test/` returns 0 matches

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
betegon and others added 3 commits March 5, 2026 20:05
…hset paths

Previously, applyPatchsetDryRun recorded every patch as applied regardless
of its action, while the real applyPatchset silently skipped unknown actions
via default: break. Both paths now return an explicit error on unrecognized
patch actions so behavior is consistent.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The catch block in the suspend/resume loop was showing "Cancelled" for
errors like network timeouts and API failures. Use "Error" to match the
label used in other error paths in the same file.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
# Conflicts:
#	.github/workflows/ci.yml
#	bun.lock
#	src/commands/project/create.ts
The merge conflict resolution inadvertently upgraded @mastra/client-js
to 1.7.2, pulling in @mastra/core@1.9.0 which introduces a quansync
peer dependency that bun 1.3.9 can't resolve with --frozen-lockfile.
Restored lockfile from ba6bd73 and re-resolved to keep @mastra/client-js
pinned at 1.7.1.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…into try/catch

Track spinner running state via a mutable SpinState object to guard
against calling spin.stop() twice when handleInteractive throws after
the spinner was already stopped. Also moved precomputeDirListing inside
the existing try/catch as a defensive improvement.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Skip all API calls (org resolution, team creation, project creation,
DSN fetch) when dryRun is true and return placeholder data instead.
Slug validation is kept before the guard so invalid names are still
caught in dry-run mode.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

When applyPatchset fails mid-application, the error response now includes
the list of already-applied patches so the server can track partial progress.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 3 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Previously, when createProject returned a 400, only the generic status
message was shown (e.g. "Failed to create project: 400 Bad Request").
Now uses ApiError.format() to include the response detail, giving users
visibility into why the request failed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

# Conflicts:
#	bun.lock
#	package.json
#	src/commands/project/create.ts
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Self-hosted getOrgBaseUrl silently drops org slug
    • Added explicit error throw for self-hosted instances to prevent silent failure when org slug would be dropped.
  • ✅ Fixed: Eval judge score zero when all criteria unknown
    • Changed default score from 0 to 1.0 when no criteria are gradable, treating inconclusive judge as pass rather than fail.

Create PR

Or push these changes by commenting:

@cursor push 83acd8e5a2
Preview (83acd8e5a2)
diff --git a/src/lib/sentry-urls.ts b/src/lib/sentry-urls.ts
--- a/src/lib/sentry-urls.ts
+++ b/src/lib/sentry-urls.ts
@@ -21,11 +21,14 @@
  *
  * @param orgSlug - Organization slug
  * @returns Origin URL with org as subdomain
+ * @throws Error if called for self-hosted instances (subdomain pattern only works for SaaS)
  */
 export function getOrgBaseUrl(orgSlug: string): string {
   const base = getSentryBaseUrl();
   if (!isSentrySaasUrl(base)) {
-    return base;
+    throw new Error(
+      `getOrgBaseUrl() only supports Sentry SaaS URLs. For self-hosted instances, use path-based URLs with /organizations/${orgSlug}/`
+    );
   }
   const parsed = new URL(base);
   parsed.hostname = `${orgSlug}.${parsed.hostname}`;

diff --git a/test/init-eval/helpers/judge.ts b/test/init-eval/helpers/judge.ts
--- a/test/init-eval/helpers/judge.ts
+++ b/test/init-eval/helpers/judge.ts
@@ -119,7 +119,7 @@
   const gradable = parsed.criteria.filter((c) => c.pass !== "unknown");
   const passing = gradable.filter((c) => c.pass === true).length;
   const total = gradable.length;
-  const score = total > 0 ? passing / total : 0;
+  const score = total > 0 ? passing / total : 1.0;
 
   const verdict: JudgeVerdict = {
     criteria: parsed.criteria,
This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.

Move single-char `&` pattern right after `&&`, `||`, `|` so multi-char
operators are checked before their single-char prefixes, matching the
stated design principle in the comment.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

export function buildOrgUrl(orgSlug: string): string {
if (isSaaS()) {
return `${getOrgBaseUrl(orgSlug)}/`;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant SaaS check in every URL construction call

Low Severity

Every URL-building function (e.g. buildOrgUrl, buildProjectUrl) calls isSaaS() which internally calls getSentryBaseUrl() + isSentrySaasUrl(), and then calls getOrgBaseUrl() which internally calls getSentryBaseUrl() + isSentrySaasUrl() again. This means each URL construction makes two redundant calls to read the environment variable and validate the hostname. The getOrgBaseUrl function could accept the already-resolved base URL as a parameter, or the SaaS check result could be passed through.

Additional Locations (1)

Fix in Cursor Fix in Web

result.error ?? inner?.message ?? "Wizard failed with an unknown error";
const exitCode = inner?.exitCode ?? 1;

log.error(String(message));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty error string shows blank message to user

Low Severity

formatError uses ?? (nullish coalescing) for the error message fallback chain: result.error ?? inner?.message ?? "Wizard failed...". If the server returns error: "" (empty string), ?? does not treat it as nullish, so message becomes "" and log.error("") displays a blank error line. Using || instead of the first ?? would fall through to the next alternative for empty strings.

Fix in Cursor Fix in Web

Copy link
Member

@BYK BYK left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we are in a good place, I don't think any of my comments are blockers to get this out of the door with a huge "experimental" banner.

One thing I noticed is we don't check if we are operating in a git repo, whether it is clear and safe for us to do things and roll back etc. I remember sentry-wizard having some code for this so I think we can just steal that for increased safety.

Once we are out of experimental mode, we should definitely re-evaluate the safety of our generic command call helper. On Linux systems, we might be able to easily jail that if we want to keep using generic bash commands.

Initialize Sentry in your project

**Flags:**
- `--force - Continue even if Sentry is already installed`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit weird as we may want to extend existing Sentry installation (only errors to errors + tracing etc)

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.",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uses a remote workflow that coordinates local file operations through the CLI.

Do we really need to call this out in the help text?

Comment on lines +41 to +46
flags: {
force: {
kind: "boolean",
brief: "Continue even if Sentry is already installed",
default: false,
},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned earlier, I vote to remove this.

features: {
kind: "parsed",
parse: String,
brief: "Comma-separated features: errors,tracing,logs,replay,metrics",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd also allow + and (for quoted args) for defensive parsing. We may also consider allowing multiple --features or --feature flags to join them. Similar to what we do with --field in the api command


export function abortIfCancelled<T>(value: T | symbol): T {
if (isCancel(value)) {
cancel(`Setup cancelled. Visit ${SENTRY_DOCS_URL} to set up manually.`);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
cancel(`Setup cancelled. Visit ${SENTRY_DOCS_URL} to set up manually.`);
cancel(`Setup cancelled. You can visit ${SENTRY_DOCS_URL} to set up manually.`);

const { directory, force, yes, dryRun, features } = options;

if (!(yes || process.stdin.isTTY)) {
process.stderr.write(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use log.error()

return;
}

process.stderr.write(`\n${formatBanner()}\n\n`);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why to stderr?

}

process.stderr.write(`\n${formatBanner()}\n\n`);
intro("sentry init");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the banner printing part not part of the intro helper already?


const tracingOptions = {
traceId: randomBytes(16).toString("hex"),
tags: ["sentry-cli", "init-wizard"],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, what? What is the sentry-cli tag? What are we doing here with a custom trace id etc?

return;
}

const resumeData = await handleSuspendedStep(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say if we can, we should support resuming from suspension from information stored on disk in case of an unexpected process termination

@betegon betegon merged commit ae5a386 into main Mar 9, 2026
21 checks passed
@betegon betegon deleted the feat/init-command branch March 9, 2026 16:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants