diff --git a/src/commands/local/run.ts b/src/commands/local/run.ts index 03642dfc7..ed2556386 100644 --- a/src/commands/local/run.ts +++ b/src/commands/local/run.ts @@ -406,8 +406,15 @@ async function* runWithVerify( ); } - const onSigint = () => child.kill("SIGINT"); - const onSigterm = () => child.kill("SIGTERM"); + let signalReceived: NodeJS.Signals | null = null; + const onSigint = () => { + signalReceived = "SIGINT"; + child.kill("SIGINT"); + }; + const onSigterm = () => { + signalReceived = "SIGTERM"; + child.kill("SIGTERM"); + }; process.once("SIGINT", onSigint); process.once("SIGTERM", onSigterm); @@ -465,6 +472,13 @@ async function* runWithVerify( await shutdownServer(server); } + // Re-emit the signal after cleanup so the default handler terminates the + // process instead of continuing with the outcome switch below. + if (signalReceived) { + process.kill(process.pid, signalReceived); + return; + } + switch (outcome.kind) { case "envelope": { logger.info("Setup verified — your app is sending events to Sentry"); diff --git a/src/lib/init/verify-setup.ts b/src/lib/init/verify-setup.ts index 20e4bf0ed..a2c86d5f1 100644 --- a/src/lib/init/verify-setup.ts +++ b/src/lib/init/verify-setup.ts @@ -282,6 +282,9 @@ export async function verifySetup( return; } + // Track whether the user sent an interrupt so we can re-emit it after + // cleanup instead of silently continuing the wizard. + let signalReceived: NodeJS.Signals | null = null; const safeKill = (sig: NodeJS.Signals) => { try { child.kill(sig); @@ -289,8 +292,14 @@ export async function verifySetup( logger.debug(`Child already exited when forwarding ${sig}`); } }; - const onSigint = () => safeKill("SIGINT"); - const onSigterm = () => safeKill("SIGTERM"); + const onSigint = () => { + signalReceived = "SIGINT"; + safeKill("SIGINT"); + }; + const onSigterm = () => { + signalReceived = "SIGTERM"; + safeKill("SIGTERM"); + }; process.once("SIGINT", onSigint); process.once("SIGTERM", onSigterm); @@ -333,6 +342,14 @@ export async function verifySetup( process.removeListener("SIGTERM", onSigterm); await shutdownServer(server); + // Re-emit the signal after cleanup so the default handler terminates the + // process. Without this, Ctrl+C during verification would be swallowed and + // the wizard would continue as if nothing happened. + if (signalReceived) { + process.kill(process.pid, signalReceived); + return; + } + // If the child crashed (non-zero exit) but the startup watcher resolved // first as "started" or "silent", correct to "exited" so the crash is // reported instead of a false success or misleading timeout message.