mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-08 16:39:42 +02:00
fix(terminal): read the colour env from the registry on every local spawn path
buildClaudeEnv(), the direct-PTY fallback taken when mux creation fails, now
reads getCli('claude').env and applies its unset and exports lists. It used to
delete COLORTERM and CLAUDECODE from a hand-maintained list of its own, which
left it contradicting the registry entry that the tmux pane and the attach
client both read. An engine value needing a mux name has nothing to resolve
against on this path, so it is skipped rather than guessed.
Claude no longer unsets NO_COLOR. The invisible-background bug does not need
it, and unsetting it overrides a preference the user set deliberately, so a
user who exports NO_COLOR globally keeps monochrome panes. The other seven
truecolor CLIs still unset it; that inconsistency is intentional and the
comment on the entry says so.
The invariants doc gains a Terminal colour env paragraph under Session launch
modes, where a reader looking up Claude will find it — the previous sentence
sat under a heading that lists only the non-Claude CLIs. It now says the lists
are the stock catalog and a clis.json override replaces them wholesale, and
that the declarations reach the tmux pane, its attach client and the direct
PTY but not a remote pane, whose command carries no env exports at all. Docker
hands COLORTERM=truecolor to every mode, including the two the registry says
must unset it.
The changeset named six peer CLIs and there are seven: deepseek also exports
truecolor. A test beside the existing OpenCode assertion pins the new
behaviour, so a future registry edit cannot make the backgrounds vanish again
in silence.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
7767b16d4f
commit
dae2ac580f
@@ -11,11 +11,17 @@ therefore quantized every RGB color its theme asked for down to the basic palett
|
|||||||
`rgb(55, 55, 55)` and every other dark background becomes `ESC[40m` — the terminal's own
|
`rgb(55, 55, 55)` and every other dark background becomes `ESC[40m` — the terminal's own
|
||||||
black. A custom Claude theme could change the color and nothing on screen moved.
|
black. A custom Claude theme could change the color and nothing on screen moved.
|
||||||
|
|
||||||
Claude now exports `COLORTERM=truecolor` and unsets `NO_COLOR`, which is what codex, gemini,
|
Claude now exports `COLORTERM=truecolor`, which is what codex, gemini, antigravity, pi, grok,
|
||||||
antigravity, pi, grok and omp already do. `CLAUDECODE` stays unset, because Claude reads it
|
deepseek and omp already do. Those seven also unset `NO_COLOR`; Claude does not, so a user who
|
||||||
as a signal that it is running nested inside itself.
|
exports `NO_COLOR` globally keeps the monochrome panes they asked for. `CLAUDECODE` stays
|
||||||
|
unset, because Claude reads it as a signal that it is running nested inside itself.
|
||||||
|
|
||||||
|
`buildClaudeEnv()`, the direct-PTY fallback used when tmux is unavailable, now reads the same
|
||||||
|
registry entry as the tmux pane and its attach client instead of deleting `COLORTERM` from a
|
||||||
|
hand-maintained list of its own. A remote pane still exports nothing — `buildRemoteLaunchCommand()`
|
||||||
|
never carried these declarations — so an SSH-remote Claude session keeps the old rendering.
|
||||||
|
|
||||||
PR #3 introduced the `unset COLORTERM` in February, citing xterm.js#484 for the claim that
|
PR #3 introduced the `unset COLORTERM` in February, citing xterm.js#484 for the claim that
|
||||||
xterm.js mishandles truecolor. xterm.js closed that issue in April 2019, Codeman now depends
|
xterm.js mishandles truecolor. xterm.js closed that issue in April 2019, Codeman now depends
|
||||||
on `@xterm/xterm` 6, and `TmuxManager` sets `terminal-overrides ",*:Tc"` on its own tmux
|
on `@xterm/xterm` 6, and `TmuxManager` sets `terminal-overrides ",*:Tc"` on its own tmux
|
||||||
server, so 24-bit color already reaches the browser for the six CLIs that ask for it.
|
server, so 24-bit color already reaches the browser for the CLIs that ask for it.
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -174,17 +174,19 @@ const CLAUDE: CliEntry = {
|
|||||||
legacyConfigAliases: { resumeId: 'resumeSessionId' },
|
legacyConfigAliases: { resumeId: 'resumeSessionId' },
|
||||||
},
|
},
|
||||||
env: {
|
env: {
|
||||||
// Claude joins the truecolor list with COLORTERM=truecolor and NO_COLOR unset.
|
// Claude asks for truecolor, like every CLI here except `shell` and `opencode`.
|
||||||
// tmux hands the pane TERM=screen, which supports-color reads as 16 colors, and
|
// tmux hands the pane TERM=screen, which supports-color reads as 16 colors, and
|
||||||
// Claude then quantizes every RGB color its theme asks for down to that palette.
|
// Claude then quantizes every RGB color its theme asks for down to that palette.
|
||||||
// Each dark background lands on ESC[40m, the terminal's own black, so the block
|
// Each dark background lands on ESC[40m, the terminal's own black, so the block
|
||||||
// Claude draws behind the user's own messages renders invisible. PR #3 unset
|
// Claude draws behind the user's own messages renders invisible. PR #3 unset
|
||||||
// COLORTERM here against xterm.js#484, which xterm.js had already closed in 2019,
|
// COLORTERM here against xterm.js#484, which xterm.js had already closed in 2019,
|
||||||
// and Codeman now ships @xterm/xterm 6 and sets `terminal-overrides *:Tc` itself.
|
// and Codeman now ships @xterm/xterm 6 and sets `terminal-overrides *:Tc` itself.
|
||||||
|
// The other truecolor CLIs also unset NO_COLOR. Claude does not, so a user who
|
||||||
|
// exports NO_COLOR globally keeps the monochrome panes they asked for.
|
||||||
// CLAUDECODE stays unset, because Claude reads it as a signal that it is running
|
// CLAUDECODE stays unset, because Claude reads it as a signal that it is running
|
||||||
// nested inside itself.
|
// nested inside itself.
|
||||||
exports: [{ name: 'COLORTERM', value: 'truecolor' }],
|
exports: [{ name: 'COLORTERM', value: 'truecolor' }],
|
||||||
unset: ['CLAUDECODE', 'NO_COLOR'],
|
unset: ['CLAUDECODE'],
|
||||||
tmuxSetenvKeys: [],
|
tmuxSetenvKeys: [],
|
||||||
dockerExecEnvNames: [],
|
dockerExecEnvNames: [],
|
||||||
allowedPrefixes: ['CLAUDE_CODE_'],
|
allowedPrefixes: ['CLAUDE_CODE_'],
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { isEffortLevel } from './types.js';
|
|||||||
import { getAugmentedPath } from './utils/index.js';
|
import { getAugmentedPath } from './utils/index.js';
|
||||||
import { compareVersions } from './utils/dependency-checker.js';
|
import { compareVersions } from './utils/dependency-checker.js';
|
||||||
import { dataPath } from './config/instance.js';
|
import { dataPath } from './config/instance.js';
|
||||||
|
import { getCli } from './config/cli-registry/registry.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build Claude CLI permission flags based on the configured mode.
|
* Build Claude CLI permission flags based on the configured mode.
|
||||||
@@ -181,10 +182,26 @@ export function buildClaudeEnv(sessionId: string): Record<string, string | undef
|
|||||||
// Path only (not the secret value) — hook curls cat it at execution time (COD-54)
|
// Path only (not the secret value) — hook curls cat it at execution time (COD-54)
|
||||||
CODEMAN_HOOK_SECRET_FILE: dataPath('hook-secret'),
|
CODEMAN_HOOK_SECRET_FILE: dataPath('hook-secret'),
|
||||||
};
|
};
|
||||||
|
// The colour and identity vars come from the registry entry, the same source
|
||||||
|
// buildEnvExports() and buildMuxAttachEnv() read, so this fallback cannot drift from
|
||||||
|
// the tmux pane the way a hand-maintained list here did.
|
||||||
// COD-115: `delete`, not `= undefined` — node-pty serializes a present-with-undefined
|
// COD-115: `delete`, not `= undefined` — node-pty serializes a present-with-undefined
|
||||||
// key as the literal string "KEY=undefined" (see buildMuxAttachEnv below).
|
// key as the literal string "KEY=undefined" (see buildMuxAttachEnv below).
|
||||||
delete env.COLORTERM;
|
const cliEnv = getCli('claude')?.env;
|
||||||
delete env.CLAUDECODE;
|
for (const name of cliEnv?.unset ?? []) delete env[name];
|
||||||
|
for (const item of cliEnv?.exports ?? []) {
|
||||||
|
// A direct PTY has no mux, so `muxName` has no value to resolve against. Claude
|
||||||
|
// declares literals only; an unresolvable engine value is skipped, never guessed.
|
||||||
|
const value =
|
||||||
|
typeof item.value === 'string'
|
||||||
|
? item.value
|
||||||
|
: item.value.engine === 'sessionId'
|
||||||
|
? sessionId
|
||||||
|
: item.value.engine === 'codemanPrefixedSessionId'
|
||||||
|
? `codeman_${sessionId}`
|
||||||
|
: undefined;
|
||||||
|
if (value !== undefined) env[item.name] = value;
|
||||||
|
}
|
||||||
return env;
|
return env;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -295,6 +295,13 @@ describe('TmuxManager (unit)', () => {
|
|||||||
expect(callBuildEnvExports('opencode')).toContain('unset COLORTERM');
|
expect(callBuildEnvExports('opencode')).toContain('unset COLORTERM');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Claude renders its themed backgrounds as RGB. Without this the pane inherits
|
||||||
|
// tmux's TERM=screen, supports-color reads 16 colors, and every dark background
|
||||||
|
// quantizes to ESC[40m — the terminal's own black — so the block goes invisible.
|
||||||
|
it('exports truecolor for Claude sessions', () => {
|
||||||
|
expect(callBuildEnvExports('claude')).toContain('export COLORTERM=truecolor');
|
||||||
|
});
|
||||||
|
|
||||||
it('exports the server-stamped CODEMAN_API_URL verbatim', () => {
|
it('exports the server-stamped CODEMAN_API_URL verbatim', () => {
|
||||||
const original = process.env.CODEMAN_API_URL;
|
const original = process.env.CODEMAN_API_URL;
|
||||||
process.env.CODEMAN_API_URL = 'https://127.0.0.1:3199';
|
process.env.CODEMAN_API_URL = 'https://127.0.0.1:3199';
|
||||||
|
|||||||
Reference in New Issue
Block a user