feat: custom accent and user-message-box colors #49
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "clfy-21-custom-colors"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes CLFY-21
accentColor(wasclaude|theme) anduserMessageBox(wastheme|claude|off) nowalso accept a user-supplied hex. Both reuse the existing
footerColortext-row machinery —same
normalizeHexColorvalidation, same inline text sub-mode — rather than adding a secondhex input path. The keywords keep working exactly as before; a hex is simply another accepted
value.
Storing escapes, never hex
pi's
Themestores ready-made ANSI escapes infgColors/bgColors—fg()onlyconcatenates. Storing hex renders a literal
#B1B9F9, widening the line past the terminal,and pi's renderer throws on overflow. That is the 2.3.0 crash, so this is the invariant the
feature had to respect.
Rather than hand-rolling a second quantizer,
ansiFromHexconstructs a throwaway piThemeand reads
getFgAnsi/getBgAnsiback out, delegating conversion to pi's ownfgAnsi/bgAnsi. Verified against pi's compiled source (not its.d.tsalone): the constructoriterates only the keys you pass, so the partial color records are safe, and both lookups use
fixed keys that are always present. Tests assert the stored value is an escape and never hex,
in both truecolor and 256-color mode.
Review gate found a real bug (fixed in
c78b609)Setting a custom accent and switching back to
Accent: themenever restored pi's own accent —the custom color stranded itself until pi restarted. Reproduced before fixing:
pi hands the same logical theme over as both the instance and a forwarding Proxy, and the
snapshot
WeakMapwas keyed on object identity — so whichever identity arrived second saw theoverride already installed and never recorded the theme's real accent.
CC_ACCENT_VALUESexisted to prevent exactly this, but listed only the two captured lavenders, so a custom hex
fell straight through.
Note this was latent for the
claudeaccent too: the same restore path was already brokenbefore this ticket. The custom-color work only made it reachable.
Fix: key the snapshot on the
fgColorscontainer (which forwards through the Proxy, so itidentifies the logical theme), and recognize every escape claudify imposes rather than a
fixed list. A Proxy regression test now covers it.
Review
An adversarial reviewer independently identified the same Proxy/snapshot corruption from the
pre-fix code, and independently verified the
PiThemeconstructor contract against pi'ssource. It found no other high-confidence issues, and traced two open concerns to ground:
writeSettingsKeyclears the settings cache beforeonSettingChange, so theuserBoxCustomBgstaleness window isn't reachable; and a custom hex never reaches atheme.fg()key argument, since these aretext-kind rows rendered via a fixed valid key.Caveat: the gate fix landed mid-review, so it re-read against final state and asked for a
re-verify — which is what the validation below is.
Validation
bun run test— 15/15 green atc78b609, including the new Proxy regression test.npx tsc --noEmit --strict …(the four extensions) — clean.test-diff-bodytwice; that is the knownshikiflakeon a fresh per-worktree
npm install, and it settles green on re-run. The worker correctlyrefused to bypass its hook and stopped to report rather than papering over it.
Not verified live. Per CLAUDE.md, mutating pi structures wants a live smoke test before
release — this changes theme color storage, the exact surface that shipped broken in 2.3.0.
Worth eyeballing a custom accent, and a switch back to
theme, in a real pi session.Deferred (not in this PR)
applyThemePaletteIfNeededrefreshes the accent but not theuser-box background, so a custom box color keeps the previous theme's color-mode escape. Low
severity (a truecolor escape still renders in practice), out of scope here.
mdCodestays accent-aliased, as the repodocuments. Deliberately not guessed.