Skip to content

v1.7.6 — 一个读不出来的凭据文件,不再带走整个账号池

Choose a tag to compare

@XDTrees XDTrees released this 01 Oct 02:35
· 52 commits to main since this release

你切了 4 个账号登录,界面显示 4 个;重启之后只剩 2 个 —— 不是账号没了,是它们被一个文件拖累了。

你会看到:用 WorkBuddy Switch 切换登录几个国内版账号后,卡片上账号数对不上——重启少了两个。

为什么:认证目录里同时存在好几种文件:明文的老格式、5.6.0+ 起的加密格式、写到一半的、还有插件不认识的版本。这些混在一起是常态,不是错误。

但旧代码里,只要碰到一个加密又打不开的文件(WorkBuddy 没运行、或者取不到它的密钥),就会抛异常终止整个扫描 —— 于是那些明明读得好好的账号也被一起丢掉。一个坏文件,带走整个池。

我复现了这个行为:3 个正常文件 + 1 个打不开的,结果不是返回 3 个,而是整个扫描抛错、0 个账号。

怎么修的:

  • 单个文件失败只跳过它自己,不会连累其他账号。这是核心修复;
  • 跳过的文件会被记录并显示在卡片上:现在账号区会明确写「有 N 个凭据文件读不出来」,并列出文件名和原因。其中「已加密 — 启动一次 WorkBuddy 才能取到密钥」是可操作的;而"不是凭据文件"就只是个无关文件。区分开很重要,不然你会去修一个压根修不好的东西。

这样账号数就可信了:不会再出现「磁盘上 4 个文件,界面显示 2 个账号」这种说不清的落差。

顺带修的第二个问题:pi-ai 跨代误用

另一份反馈报的是「每轮对话必崩,报 Cannot read properties of undefined 且不可重试」。根因是同一条调用链上混用了两代 pi-ai —— 插件用 0.85.x 组装 provider,宿主适配器用 0.87.x 消费事件流,两代对终态消息的形状约定不同,接缝处直接抛异常。而宿主把它归为不可重试的 PI_AI_ERROR,栈还被丢弃,所以极难排查。

为什么 package.json 的范围拦不住:旧的 peer 声明是 >=0.82.1 <0.85.0,上界把宿主的 0.87 代际整个排除在外 —— 等于把「跨代混用」变成了一种合法的安装组合。版本范围只能描述"我能接受什么",描述不了"机器上实际装的是哪一份"。

所以改成两条:

  • 放开上界(>=0.82.1),不再把宿主代际排除成非法组合;
  • 加载时实测并告警:比对插件这份与宿主那份 pi-ai 的代际,不一致就在日志里点名两个版本并给出修法(用 pnpm overrides 把代际对齐宿主)。

只告警、不阻止启动 —— 版本不一致也可能是无害的,因为一个猜测就让插件拒绝加载会更糟。

验证

  • 类型检查全绿,测试 313 项全绿(+9),连续两次全量运行稳定。
  • 新增 tests/account-discovery.test.ts(7 项):单个坏文件不拖垮扫描、全部文件都坏时也不抛错、跳过的文件带原因上报、坏文件不会被算成账号、非 JSON / 结构不对的文件同样只跳过。
  • 新增 tests/pi-ai-generation.test.ts(9 项):代际归约(补丁差异不算跨代)、0.85 / 0.87 分裂能被识别、任一侧解析不到时判为未知、告警文案包含两个版本与修法。
  • 反向验证:把「加密错误重新抛出」放回 → 4 项变红,确认测试确实能抓住这个缺陷。
  • 构建后校验产物已内联代际检测模块(无外部 .ts 引用),并直接加载 lib/index.js 确认可运行。

已知未覆盖

「每轮必崩」的那份报告里,还建议了宿主侧两处加固(mapStopReason 对空 content 加守卫、classifyPiAiError 保留原始 error.stack)。那是 DSH 宿主的代码,不在这个插件仓库内,需要另开 issue 到 DSH。