From 363fcdc4616fbc4b056ab777a492e3f31bd0428a Mon Sep 17 00:00:00 2001 From: Sentry Bot Date: Sat, 2 May 2026 03:44:49 +0000 Subject: [PATCH 1/2] feat(init): suppress ASCII art banner for agent-driven runs Fixes #889 When an AI agent invokes `sentry init` and the run fails early (e.g. missing org context), the large Sentry ASCII art banner was printed unconditionally before the error, wasting tokens and adding noise to structured agent output. Call `detectAgent()` synchronously in `preamble()` and skip the `process.stderr.write` banner call when an agent is detected. The `intro("sentry init")` line and all subsequent wizard logic are unaffected. --- src/lib/init/wizard-runner.ts | 7 ++++- test/lib/init/wizard-runner.test.ts | 43 +++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/lib/init/wizard-runner.ts b/src/lib/init/wizard-runner.ts index 162fef049..696bbb299 100644 --- a/src/lib/init/wizard-runner.ts +++ b/src/lib/init/wizard-runner.ts @@ -12,6 +12,7 @@ import { MastraClient } from "@mastra/client-js"; import { captureException, getTraceData } from "@sentry/node-core/light"; import { formatBanner } from "../banner.js"; import { CLI_VERSION } from "../constants.js"; +import { detectAgent } from "../detect-agent.js"; import { EXIT, WizardError } from "../errors.js"; import { terminalLink } from "../formatters/colors.js"; import { @@ -328,7 +329,11 @@ async function preamble( ); } - process.stderr.write(`\n${formatBanner()}\n\n`); + // Suppress the ASCII art banner for agent-driven runs — it wastes tokens + // and adds noise to structured output without providing value to the agent. + if (!detectAgent()) { + process.stderr.write(`\n${formatBanner()}\n\n`); + } intro("sentry init"); let confirmed: boolean; diff --git a/test/lib/init/wizard-runner.test.ts b/test/lib/init/wizard-runner.test.ts index a8d9a9ddc..09b664879 100644 --- a/test/lib/init/wizard-runner.test.ts +++ b/test/lib/init/wizard-runner.test.ts @@ -13,6 +13,8 @@ import { MastraClient } from "@mastra/client-js"; // biome-ignore lint/performance/noNamespaceImport: spyOn requires object reference import * as banner from "../../../src/lib/banner.js"; import { WizardError } from "../../../src/lib/errors.js"; +import { ENV_VAR_AGENTS } from "../../../src/lib/detect-agent.js"; +import { setEnv } from "../../../src/lib/env.js"; import { WizardCancelledError } from "../../../src/lib/init/clack-utils.js"; // biome-ignore lint/performance/noNamespaceImport: spyOn requires object reference import * as fmt from "../../../src/lib/init/formatters.js"; @@ -223,6 +225,9 @@ afterEach(() => { } else { process.env.SENTRY_PLAIN_OUTPUT = savedPlainOutput; } + + // Restore the env sandbox in case any test used setEnv without try/finally. + setEnv(process.env); }); describe("runWizard", () => { @@ -278,6 +283,44 @@ describe("runWizard", () => { expect(getWorkflowSpy).not.toHaveBeenCalled(); }); + test("suppresses the ASCII art banner when an agent is detected", async () => { + setEnv({ ...process.env, CLAUDE_CODE: "1" } as NodeJS.ProcessEnv); + try { + await runWizard(makeOptions()); + } finally { + setEnv(process.env); + } + + expect(formatBannerSpy).not.toHaveBeenCalled(); + expect(stderrSpy).not.toHaveBeenCalledWith( + expect.stringContaining("BANNER") + ); + }); + + test("prints the ASCII art banner when no agent is detected", async () => { + // Strip all agent-detection env vars so detectAgent() returns undefined + // even when running inside an agent environment (e.g. OpenCode in CI). + const agentKeys = new Set([ + "AI_AGENT", + "AGENT", + "CLAUDECODE", + "CLAUDE_CODE", + ...ENV_VAR_AGENTS.keys(), + ]); + const cleanEnv = Object.fromEntries( + Object.entries(process.env).filter(([k]) => !agentKeys.has(k)) + ); + setEnv(cleanEnv as NodeJS.ProcessEnv); + try { + await runWizard(makeOptions()); + } finally { + setEnv(process.env); + } + + expect(formatBannerSpy).toHaveBeenCalled(); + expect(stderrSpy).toHaveBeenCalledWith(expect.stringContaining("BANNER")); + }); + test("dispatches tool payloads through the registry", async () => { const payload: ToolPayload = { type: "tool", From f05b897d21bff5a6d984cf57f82691bcb278eaf1 Mon Sep 17 00:00:00 2001 From: Sentry Bot Date: Sat, 2 May 2026 03:59:22 +0000 Subject: [PATCH 2/2] Fix CI: sort imports and remove unused biome-ignore suppression Two lint errors caused the Build job to fail: 1. test/lib/init/wizard-runner.test.ts: Biome's organizeImports rule flagged the three new local imports (detect-agent.js, env.js, errors.js) as out of alphabetical order. Sorted them so detect-agent.js and env.js precede errors.js. 2. src/lib/formatters/markdown.ts:281: A biome-ignore suppression for lint/complexity/noExcessiveCognitiveComplexity on renderOneInline() was flagged as unused (the function's complexity score no longer exceeds the threshold). Removed the now-stale suppression comment. Failed run: https://github.com/getsentry/cli/actions/runs/25243031491 --- src/lib/formatters/markdown.ts | 1 - test/lib/init/wizard-runner.test.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib/formatters/markdown.ts b/src/lib/formatters/markdown.ts index f2b71fdc0..cddc104a5 100644 --- a/src/lib/formatters/markdown.ts +++ b/src/lib/formatters/markdown.ts @@ -278,7 +278,6 @@ function renderCodespan(token: Tokens.Codespan): string { /** * Render a single inline token to an ANSI string. */ -// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: inline token switch is inherently branchy function renderOneInline(token: Token): string { switch (token.type) { case "strong": diff --git a/test/lib/init/wizard-runner.test.ts b/test/lib/init/wizard-runner.test.ts index 09b664879..cc422856d 100644 --- a/test/lib/init/wizard-runner.test.ts +++ b/test/lib/init/wizard-runner.test.ts @@ -12,9 +12,9 @@ import * as clack from "@clack/prompts"; import { MastraClient } from "@mastra/client-js"; // biome-ignore lint/performance/noNamespaceImport: spyOn requires object reference import * as banner from "../../../src/lib/banner.js"; -import { WizardError } from "../../../src/lib/errors.js"; import { ENV_VAR_AGENTS } from "../../../src/lib/detect-agent.js"; import { setEnv } from "../../../src/lib/env.js"; +import { WizardError } from "../../../src/lib/errors.js"; import { WizardCancelledError } from "../../../src/lib/init/clack-utils.js"; // biome-ignore lint/performance/noNamespaceImport: spyOn requires object reference import * as fmt from "../../../src/lib/init/formatters.js";