fix(dsh): session_update 在插件重启后仍能定位活会话(权限热更新不再静默失效)
sessionMap 是纯内存表,插件重启后为空。而 session_update(人在 WebUI 改权限 档位)原来只查这张表 —— 于是「插件刚重启 + 那条会话还没收到新邮件」时, 那条更新被静默忽略:人在界面上把 full 改回 workspace,DSH 运行时仍按 full 执行。 人以为自己收紧了权限,实际上没有。 邮件新建的会话 id 是确定性的(mail-<邮件会话 id>,模型降级重试时带 -r<i>), 所以重启后可以按前缀在活会话里定位,并顺手把 sessionMap/reverseMap 补回去 —— 不补的话这条会话后续的自动转发也会一起失效。 - lib/mail-session-id.js(dsh 专用,9 例测试):id 派生与匹配的纯函数。 放宽成前缀匹配会把 mail-abcdef 误判成 mail-abc 的会话;非数字后缀 (-retry / -rx)也不匹配,避免误改别的会话的档位。 - 接管会话(adopted)仍是例外:其 DSH 会话 id 由平台生成、推不出来, 重启后无法热更新 —— 已知取舍;下次投递会按邮件里的 permission_mode 重设。 - tsconfig 清理:allowJs 原先写在根层(无效位置),移入 compilerOptions 后 会让 lib/*.js 进入 TS 程序并违反 rootDir;这些模块已有 .d.ts 提供类型, 该选项本就不需要,直接移除。 测试:dsh 358(新增 9)/ opencode 316 / pi 405 全绿。
This commit is contained in:
64
plugins/dsh-mail-bridge/test/mail-session-id.test.mjs
Normal file
64
plugins/dsh-mail-bridge/test/mail-session-id.test.mjs
Normal file
@ -0,0 +1,64 @@
|
||||
/**
|
||||
* 邮件会话 → DSH 会话 id 的派生约定。
|
||||
*
|
||||
* 这组函数存在的原因是一个具体的静默失效:插件重启后 `sessionMap` 为空,
|
||||
* 人在 WebUI 改档位的 `session_update` 找不到目标会话就被忽略,
|
||||
* 运行时仍按旧档位执行 —— 人以为自己收紧了权限。
|
||||
*/
|
||||
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
|
||||
import {
|
||||
dshSessionIdForMail,
|
||||
matchesMailSession,
|
||||
pickMailSession,
|
||||
} from '../lib/mail-session-id.js';
|
||||
|
||||
test('首次尝试的 id 是 mail-<邮件会话 id>', () => {
|
||||
assert.equal(dshSessionIdForMail('abc-123'), 'mail-abc-123');
|
||||
});
|
||||
|
||||
test('匹配首次尝试的 id', () => {
|
||||
assert.equal(matchesMailSession('mail-abc', 'abc'), true);
|
||||
});
|
||||
|
||||
test('匹配模型降级重试的 -r<i>', () => {
|
||||
assert.equal(matchesMailSession('mail-abc-r1', 'abc'), true);
|
||||
assert.equal(matchesMailSession('mail-abc-r12', 'abc'), true);
|
||||
});
|
||||
|
||||
test('不匹配别的会话(前缀相同也不行)', () => {
|
||||
assert.equal(matchesMailSession('mail-abcdef', 'abc'), false, 'mail-abc 的前缀不能吃掉 mail-abcdef');
|
||||
assert.equal(matchesMailSession('mail-abd', 'abc'), false);
|
||||
assert.equal(matchesMailSession('other-abc', 'abc'), false);
|
||||
assert.equal(matchesMailSession('', 'abc'), false);
|
||||
});
|
||||
|
||||
test('不匹配非数字后缀(避免误吞其它会话)', () => {
|
||||
assert.equal(matchesMailSession('mail-abc-rx', 'abc'), false);
|
||||
assert.equal(matchesMailSession('mail-abc-r', 'abc'), false);
|
||||
assert.equal(matchesMailSession('mail-abc-retry', 'abc'), false);
|
||||
});
|
||||
|
||||
test('pickMailSession 优先首次尝试,而不是数组顺序', () => {
|
||||
// 数组顺序可能来自 ctx.agents.list(),与尝试顺序无关
|
||||
assert.equal(pickMailSession(['mail-abc-r2', 'mail-abc-r1', 'mail-abc'], 'abc'), 'mail-abc');
|
||||
});
|
||||
|
||||
test('pickMailSession 没有首次尝试时取序号最小的重试', () => {
|
||||
assert.equal(pickMailSession(['mail-abc-r3', 'mail-abc-r1', 'mail-abc-r2'], 'abc'), 'mail-abc-r1');
|
||||
});
|
||||
|
||||
test('pickMailSession 找不到时返回 undefined(调用方据此跳过)', () => {
|
||||
assert.equal(pickMailSession(['other-1', 'mail-def'], 'abc'), undefined);
|
||||
assert.equal(pickMailSession([], 'abc'), undefined);
|
||||
assert.equal(pickMailSession(undefined, 'abc'), undefined);
|
||||
});
|
||||
|
||||
test('接管的平台会话推不出 id:不能被误判成邮件会话', () => {
|
||||
// 平台自己生成的 id(如 DSH 界面里开的会话)与邮件会话无关,
|
||||
// 匹配函数必须说「不是」,否则会给错误的会话改档位。
|
||||
assert.equal(matchesMailSession('session-7f3a91', 'abc'), false);
|
||||
assert.equal(pickMailSession(['session-7f3a91'], 'abc'), undefined);
|
||||
});
|
||||
Reference in New Issue
Block a user