fix(桥): 「读不出来」被当成「不存在」—— 这一行把 dsh 的邮件通道整条弄断
`persistedCwd()` 原来是 `catch { return undefined }`,把 readSession 的**三种**
抛出情形压成同一个「磁盘上没有」。调用方只把 `undefined` 读作"可以 create":
读失败(格式迁移拒绝 / 日志损坏)→ 当成不存在 → 走 create
→ 磁盘上**确实有**那个 id ⇒ `session "…" already exists`
⇒ 该会话的邮件全投不进去,而日志里只有 create 的错,
**真正的读失败被那个 catch 吃掉了**。
2026-09-19 DSH 升到 0.1.5-rc.2 后 40 个 `mail-*` 会话全部命中。
修法:`readSession` 的报错**本来就带可区分的 code**
(`dsh-session-query` 的 `notFound()` 给 `SESSION_QUERY_SESSION_NOT_FOUND`;
格式/损坏给 `SESSION_QUERY_CORRUPT_SESSION` / `SESSION_QUERY_PERSISTENCE_FAILED`)。
现在**只有 `SESSION_QUERY_SESSION_NOT_FOUND` 返回 `undefined`**,其余一律抛出,
让原文错误浮到调用方 —— 不再降级成"不存在"。
判据 `test/persisted-cwd-not-found.test.mjs`(2 条,已进 `npm test` 门禁)钉的是
**区分本身**,不是"有没有 try/catch"。三个变异逐个验过:
① catch 改回无条件 `return undefined` ⇒ 红
② 任何抛错都返回 undefined ⇒ 红
③ `throw e` 提到 code 判断之前("不存在"也抛 ⇒ create 不可达)⇒ 红
★ 变异③第一次**没落在目标上**:全局正则命中了文件里第一个无关的
`catch (e: any)`,判据全绿 —— 于是把它写成自检里的一条断言(变异必须真的落下),
避免这条自检本身变成恒真的假判据。
顺带记两个事实:
- `src/index.ts` 是桥的真源,`dist/` 是部署产物(`.gitignore` 忽略);已 `tsc` 重建并在产物里复验。
- 姊妹桥(pi/opencode/zcode)不含 `persistedCwd`,本缺陷只在 dsh 这条链上。
This commit is contained in:
@ -687,9 +687,26 @@ export function apply(ctx: any, config: PluginConfig): void {
|
||||
* 「新开会话」那条路,用回同一个 `mail-<session_id>` —— 而那个 id 上一次
|
||||
* 已经落过盘。只能问持久化层,因为这是重启后唯一还存在的事实来源。
|
||||
*
|
||||
* 读不到就当作不存在:`readSession` 在会话不存在、日志不可读、replay 校验
|
||||
* 不过时都会抛。三种情形里只有第一种适合 create,但后两种 resume 也一样
|
||||
* 救不回来 —— 那就让 create 去报它自己的错。
|
||||
* ★★★ 2026-09-25:「读不出来」**不是**「不存在」(这行曾把邮件通道整条弄断)
|
||||
*
|
||||
* 原来这里 `catch { return undefined }` —— 把**三种**抛出情形压成同一个
|
||||
* 「磁盘上没有」。而调用方只把 `undefined` 读作"可以 create",于是:
|
||||
*
|
||||
* 读失败(格式迁移拒绝 / 日志损坏) → 被当成"不存在" → 走 create
|
||||
* → 可磁盘上**确实有**那个 id ⇒ `session "…" already exists`
|
||||
* ⇒ 该会话的邮件全部投不进去,且日志里只有 create 的错,
|
||||
* **看不到真正的读失败**(它在另一个 catch 里被吃掉了)。
|
||||
*
|
||||
* 实测(2026-09-19,DSH 0.1.5-rc.2 升级后):40 个 `mail-*` 会话全部命中,
|
||||
* 整条邮件通道全断。`readSession` 的报错**本来就带可区分的 code**,
|
||||
* 是这里丢掉的区别(`dsh-session-query`:`notFound()` 给
|
||||
* `SESSION_QUERY_SESSION_NOT_FOUND`;格式/损坏给
|
||||
* `SESSION_QUERY_CORRUPT_SESSION` / `SESSION_QUERY_PERSISTENCE_FAILED`)。
|
||||
*
|
||||
* 现在:**只有 `SESSION_QUERY_SESSION_NOT_FOUND` 才返回 `undefined`**(真的可以 create);
|
||||
* 其余一律**抛出**(让原文错误浮到调用方,别再降级成"不存在")。
|
||||
* 这与本仓反复吃到的同一形状:「我没看到」≠「不存在」——
|
||||
* 一旦把读失败降级成"没有",bug 就从"报一句错"变成"静默走错分支"。
|
||||
*/
|
||||
async function persistedCwd(sessionId: string): Promise<string | undefined> {
|
||||
const q: any = (ctx as any).get?.('sessionQuery');
|
||||
@ -697,8 +714,12 @@ export function apply(ctx: any, config: PluginConfig): void {
|
||||
try {
|
||||
const snap = await q.readSession(sessionId);
|
||||
return snap?.header?.cwd ?? '';
|
||||
} catch {
|
||||
return undefined;
|
||||
} catch (e: any) {
|
||||
// 只有「确实不在磁盘上」才允许 create;其余是**读失败**,必须出声。
|
||||
if (e?.code === 'SESSION_QUERY_SESSION_NOT_FOUND') return undefined;
|
||||
console.error(`[dsh-mail-bridge] 读会话 ${sessionId} 失败(**不是**"不存在",不降级为 create): `
|
||||
+ `${e?.code || '(无 code)'}: ${e?.message || e}`);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user