diff --git a/bin.ts b/bin.ts index 6692c1e47..1a7ba64d1 100644 --- a/bin.ts +++ b/bin.ts @@ -160,6 +160,41 @@ const argv = yargs(hideBin(process.argv), process.cwd()) 'Enable Spotlight for local development. This does not require a Sentry account or project.', type: 'boolean', }, + 'skip-auth': { + default: false, + describe: + 'Skip Sentry authentication and use environment variable placeholders. Enables fully headless CLI operation.', + type: 'boolean', + }, + tracing: { + describe: + 'Enable performance/tracing monitoring. When set, skips the tracing prompt.', + type: 'boolean', + }, + replay: { + describe: 'Enable Session Replay. When set, skips the replay prompt.', + type: 'boolean', + }, + logs: { + describe: 'Enable Sentry Logs. When set, skips the logs prompt.', + type: 'boolean', + }, + 'tunnel-route': { + describe: + 'Enable tunnel route for ad-blocker circumvention. When set, skips the tunnel route prompt.', + type: 'boolean', + }, + 'example-page': { + describe: + 'Create an example page to test Sentry. When set, skips the example page prompt.', + type: 'boolean', + }, + mcp: { + describe: + 'Add MCP (Model Context Protocol) config for specified IDE(s). Options: cursor, vscode, claude, opencode, jetbrains', + type: 'array', + choices: ['cursor', 'vscode', 'claude', 'opencode', 'jetbrains'], + }, 'xcode-project-dir': xcodeProjectDirOption, ...PRESELECTED_PROJECT_OPTIONS, }) diff --git a/src/nextjs/nextjs-wizard.ts b/src/nextjs/nextjs-wizard.ts index a86750d5f..3a08835c4 100644 --- a/src/nextjs/nextjs-wizard.ts +++ b/src/nextjs/nextjs-wizard.ts @@ -31,7 +31,14 @@ import { } from '../utils/clack'; import { getPackageVersion, hasPackageInstalled } from '../utils/package-json'; import type { SentryProjectData, WizardOptions } from '../utils/types'; -import { offerProjectScopedMcpConfig } from '../utils/clack/mcp-config'; +import { + offerProjectScopedMcpConfig, + addCursorMcpConfig, + addVsCodeMcpConfig, + addClaudeCodeMcpConfig, + addOpenCodeMcpConfig, + showJetBrainsMcpConfig, +} from '../utils/clack/mcp-config'; import { getFullUnderscoreErrorCopyPasteSnippet, getGlobalErrorCopyPasteSnippet, @@ -54,6 +61,7 @@ import { getInstrumentationClientHookCopyPasteSnippet, getRootLayoutWithGenerateMetadata, getGenerateMetadataSnippet, + getSentryEnvExampleContents, } from './templates'; import { getMaybeAppDirLocation, @@ -77,7 +85,7 @@ export function runNextjsWizard(options: WizardOptions) { export async function runNextjsWizardWithTelemetry( options: WizardOptions, ): Promise { - const { promoCode, telemetryEnabled, forceInstall } = options; + const { promoCode, telemetryEnabled, forceInstall, skipAuth } = options; printWelcome({ wizardName: 'Sentry Next.js Wizard', @@ -99,37 +107,29 @@ export async function runNextjsWizardWithTelemetry( const nextVersion = getPackageVersion('next', packageJson); Sentry.setTag('nextjs-version', getNextJsVersionBucket(nextVersion)); - const projectData = await getOrAskForProjectData( - options, - 'javascript-nextjs', - ); - - const sdkAlreadyInstalled = hasPackageInstalled( - '@sentry/nextjs', - packageJson, - ); - Sentry.setTag('sdk-already-installed', sdkAlreadyInstalled); - - const { packageManager: packageManagerFromInstallStep } = - await installPackage({ - packageName: '@sentry/nextjs@^10', - packageNameDisplayLabel: '@sentry/nextjs', - alreadyInstalled: !!packageJson?.dependencies?.['@sentry/nextjs'], - forceInstall, - }); - + // In skip-auth mode, we don't need to authenticate with Sentry + // We'll use environment variable placeholders instead let selectedProject: SentryProjectData; let authToken: string; let selfHosted: boolean; let sentryUrl: string; let spotlight: boolean; + let useEnvVars: boolean; + + if (skipAuth) { + Sentry.setTag('skip-auth-mode', true); + clack.log.info( + chalk.cyan( + 'Running in skip-auth mode. Environment variable placeholders will be used.', + ), + ); - if (projectData.spotlight) { - // Spotlight mode: use empty DSN and skip auth - spotlight = true; + // Skip auth mode: use placeholder data with env vars + spotlight = false; selfHosted = false; - sentryUrl = ''; + sentryUrl = 'https://sentry.io/'; authToken = ''; + useEnvVars = true; // Create a minimal project structure for type compatibility selectedProject = { id: '', @@ -138,13 +138,49 @@ export async function runNextjsWizardWithTelemetry( keys: [{ dsn: { public: '' } }], }; } else { - spotlight = false; - ({ selectedProject, authToken, selfHosted, sentryUrl } = projectData); + useEnvVars = false; + const projectData = await getOrAskForProjectData( + options, + 'javascript-nextjs', + ); + + if (projectData.spotlight) { + // Spotlight mode: use empty DSN and skip auth + spotlight = true; + selfHosted = false; + sentryUrl = ''; + authToken = ''; + // Create a minimal project structure for type compatibility + selectedProject = { + id: '', + slug: '', + organization: { id: '', slug: '', name: '' }, + keys: [{ dsn: { public: '' } }], + }; + } else { + spotlight = false; + ({ selectedProject, authToken, selfHosted, sentryUrl } = projectData); + } } - const { logsEnabled } = await traceStep('configure-sdk', async () => { - const tunnelRoute = await askShouldSetTunnelRoute(); + const sdkAlreadyInstalled = hasPackageInstalled( + '@sentry/nextjs', + packageJson, + ); + Sentry.setTag('sdk-already-installed', sdkAlreadyInstalled); + const { packageManager: packageManagerFromInstallStep } = + await installPackage({ + packageName: '@sentry/nextjs@^10', + packageNameDisplayLabel: '@sentry/nextjs', + alreadyInstalled: !!packageJson?.dependencies?.['@sentry/nextjs'], + forceInstall, + }); + + // Determine tunnel route setting - use CLI flag if provided, otherwise prompt + const tunnelRoute = options.tunnelRoute ?? (await askShouldSetTunnelRoute()); + + const { logsEnabled } = await traceStep('configure-sdk', async () => { return await createOrMergeNextJsFiles( selectedProject, selfHosted, @@ -153,6 +189,8 @@ export async function runNextjsWizardWithTelemetry( tunnelRoute, }, spotlight, + options, + useEnvVars, ); }); @@ -377,7 +415,11 @@ export async function runNextjsWizardWithTelemetry( } }); - const shouldCreateExamplePage = await askShouldCreateExamplePage(); + // Example page - use CLI flag if provided, otherwise prompt (skip in skip-auth mode if not explicitly enabled) + const shouldCreateExamplePage = + options.examplePage ?? + (skipAuth ? false : await askShouldCreateExamplePage()); + if (shouldCreateExamplePage) { await traceStep('create-example-page', async () => createExamplePage( @@ -390,28 +432,72 @@ export async function runNextjsWizardWithTelemetry( ); } - if (!spotlight) { + // In skip-auth mode, create .env.example instead of .env.sentry-build-plugin + if (skipAuth) { + await traceStep('create-env-example', async () => { + const envExamplePath = path.join(process.cwd(), '.env.example'); + const envExampleExists = fs.existsSync(envExamplePath); + + if (envExampleExists) { + // Append Sentry env vars to existing .env.example + const existingContent = fs.readFileSync(envExamplePath, 'utf8'); + if (!existingContent.includes('SENTRY_DSN')) { + await fs.promises.appendFile( + envExamplePath, + '\n' + getSentryEnvExampleContents(), + 'utf8', + ); + clack.log.success( + `Added Sentry environment variables to ${chalk.cyan( + '.env.example', + )}.`, + ); + } else { + clack.log.info( + `${chalk.cyan( + '.env.example', + )} already contains Sentry configuration.`, + ); + } + } else { + await fs.promises.writeFile( + envExamplePath, + getSentryEnvExampleContents(), + { encoding: 'utf8', flag: 'w' }, + ); + clack.log.success(`Created ${chalk.cyan('.env.example')}.`); + } + }); + } else if (!spotlight) { await addDotEnvSentryBuildPluginFile(authToken); } + // Turbopack warning - log in skip-auth mode, prompt otherwise const isLikelyUsingTurbopack = await checkIfLikelyIsUsingTurbopack(); if (isLikelyUsingTurbopack || isLikelyUsingTurbopack === null) { - await abortIfCancelled( - clack.select({ - message: - 'Warning: The Sentry SDK is only compatible with Turbopack on Next.js version 15.4.1 or later.', - options: [ - { - label: 'I understand.', - hint: 'press enter', - value: true, - }, - ], - initialValue: true, - }), - ); + if (skipAuth) { + clack.log.warn( + 'The Sentry SDK is only compatible with Turbopack on Next.js version 15.4.1 or later.', + ); + } else { + await abortIfCancelled( + clack.select({ + message: + 'Warning: The Sentry SDK is only compatible with Turbopack on Next.js version 15.4.1 or later.', + options: [ + { + label: 'I understand.', + hint: 'press enter', + value: true, + }, + ], + initialValue: true, + }), + ); + } } + // CI setup - log in skip-auth mode, prompt/setup otherwise const mightBeUsingVercel = fs.existsSync( path.join(process.cwd(), 'vercel.json'), ); @@ -421,6 +507,15 @@ export async function runNextjsWizardWithTelemetry( "▲ It seems like you're using Vercel. We recommend using the Sentry Vercel \ integration to set up an auth token for Vercel deployments: https://vercel.com/integrations/sentry", ); + } else if (skipAuth) { + clack.log.info( + `To upload source maps in CI, set ${chalk.cyan( + 'SENTRY_AUTH_TOKEN', + )} environment variable. ` + + `Create a token at ${chalk.cyan( + 'https://sentry.io/orgredirect/organizations/:orgslug/settings/auth-tokens/', + )}`, + ); } else if (!spotlight) { await setupCI('nextjs', authToken, options.comingFrom); } @@ -428,27 +523,78 @@ export async function runNextjsWizardWithTelemetry( const packageManagerForOutro = packageManagerFromInstallStep ?? (await getPackageManager()); - // Offer optional project-scoped MCP config for Sentry with org and project scope - await offerProjectScopedMcpConfig( - selectedProject.organization.slug, - selectedProject.slug, - ); + // Handle MCP config - if --mcp flag provided, use it; otherwise offer interactive selection + if (options.mcp && options.mcp.length > 0) { + // Use CLI-provided MCP providers + // In skip-auth mode, use base MCP URL without org/project scope + const orgSlug = skipAuth ? undefined : selectedProject.organization.slug; + const projectSlug = skipAuth ? undefined : selectedProject.slug; + + clack.log.info('Adding MCP configurations...'); + + if (options.mcp.includes('cursor')) { + await addCursorMcpConfig(orgSlug, projectSlug); + } + if (options.mcp.includes('vscode')) { + await addVsCodeMcpConfig(orgSlug, projectSlug); + } + if (options.mcp.includes('claude')) { + await addClaudeCodeMcpConfig(orgSlug, projectSlug); + } + if (options.mcp.includes('opencode')) { + await addOpenCodeMcpConfig(orgSlug, projectSlug); + } + if (options.mcp.includes('jetbrains')) { + await showJetBrainsMcpConfig(orgSlug, projectSlug); + } + } else if (!skipAuth) { + // Offer optional project-scoped MCP config for Sentry with org and project scope + await offerProjectScopedMcpConfig( + selectedProject.organization.slug, + selectedProject.slug, + ); + } // Run formatters as the last step to fix any formatting issues in generated/modified files await runFormatters({ cwd: undefined }); - clack.outro(` + // Different outro message for skip-auth mode + if (skipAuth) { + clack.outro(` +${chalk.green('Successfully scaffolded the Sentry Next.js SDK!')} + +${chalk.yellow('Next steps:')} +1. Copy ${chalk.cyan('.env.example')} to ${chalk.cyan('.env.local')} +2. Fill in your Sentry DSN, org, project, and auth token from ${chalk.cyan( + 'https://sentry.io', + )} +3. Restart your dev environment (e.g. ${chalk.cyan( + `${packageManagerForOutro.runScriptCommand} dev`, + )}) + +${chalk.dim('Environment variables needed:')} + - NEXT_PUBLIC_SENTRY_DSN + - SENTRY_ORG + - SENTRY_PROJECT + - SENTRY_AUTH_TOKEN + +${chalk.dim( + 'If you encounter any issues, let us know here: https://github.com/getsentry/sentry-javascript/issues', +)}`); + } else { + clack.outro(` ${chalk.green('Successfully installed the Sentry Next.js SDK!')} ${ - shouldCreateExamplePage - ? `\n\nYou can validate your setup by (re)starting your dev environment (e.g. ${chalk.cyan( - `${packageManagerForOutro.runScriptCommand} dev`, - )}) and visiting ${chalk.cyan('"/sentry-example-page"')}` - : '' - } + shouldCreateExamplePage + ? `\n\nYou can validate your setup by (re)starting your dev environment (e.g. ${chalk.cyan( + `${packageManagerForOutro.runScriptCommand} dev`, + )}) and visiting ${chalk.cyan('"/sentry-example-page"')}` + : '' + } ${chalk.dim( 'If you encounter any issues, let us know here: https://github.com/getsentry/sentry-javascript/issues', )}`); + } } type SDKConfigOptions = { @@ -461,31 +607,94 @@ async function createOrMergeNextJsFiles( sentryUrl: string, sdkConfigOptions: SDKConfigOptions, spotlight = false, + wizardOptions: WizardOptions, + useEnvVars = false, ): Promise<{ logsEnabled: boolean }> { const dsn = selectedProject.keys[0].dsn.public; - const selectedFeatures = await featureSelectionPrompt([ - { - id: 'performance', - prompt: `Do you want to enable ${chalk.bold( - 'Tracing', - )} to track the performance of your application?`, - enabledHint: 'recommended', - }, - { - id: 'replay', - prompt: `Do you want to enable ${chalk.bold( - 'Session Replay', - )} to get a video-like reproduction of errors during a user session?`, - enabledHint: 'recommended, but increases bundle size', - }, - { - id: 'logs', - prompt: `Do you want to enable ${chalk.bold( - 'Logs', - )} to send your application logs to Sentry?`, - enabledHint: 'recommended', - }, - ] as const); + + // Check if CLI flags are provided for features + // If a flag is set (true or false), use it; otherwise prompt the user + const tracingFlagProvided = wizardOptions.tracing !== undefined; + const replayFlagProvided = wizardOptions.replay !== undefined; + const logsFlagProvided = wizardOptions.logs !== undefined; + + let selectedFeatures: { + performance: boolean; + replay: boolean; + logs: boolean; + }; + + // If all flags are provided via CLI, skip prompts entirely + if (tracingFlagProvided && replayFlagProvided && logsFlagProvided) { + selectedFeatures = { + performance: wizardOptions.tracing ?? false, + replay: wizardOptions.replay ?? false, + logs: wizardOptions.logs ?? false, + }; + clack.log.info( + `Features enabled: ${chalk.cyan( + [ + selectedFeatures.performance && 'Tracing', + selectedFeatures.replay && 'Session Replay', + selectedFeatures.logs && 'Logs', + ] + .filter(Boolean) + .join(', ') || 'None', + )}`, + ); + } else { + // Build list of features to prompt for (only those not provided via CLI) + const featuresToPrompt = []; + + if (!tracingFlagProvided) { + featuresToPrompt.push({ + id: 'performance' as const, + prompt: `Do you want to enable ${chalk.bold( + 'Tracing', + )} to track the performance of your application?`, + enabledHint: 'recommended', + }); + } + + if (!replayFlagProvided) { + featuresToPrompt.push({ + id: 'replay' as const, + prompt: `Do you want to enable ${chalk.bold( + 'Session Replay', + )} to get a video-like reproduction of errors during a user session?`, + enabledHint: 'recommended, but increases bundle size', + }); + } + + if (!logsFlagProvided) { + featuresToPrompt.push({ + id: 'logs' as const, + prompt: `Do you want to enable ${chalk.bold( + 'Logs', + )} to send your application logs to Sentry?`, + enabledHint: 'recommended', + }); + } + + // Prompt for features not provided via CLI + const promptedFeatures = + featuresToPrompt.length > 0 + ? await featureSelectionPrompt(featuresToPrompt) + : { performance: false, replay: false, logs: false }; + + // Merge CLI-provided flags with prompted values + selectedFeatures = { + performance: tracingFlagProvided + ? wizardOptions.tracing ?? false + : promptedFeatures.performance, + replay: replayFlagProvided + ? wizardOptions.replay ?? false + : promptedFeatures.replay, + logs: logsFlagProvided + ? wizardOptions.logs ?? false + : promptedFeatures.logs, + }; + } const typeScriptDetected = isUsingTypeScript(); @@ -546,6 +755,7 @@ async function createOrMergeNextJsFiles( configVariant, selectedFeatures, spotlight, + useEnvVars, ), { encoding: 'utf8', flag: 'w' }, ); @@ -713,7 +923,12 @@ async function createOrMergeNextJsFiles( const successfullyCreated = await createNewConfigFile( newInstrumentationClientHookPath, - getInstrumentationClientFileContents(dsn, selectedFeatures, spotlight), + getInstrumentationClientFileContents( + dsn, + selectedFeatures, + spotlight, + useEnvVars, + ), ); if (!successfullyCreated) { @@ -751,6 +966,7 @@ async function createOrMergeNextJsFiles( selfHosted, sentryUrl, tunnelRoute: sdkConfigOptions.tunnelRoute, + useEnvVars, }); const nextConfigPossibleFilesMap = { diff --git a/src/nextjs/templates.ts b/src/nextjs/templates.ts index 08ee1338a..23d1fd51a 100644 --- a/src/nextjs/templates.ts +++ b/src/nextjs/templates.ts @@ -1,12 +1,39 @@ import chalk from 'chalk'; import { makeCodeSnippet } from '../utils/clack'; +/** + * Generates the content for .env.example file with Sentry environment variables. + * Used in --skip-auth mode to document required environment variables. + */ +export function getSentryEnvExampleContents(): string { + return `# Sentry Configuration +# These environment variables are required for Sentry to work properly. +# Copy this file to .env.local and fill in the values from your Sentry project. + +# Your Sentry DSN (from Project Settings > Client Keys) +# The NEXT_PUBLIC_ prefix exposes this to the browser for client-side error reporting +NEXT_PUBLIC_SENTRY_DSN= + +# Your Sentry organization slug (from Organization Settings) +SENTRY_ORG= + +# Your Sentry project slug (from Project Settings) +SENTRY_PROJECT= + +# Auth token for source map uploads (from Organization Settings > Auth Tokens) +# Required for source map uploads during build +# Create a token with org:read and project:releases scopes +SENTRY_AUTH_TOKEN= +`; +} + type WithSentryConfigOptions = { orgSlug: string; projectSlug: string; selfHosted: boolean; sentryUrl: string; tunnelRoute: boolean; + useEnvVars?: boolean; }; export function getWithSentryConfigOptionsTemplate({ @@ -15,15 +42,19 @@ export function getWithSentryConfigOptionsTemplate({ selfHosted, tunnelRoute, sentryUrl, + useEnvVars = false, }: WithSentryConfigOptions): string { + const orgValue = useEnvVars ? 'process.env.SENTRY_ORG' : `"${orgSlug}"`; + const projectValue = useEnvVars + ? 'process.env.SENTRY_PROJECT' + : `"${projectSlug}"`; + return `{ // For all available options, see: // https://www.npmjs.com/package/@sentry/webpack-plugin#options - org: "${orgSlug}", - project: "${projectSlug}",${ - selfHosted ? `\n sentryUrl: "${sentryUrl}",` : '' - } + org: ${orgValue}, + project: ${projectValue},${selfHosted ? `\n sentryUrl: "${sentryUrl}",` : ''} // Only print logs for uploading source maps in CI silent: !process.env.CI, @@ -138,6 +169,7 @@ export function getSentryServersideConfigContents( logs: boolean; }, spotlight = false, + useEnvVars = false, ): string { let primer = ''; if (config === 'server') { @@ -169,13 +201,18 @@ export function getSentryServersideConfigContents( const spotlightOptions = getSpotlightOption(spotlight); + // Use NEXT_PUBLIC_SENTRY_DSN for consistency - it works on both server and client + const dsnValue = useEnvVars + ? 'process.env.NEXT_PUBLIC_SENTRY_DSN' + : `"${dsn}"`; + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions return `${primer} import * as Sentry from "@sentry/nextjs"; Sentry.init({ - dsn: "${dsn}",${performanceOptions}${logsOptions} + dsn: ${dsnValue},${performanceOptions}${logsOptions} // Enable sending user PII (Personally Identifiable Information) // https://docs.sentry.io/platforms/javascript/guides/nextjs/configuration/options/#sendDefaultPii @@ -192,6 +229,7 @@ export function getInstrumentationClientFileContents( logs: boolean; }, spotlight = false, + useEnvVars = false, ): string { const integrationsOptions = getClientIntegrationsSnippet({ replay: selectedFeaturesMap.replay, @@ -228,6 +266,11 @@ export function getInstrumentationClientFileContents( const spotlightOptions = getSpotlightOption(spotlight); + // Client-side needs NEXT_PUBLIC_ prefix for env vars + const dsnValue = useEnvVars + ? 'process.env.NEXT_PUBLIC_SENTRY_DSN' + : `"${dsn}"`; + return `// This file configures the initialization of Sentry on the client. // The added config here will be used whenever a users loads a page in their browser. // https://docs.sentry.io/platforms/javascript/guides/nextjs/ @@ -235,7 +278,7 @@ export function getInstrumentationClientFileContents( import * as Sentry from "@sentry/nextjs"; Sentry.init({ - dsn: "${dsn}",${integrationsOptions}${performanceOptions}${logsOptions}${replayOptions} + dsn: ${dsnValue},${integrationsOptions}${performanceOptions}${logsOptions}${replayOptions} // Enable sending user PII (Personally Identifiable Information) // https://docs.sentry.io/platforms/javascript/guides/nextjs/configuration/options/#sendDefaultPii diff --git a/src/run.ts b/src/run.ts index c3304b08e..c9b48b763 100644 --- a/src/run.ts +++ b/src/run.ts @@ -68,6 +68,15 @@ type Args = { comingFrom?: string; ignoreGitChanges?: boolean; xcodeProjectDir?: string; + + // Headless mode options + skipAuth?: boolean; + tracing?: boolean; + replay?: boolean; + logs?: boolean; + tunnelRoute?: boolean; + examplePage?: boolean; + mcp?: string[]; }; function preSelectedProjectArgsToObject( @@ -156,6 +165,14 @@ export async function run(argv: Args) { comingFrom: finalArgs.comingFrom, ignoreGitChanges: finalArgs.ignoreGitChanges, spotlight: finalArgs.spotlight, + // Headless mode options + skipAuth: finalArgs.skipAuth, + tracing: finalArgs.tracing, + replay: finalArgs.replay, + logs: finalArgs.logs, + tunnelRoute: finalArgs.tunnelRoute, + examplePage: finalArgs.examplePage, + mcp: finalArgs.mcp, }; switch (integration) { diff --git a/src/utils/clack/mcp-config.ts b/src/utils/clack/mcp-config.ts index 99c0655d3..4c97d738d 100644 --- a/src/utils/clack/mcp-config.ts +++ b/src/utils/clack/mcp-config.ts @@ -143,7 +143,7 @@ function getGenericMcpJsonSnippet( return JSON.stringify(obj, null, 2); } -async function addCursorMcpConfig( +export async function addCursorMcpConfig( orgSlug?: string, projectSlug?: string, ): Promise { @@ -172,7 +172,7 @@ async function addCursorMcpConfig( } } -async function addVsCodeMcpConfig( +export async function addVsCodeMcpConfig( orgSlug?: string, projectSlug?: string, ): Promise { @@ -202,7 +202,7 @@ async function addVsCodeMcpConfig( } } -async function addClaudeCodeMcpConfig( +export async function addClaudeCodeMcpConfig( orgSlug?: string, projectSlug?: string, ): Promise { @@ -229,7 +229,7 @@ async function addClaudeCodeMcpConfig( } } -async function addOpenCodeMcpConfig( +export async function addOpenCodeMcpConfig( orgSlug?: string, projectSlug?: string, ): Promise { @@ -296,7 +296,7 @@ async function copyToClipboard(text: string): Promise { /** * Shows MCP configuration for JetBrains IDEs with copy-to-clipboard option */ -async function showJetBrainsMcpConfig( +export async function showJetBrainsMcpConfig( orgSlug?: string, projectSlug?: string, ): Promise { diff --git a/src/utils/types.ts b/src/utils/types.ts index 9f4e2dd49..be8b9fccd 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -89,6 +89,56 @@ export type WizardOptions = { * This can be passed via the `--spotlight` arg. */ spotlight?: boolean; + + /** + * Skip Sentry authentication and use environment variable placeholders. + * Enables fully headless CLI operation where an agent can populate values later. + * This can be passed via the `--skip-auth` arg. + */ + skipAuth?: boolean; + + /** + * Enable performance/tracing monitoring. + * When set, skips the tracing prompt. + * This can be passed via the `--tracing` arg. + */ + tracing?: boolean; + + /** + * Enable Session Replay. + * When set, skips the replay prompt. + * This can be passed via the `--replay` arg. + */ + replay?: boolean; + + /** + * Enable Sentry Logs. + * When set, skips the logs prompt. + * This can be passed via the `--logs` arg. + */ + logs?: boolean; + + /** + * Enable tunnel route for ad-blocker circumvention. + * When set, skips the tunnel route prompt. + * This can be passed via the `--tunnel-route` arg. + */ + tunnelRoute?: boolean; + + /** + * Create an example page to test Sentry. + * When set, skips the example page prompt. + * This can be passed via the `--example-page` arg. + */ + examplePage?: boolean; + + /** + * MCP (Model Context Protocol) providers to configure. + * Options: cursor, vscode, claude, opencode, jetbrains + * This can be passed via the `--mcp` arg. + * Example: `--mcp cursor --mcp vscode` or `--mcp cursor,vscode` + */ + mcp?: string[]; }; export interface Feature {