Skip to content

fix(terminal): opencode not getting right theme#1951

Draft
janburzinski wants to merge 2 commits into
generalaction:mainfrom
janburzinski:emdash/opencode-theme-not-recog-2yqk2
Draft

fix(terminal): opencode not getting right theme#1951
janburzinski wants to merge 2 commits into
generalaction:mainfrom
janburzinski:emdash/opencode-theme-not-recog-2yqk2

Conversation

@janburzinski
Copy link
Copy Markdown
Collaborator

No description provided.

@janburzinski
Copy link
Copy Markdown
Collaborator Author

@greptile

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 9, 2026

Greptile Summary

This PR fixes opencode and other termenv-based TUIs launching with the wrong light/dark colorscheme by propagating the app's effective theme as COLORFGBG into every PTY environment at spawn time. It also hardens the xterm CSS variables in the renderer to match the reported background color.

  • pty-env.ts: Adds EffectiveTheme, colorFgBgFor, and withThemeColorFgBg helpers; extends buildAgentEnv and buildTerminalEnv to accept a theme option that writes COLORFGBG after providerVars, keeping the theme authoritative.
  • effective-theme.ts: New thin module resolves the active theme at spawn time — returning the explicit 'emlight'/'emdark' setting or falling back to Electron's nativeTheme.shouldUseDarkColors for the system setting.
  • All four provider files (local/ssh × terminal/conversation): call resolveEffectiveTheme() before spawning and inject COLORFGBG via the new helpers.

Confidence Score: 5/5

Safe to merge; the change is additive env-var injection at spawn time with no effect on existing env var semantics.

Every code path that spawns a PTY now resolves the theme once and injects COLORFGBG before the process starts. The logic is covered by unit tests that verify both the correct values and the priority ordering over providerVars. The CSS hardcoding is a straightforward alignment of visual colors with the reported values.

No files require special attention.

Important Files Changed

Filename Overview
src/main/core/pty/pty-env.ts Adds EffectiveTheme type, colorFgBgFor, and withThemeColorFgBg helpers; extends buildAgentEnv and buildTerminalEnv to accept an optional theme that sets COLORFGBG. Logic is correct: theme is applied after providerVars so it is authoritative over provider-supplied overrides.
src/main/core/settings/effective-theme.ts New helper resolves the app theme at spawn time: returns the explicit 'emlight'/'emdark' setting or falls back to Electron's nativeTheme.shouldUseDarkColors for system/unset themes. Clean and correct.
src/main/core/conversations/impl/local-conversation.ts Resolves theme before spawning the agent PTY and passes it to both buildAgentEnv (sets COLORFGBG internally) and the outer withThemeColorFgBg wrapper, resulting in COLORFGBG being written twice for the same value.
src/main/core/terminals/impl/local-terminal-provider.ts buildTerminalEnv() is correctly called without a theme option; withThemeColorFgBg applies the theme after merging taskEnvVars, ensuring theme beats any provider-supplied COLORFGBG.
src/main/core/pty/pty-env.test.ts Adds two well-structured tests: one verifying light/dark COLORFGBG values and the absence of COLORFGBG when theme is omitted; one confirming theme is authoritative over providerVars.
src/renderer/index.css Replaces CSS variable references for xterm-bg/xterm-fg with hardcoded hex values that match the COLORFGBG indices set in the PTY env, aligning the visual terminal background with the value reported to TUIs.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Spawn PTY / SSH session] --> B[resolveEffectiveTheme]
    B --> C{theme setting}
    C -->|'emlight' or 'emdark'| D[Return explicit theme]
    C -->|'system' / unset| E[nativeTheme.shouldUseDarkColors]
    E -->|true| F[emdark]
    E -->|false| G[emlight]
    D --> H[colorFgBgFor theme]
    F --> H
    G --> H
    H -->|emdark → 15;0| I[COLORFGBG]
    H -->|emlight → 0;15| I
    I --> J[buildAgentEnv / buildTerminalEnv]
    J --> K[withThemeColorFgBg wraps merged env]
    K --> L[PTY spawned with correct COLORFGBG]
    L --> M[termenv TUI detects light/dark correctly]
Loading

Reviews (2): Last reviewed commit: "fix(terminal): rely on color env for the..." | Re-trigger Greptile

args: resolved.args,
cwd: resolved.cwd,
env: { ...buildTerminalEnv(), ...this.taskEnvVars },
env: withThemeColorFgBg({ ...buildTerminalEnv({ theme }), ...this.taskEnvVars }, theme),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 COLORFGBG ends up being set twice here. buildTerminalEnv({ theme }) already calls colorFgBgFor(theme) internally (pty-env.ts line 179), and then withThemeColorFgBg sets it again from the same value. The outer wrap only adds real value when this.taskEnvVars might carry its own COLORFGBG that should be overridden by the theme — if that's the intent, a comment explaining this would help; otherwise the inner theme option to buildTerminalEnv could be dropped.

Suggested change
env: withThemeColorFgBg({ ...buildTerminalEnv({ theme }), ...this.taskEnvVars }, theme),
env: withThemeColorFgBg({ ...buildTerminalEnv(), ...this.taskEnvVars }, theme),
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/main/core/terminals/impl/local-terminal-provider.ts
Line: 146

Comment:
`COLORFGBG` ends up being set twice here. `buildTerminalEnv({ theme })` already calls `colorFgBgFor(theme)` internally (pty-env.ts line 179), and then `withThemeColorFgBg` sets it again from the same value. The outer wrap only adds real value when `this.taskEnvVars` might carry its own `COLORFGBG` that should be overridden by the theme — if that's the intent, a comment explaining this would help; otherwise the inner `theme` option to `buildTerminalEnv` could be dropped.

```suggestion
      env: withThemeColorFgBg({ ...buildTerminalEnv(), ...this.taskEnvVars }, theme),
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +222 to +234
});
}

private primeTerminalColorDetection(
pty: Pty,
theme: Awaited<ReturnType<typeof resolveEffectiveTheme>>
) {
const response = terminalColorQueryResponseFor(theme);
for (const delayMs of [0, 50, 150]) {
setTimeout(() => {
try {
pty.write(response);
} catch {}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 primeTerminalColorDetection is duplicated character-for-character in both LocalConversationProvider and SshConversationProvider. Consider extracting it to a shared utility in pty-env.ts or a sibling helper module so the retry counts and delay values can't drift between the two implementations.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/main/core/conversations/impl/local-conversation.ts
Line: 222-234

Comment:
`primeTerminalColorDetection` is duplicated character-for-character in both `LocalConversationProvider` and `SshConversationProvider`. Consider extracting it to a shared utility in `pty-env.ts` or a sibling helper module so the retry counts and delay values can't drift between the two implementations.

How can I resolve this? If you propose a fix, please make it concise.

@janburzinski
Copy link
Copy Markdown
Collaborator Author

@greptile

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