fix(cc-config): stop pinning CLAUDE_CONFIG_DIR when CLAUDE_HOME is unset

runClaude() unconditionally set CLAUDE_CONFIG_DIR to getClaudeHome()
(~/.claude), so the CLI wrote ~/.claude/.claude.json — a file
cc-discovery.getClaudeJsonPath() never reads (it reads ~/.claude.json,
beside ~/.claude/, by design). Every default-install MCP add/remove and
plugin/marketplace mutation was inert: add toasted success and vanished on
refetch, remove 422'd for every server the panel lists.

With CLAUDE_HOME unset (the default), leave CLAUDE_CONFIG_DIR unset too —
the CLI's own default config dir already lines up with what cc-discovery
reads, so alignment comes from doing nothing. Only pin it when the operator
explicitly set CLAUDE_HOME, which is the one case the pin is meant for.
Left a residual, documented at both sites: with CLAUDE_HOME set, reads still
come from $HOME/.claude.json while the CLI writes
<CLAUDE_HOME>/.claude.json — a split predating this task, affecting a
configuration nobody here runs.

New tests pin the env contract directly (no real CLI needed): runClaude
must not set CLAUDE_CONFIG_DIR when CLAUDE_HOME is absent, and must set it
to CLAUDE_HOME's value when present.
This commit is contained in:
2026-09-09 09:48:28 +07:00
parent 6d27c115d8
commit 0ad4b8c920
3 changed files with 58 additions and 3 deletions
+15 -3
View File
@@ -131,15 +131,27 @@ function serialize(fn) {
function runClaude(args, opts = {}) {
const timeout = opts.timeoutMs || DEFAULT_TIMEOUT_MS;
return new Promise((resolve, reject) => {
// Only pin CLAUDE_CONFIG_DIR when the operator explicitly set CLAUDE_HOME
// (a non-default install). Left unset, the CLI's own default config dir
// is `~/.claude` and it writes `.claude.json` NEXT TO it (`~/.claude.json`)
// — the exact file cc-discovery.getClaudeJsonPath() reads (see that
// function's own comment). Pinning CLAUDE_CONFIG_DIR unconditionally to
// getClaudeHome() made the CLI write `~/.claude/.claude.json` instead —
// a file nothing reads — so every default-install add/remove was inert.
// When CLAUDE_HOME IS set, this still pins it, but note the residual:
// cc-discovery's read stays pinned to $HOME/.claude.json regardless (see
// getClaudeJsonPath's comment) while the CLI then writes
// <CLAUDE_HOME>/.claude.json — a pre-existing split this task does not
// attempt to fix, since no install in this repo runs with CLAUDE_HOME set.
const env = { ...process.env };
if (process.env.CLAUDE_HOME) env.CLAUDE_CONFIG_DIR = getClaudeHome();
const child = execFile(
"claude",
args,
{
timeout,
maxBuffer: MAX_OUTPUT_BYTES,
// Pin the CLI to the same config dir cc-discovery reads, so a write
// made here is a write the dashboard can see.
env: { ...process.env, CLAUDE_CONFIG_DIR: getClaudeHome() },
env,
},
(err, stdout, stderr) => {
const out = String(stdout || "");