[BUG] JetBrains plugin (WSL): ENABLE_IDE_INTEGRATION / CLAUDE_CODE_SSE_PORT never reach the Linux shell — TerminalCustomizer does not append them to WSLENV
Environment
- PhpStorm 2026.1 (Windows), Claude Code JetBrains plugin 0.1.14-beta
- Terminal shell path:
wsl.exe -d Debian(WSL2, Debian trixie) - Claude Code CLI inside WSL (reproduced on 2.1.165–2.1.172)
Summary
For IDE terminals spawned through the classic pty4j/wsl.exe path, the plugin's env vars are set on the Windows process but are silently dropped at the Win→Linux boundary, because wsl.exe only forwards variables listed in WSLENV — and the plugin never adds its variable names to WSLENV. The same terminals work when the IDE happens to spawn the shell via IJent (env map passed directly over gRPC, no wsl.exe filtering), which makes the breakage look intermittent/machine-specific.
Evidence
1. The IDE does set the vars — idea.log terminal launch line:
LocalTerminalDirectRunner - Started com.pty4j.windows.conpty.WinConPtyProcess from [wsl.exe, -d, Debian]
in \\wsl$\Debian\...\<project>,
diff_envs={CLAUDE_CODE_SSE_PORT=58925, ENABLE_IDE_INTEGRATION=true,
TERMINAL_EMULATOR=JetBrains-JediTerm, TERM_SESSION_ID=...,
WSLENV=TERMINAL_EMULATOR/u:TERM_SESSION_ID/u}
Note WSLENV lists only the two JetBrains vars — not the plugin's two.
2. The Linux shell never receives them — full /proc/<shellpid>/environ of that exact terminal's bash (matched by TERM_SESSION_ID): a minimal WSL login env containing TERMINAL_EMULATOR, TERM_SESSION_ID and WSLENV=TERMINAL_EMULATOR/u:TERM_SESSION_ID/u — no CLAUDE_CODE_SSE_PORT, no ENABLE_IDE_INTEGRATION. This is standard wsl.exe behavior: only WSLENV-listed vars cross.
3. The injection site (decompiled com.anthropic.code.plugin.TerminalCustomizer):
mutableEnvs.put("ENABLE_IDE_INTEGRATION", "true");
int port = TerminalUtil.INSTANCE.getRunningMcpServerPorts()
.getOrDefault(project.getLocationHash(), -1);
if (port != -1) mutableEnvs.put("CLAUDE_CODE_SSE_PORT", String.valueOf(port));
// no WSLENV handling anywhere
4. Contrast — IJent-spawned terminals on an identical setup: shell ancestry bash --rcfile .../bash-integration.bash ← ijent grpc-server; the shell's initial environ does contain both vars (env map passed directly, no WSLENV filtering). Same IDE, same plugin — whether integration env reaches WSL depends purely on which engine spawned the tab.
Impact
- Env-based IDE detection/auto-connect inside WSL silently fails for every classic-path terminal; only lockfile discovery (
/mnt/c/Users/<user>/.claude/ide/*.lock) saves it. - Likely underlies a class of intermittent "plugin doesn't connect on WSL" reports (e.g. #58014): the same user gets working and broken terminals depending on which engine spawned the tab.
Proposed fix
In TerminalCustomizer.customizeCommandAndEnvironment, when the shell command is wsl.exe (or unconditionally — it's harmless elsewhere), merge-append the injected names into WSLENV instead of leaving it untouched:
String wslenv = envs.get("WSLENV");
String add = "ENABLE_IDE_INTEGRATION/u" + (port != -1 ? ":CLAUDE_CODE_SSE_PORT/u" : "");
envs.put("WSLENV", wslenv == null || wslenv.isBlank() ? add : wslenv + ":" + add);This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗