feat: add session-color patch for env-based prompt bar color#657
feat: add session-color patch for env-based prompt bar color#657VitalyOstanin wants to merge 3 commits intoPiebald-AI:mainfrom
Conversation
📝 WalkthroughWalkthroughAdds a new patch "session-color" that injects an environment-driven session color snippet into serialized state initializers and registers the implementation; includes tests verifying injection, validation, idempotency, multi-location insertion, and no-op behavior when patterns are absent. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
src/patches/index.ts (1)
426-432: Placesession-colorin the existing “Always Applied” block for ordering consistency.
PATCH_DEFINITIONSorder controls both apply order and listing. Keeping thisALWAYS_APPLIEDitem with the other always-applied entries will make ordering expectations clearer.♻️ Suggested reordering
{ id: 'statusline-update-throttle', name: `Statusline update throttling correction`, group: PatchGroup.ALWAYS_APPLIED, description: `Statusline updates will be properly throttled instead of queued (or debounced)`, }, + { + id: 'session-color', + name: 'Session color from env', + group: PatchGroup.ALWAYS_APPLIED, + description: + 'Set session prompt bar color via TWEAKCC_SESSION_COLOR env var', + }, // Misc Configurable @@ - { - id: 'session-color', - name: 'Session color from env', - group: PatchGroup.ALWAYS_APPLIED, - description: - 'Set session prompt bar color via TWEAKCC_SESSION_COLOR env var', - }, ] as const;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/patches/index.ts` around lines 426 - 432, The 'session-color' patch object is declared separately; move the object with id 'session-color' (name 'Session color from env', group PatchGroup.ALWAYS_APPLIED) into the existing ALWAYS_APPLIED block inside the PATCH_DEFINITIONS array so it sits alongside the other always-applied entries to preserve apply/listing order; locate the current standalone object (id 'session-color') and cut-and-paste it into the existing block where other PatchGroup.ALWAYS_APPLIED items are defined, ensuring no duplicate IDs and keeping the same properties.src/patches/sessionColor.ts (1)
25-27: Tighten the idempotency sentinel to this patch’s actual injection marker.A plain
includes('TWEAKCC_SESSION_COLOR')can false-positive if that token appears elsewhere, causing an unintended early return.🔧 Suggested guard refinement
export const writeSessionColor = (oldFile: string): string | null => { - if (oldFile.includes('TWEAKCC_SESSION_COLOR')) { + if ( + oldFile.includes( + 'standaloneAgentContext:(()=>{let __c=process.env.TWEAKCC_SESSION_COLOR;' + ) + ) { return oldFile; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/patches/sessionColor.ts` around lines 25 - 27, The idempotency check using oldFile.includes('TWEAKCC_SESSION_COLOR') is too broad and can false-positive; tighten it by checking for the exact injected sentinel (e.g., a unique marker string you insert with the patch like '/* TWEAKCC_SESSION_COLOR_INJECTED */' or the full block snippet) or use a precise regex that matches the exact injection start/end, replacing the current includes call on oldFile with that exact-marker check so the function only returns early when the patch’s real injection is present.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/patches/index.ts`:
- Around line 426-432: The 'session-color' patch object is declared separately;
move the object with id 'session-color' (name 'Session color from env', group
PatchGroup.ALWAYS_APPLIED) into the existing ALWAYS_APPLIED block inside the
PATCH_DEFINITIONS array so it sits alongside the other always-applied entries to
preserve apply/listing order; locate the current standalone object (id
'session-color') and cut-and-paste it into the existing block where other
PatchGroup.ALWAYS_APPLIED items are defined, ensuring no duplicate IDs and
keeping the same properties.
In `@src/patches/sessionColor.ts`:
- Around line 25-27: The idempotency check using
oldFile.includes('TWEAKCC_SESSION_COLOR') is too broad and can false-positive;
tighten it by checking for the exact injected sentinel (e.g., a unique marker
string you insert with the patch like '/* TWEAKCC_SESSION_COLOR_INJECTED */' or
the full block snippet) or use a precise regex that matches the exact injection
start/end, replacing the current includes call on oldFile with that exact-marker
check so the function only returns early when the patch’s real injection is
present.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 6c0a9a3a-d57c-41eb-9844-8219b96cb972
📒 Files selected for processing (3)
src/patches/index.tssrc/patches/sessionColor.test.tssrc/patches/sessionColor.ts
6f71f32 to
6f25c6b
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/patches/sessionColor.ts`:
- Around line 51-57: The current showDiff call uses the post-patch `result` and
the full `replacement`, which can produce misleading diffs after the first
patch; update the call to use the pre-patch buffer (the buffer state before
applying the current replacement) for the index calculations and pass only the
INJECTION text as the injectedText argument to showDiff (keep the same start/end
as match.index and match.index + match[0].length but computed against the
pre-patch buffer), so replace the showDiff(oldFile, result, replacement, ...)
invocation with one that uses the pre-patch buffer for indices and INJECTION for
the injectedText parameter.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 13605414-8faf-4988-b1d2-660eda55da2a
📒 Files selected for processing (3)
src/patches/index.tssrc/patches/sessionColor.test.tssrc/patches/sessionColor.ts
✅ Files skipped from review due to trivial changes (2)
- src/patches/index.ts
- src/patches/sessionColor.test.ts
| showDiff( | ||
| oldFile, | ||
| result, | ||
| replacement, | ||
| match.index, | ||
| match.index + match[0].length | ||
| ); |
There was a problem hiding this comment.
showDiff args are inconsistent after the first patch.
Use the pre-patch buffer for indices and pass only INJECTION as injectedText; current call can produce misleading diffs when both patterns are patched.
Suggested fix
for (const pattern of patterns) {
- const match = result.match(pattern);
+ const beforePatch = result;
+ const match = beforePatch.match(pattern);
if (!match || match.index === undefined) continue;
const replacement = INJECTION + match[0];
result =
- result.slice(0, match.index) +
+ beforePatch.slice(0, match.index) +
replacement +
- result.slice(match.index + match[0].length);
+ beforePatch.slice(match.index + match[0].length);
showDiff(
- oldFile,
+ beforePatch,
result,
- replacement,
+ INJECTION,
match.index,
match.index + match[0].length
);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/patches/sessionColor.ts` around lines 51 - 57, The current showDiff call
uses the post-patch `result` and the full `replacement`, which can produce
misleading diffs after the first patch; update the call to use the pre-patch
buffer (the buffer state before applying the current replacement) for the index
calculations and pass only the INJECTION text as the injectedText argument to
showDiff (keep the same start/end as match.index and match.index +
match[0].length but computed against the pre-patch buffer), so replace the
showDiff(oldFile, result, replacement, ...) invocation with one that uses the
pre-patch buffer for indices and INJECTION for the injectedText parameter.
There was a problem hiding this comment.
@coderabbitai Fixed in 35e30f0. showDiff now uses prePatch (pre-patch buffer) for both slicing and diff indices, ensuring consistent results when multiple patterns are patched.
There was a problem hiding this comment.
@VitalyOstanin, thanks for the update! Using prePatch as the base for both slicing and the showDiff indices ensures that each iteration operates on a stable snapshot, so the displayed diffs remain accurate even when both patterns are matched and patched in the same run. The fix looks correct. ✅
🧠 Learnings used
Learnt from: VitalyOstanin
Repo: Piebald-AI/tweakcc PR: 634
File: src/patches/inputChevronColor.ts:8-9
Timestamp: 2026-03-30T16:29:19.451Z
Learning: In src/patches/inputChevronColor.ts, the Claude Code minified binary uses `\xA0` (U+00A0 non-breaking space) rather than a regular ASCII space `" "` in the chevron component child tail (e.g., after `s6.pointer`). Any regex anchor using `," "` (regular space) to uniquely identify the chevron element will never match the minified output. The pattern ending at `{color:VAR,dimColor:VAR}` is already unique due to the `{isLoading, themeColor}` destructuring context.
Learnt from: bl-ue
Repo: Piebald-AI/tweakcc PR: 421
File: src/patches/thinkerSymbolSpeed.ts:46-58
Timestamp: 2026-01-27T21:16:01.318Z
Learning: In patches under src/patches/, assume code works with minified, original Claude Code installations. Patch regexes must be strict and match the minified format exactly (ignore formatting differences like whitespace/newlines). This guidance applies to all .ts files in src/patches and should be followed when adding or reviewing patches.
Learnt from: ljepson
Repo: Piebald-AI/tweakcc PR: 437
File: src/patches/toolsets.ts:811-833
Timestamp: 2026-01-29T21:19:04.770Z
Learning: In src/patches/toolsets.ts, when matching mode change patterns like `let X=Y(Z,{type:"setMode",mode:vv(TA),destination:"session"});`, the regex should capture the inner variable name (TA) not the entire expression (vv(TA)), because the variable holds the raw mode string value (e.g., "plan", "default", "acceptEdits") and is used in direct string comparisons like `if(${modeVar}==="plan")`. The wrapping function vv() is only for dispatch transformation.
Learnt from: CR
Repo: Piebald-AI/tweakcc PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-06T21:30:11.641Z
Learning: Applies to **/*.{ts,tsx} : Use `chalk` for terminal colors
Learnt from: CR
Repo: Piebald-AI/tweakcc PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-06T21:30:11.641Z
Learning: Applies to **/patches/**/*.{ts,tsx} : Use `,` `;` `}` `{` literal characters at regex start instead of `\\b` for performance in patch patterns
Learnt from: CR
Repo: Piebald-AI/tweakcc PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-06T21:30:11.641Z
Learning: Applies to **/patches/**/*.{ts,tsx} : Avoid `\\b` in regex patterns due to V8 performance issues; use literal character alternatives
Learnt from: CR
Repo: Piebald-AI/tweakcc PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-06T21:30:11.641Z
Learning: Applies to **/patches/**/*.{ts,tsx} : Use `[\$\\w]+` instead of `\\w+` for identifier matching in regex patterns to include `$` for React refs
Learnt from: VitalyOstanin
Repo: Piebald-AI/tweakcc PR: 647
File: src/patches/clearScreen.test.ts:1-1
Timestamp: 2026-03-31T12:24:56.066Z
Learning: In Piebald-AI/tweakcc, test files (`**/*.test.{ts,tsx}`) must explicitly import Vitest functions (`describe`, `it`, `expect`, `beforeEach`, `vi`) from `'vitest'` rather than relying on globals. Although `vitest.config.ts` sets `globals: true`, the `tsconfig.json` does NOT include `"types": ["vitest/globals"]`, so `tsc --noEmit` (run by the pre-commit hook via `pnpm lint`) fails if globals are used without explicit imports. All test files in the repo follow this explicit-import pattern.
If you found this review helpful, would you consider giving us a shout-out on X?
Thank you for using CodeRabbit!
Set the session prompt bar color via TWEAKCC_SESSION_COLOR env var.
Intended for use in wrapper scripts (e.g. ccw) that determine color
based on the working directory before launching Claude Code.
Valid values: red, blue, green, yellow, purple, orange, pink, cyan.
Invalid or unset values are silently ignored (no color applied).
How it works:
Claude Code has two app state initialization sites — the CLI
bootstrap (which builds initialState inline with dynamic values like
effortValue, fastMode) and the default state factory u3H() used as
fallback. Neither includes standaloneAgentContext, so it defaults to
undefined and the prompt bar shows no color.
The patch injects a standaloneAgentContext IIFE into both sites that
reads TWEAKCC_SESSION_COLOR at startup, validates it against the
hardcoded allowed list, and returns {name:"",color:value} or void 0.
This is the same state shape that /color sets interactively.
On session resume, Claude Code restores the color from the session
file, so the env var only affects new sessions.
1. Move session-color definition into the ALWAYS_APPLIED block
(next to statusline-update-throttle) for ordering consistency.
2. Tighten idempotency check: match the full injection sentinel
'standaloneAgentContext:(()=>{let __c=process.env.TWEAKCC_SESSION_COLOR;'
instead of the broad 'TWEAKCC_SESSION_COLOR' substring to avoid
false-positive early returns.
3. Rebase onto upstream/main to resolve conflict with channels-mode
patch (Piebald-AI#653).
35e30f0 to
5620d5b
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (2)
src/patches/index.ts (1)
899-901: Placesession-colorwith the Always Applied implementation block.Functionally correct, but moving this entry near the other Always Applied implementations will reduce maintenance drift between definition and implementation sections.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/patches/index.ts` around lines 899 - 901, The 'session-color' patch entry should be relocated into the "Always Applied" implementation block to match its implementation; move the object with key 'session-color' (fn: c => writeSessionColor(c)) so that it sits with the other Always Applied entries next to the implementation of writeSessionColor, ensuring the definition and implementation remain adjacent and reduce maintenance drift.src/patches/sessionColor.test.ts (1)
15-55: Add tests for remaining session lifecycle edge cases.Please add coverage for the two still-unverified behaviors (
/clearpersistence and resume restoring session color without env var) to lock in intended semantics.As per coding guidelines: "Test edge cases and error conditions in test files".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/patches/sessionColor.test.ts` around lines 15 - 55, Add two new unit tests inside the existing describe('writeSessionColor') block to cover the missing edge cases: one test that exercises the "/clear" persistence behavior by feeding an appropriate fixture into writeSessionColor (use or extend makeCLIState/makeBoth to include a clear action) and assert the returned patch reflects the expected persisted-clear semantics; and a second test that simulates a resume restore path without the TWEAKCC_SESSION_COLOR env var (create a fixture representing resumed state and call writeSessionColor or the resume helper) and assert the function injects/restores the session color correctly in the output. Reference writeSessionColor, makeCLIState, makeDefaultState and makeBoth to locate where to add these tests.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/patches/index.ts`:
- Around line 899-901: The 'session-color' patch entry should be relocated into
the "Always Applied" implementation block to match its implementation; move the
object with key 'session-color' (fn: c => writeSessionColor(c)) so that it sits
with the other Always Applied entries next to the implementation of
writeSessionColor, ensuring the definition and implementation remain adjacent
and reduce maintenance drift.
In `@src/patches/sessionColor.test.ts`:
- Around line 15-55: Add two new unit tests inside the existing
describe('writeSessionColor') block to cover the missing edge cases: one test
that exercises the "/clear" persistence behavior by feeding an appropriate
fixture into writeSessionColor (use or extend makeCLIState/makeBoth to include a
clear action) and assert the returned patch reflects the expected
persisted-clear semantics; and a second test that simulates a resume restore
path without the TWEAKCC_SESSION_COLOR env var (create a fixture representing
resumed state and call writeSessionColor or the resume helper) and assert the
function injects/restores the session color correctly in the output. Reference
writeSessionColor, makeCLIState, makeDefaultState and makeBoth to locate where
to add these tests.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: c34df35d-b2fa-43f1-bac8-be987e40b8b5
📒 Files selected for processing (3)
src/patches/index.tssrc/patches/sessionColor.test.tssrc/patches/sessionColor.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- src/patches/sessionColor.ts
Summary
Add an always-applied patch that reads
TWEAKCC_SESSION_COLORenv var at startupand sets the session prompt bar color accordingly.
ccw) that determine color based on theworking directory before launching Claude Code
red,blue,green,yellow,purple,orange,pink,cyanenv var only affects new sessions
How it works
Claude Code has two app state initialization sites — the CLI bootstrap (builds
initialStateinline with dynamic values likeeffortValue,fastMode) andthe default state factory (used as fallback). Neither includes
standaloneAgentContext, so it defaults toundefined.The patch injects a
standaloneAgentContextIIFE into both sites that readsTWEAKCC_SESSION_COLOR, validates it against the hardcoded allowed color list,and returns
{name:"",color:value}orvoid 0. This is the same state shapethat
/colorsets interactively.Test plan
both locations, color validation, idempotency, pattern-not-found)
pnpm lintclean (tsc + eslint)TWEAKCC_SESSION_COLOR=cyan ccw-testshows cyan prompt bar/clearSummary by CodeRabbit
New Features
Tests