Repository navigation
fix(theme): select the nearest 256-color palette entry - #3112
Conversation
|
Took a close read of this since it supersedes my Three things surfaced that I think block a clean merge, flagging so they don't bite later:
I've got a validated regen + changelog-move patch ready to hand over once #2464 is in, if that's useful. Nice work. |
|
@mpaiva Thanks for the detailed review and your original investigation on #2550, and welcome back! Since this was originally assigned to you, would you like to take over the remaining work on #3112 end to end? Please feel free to continue from the existing implementation. That includes bringing it up to date with main, keeping success/error/pending backgrounds distinguishable in 256-color mode, removing the unrelated native-binding changes, moving the changelog entry into Your proposed ordering makes sense: land #2464 first, then regenerate the contrast baseline here. Please take those updates through together, including any remaining review feedback and CI failures. We'll hold off on further edits to this branch so there's no overlap. Thanks again for picking this back up! |
|
@flora131 Picked this back up and completed the unblocked Phase 1 work. I don't have push access to the git fetch https://github.com/mpaiva/atomic.git fix/2550-nearest-256-color-phase1
git push origin FETCH_HEAD:fix/2550-nearest-256-color --force-with-lease=fix/2550-nearest-256-color:0fb56d5ecWhat changed
Final diff is limited to: Verification
Deliberately out of scope (as agreed)
Measurement-only, no baseline regen, no native changes. |
|
@mpaiva Thanks so much for picking this up and finishing the remaining work! Sorry, I missed that this branch lives in the org repo, so you couldn't push to it when we handed it over. Could you open a new PR from your fork with Once your new PR is open, we'll close this one and point to yours. We'll handle the fork CI approvals and review there. Thanks again! |
0fb56d5 to
ac0d715
Compare
Compare every grayscale candidate by weighted RGB distance and remove the saturation gate. Preserve exact cube search and cube tie preference. Fixes #2550 Assistant-model: GPT-5.5
Review feedback: root suites import TypeScript sources with .js ESM
specifiers. Rebased onto main; the accidentally regenerated native
binding loader (packages/natives/native/index.{js,d.ts}) is no longer
part of this change, and the changelog entry moved to Unreleased.
Assistant-model: Claude Opus 5.5
Assistant-workflow: issues-to-merged-prs (run 190ca577-ae43-4b81-838d-931a3186d654)
Assistant-verification: npm run check passed: biome, both typecheck passes, shrinkwrap
Assistant-verification: vitest unit passed: test/unit/theme-color-quantization.test.ts test/unit/changelog.test.ts
Assistant-verification: vitest coding-agent passed: test/atomic-working-status.test.ts
Co-authored-by: Norin Lavaee <nlavaee@umich.edu>
…tion Name the #2550 regressions in their test names, expect gray 237 for the #3c3544 user-message background in the resource-loader color-mode tests, and pin the subagent notification tool-block test to truecolor so it checks status-token routing rather than the 256-color palette, where the dark success and error backgrounds now both map to gray 236. Assistant-model: Claude Opus 5.5 Assistant-workflow: issues-to-merged-prs (run 190ca577-ae43-4b81-838d-931a3186d654) Assistant-verification: vitest unit passed: theme-color-quantization and subagents-notification-tool-block with COLORTERM unset and TERM empty Assistant-verification: vitest agent passed: npm run test --workspace=@bastani/atomic (752 files, 6628 tests) in 256-color env Assistant-verification: npm run check passed: biome, bun typecheck, shrinkwrap Assistant-verification: vitest unit failed: npm run test:unit locally, only subagents-run-control and task-stage-pause, which fail because the local native binding is stale (CancelCause lacks pause/quit) and pass in CI Co-authored-by: Norin Lavaee <nlavaee@umich.edu>
Nearest-entry quantization (#2550) collapsed the dark theme's tool status backgrounds to grays (pending 235, success 236, error 236), so success and error became identical in 256-color terminals. Tool status background tokens now quantize to the nearest palette entry whose strongest RGB channels match the source color, restoring 17/22/52 for the dark theme while ordinary backgrounds keep the nearest-entry result (#343541 -> 237). The Catppuccin themes drew all three status backgrounds on surface_0; success and error are now green and red tints so every bundled theme keeps the three states distinct. Reverts the COLORTERM=truecolor stub in the subagent notification tool-block test so it covers 256-color mode again. Assistant-model: Claude Opus 5.5 Assistant-workflow: issues-to-merged-prs (run acd9434d-9aeb-4b9f-88d6-07be4d11ca63) Assistant-verification: vitest unit passed: theme-color-quantization.test.ts (5 tests) and subagents-notification-tool-block.test.ts under TERM=dumb with COLORTERM unset (256-color) Assistant-verification: vitest unit passed: new regression failed with status tokens forced to nearest (RED) and passed after (GREEN) Assistant-verification: npm run check passed: biome, bun typecheck, shrinkwrap Assistant-verification: vitest coding-agent passed: npm run test --workspace=@bastani/atomic, 6766 tests Assistant-verification: vitest unit failed: npm run test:unit under TERM=dumb, 15 failures only in interactive-engine-remote-input.test.ts, which also fail without this change under TERM=dumb and pass in the default environment User-preference: keep status hues in 256-color mode; status colors must stay distinguishable in every bundled theme Co-authored-by: Norin Lavaee <nlavaee@umich.edu>
47dadc1 to
21f293c
Compare
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Automations to automatically generate PRs for you. |
Revert the Catppuccin toolSuccessBg/toolErrorBg tints and their changelog entry. The 256-color regression test now requires the three tool status backgrounds to stay pairwise distinct only when they differ in truecolor, and separately requires dark and light to keep them distinct. Assistant-model: Claude Opus 5.5 Assistant-workflow: issues-to-merged-prs (run 1493dde6-a26c-48dc-b68d-cd56c57db25f) Assistant-verification: vitest unit passed: test/unit/theme-color-quantization.test.ts and test/unit/subagents-notification-tool-block.test.ts Assistant-verification: vitest coding-agent passed: test/atomic-working-status.test.ts and test/resource-loader-theme.test.ts Assistant-verification: npm run check passed: biome, bun check typecheck, shrinkwrap User-preference: keep status hues in 256-color mode without redesigning themes; Catppuccin keeps surface_0 for all tool status backgrounds Co-authored-by: Norin Lavaee <nlavaee@umich.edu>
Summary
Fixes #2550. In 256-color terminals, ordinary theme colors now use the nearest 256-color palette entry (all 216 cube colors and 24 grayscale colors under the existing weighted RGB distance). Tool status backgrounds keep their hue, so 256-color quantization never merges tool status colors that a theme keeps distinct in truecolor. No bundled theme's colors change.
Final behavior
Ordinary colors: nearest entry
#2f3a2f).#343541(darkuserMessageBg)237 / #3a3a3a(was59 / #5f5f5f)#2f3a2f237 / #3a3a3a#282832via plainbgAnsi235 / #262626#808080The 256-color status-hue rule
toolPendingBg,toolSuccessBg, andtoolErrorBgare markedstatus: trueinTHEME_TOKENS. In 256-color mode theThemequantizes them withpreserve-hue: the nearest palette entry whose set of strongest RGB channels equals the source's. A blue-dominant color stays blue, a green-dominant one stays green, and a neutral color (all channels equal) can only map to a gray, which is the same as the nearest entry. Explicit palette indices in a theme are still used as given.The rule: if a theme keeps its three tool status backgrounds distinct in truecolor, they stay distinct in 256-color mode. A theme that deliberately draws them on one color keeps them on one color.
Why this mechanism:
THEME_TOKENSalready describes every token in one place, so marking which tokens carry status is one flag there. No schema change and no new theme-file field.dark.jsonkeep their tinted status blocks instead of collapsing to grays.spread < 10gate 256-color quantization: rgbTo256() collapses near-neutral dark backgrounds to #5f5f5f (saturated corners for tool bgs) #2550 removed: it brings back#343541 → #5f5f5ffor message and selection backgrounds.The Catppuccin themes are unchanged from
main: they deliberately usesurface_0for all three tool status backgrounds in every color mode, so they stay equal in 256-color mode too.Trade-off
#282832as a status token. #2550 liststoolPendingBg #282832 → #00005fas a defect and expects the gray235. That conflicts with keeping status hues, so status wins: the dark pending tool background renders as17, as onmain. PlainbgAnsi("#282832", "256color")and every non-status token still give235. The issue's other status rows (#283228,#3c2828) likewise keep theirmainhues (22/52). The non-status rows (#343541,#3a3a4a,#363a4f) get the grays the issue asked for.Changes
color-utils.ts: nearest-entry quantization for ordinary colors, plusQuantization = "nearest" | "preserve-hue"as an optionalbgAnsiargument (defaultnearest).theme-tokens.ts/theme-class.ts:status: trueon the three tool status backgrounds;Themequantizes those withpreserve-hue.test/unit/theme-color-quantization.test.ts): exact 256-color quantization: rgbTo256() collapses near-neutral dark backgrounds to #5f5f5f (saturated corners for tool bgs) #2550 regressions; a stride-5 sweep (140,608 inputs) that the plain path is always a nearest entry; for every bundled theme, the pending/success/error backgrounds keep their source's strongest channels in 256-color mode and are pairwise distinct there whenever they are pairwise distinct in truecolor (Catppuccin passes with all three equal); dark and light keep the three distinct in truecolor; dark is pinned to 17/22/52 withuserMessageBg237.test/unit/subagents-notification-tool-block.test.ts: theCOLORTERM=truecolorstub from 47dadc1 is reverted. The file is byte-identical tomainand passes in 256-color mode.238,#767676…#eeeeee,237).docs/themes/reference.mddocuments the status-hue rule; one changelog entry under Fixed.Verification
npx vitest --run --project unit test/unit/theme-color-quantization.test.ts test/unit/subagents-notification-tool-block.test.tsnpx vitest --run test/atomic-working-status.test.ts test/resource-loader-theme.test.ts(coding-agent)npm run checkAssistant-workflow: issues-to-merged-prs (run 1493dde6-a26c-48dc-b68d-cd56c57db25f)
Assistant-verification: vitest unit passed: theme-color-quantization and subagents-notification-tool-block in 256-color mode
Assistant-verification: vitest coding-agent passed: atomic-working-status and resource-loader-theme
Assistant-verification: npm run check passed: biome, typecheck, shrinkwrap
Assistant-verification: GitHub Actions CI passed: test (all platforms) on ad2340f (unit, integration, agent-suite, static-checks, release-archive on linux-x64 and windows-x64; CodeQL)
Assistant-verification: Greptile review passed: confidence 5/5, no outstanding findings on ad2340f
User-preference: keep status hues in 256-color mode; 256-color quantization must never merge tool status colors a theme keeps distinct; not a theme redesign, Catppuccin keeps surface_0
User-preference: loop each PR until CI is green and Greptile has no feedback, then merge
Assistant-duration: 24m converged, estimated 2h
Co-authored-by: Norin Lavaee nlavaee@umich.edu


Confidence Score: 5/5
No outstanding findings prevent merging the reviewed changes.Summary
Ordinary theme colors now use the nearest cube or grayscale entry in 256-color terminals. Tool status backgrounds use a separate rule that preserves their strongest RGB channels.
No blocking issues were identified in the reviewed changes.
Reviews (6) · Last reviewed commit: "fix(theme): restore Catppuccin tool stat..." · Reviewed by Greptile