Skip to content

feat: add session-color patch for env-based prompt bar color#657

Open
VitalyOstanin wants to merge 5 commits intoPiebald-AI:mainfrom
VitalyOstanin:feature/session-color
Open

feat: add session-color patch for env-based prompt bar color#657
VitalyOstanin wants to merge 5 commits intoPiebald-AI:mainfrom
VitalyOstanin:feature/session-color

Conversation

@VitalyOstanin
Copy link
Copy Markdown

@VitalyOstanin VitalyOstanin commented Apr 2, 2026

Summary

Add an always-applied patch that reads TWEAKCC_SESSION_COLOR env var at startup
and sets the session prompt bar color accordingly.

  • Designed for 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)
  • On session resume, Claude Code restores color from the session file, so the
    env var only affects new sessions

How it works

Claude Code has two app state initialization sites — the CLI bootstrap (builds
initialState inline with dynamic values like effortValue, fastMode) and
the default state factory (used as fallback). Neither includes
standaloneAgentContext, so it defaults to undefined.

The patch injects a standaloneAgentContext IIFE into both sites that reads
TWEAKCC_SESSION_COLOR, validates it against the hardcoded allowed color list,
and returns {name:"",color:value} or void 0. This is the same state shape
that /color sets interactively.

Test plan

  • Unit tests pass (6 tests: CLI state injection, default state injection,
    both locations, color validation, idempotency, pattern-not-found)
  • pnpm lint clean (tsc + eslint)
  • Manual test: TWEAKCC_SESSION_COLOR=cyan ccw-test shows cyan prompt bar
  • Verify color persists after /clear
  • Verify session resume restores color without env var

Summary by CodeRabbit

  • New Features

    • Session color can be set via an environment variable; values are validated against an allowlist and injected automatically into session initialization points when applicable. Changes are reported when applied.
  • Tests

    • Added tests covering injection points, validation behavior, idempotency, multiple-insertion handling, scheduling of save behavior, and no-op/error cases.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 2, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a new "session-color" patch that injects environment-driven session color initialization into serialized state code, registers the implementation, and includes tests covering injection, validation, idempotency, multi-location insertion, and failure/no-op cases.

Changes

Cohort / File(s) Summary
Patch registration
src/patches/index.ts
Imported writeSessionColor, registered a session-color entry in PATCH_DEFINITIONS (name: "Session color from env", group: PatchGroup.ALWAYS_APPLIED) and mapped patchImplementations['session-color'] to call writeSessionColor.
Patch implementation
src/patches/sessionColor.ts
Added `writeSessionColor(oldFile: string): string
Tests
src/patches/sessionColor.test.ts
New Vitest tests validating writeSessionColor and patchSaveAgentColor: successful injections (single and dual locations), presence of TWEAKCC_SESSION_COLOR and validation .includes(__c), allowed literals (e.g., "green", "cyan"), idempotency, queueMicrotask scheduling, exposing globalThis.__tweakccSaveAgentColor, and null when patterns are absent.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • bl-ue
  • georpar

Poem

🐇 I twirl my whiskers, nibble lines of light,
I tuck a color token in the silent night.
Env whispers green or cyan to the start,
I stitch it into state with a careful heart.
Hop—two spots patched—now the session's bright.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding a session-color patch that reads the TWEAKCC_SESSION_COLOR environment variable to set the prompt bar color, which aligns precisely with the changeset's primary functionality.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
src/patches/index.ts (1)

426-432: Place session-color in the existing “Always Applied” block for ordering consistency.

PATCH_DEFINITIONS order controls both apply order and listing. Keeping this ALWAYS_APPLIED item 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

📥 Commits

Reviewing files that changed from the base of the PR and between 88b8ed0 and 6f71f32.

📒 Files selected for processing (3)
  • src/patches/index.ts
  • src/patches/sessionColor.test.ts
  • src/patches/sessionColor.ts

@VitalyOstanin VitalyOstanin force-pushed the feature/session-color branch from 6f71f32 to 6f25c6b Compare April 2, 2026 07:28
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

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

📥 Commits

Reviewing files that changed from the base of the PR and between 6f71f32 and 6f25c6b.

📒 Files selected for processing (3)
  • src/patches/index.ts
  • src/patches/sessionColor.test.ts
  • src/patches/sessionColor.ts
✅ Files skipped from review due to trivial changes (2)
  • src/patches/index.ts
  • src/patches/sessionColor.test.ts

Comment thread src/patches/sessionColor.ts
@VitalyOstanin VitalyOstanin force-pushed the feature/session-color branch from 35e30f0 to 5620d5b Compare April 4, 2026 21:45
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
src/patches/index.ts (1)

899-901: Place session-color with 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 (/clear persistence 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

📥 Commits

Reviewing files that changed from the base of the PR and between 35e30f0 and 5620d5b.

📒 Files selected for processing (3)
  • src/patches/index.ts
  • src/patches/sessionColor.test.ts
  • src/patches/sessionColor.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/patches/sessionColor.ts

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).
Patch saveAgentColor to expose it via globalThis, then call it
from the INJECTION via queueMicrotask so the env-based color
is written to the session transcript. On resume,
computeStandaloneAgentContext reads agentColor from the log
and restores the prompt bar color automatically.
@VitalyOstanin VitalyOstanin force-pushed the feature/session-color branch from 5620d5b to 644621a Compare April 10, 2026 01:54
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

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 54-60: The showDiff call is passing the full replacement (which
contains the original matched text) as the injectedText, causing match[0] to
appear as newly injected; update the showDiff invocation in sessionColor.ts to
pass the constant INJECTION (instead of the variable replacement) as the
injectedText argument while leaving the other arguments (prePatch, result,
match.index, match.index + match[0].length) unchanged so that only the intended
INJECTION is shown as the inserted text; reference the symbols showDiff,
INJECTION, replacement, match, prePatch, and result to locate and modify the
call.
🪄 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: c26753e0-d76e-4fd1-8f65-fe4125fdc038

📥 Commits

Reviewing files that changed from the base of the PR and between 5620d5b and 644621a.

📒 Files selected for processing (3)
  • src/patches/index.ts
  • src/patches/sessionColor.test.ts
  • src/patches/sessionColor.ts
✅ Files skipped from review due to trivial changes (1)
  • src/patches/sessionColor.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/patches/index.ts

Comment thread src/patches/sessionColor.ts
…ied block

Pass only the actual injected text (INJECTION / injection) to showDiff
instead of the full replacement string, so debug diffs don't misleadingly
show original matched text as newly inserted. Move session-color
implementation entry next to other Always Applied patches.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant