Repository navigation
[Bug] 自定义配置目录(CLAUDE_CONFIG_DIR 等)下历史会话点开「当前会话暂无消息」——parser 不读 agent 设置的 env_json(影响全部 agent) #948
Description
现象
给 agent 配了自定义配置目录(agent 设置里的 env_json,如 Claude 的 CLAUDE_CONFIG_DIR、Codex 的 CODEX_HOME)后:
- 侧栏能列出会话标题;
- 但点开会话显示「当前会话暂无消息」(
messageList.emptyConversation); - 在会话里继续发消息,上下文完全对得上。
数据没丢(会话 jsonl 都在磁盘上),只是界面读不出来,也无报错日志 —— parser 找不到文件后静默返回空 turn 列表。
复现
- 给
claude_code配env_json = {"CLAUDE_CONFIG_DIR": "C:\\Users\\<用户>\\.claude-ocx"}(agent 设置里的环境变量); - 用 codeg 起一个 Claude 会话、聊几句 → 会话文件写到
~\.claude-ocx\projects\<项目>\<sessionId>.jsonl; - 重启 codeg;
- 点开该会话 → 「当前会话暂无消息」;
- 在该会话里继续发消息 → 上下文正常(说明是"界面读不到",不是数据丢)。
对照实验:把 ~\.claude\projects 做成指向 ~\.claude-ocx\projects 的 junction 后,同一批会话立刻能显示 —— 坐实了"parser 去错目录"。
根因
codeg 读 CLAUDE_CONFIG_DIR 有两条路,只通了一条:
| 用途 | 读哪里 | 结果 |
|---|---|---|
| 启动 agent 子进程 | agent_setting.env_json(runtime_env) |
✅ 用了自定义目录 |
| 读历史会话(parser) | std::env::var_os("CLAUDE_CONFIG_DIR")(进程环境变量) |
❌ 主进程没有 → fallback 到 ~\.claude |
src-tauri/src/parsers/claude.rs:1563:
pub(crate) fn resolve_claude_config_dir() -> PathBuf {
resolve_claude_config_dir_from(std::env::var_os("CLAUDE_CONFIG_DIR"), dirs::home_dir())
}而 build_agent_parser(src-tauri/src/parsers/mod.rs:376)只接收 agent_type,拿不到该 agent 的 env_json:
pub fn build_agent_parser(agent_type: AgentType) -> Box<dyn AgentParser> {
let inner: Box<dyn AgentParser> = match agent_type {
AgentType::ClaudeCode => Box::new(claude::ClaudeParser::new()), // new() 无 env 参数
AgentType::Codex => Box::new(codex::CodexParser::new()),
// …
AgentType::Custom(_) => Box::new(acp_native::AcpNativeParser::new(agent_type)),
};
Box::new(RouteSanitized(inner))
}且 codeg 并不会在启动时把 env_json 注入主进程环境:全仓 std::env::set_var 只用于 CODEG_DATA_DIR、WEBVIEW2_ARGS_ENV、CODEG_ACP_* 测试开关等,从不写 CLAUDE_CONFIG_DIR / CODEX_HOME 之类。这些变量通常也不是用户级/系统级环境变量 ⇒ 主进程侧永远读不到 ⇒ parser 恒定去默认目录。
影响面:全部 agent,不止 Claude
build_agent_parser 是所有 agent 的统一入口,而每个 parser 的目录解析都直接读进程环境变量:
| parser | 读的变量 |
|---|---|
claude.rs |
CLAUDE_CONFIG_DIR |
codex.rs |
CODEX_HOME |
codebuddy.rs |
CODEBUDDY_CONFIG_DIR |
cursor.rs |
CURSOR_CONFIG_DIR / XDG_CONFIG_HOME |
grok.rs |
GROK_HOME |
gemini.rs |
GEMINI_CLI_HOME |
antigravity.rs |
GEMINI_HOME |
deepseek.rs |
DSH_HOME / DSH_AGENTS_HOME |
⇒ 只要用户在 agent 设置里配了自定义目录,该 agent 的历史会话就都读不出来。
建议修复方向
codeg 已经有正确做法,只是 parser 层没接上:
src-tauri/src/acp/file_system_runtime.rs:273的agent_data_roots(agent_type, runtime_env)—— 注释写着「env_jsonmoves the agent's state, so it must move the allowed root too」,并有测试agent_data_roots_honor_runtime_env_relocation()佐证 codeg 明确知道runtime_env会搬移状态目录;- 同一文件里的
raw_env_value(runtime_env, key)/env_value(runtime_env, key)就是「先读该 agent 的runtime_env,再退回 codeg 进程 env」的标准解析;FileSystemPolicy::from_env(workspace_root, agent_type, runtime_env)是已采用该模式的样例。
方向:让 build_agent_parser 接收该 agent 的 runtime_env(或复用 agent_data_roots),各 parser 的 new() 用 raw_env_value(runtime_env, "CLAUDE_CONFIG_DIR") 之类的解析结果,替代裸 std::env::var_os。
临时规避(用户侧,不改 codeg)
把默认目录做成指向自定义目录的 junction,让 parser 找得到:
New-Item -ItemType Junction -Path "$env:USERPROFILE\.claude\projects" -Target "$env:USERPROFILE\.claude-ocx\projects"(先把两边数据合并。注意别用 cmd 的 mklink —— 在 git-bash 下 /J 会被当成路径参数吃掉。)
相关 issue
- Agent 识别仅扫描默认路径,未正确识别通过环境变量自定义的安装位置 #310 — Agent 识别环节同样不认环境变量自定义的安装位置(同类模式,但在检测而非 parser);
- DeepSeek sessions written by
deepseek-acp0.9.0 render empty — the parser only reads the v0 session filename #734 — 同一症状messageList.emptyConversation(parser 只读旧版 session 文件名),已成因不同但证明该「parser 读空」类问题可被接受并修复。
环境
- codeg v0.35.1(Windows 安装版)
- OS:Windows 10 Pro 19045
- agent:
claude_code(内置 ACP) - 自定义目录:
CLAUDE_CONFIG_DIR=%USERPROFILE%\.claude-ocx(agent 设置env_json内)
Activity
xintaofei commentedon Oct 14, 2026
codeg work task
344is done — merged locally intomainas8131bc1(25 files, +1259/-178).fix(parsers): read agent history from the dirs its settings relocate