Skip to content

fix: avoid mutating tinyrainbow default colors in agent mode#10062

Open
teee32 wants to merge 3 commits intovitest-dev:mainfrom
teee32:fix/agent-colors-tinyrainbow
Open

fix: avoid mutating tinyrainbow default colors in agent mode#10062
teee32 wants to merge 3 commits intovitest-dev:mainfrom
teee32:fix/agent-colors-tinyrainbow

Conversation

@teee32
Copy link
Copy Markdown

@teee32 teee32 commented Apr 4, 2026

Problem

In agent environments, Vitest disabled colors by mutating tinyrainbow's shared default export. That leaked into user code running under test, so code importing tinyrainbow could unexpectedly lose ANSI output.

Reproduction / Observation

Issue #10046 reports that agent detection turns tinyrainbow color functions into identity functions for user code. This change adds a regression that runs Vitest in agent mode and verifies user code can still observe tinyrainbow color output while Vitest reporter output remains uncolored.

Root cause

Vitest called disableDefaultColors() on the shared tinyrainbow singleton during CLI and worker startup. Because user code and Vitest resolve the same default export, that mutation escaped Vitest internals.

Change

  • remove the global disableDefaultColors() calls from CLI and worker startup
  • introduce a Vitest-local colors wrapper in packages/vitest/src/utils/colors.ts
  • switch Vitest internal color consumers in packages/vitest/src/** to use that local wrapper
  • add an agent-mode regression fixture/test covering user-imported tinyrainbow

Why this fix

This preserves the existing agent-mode intent for Vitest’s own output, but stops mutating shared library state that user code depends on. It is a narrow internal fix with a direct regression test.

Risk

Low to moderate. The behavior change is limited to how Vitest sources internal colors in agent mode. No public API changes are involved.

Validation

  • cd vitest/test/config && pnpm exec vitest run test/console-color.test.ts -t 'agent'
  • cd vitest && pnpm --filter vitest build
  • cd vitest && pnpm exec eslint packages/vitest/src/utils/colors.ts packages/vitest/src/node/cli/cac.ts packages/vitest/src/runtime/workers/init.ts test/config/test/console-color.test.ts test/config/fixtures/console-color-agent-user-code/basic.test.ts test/config/fixtures/console-color-agent-user-code/vitest.config.ts --no-ignore
  • cd vitest && git diff --check

Closes #10046

Vitest disabled colors in agent mode by mutating tinyrainbow's
shared default export during CLI and worker startup. That made
user code importing tinyrainbow observe identity color formatters,
which violates the boundary between Vitest internals and the code
under test.

This change removes the global mutation path and routes Vitest's
internal color consumers through a local wrapper that uses a
non-mutating disabled-colors instance only when agent mode is on.
A focused config regression covers the user-code boundary while
keeping reporter output uncolored in agent mode.

Constraint: Only core-code fixes are allowed for this run
Constraint: The fix must stay small and avoid public API changes
Rejected: Leave disableDefaultColors in place and patch specific call sites | still leaks shared state to user code
Rejected: Add a test-only PR without code changes | user explicitly rejected non-core-code submissions
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep internal color policy isolated from shared third-party singletons unless cross-package behavior is explicitly intended
Tested: pnpm --filter vitest build
Tested: pnpm exec vitest run test/console-color.test.ts -t 'agent'
Tested: pnpm exec eslint packages/vitest/src/utils/colors.ts packages/vitest/src/node/cli/cac.ts packages/vitest/src/runtime/workers/init.ts test/config/test/console-color.test.ts test/config/fixtures/console-color-agent-user-code/basic.test.ts test/config/fixtures/console-color-agent-user-code/vitest.config.ts --no-ignore
Tested: git diff --check
Not-tested: Full monorepo test suite
Related: vitest-dev#10046
@netlify
Copy link
Copy Markdown

netlify bot commented Apr 4, 2026

Deploy Preview for vitest-dev ready!

Built without sensitive environment variables

Name Link
🔨 Latest commit 6bb6c43
🔍 Latest deploy log https://app.netlify.com/projects/vitest-dev/deploys/69d137639e787a0008c275cd
😎 Deploy Preview https://deploy-preview-10062--vitest-dev.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

The regression fixture relies on a runtime alias to load tinyrainbow,
but the test/config package does not declare tinyrainbow as a direct
devDependency. CI typecheck therefore rejects the import even though the
fixture is intentionally resolved by Vitest config at runtime.

This records that expectation explicitly on the fixture import so the
focused regression remains small and the lint job stops failing on the
known fixture-only resolution gap.

Constraint: The PR must stay narrowly scoped to the vitest-dev#10046 regression
Rejected: Add tinyrainbow to test/config devDependencies | widens package metadata for a fixture-only need
Rejected: Rework the fixture to avoid tinyrainbow import | would weaken direct coverage of the reported user-code boundary
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: If fixture resolution should become statically typed later, prefer a package-local declaration over growing runtime-only aliases
Tested: pnpm exec eslint test/config/fixtures/console-color-agent-user-code/basic.test.ts --no-ignore
Tested: cd test/config && pnpm exec vitest run test/console-color.test.ts -t 'agent keeps tinyrainbow colors enabled in user code'
Not-tested: Full monorepo CI rerun after push
Related: vitest-dev#10046
Related: vitest-dev#10062
EOF && git push
Copy link
Copy Markdown
Member

@sheremet-va sheremet-va left a comment

Choose a reason for hiding this comment

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

This is AI slop. The issue is bigger - we use tinyrainbow in multiple packages, including expect, pretty-format and utils

The initial fix stopped Vitest from mutating tinyrainbow's shared
singleton, but maintainer review correctly pointed out that agent-mode
color policy still leaked through other internal packages that import
and use tinyrainbow directly.

This follow-up routes internal color consumers in utils, expect,
pretty-format, browser, UI, and coverage/browser-playwright helpers
through detached agent-aware wrappers, while preserving user-space
imports of tinyrainbow. The config regression suite now also proves
that failed matcher output stays uncolored in agent mode while user code
still sees ANSI colors from tinyrainbow.

Constraint: Review feedback requires covering shared internal packages, not just packages/vitest
Constraint: Avoid introducing a utils <-> pretty-format package cycle
Rejected: Keep the fix scoped to packages/vitest | reviewer confirmed the behavior boundary is wider
Rejected: Make pretty-format depend on @vitest/utils/colors | would create a package cycle because utils already depends on pretty-format
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: New internal color consumers should use package-local or shared detached wrappers instead of importing tinyrainbow default state directly in agent-sensitive paths
Tested: pnpm build
Tested: cd test/config && pnpm exec vitest run test/console-color.test.ts -t 'agent'
Tested: pnpm exec eslint packages/utils/src/colors.ts packages/utils/src/diff/index.ts packages/utils/src/diff/normalizeDiffOptions.ts packages/expect/src/types.ts packages/expect/src/jest-matcher-utils.ts packages/expect/src/jest-expect.ts packages/pretty-format/src/index.ts packages/pretty-format/src/colors.ts packages/browser/src/node/index.ts packages/ui/node/index.ts packages/ui/node/reporter.ts packages/coverage-v8/src/provider.ts packages/coverage-istanbul/src/provider.ts packages/browser-playwright/src/playwright.ts packages/vitest/src/utils/colors.ts test/config/test/console-color.test.ts test/config/fixtures/console-color-agent-expect/basic.test.ts test/config/fixtures/console-color-agent-user-code/basic.test.ts --no-ignore
Tested: git diff --check
Not-tested: Full PR CI after push
Related: vitest-dev#10046
Related: vitest-dev#10062
EOF && git push
@teee32
Copy link
Copy Markdown
Author

teee32 commented Apr 4, 2026

Thanks — you were right that the first pass was too narrow. I pushed a follow-up that routes agent-mode color handling through detached wrappers across the shared internal paths called out in review, including utils / expect / pretty-format, plus the remaining internal tinyrainbow consumers that participate in agent-sensitive output. I also added a regression covering failed matcher output in agent mode while keeping user-imported tinyrainbow colors enabled.

@sheremet-va sheremet-va added the maybe automated User is likely an AI agent, or the content was generated by an AI assistant without user control label Apr 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

maybe automated User is likely an AI agent, or the content was generated by an AI assistant without user control

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Agent detection disables colors in user code via shared tinyrainbow singleton

2 participants