Others

把 WSL 里的 Claude Code 会话接进 Windows 的 cc-switch

1667 字约 6 分钟

摘要Claude Code 跑在 WSL2 里,用量统计和会话历史却想放在 Windows 上的 cc-switch 里看。用符号链接可以接上,但同步不触发,自动更新之后又悄悄失效,记录了整个排查过程。

我最近把开发环境搬到了 Windows 的 WSL2 里,Claude Code 也跟着在 WSL 里运行。而我在 Windows 上一直用着 cc-switch,它是一个桌面应用,可以切换 Claude Code 和 Codex 的接口配置,也能统计用量、浏览历史会话。

搬家之后,WSL 里的对话不再出现在 cc-switch 里了,用量统计和会话历史都少了一大块。原因不难猜,cc-switch 读的是 Windows 用户目录下的 .claude/projects,而 WSL 里的会话都写在 Linux 自己的家目录里,两边不是同一个地方。

我想到的办法是符号链接,把 WSL 里的目录挂到 Windows 那边。让助手去试,这件事花的时间比想象中长得多。

先看它是怎么扫描的

在动手建链接之前,助手先把 cc-switch 的源码拉下来看了一遍扫描逻辑,这一步省了后面很多弯路。

  • 会话历史那边的扫描是递归的,遇到目录就往下找,判断目录用的方法会顺着符号链接走。
  • 用量统计那边则只扫 projects/<项目名>/*.jsonl 这一层,不往下递归。

这意味着,在 projects 下面放一个指向整个 WSL projects 目录的链接是没用的,那样会多出一层目录,用量统计看不到。链接必须直接挂在 projects 下面,每个 WSL 里的项目目录各建一个。

通俗比喻:小区门口的指路牌

符号链接就像在 Windows 小区门口立一块指路牌,写着“这家人住在 WSL 小区”。cc-switch 路过看到牌子,顺着牌子走过去,就能看到里面的东西。东西本身还留在原来的地方,没有搬家。

但这位访客只愿意查看每户门口的信箱,不会再往里面走一层,所以每一户都要立一块牌子,而不是只在小区大门口立一块。

创建链接并不顺利

链接的目标是 WSL 的网络路径,也就是 \\wsl.localhost\<发行版>\home\<用户名>\.claude\projects\<项目名>。创建时我连续遇到了几个不起眼的阻碍。

第一次用 cmd.exe /c mklink /D 直接调用,报“文件名、目录名或卷标语法不正确”。命令里嵌套了好几层引号和反斜杠,应该是经过 bash 传给 Windows 之后路径被弄坏了。

第二次改用 PowerShell 的 New-Item -ItemType SymbolicLink,提示需要管理员权限。可是这台机器的开发者模式是开着的,按理说创建符号链接不需要提权。后来的结论是,Windows PowerShell 5 的 New-Item 创建链接时不带“允许非特权创建”的标志,而 mklink 带。所以同样是开发者模式,前者不行,后者可以。

最后的做法是,把 mklink 命令写进一个临时的 .cmd 文件,再用 cmd.exe 去执行它,避开了引号转义。这次链接创建成功了。

验证要在 Windows 一侧做。从 Windows 数这个目录下的会话文件有 14 个,和 WSL 里的数量一致。在 WSL 里直接 ls 这些链接则会报 Input/output error,这是正常的,WSL 读不了 Windows 一侧创建的这种网络路径链接。

之后又写了一个小脚本 ccswitch-link-wsl,遍历 WSL 里所有项目目录,给还没有链接的项目补上链接,已有的跳过。以后新开一个项目,跑一次就行。

链接建好了,数据还是没有

我打开 cc-switch,什么也没看到。助手去查它的数据库,里面记录同步进度的表,最后一次同步还停在建链接之前。cc-switch 本身在运行,但自从那之后一次同步也没触发过。

我手动重启了 cc-switch,这次数据库里就出现了 19 个 WSL 会话文件。看起来问题解决了,但没过多久,我发现点“立即同步”之后,当前这个会话的用量还是旧的。

同步到一半就悄悄失效了

这一次助手把可能的原因逐个排除。

先看文件本身。数据库里这个会话文件的同步进度停在 11:37,而文件一直在变大。从 Windows 一侧读到的修改时间和大小都是最新的,无论是经过链接,还是直接通过网络路径。所以文件系统缓存不是原因。

再看 cc-switch 的版本。日志里有两行很显眼,11:36:03 启动的是 v4.0.12,11:38:50 又启动了一次,版本变成了 v4.0.14。原来它在我手动重启之后,又自己更新并重启了一次。对比两个版本的源码,负责扫描的文件一行没改,说明不是代码变了。

最关键的线索是扫描的文件数。更新之后每次同步显示扫描 688 个文件,这个数字恰好等于 Windows 原生的 6 个 Claude 会话文件加上 682 个 Codex 会话文件。19 个 WSL 会话文件一个也不在里面,所以也就没有新增的用量。

从 Windows 的普通进程去读,这些链接是能正常打开的,cc-switch 也不是以管理员身份在运行。所以问题似乎出在“被自动更新拉起来的那个进程”上,它读不到网络路径下的链接。这是我的推断,具体卡在哪个权限或环境上,从外面查不出来,没有完全证实。

解决办法很朴素。从托盘图标里彻底退出 cc-switch,直接关窗口只是缩进托盘,再从开始菜单重新打开,然后点一次“立即同步”。重启之后,数据库里同步到了 21 个 WSL 会话文件,刚才这几轮对话的用量也记进去了。

以后每次 cc-switch 自动更新完,如果 WSL 的会话又不更新了,就用同样的办法重启一次。

使用时要注意的几件事

不要在 cc-switch 里删除 WSL 的会话

链接背后是真实的文件。在 cc-switch 里删除这些会话,删的是 WSL 里的原始文件,而且不会进回收站。

  • 在 cc-switch 里“恢复”这些会话,会在 Windows 终端里用 /home/... 这样的路径打开,大概率用不了。要继续某个会话,还是回 WSL 里用 claude --resume。
  • WSL 里原来的文件没有任何改动,Claude Code 仍然照常往 Linux 的磁盘上写,链接只是让 Windows 多了一个读取入口。
  • 这套办法依赖 Windows 的开发者模式,没开的话 mklink 创建符号链接需要管理员权限。
  • Codex 在 WSL 里的会话我没有处理,理论上可以用同样的办法接进去。

评论