dsh-remote-control 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cordis.patch.yml +4 -0
- package/dist/bundle/client.cjs +484 -0
- package/dist/bundle/index.js +577 -433
- package/package.json +14 -6
- package/dist/src/core/clock.d.ts +0 -45
- package/dist/src/core/clock.js +0 -83
- package/dist/src/core/clock.js.map +0 -1
- package/dist/src/core/keys.d.ts +0 -98
- package/dist/src/core/keys.js +0 -176
- package/dist/src/core/keys.js.map +0 -1
- package/dist/src/core/pairing-window.d.ts +0 -95
- package/dist/src/core/pairing-window.js +0 -92
- package/dist/src/core/pairing-window.js.map +0 -1
- package/dist/src/core/runtime.d.ts +0 -104
- package/dist/src/core/runtime.js +0 -491
- package/dist/src/core/runtime.js.map +0 -1
- package/dist/src/core/sleep-policy.d.ts +0 -81
- package/dist/src/core/sleep-policy.js +0 -134
- package/dist/src/core/sleep-policy.js.map +0 -1
- package/dist/src/core/window.d.ts +0 -88
- package/dist/src/core/window.js +0 -185
- package/dist/src/core/window.js.map +0 -1
- package/dist/src/index.d.ts +0 -70
- package/dist/src/index.js +0 -882
- package/dist/src/index.js.map +0 -1
- package/dist/src/platform/carrier-services.d.ts +0 -96
- package/dist/src/platform/carrier-services.js +0 -982
- package/dist/src/platform/carrier-services.js.map +0 -1
- package/dist/src/platform/guard.d.ts +0 -60
- package/dist/src/platform/guard.js +0 -124
- package/dist/src/platform/guard.js.map +0 -1
- package/dist/src/platform/mock-kernel.d.ts +0 -95
- package/dist/src/platform/mock-kernel.js +0 -180
- package/dist/src/platform/mock-kernel.js.map +0 -1
- package/dist/src/platform/qr.d.ts +0 -28
- package/dist/src/platform/qr.js +0 -80
- package/dist/src/platform/qr.js.map +0 -1
- package/dist/src/platform/sleep-posix.d.ts +0 -17
- package/dist/src/platform/sleep-posix.js +0 -91
- package/dist/src/platform/sleep-posix.js.map +0 -1
- package/dist/src/ports/index.d.ts +0 -246
- package/dist/src/ports/index.js +0 -2
- package/dist/src/ports/index.js.map +0 -1
- package/dist/src/shell/config.d.ts +0 -56
- package/dist/src/shell/config.js +0 -212
- package/dist/src/shell/config.js.map +0 -1
- package/dist/src/shell/pairing-text.d.ts +0 -38
- package/dist/src/shell/pairing-text.js +0 -22
- package/dist/src/shell/pairing-text.js.map +0 -1
- package/dist/src/shell/status.d.ts +0 -39
- package/dist/src/shell/status.js +0 -119
- package/dist/src/shell/status.js.map +0 -1
- package/dist/src/transport/relay.d.ts +0 -107
- package/dist/src/transport/relay.js +0 -359
- package/dist/src/transport/relay.js.map +0 -1
- package/dist/tests/carrier-events.test.d.ts +0 -1
- package/dist/tests/carrier-events.test.js +0 -88
- package/dist/tests/carrier-events.test.js.map +0 -1
- package/dist/tests/carrier-services.test.d.ts +0 -1
- package/dist/tests/carrier-services.test.js +0 -562
- package/dist/tests/carrier-services.test.js.map +0 -1
- package/dist/tests/carrier-vocabulary.test.d.ts +0 -1
- package/dist/tests/carrier-vocabulary.test.js +0 -149
- package/dist/tests/carrier-vocabulary.test.js.map +0 -1
- package/dist/tests/clock-probe-timers.test.d.ts +0 -1
- package/dist/tests/clock-probe-timers.test.js +0 -73
- package/dist/tests/clock-probe-timers.test.js.map +0 -1
- package/dist/tests/command-result.test.d.ts +0 -1
- package/dist/tests/command-result.test.js +0 -185
- package/dist/tests/command-result.test.js.map +0 -1
- package/dist/tests/config.test.d.ts +0 -1
- package/dist/tests/config.test.js +0 -223
- package/dist/tests/config.test.js.map +0 -1
- package/dist/tests/guard.test.d.ts +0 -1
- package/dist/tests/guard.test.js +0 -175
- package/dist/tests/guard.test.js.map +0 -1
- package/dist/tests/ids-and-keys.test.d.ts +0 -1
- package/dist/tests/ids-and-keys.test.js +0 -211
- package/dist/tests/ids-and-keys.test.js.map +0 -1
- package/dist/tests/pairing-text.test.d.ts +0 -1
- package/dist/tests/pairing-text.test.js +0 -62
- package/dist/tests/pairing-text.test.js.map +0 -1
- package/dist/tests/pairing-window.test.d.ts +0 -1
- package/dist/tests/pairing-window.test.js +0 -165
- package/dist/tests/pairing-window.test.js.map +0 -1
- package/dist/tests/relay-client.test.d.ts +0 -1
- package/dist/tests/relay-client.test.js +0 -557
- package/dist/tests/relay-client.test.js.map +0 -1
- package/dist/tests/runtime.test.d.ts +0 -1
- package/dist/tests/runtime.test.js +0 -963
- package/dist/tests/runtime.test.js.map +0 -1
- package/dist/tests/sleep.test.d.ts +0 -1
- package/dist/tests/sleep.test.js +0 -264
- package/dist/tests/sleep.test.js.map +0 -1
- package/dist/tests/status.test.d.ts +0 -1
- package/dist/tests/status.test.js +0 -238
- package/dist/tests/status.test.js.map +0 -1
- package/dist/tests/window.test.d.ts +0 -1
- package/dist/tests/window.test.js +0 -210
- package/dist/tests/window.test.js.map +0 -1
|
@@ -1,238 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* status.test — `shell/status.ts`:status.json(GUI 宿主里唯一的排错入口)。
|
|
3
|
-
*
|
|
4
|
-
* 需求来源:docs/DESIGN.md §7 阶段 C 第 ⑦ 条("status.json 字段与 0600 原子写")与
|
|
5
|
-
* docs/legacy-spec/host-plugin-cordis.md §5.3(旧实现靠 `carrier` 与 `relay`+`relayProblem`
|
|
6
|
-
* 两组字段区分了两类完全不同的故障)。
|
|
7
|
-
*
|
|
8
|
-
* 三条要守的东西:
|
|
9
|
-
* 1. **0600 + 临时文件改名**——文件里可能出现"仍然有效的配对码 + PSK"(pairOnStartSec),
|
|
10
|
-
* 半写状态被读到会误判,权限松了就是凭据泄露(M19/N19)。
|
|
11
|
-
* 2. **绝不含 token 真值**——只允许 `redact()` 之后的形态出现。
|
|
12
|
-
* 3. **写失败不许影响主流程**——排错入口没了是遗憾,插件崩了是事故。
|
|
13
|
-
*/
|
|
14
|
-
import { test } from 'node:test';
|
|
15
|
-
import assert from 'node:assert/strict';
|
|
16
|
-
import { chmodSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
17
|
-
import { homedir, tmpdir } from 'node:os';
|
|
18
|
-
import path from 'node:path';
|
|
19
|
-
import { pairingImagePath, StatusFile, writePrivateFile } from '../src/shell/status.js';
|
|
20
|
-
import { DEFAULT_SYSTEM_CLOCK, FakeClock } from '../src/core/clock.js';
|
|
21
|
-
import { redact } from '../src/shell/config.js';
|
|
22
|
-
/** 一眼假的 token:仓库里不许出现任何真凭据,这条只验形状。 */
|
|
23
|
-
const FAKE_TOKEN = 'fake-token-not-a-real-secret-0123456789abcdef';
|
|
24
|
-
function tempDir() {
|
|
25
|
-
const dir = mkdtempSync(path.join(tmpdir(), 'drc-status-'));
|
|
26
|
-
const file = path.join(dir, 'status.json');
|
|
27
|
-
return { dir, file, cleanup: () => rmSync(dir, { recursive: true, force: true }) };
|
|
28
|
-
}
|
|
29
|
-
const modeOf = (file) => (statSync(file).mode & 0o777).toString(8);
|
|
30
|
-
test('快照以 0600 落盘:里面可能出现仍然有效的配对码与 PSK', () => {
|
|
31
|
-
const { file, cleanup } = tempDir();
|
|
32
|
-
try {
|
|
33
|
-
new StatusFile(file, DEFAULT_SYSTEM_CLOCK).write({ carrier: 'services', relay: 'online', conversations: 1 });
|
|
34
|
-
assert.equal(modeOf(file), '600', `实际权限 ${modeOf(file)}:同机其它用户能读走配对码,等于配对被偷`);
|
|
35
|
-
assert.equal(existsTmp(file), false, '写完必须把临时文件改名走,不许留下 .tmp-*');
|
|
36
|
-
}
|
|
37
|
-
finally {
|
|
38
|
-
cleanup();
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
test('原子替换:内容永远是一份完整 JSON,读的人不会看到半写的快照', () => {
|
|
42
|
-
const { dir, file, cleanup } = tempDir();
|
|
43
|
-
try {
|
|
44
|
-
const status = new StatusFile(file, DEFAULT_SYSTEM_CLOCK);
|
|
45
|
-
status.write({ carrier: 'services', relay: 'online', conversations: 1 });
|
|
46
|
-
status.write({ carrier: 'services', relay: 'offline', conversations: 0, relayProblem: '连接关闭 1006' });
|
|
47
|
-
const text = readFileSync(file, 'utf8');
|
|
48
|
-
const parsed = JSON.parse(text);
|
|
49
|
-
assert.equal(parsed.relay, 'offline', '第二次写没覆盖掉第一次的:外部脚本会读到已经消失的故障');
|
|
50
|
-
assert.equal(text.endsWith('\n'), true, '末尾留一个换行:tail/cat 与 diff 都不会打出无主字符');
|
|
51
|
-
assert.equal(readdirSync(dir).filter((name) => name.includes('.tmp-')).length, 0, '目录里残留了临时文件:说明 rename 之前崩过或改名没做');
|
|
52
|
-
assert.equal(typeof parsed.updatedAt, 'string', 'updatedAt 必须在:这是"快照多旧"的唯一判据(外部脚本靠年龄<25s 接受配对码)');
|
|
53
|
-
assert.equal(Number.isNaN(Date.parse(String(parsed.updatedAt))), false, 'updatedAt 必须是 Date.parse 认得出的字符串');
|
|
54
|
-
assert.equal(typeof parsed.pid, 'number', 'pid 要在:区分两个宿主进程抢同一个 status.json 时靠它');
|
|
55
|
-
}
|
|
56
|
-
finally {
|
|
57
|
-
cleanup();
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
test('快照里不得出现 token 真值:只能出现 redact() 之后的形态', () => {
|
|
61
|
-
const { file, cleanup } = tempDir();
|
|
62
|
-
try {
|
|
63
|
-
// 复刻 index.ts 的 state() 形状:hostToken 恒为 undefined,真值只以脱敏形态出现。
|
|
64
|
-
new StatusFile(file, DEFAULT_SYSTEM_CLOCK).write({
|
|
65
|
-
carrier: 'services',
|
|
66
|
-
serverUrl: 'wss://drc.example.com',
|
|
67
|
-
hostToken: undefined,
|
|
68
|
-
hostTokenShape: redact(FAKE_TOKEN),
|
|
69
|
-
token: undefined,
|
|
70
|
-
psk: undefined,
|
|
71
|
-
});
|
|
72
|
-
const text = readFileSync(file, 'utf8');
|
|
73
|
-
const parsed = JSON.parse(text);
|
|
74
|
-
assert.equal(parsed.hostToken, undefined, 'status.json 里带着 hostToken 真值:这个文件是被设计成"随时贴进工单"的');
|
|
75
|
-
assert.equal(text.includes(FAKE_TOKEN), false, '整条 token 出现在文件里');
|
|
76
|
-
assert.equal(text.includes('not-a-real-secret'), false, 'token 的中段出现在文件里');
|
|
77
|
-
assert.equal(typeof parsed.hostTokenShape, 'string', '脱敏形态必须留着:排错时要靠长度判断是不是拿错了变量');
|
|
78
|
-
assert.equal(String(parsed.hostTokenShape).length < FAKE_TOKEN.length, true, '脱敏后的字符串必须明显短于原值');
|
|
79
|
-
}
|
|
80
|
-
finally {
|
|
81
|
-
cleanup();
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
test('statusFile 为空字符串就是关闭整个功能:不建文件、不装定时器、绝不抛', () => {
|
|
85
|
-
const { dir, cleanup } = tempDir();
|
|
86
|
-
try {
|
|
87
|
-
const clock = new FakeClock();
|
|
88
|
-
const status = new StatusFile('', clock, 1_000);
|
|
89
|
-
assert.equal(status.path, '', 'path 就是那个空串:调用方用它判断功能是否开启');
|
|
90
|
-
assert.doesNotThrow(() => status.write({ carrier: 'services' }), '关闭状态下 write 抛了出去 → 主流程被一个可选项带崩');
|
|
91
|
-
let refreshed = 0;
|
|
92
|
-
assert.doesNotThrow(() => status.start(() => {
|
|
93
|
-
refreshed += 1;
|
|
94
|
-
return {};
|
|
95
|
-
}));
|
|
96
|
-
assert.equal(clock.pending, 0, '关闭状态下不许装刷新定时器');
|
|
97
|
-
return void clock.advance(10_000).then(() => {
|
|
98
|
-
assert.equal(refreshed, 0, '关闭状态下定时器还在刷新快照');
|
|
99
|
-
assert.equal(readdirSync(dir).length, 0, '关闭状态下仍然往目录里写了东西');
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
finally {
|
|
103
|
-
// 断言在 promise 里,cleanup 必须等它落定
|
|
104
|
-
void cleanup;
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
test('写失败(目录不可写)不许影响主流程:排错入口没了是遗憾,插件崩了是事故', () => {
|
|
108
|
-
const { dir, cleanup } = tempDir();
|
|
109
|
-
try {
|
|
110
|
-
const readonly = path.join(dir, 'locked');
|
|
111
|
-
mkdirSync(readonly, { mode: 0o500 });
|
|
112
|
-
const status = new StatusFile(path.join(readonly, 'nested', 'status.json'), DEFAULT_SYSTEM_CLOCK);
|
|
113
|
-
assert.doesNotThrow(() => status.write({ carrier: 'services' }), `目录不可写时把异常抛了出去(chmod=${modeOf(readonly)})`);
|
|
114
|
-
assert.equal(existsTmp(path.join(readonly, 'status.json')), false, '失败后不许留下半成品');
|
|
115
|
-
// 另一种失败形状:父路径是个普通文件,mkdirSync 直接 ENOTDIR。
|
|
116
|
-
const notADir = path.join(dir, 'afile');
|
|
117
|
-
writeFileSync(notADir, 'x');
|
|
118
|
-
assert.doesNotThrow(() => new StatusFile(path.join(notADir, 'status.json'), DEFAULT_SYSTEM_CLOCK).write({ carrier: 'mock' }), 'ENOTDIR 抛了出去');
|
|
119
|
-
}
|
|
120
|
-
finally {
|
|
121
|
-
chmodSync(path.join(dir, 'locked'), 0o700);
|
|
122
|
-
cleanup();
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
test('定时刷新的节拍、自我续期与"真的落盘":status.json 是外部脚本取配对码的唯一入口', async () => {
|
|
126
|
-
const { file, cleanup } = tempDir();
|
|
127
|
-
try {
|
|
128
|
-
const clock = new FakeClock();
|
|
129
|
-
const status = new StatusFile(file, clock, 3_000);
|
|
130
|
-
let built = 0;
|
|
131
|
-
// 调用方给的必须是**纯构造器**:只返回状态,写盘由 StatusFile 负责。
|
|
132
|
-
// 第一版写成"tick 里调 refresh() 把返回值丢掉",于是文件永远停在启动那一版,
|
|
133
|
-
// 而 live-e2e 判配对码是否新鲜读的就是这个文件(取证 §5.3 的"年龄 < 25s")。
|
|
134
|
-
status.start(() => {
|
|
135
|
-
built += 1;
|
|
136
|
-
return { carrier: 'services', conversations: built };
|
|
137
|
-
});
|
|
138
|
-
assert.equal(built, 0, 'start() 只装定时器,不该同步抢跑一次');
|
|
139
|
-
await clock.advance(3_000);
|
|
140
|
-
assert.ok(built >= 1, `等了 3 秒一次都没刷新(built=${built}):status.json 会永远停在启动那一版`);
|
|
141
|
-
await clock.advance(9_000);
|
|
142
|
-
assert.ok(built >= 4, `12 秒里只刷新了 ${built} 次:定时器没有自我续期`);
|
|
143
|
-
const parsed = JSON.parse(readFileSync(file, 'utf8'));
|
|
144
|
-
assert.equal(parsed.conversations, built, '刷新写进去的必须是最新一次构建的快照');
|
|
145
|
-
assert.equal(typeof parsed.updatedAt, 'string', '每一版都要带 updatedAt:外部脚本靠"年龄 < 25s"决定能不能用这张码(§5.3)');
|
|
146
|
-
// 再走一拍:文件内容必须跟着变(只看 built 会放过"构造器跑了但没写盘"这个 bug)。
|
|
147
|
-
await clock.advance(3_000);
|
|
148
|
-
const again = JSON.parse(readFileSync(file, 'utf8'));
|
|
149
|
-
assert.equal(again.conversations, built, `文件停在 ${String(parsed.conversations)},构造器已经跑到 ${built}:tick 没有落盘`);
|
|
150
|
-
status.stop();
|
|
151
|
-
const pendingAfterStop = clock.pending;
|
|
152
|
-
await clock.advance(30_000);
|
|
153
|
-
assert.equal(pendingAfterStop, 0, `stop() 之后还剩 ${pendingAfterStop} 个定时器:宿主是用户的内核进程,插件不能让它赖着不退`);
|
|
154
|
-
assert.equal(built >= 5, true, '夹具自检:停机前刷新次数要有下界');
|
|
155
|
-
}
|
|
156
|
-
finally {
|
|
157
|
-
cleanup();
|
|
158
|
-
}
|
|
159
|
-
});
|
|
160
|
-
test('start() 重复调用不许叠出第二份定时器(刷新频率翻倍会把文件写坏)', async () => {
|
|
161
|
-
const { file, cleanup } = tempDir();
|
|
162
|
-
try {
|
|
163
|
-
const clock = new FakeClock();
|
|
164
|
-
const status = new StatusFile(file, clock, 1_000);
|
|
165
|
-
let built = 0;
|
|
166
|
-
const refresh = () => {
|
|
167
|
-
built += 1;
|
|
168
|
-
return { n: built };
|
|
169
|
-
};
|
|
170
|
-
status.start(refresh);
|
|
171
|
-
status.start(refresh);
|
|
172
|
-
status.start(refresh);
|
|
173
|
-
assert.equal(clock.pending, 1, `装了 ${clock.pending} 个定时器:重复 start() 必须幂等`);
|
|
174
|
-
await clock.advance(1_000);
|
|
175
|
-
assert.equal(built, 1, `一次 tick 刷新了 ${built} 次`);
|
|
176
|
-
status.stop();
|
|
177
|
-
}
|
|
178
|
-
finally {
|
|
179
|
-
cleanup();
|
|
180
|
-
}
|
|
181
|
-
});
|
|
182
|
-
test('嵌套字段(pairing / keepAwake / kernel)必须原样落地:那是区分两类故障的判据', () => {
|
|
183
|
-
const { file, cleanup } = tempDir();
|
|
184
|
-
try {
|
|
185
|
-
new StatusFile(file, DEFAULT_SYSTEM_CLOCK).write({
|
|
186
|
-
carrier: 'services',
|
|
187
|
-
relay: 'online',
|
|
188
|
-
pairing: { token: '123456', expiresAt: '2026-10-02T08:00:00.000Z', ageSec: 12 },
|
|
189
|
-
keepAwake: { enabled: true, active: false, platform: 'darwin', backend: 'caffeinate' },
|
|
190
|
-
kernel: { listingSource: 'attached only', hiddenSubagents: 1 },
|
|
191
|
-
problems: ['warn:pairOnStartSec'],
|
|
192
|
-
nothingHere: null,
|
|
193
|
-
});
|
|
194
|
-
const parsed = JSON.parse(readFileSync(file, 'utf8'));
|
|
195
|
-
assert.equal(parsed.pairing.token, '123456', 'pairing 结构丢了:CLI/e2e 就没法取码(status.json 是唯一的广播介质)');
|
|
196
|
-
assert.equal(parsed.keepAwake.active, false, 'keepAwake.active 必须如实:它表示"此刻是否正在阻止休眠"');
|
|
197
|
-
assert.equal(parsed.kernel.hiddenSubagents, 1, 'kernel.describe() 的诊断要能进快照:"适配器静默返回 []"与"真的没有会话"必须可区分(M27)');
|
|
198
|
-
assert.deepEqual(parsed.problems, ['warn:pairOnStartSec'], '配置问题列表要在,否则"为什么什么都没发生"没有答案');
|
|
199
|
-
assert.equal('nothingHere' in parsed, true, 'null 字段必须保留(undefined 会被 JSON 丢掉,这是调用方的选择)');
|
|
200
|
-
}
|
|
201
|
-
finally {
|
|
202
|
-
cleanup();
|
|
203
|
-
}
|
|
204
|
-
});
|
|
205
|
-
test('pairingImagePath:会话工作区的 .dsh,解析不出工作区才退回 ~/.dsh,空串表示关闭', () => {
|
|
206
|
-
assert.equal(pairingImagePath(''), '', 'statusFile 为空时二维码路径也必须为空,否则 PNG 会写到进程 CWD');
|
|
207
|
-
assert.equal(pairingImagePath('/home/u/.dsh/dsh-remote-control/status.json', '/Users/u/project'), path.join('/Users/u/project', '.dsh', 'pairing-qr.png'), '有工作区就落在工作区的 .dsh 下:2026-10-02 用户拍板"要工作区的 .dsh,不是 home 下的 .dsh"');
|
|
208
|
-
assert.equal(pairingImagePath('/home/u/.dsh/dsh-remote-control/status.json'), path.join(homedir(), '.dsh', 'pairing-qr.png'), '解析不出会话工作区时退回 ~/.dsh 根部(而不是埋进 ~/.dsh/dsh-remote-control/ 实现目录)');
|
|
209
|
-
for (const bogus of ['', undefined]) {
|
|
210
|
-
assert.equal(pairingImagePath('status.json', bogus), path.join(homedir(), '.dsh', 'pairing-qr.png'), `工作区为空(${String(bogus)})时必须退回 home,而不是拼出一个相对路径写到进程 CWD`);
|
|
211
|
-
}
|
|
212
|
-
});
|
|
213
|
-
test('writePrivateFile 也是 0600:里面躺着一张仍然有效的配对二维码', () => {
|
|
214
|
-
const { dir, cleanup } = tempDir();
|
|
215
|
-
try {
|
|
216
|
-
const png = path.join(dir, 'sub', 'pairing-qr.png');
|
|
217
|
-
assert.equal(writePrivateFile(png, Buffer.from([0x89, 0x50, 0x4e, 0x47])), true, 'writePrivateFile 声称写成功但返回 false');
|
|
218
|
-
assert.equal(modeOf(png), '600', `PNG 实际权限 ${modeOf(png)}:QR 里含 PSK,谁读到谁就能配对`);
|
|
219
|
-
assert.equal(readFileSync(png).subarray(0, 4).toString('hex'), '89504e47', '写入内容必须逐字节一致');
|
|
220
|
-
assert.equal(writePrivateFile('', Buffer.from('x')), false, '空路径要返回 false 而不是抛:调用方靠它决定要不要退回文本二维码');
|
|
221
|
-
const notADir = path.join(dir, 'afile');
|
|
222
|
-
writeFileSync(notADir, 'x');
|
|
223
|
-
assert.equal(writePrivateFile(path.join(notADir, 'qr.png'), 'data'), false, '写失败必须折成 false:不许抛出去打断 /drc pair');
|
|
224
|
-
}
|
|
225
|
-
finally {
|
|
226
|
-
cleanup();
|
|
227
|
-
}
|
|
228
|
-
});
|
|
229
|
-
/** 目标路径的临时兄弟文件是否存在(用于"失败后不许留半成品")。 */
|
|
230
|
-
function existsTmp(file) {
|
|
231
|
-
try {
|
|
232
|
-
return statSync(`${file}.tmp-${process.pid}`).isFile();
|
|
233
|
-
}
|
|
234
|
-
catch {
|
|
235
|
-
return false;
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
//# sourceMappingURL=status.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"status.test.js","sourceRoot":"","sources":["../../tests/status.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* window.test — `core/window.ts` 的 DeltaWindow。
|
|
3
|
-
*
|
|
4
|
-
* 这一层守的是手机上"看得见"的两件事:**文本一个都不丢、顺序一个都不乱**,
|
|
5
|
-
* 以及**每条消息最终必须有一条 done:true**。编号对应 docs/DESIGN.md §2.2 的 F9,
|
|
6
|
-
* 需求与事故来源是 docs/legacy-spec/host-plugin-runtime.md §3.5/§3.6/§7.2 与
|
|
7
|
-
* docs/legacy-spec/mp-client-contract.md §2.3(`ev.message_delta` 那张表)。
|
|
8
|
-
*
|
|
9
|
-
* 夹具刻意用 `FakeClock`(`core/clock.ts`)而不是真定时器:
|
|
10
|
-
* 旧实现那 5 条窗口测试要 `setTimeout(260)` 真等,所以"定时器只在首字装填"
|
|
11
|
-
* 和两个上限路径(4096 字符 / 32 会话)从来没被测试覆盖过
|
|
12
|
-
* (取证 host-plugin-runtime.md §7.1 §7.4 第 7 条)。这里 120ms 与 300s 都是 `advance()`。
|
|
13
|
-
*/
|
|
14
|
-
import { test } from 'node:test';
|
|
15
|
-
import assert from 'node:assert/strict';
|
|
16
|
-
import { DeltaWindow, DEFAULT_WINDOW_OPTIONS } from '../src/core/window.js';
|
|
17
|
-
import { FakeClock } from '../src/core/clock.js';
|
|
18
|
-
/** 只测合帧器本身:emit 直接落进数组,不认识 socket,也不认识 cordis。 */
|
|
19
|
-
function harness(overrides = {}) {
|
|
20
|
-
const clock = new FakeClock();
|
|
21
|
-
const frames = [];
|
|
22
|
-
const win = new DeltaWindow((frame) => {
|
|
23
|
-
frames.push(frame);
|
|
24
|
-
}, clock, { ...DEFAULT_WINDOW_OPTIONS, ...overrides });
|
|
25
|
-
return { clock, frames, win };
|
|
26
|
-
}
|
|
27
|
-
test('空文本的 done 帧绝不丢:丢了它手机上「运行中…」会永远转圈(F9)', async () => {
|
|
28
|
-
const { clock, frames, win } = harness();
|
|
29
|
-
win.push('ses_a', 'msg_1', '答案');
|
|
30
|
-
await clock.advance(200); // 越过 120ms 窗口,让带文本的那帧先单独出去
|
|
31
|
-
assert.equal(frames.length, 1, '窗口到期必须出 1 帧,实际没有按窗口合帧');
|
|
32
|
-
// 内核 turn/end 的真实形状:一条空文本 + done:true(adapter-dsh 的 messageId:'turn')。
|
|
33
|
-
win.complete('ses_a', 'msg_1');
|
|
34
|
-
assert.ok(frames.length >= 2, `done 帧被吞了:只收到 ${frames.length} 帧 → 手机永远收不到"这一轮跑完了"`);
|
|
35
|
-
const tail = frames[frames.length - 1];
|
|
36
|
-
assert.equal(tail.t, 'ev.message_delta', '帧名不是 ev.message_delta → 小程序 if 链不匹配,静默丢弃');
|
|
37
|
-
assert.equal(tail.delta, '', 'done 帧的文本必须是空串(不是 undefined:手机会 += 出 "undefined")');
|
|
38
|
-
assert.equal(tail.done, true, "手机端 chat.js 靠 done:true 收起转圈,缺了就一直显示'运行中…'");
|
|
39
|
-
assert.equal(tail.messageId, 'msg_1', 'messageId 丢了 → 手机把这条挂到错误的消息行上');
|
|
40
|
-
assert.equal(win.stats.droppedEmpty, 0, 'done 帧不是"空消息",绝不能进丢弃计数');
|
|
41
|
-
});
|
|
42
|
-
test('done 与文本落在同一个窗口里时必须合并成一帧(既不另发一帧,也不把 done 弄丢)', () => {
|
|
43
|
-
const { frames, win } = harness();
|
|
44
|
-
win.push('ses_a', 'msg_1', '结论是');
|
|
45
|
-
win.complete('ses_a', 'msg_1');
|
|
46
|
-
assert.equal(frames.length, 1, `done 被拆成了独立帧(${frames.length} 帧)→ 手机要多收一帧,且旧实现这里曾丢过 done`);
|
|
47
|
-
const only = frames[0];
|
|
48
|
-
assert.equal(only.delta, '结论是', '合并必须保序带出原文');
|
|
49
|
-
assert.equal(only.done, true, 'sticky-OR 的 done 必须在合并帧上活着');
|
|
50
|
-
});
|
|
51
|
-
test('缓冲里根本没有这条消息时(工具调用没出字就直接结束),也必须补一条 done-only 帧', () => {
|
|
52
|
-
const { frames, win } = harness();
|
|
53
|
-
win.complete('ses_b', 'turn');
|
|
54
|
-
assert.ok(frames.length >= 1, '一条文本都没有的收尾同样必须出站,否则手机停在转圈态');
|
|
55
|
-
const only = frames[0];
|
|
56
|
-
assert.equal(only.messageId, 'turn', 'done-only 帧的 messageId 必须逐字回传(手机用它定位消息行)');
|
|
57
|
-
assert.equal(only.delta, '');
|
|
58
|
-
assert.equal(only.done, true);
|
|
59
|
-
});
|
|
60
|
-
test('合帧定时器只在首字装填:后续字符不许续期,否则长输出永远发不出去', async () => {
|
|
61
|
-
const { clock, frames, win } = harness({ windowMs: 120 });
|
|
62
|
-
win.push('ses_a', 'msg_1', 'a');
|
|
63
|
-
await clock.advance(119);
|
|
64
|
-
assert.equal(frames.length, 0, '未到窗口就发 → 等于没有合帧(帧率退化成 1 帧/字)');
|
|
65
|
-
// 首字之后 119ms 又来一个字:如果实现按"每个字符续期",出站时刻会被推到 239ms,
|
|
66
|
-
// 一条持续出字的长回答就永远发不出去(手机表现为卡住不动)。
|
|
67
|
-
win.push('ses_a', 'msg_1', 'b');
|
|
68
|
-
await clock.advance(2); // 此刻 121ms:首字装填的那个定时器早该到期
|
|
69
|
-
assert.ok(frames.length >= 1, '后续字符续期了定时器 → 流式输出会一路被推迟,手机看不到增量');
|
|
70
|
-
assert.equal(frames[0].delta, 'ab', '窗口内的字必须按到达顺序串接,一个都不能少');
|
|
71
|
-
});
|
|
72
|
-
test('flushSession 冲刷同会话缓冲:非 delta 事件之前必须先调它,否则工具行会插到自己的文本前面', async () => {
|
|
73
|
-
const { clock, frames, win } = harness({ windowMs: 5_000 });
|
|
74
|
-
win.push('ses_a', 'msg_1', '我先说明一下');
|
|
75
|
-
win.flushSession('ses_a'); // runtime 在 ev.tool_event 之前走的就是这一步
|
|
76
|
-
win.push('ses_a', 'msg_1', '然后是调用后的补充');
|
|
77
|
-
win.complete('ses_a', 'msg_1'); // turn/end:这一条消息到此为止
|
|
78
|
-
await clock.advance(0);
|
|
79
|
-
assert.ok(frames.length >= 2, `只收到 ${frames.length} 帧:文本被工具行插队 → 手机先看到工具调用、后看到调用前的说明`);
|
|
80
|
-
assert.equal(frames[0].delta, '我先说明一下', '第一帧必须是先产生的那段文本');
|
|
81
|
-
assert.equal(frames[1].delta, '然后是调用后的补充', '第二帧才是后产生的文本');
|
|
82
|
-
assert.equal(frames[0]?.done, undefined, '中途切帧不许把 done 提前带上(done 只能出现在收尾帧)');
|
|
83
|
-
assert.equal(frames[1].done, true, '收尾必须有一条 done:true');
|
|
84
|
-
// 已经冲过的会话再冲一次不许重复出站(也不许凭空造帧)。
|
|
85
|
-
const before = frames.length;
|
|
86
|
-
win.flushSession('ses_a');
|
|
87
|
-
win.flushSession('ses_never_buffered');
|
|
88
|
-
assert.equal(frames.length, before, 'flush 幂等性破了 → 手机上同一段文字出现两遍');
|
|
89
|
-
});
|
|
90
|
-
test('maxCharsPerFrame 切帧:字符一个都不丢、顺序不乱,且不提前带上 done', () => {
|
|
91
|
-
const { frames, win } = harness({ windowMs: 10_000, maxCharsPerFrame: 10 });
|
|
92
|
-
const input = '0123456789abcdefghij01234'; // 25 个字符,按上限切成 10+10+5
|
|
93
|
-
win.push('ses_a', 'msg_1', input.slice(0, 10));
|
|
94
|
-
assert.ok(frames.length >= 1, '到顶必须立刻 flush,不许等窗口(否则单帧可能顶到中继帧上限)');
|
|
95
|
-
win.push('ses_a', 'msg_1', input.slice(10, 20));
|
|
96
|
-
win.push('ses_a', 'msg_1', input.slice(20));
|
|
97
|
-
win.complete('ses_a', 'msg_1'); // 收尾:剩下的 5 个字符必须跟着 done 一起出去
|
|
98
|
-
assert.ok(frames.length >= 3, `切了 ${frames.length} 帧,少于预期的 3 帧 → 有字符被合并逻辑吞掉`);
|
|
99
|
-
assert.equal(frames.map((frame) => frame.delta).join(''), input, '切帧后拼回来的正文必须与输入逐字符相等');
|
|
100
|
-
assert.equal(frames[0]?.done, undefined, '切出来的中间帧不许带 done → 手机会提前收起转圈、后面正文没地方放');
|
|
101
|
-
assert.equal(frames[frames.length - 1]?.done, true, '最后一帧必须带 done');
|
|
102
|
-
assert.equal(new Set(frames.map((frame) => frame.messageId)).size, 1, '同一条消息切帧不许换 messageId(换了手机会拆成两段)');
|
|
103
|
-
});
|
|
104
|
-
test('maxCharsPerFrame 是出站硬上限:一次 push 就写超也要切,不许出一帧 5 万字符', () => {
|
|
105
|
-
const { frames, win } = harness({ windowMs: 10_000, maxCharsPerFrame: 10 });
|
|
106
|
-
const input = 'x'.repeat(37); // 一次到达就超上限三次以上:内核一个 delta 事件带一大段文本是常态
|
|
107
|
-
win.push('ses_a', 'msg_1', input);
|
|
108
|
-
win.complete('ses_a', 'msg_1');
|
|
109
|
-
assert.ok(frames.length >= 4, `一帧 37 字符(上限 10)只切了 ${frames.length} 帧:上限只管了"何时 flush",没管"多大"`);
|
|
110
|
-
assert.ok(frames.every((frame) => frame.delta.length <= 10), `仍有超限帧:${JSON.stringify(frames.map((frame) => frame.delta.length))}。中继侧 MAX_FRAME_BYTES 会把整条连接断开,手机表现为"聊着聊着掉线"`);
|
|
111
|
-
assert.equal(frames.map((frame) => frame.delta).join(''), input, '切帧不许丢字符');
|
|
112
|
-
// 到顶的那一次先冲掉 4 片(part 0..3),随后 complete() 补一条收尾帧(part 4)。
|
|
113
|
-
// 这条 done 只能是独立一帧:前 4 帧已经在 complete 之前发出去了。
|
|
114
|
-
assert.deepEqual(frames.map((frame) => frame.part), [0, 1, 2, 3, 4], '同一条消息的分片序号必须逐帧递增:手机与日志靠它判断"分片是否连续",全 0 就等于没有这个判据');
|
|
115
|
-
assert.equal(frames[frames.length - 1]?.done, true, 'done 只能落在最后一片上');
|
|
116
|
-
assert.equal(frames.slice(0, -1).every((frame) => frame.done === undefined), true, '中间片不许提前带 done');
|
|
117
|
-
});
|
|
118
|
-
test('part 跨 flush 连续:同一条消息被窗口切成两帧时,序号不能归零', async () => {
|
|
119
|
-
const { clock, frames, win } = harness({ windowMs: 120 });
|
|
120
|
-
win.push('ses_a', 'msg_1', '第一段');
|
|
121
|
-
await clock.advance(200); // 窗口到期 → part 0
|
|
122
|
-
win.push('ses_a', 'msg_1', '第二段');
|
|
123
|
-
await clock.advance(200); // 同一个 messageId 的下一片 → 必须是 part 1
|
|
124
|
-
win.complete('ses_a', 'msg_1');
|
|
125
|
-
assert.equal(frames.length, 3, `预期 3 帧,实收 ${frames.length}`);
|
|
126
|
-
assert.deepEqual(frames.map((frame) => frame.part), [0, 1, 2], 'flush 把 entry 删掉、下一条重建时 part 归零 → 一条长回答的所有分片都是 part:0,"分片完整性"无从判断');
|
|
127
|
-
assert.equal(new Set(frames.map((frame) => frame.messageId)).size, 1, '同一条消息不许换 messageId');
|
|
128
|
-
// 换一条消息才是新的序列:从 0 重新开始。
|
|
129
|
-
const second = harness({ windowMs: 120 });
|
|
130
|
-
second.win.push('ses_a', 'msg_1', '甲');
|
|
131
|
-
await second.clock.advance(200);
|
|
132
|
-
second.win.push('ses_a', 'msg_1', '乙');
|
|
133
|
-
await second.clock.advance(200);
|
|
134
|
-
second.win.push('ses_a', 'msg_2', '丙');
|
|
135
|
-
second.win.stop();
|
|
136
|
-
const msg2 = second.frames.filter((frame) => frame.messageId === 'msg_2');
|
|
137
|
-
assert.equal(msg2[0]?.part, 0, `新消息的分片序号应从 0 开始,实际 ${msg2[0]?.part}`);
|
|
138
|
-
});
|
|
139
|
-
test('maxSessionsPerRound 生效:一轮只冲最旧的 N 个会话,吵闹的会话饿死不了其它会话', () => {
|
|
140
|
-
const { frames, win } = harness({ windowMs: 10_000, maxSessionsPerRound: 2 });
|
|
141
|
-
for (const sessionId of ['ses_1', 'ses_2', 'ses_3', 'ses_4', 'ses_5']) {
|
|
142
|
-
win.push(sessionId, 'msg_x', `字-${sessionId}`);
|
|
143
|
-
}
|
|
144
|
-
assert.equal(win.stats.buffered, 5, '五条会话都该在缓冲里');
|
|
145
|
-
win.flushRound();
|
|
146
|
-
assert.equal(frames.length, 2, '一轮最多冲 maxSessionsPerRound 个,多冲/少冲都说明上限没生效');
|
|
147
|
-
assert.deepEqual(frames.map((frame) => frame.sessionId).sort(), ['ses_1', 'ses_2'], '必须先冲缓冲最久的会话(不按 since 排序就是"最后写入者赢",某个会话可能永远轮不到)');
|
|
148
|
-
assert.equal(win.stats.buffered, 3, '剩下的三条不许被顺手丢掉');
|
|
149
|
-
win.flushRound();
|
|
150
|
-
win.flushRound();
|
|
151
|
-
assert.equal(frames.length, 5, `两轮之后还剩会话没冲:${win.stats.buffered} 条`);
|
|
152
|
-
assert.equal(win.stats.buffered, 0, '全部会话都必须最终被冲出去(上限只能提前结束窗口,不能丢数据)');
|
|
153
|
-
});
|
|
154
|
-
test('stop() 全量 flush 并撤掉所有定时器:停机时尾句不许蒸发,也不许留下吊住宿主的定时器', async () => {
|
|
155
|
-
const { clock, frames, win } = harness({ windowMs: 10_000 });
|
|
156
|
-
win.push('ses_a', 'msg_1', '尾句A');
|
|
157
|
-
win.push('ses_b', 'msg_2', '尾句B');
|
|
158
|
-
win.push('ses_c', 'msg_3', '尾句C');
|
|
159
|
-
assert.ok(clock.pending >= 3, '夹具自检:每个会话都该装了一个窗口定时器');
|
|
160
|
-
win.stop();
|
|
161
|
-
await clock.advance(10_000);
|
|
162
|
-
assert.ok(frames.length >= 3, `停机只冲出 ${frames.length} 帧 → 缓冲里的正文随进程一起蒸发`);
|
|
163
|
-
assert.equal(frames
|
|
164
|
-
.map((frame) => frame.delta)
|
|
165
|
-
.sort()
|
|
166
|
-
.join('|'), ['尾句A', '尾句B', '尾句C'].sort().join('|'), '停机必须把每条会话的缓冲都发出去(顺序:flush 在拆 socket 之前)');
|
|
167
|
-
assert.equal(win.stats.buffered, 0, 'stop() 之后缓冲必须清空');
|
|
168
|
-
assert.equal(clock.pending, 0, 'stop() 之后不许残留定时器:宿主是用户的内核进程,插件不能让它赖着不退');
|
|
169
|
-
});
|
|
170
|
-
test('唯一允许丢弃的情形是"既无文本也非 done",并且必须被 stats.droppedEmpty 观察到', () => {
|
|
171
|
-
const { frames, win } = harness();
|
|
172
|
-
win.push('ses_a', 'msg_1', ''); // 空文本、未收尾
|
|
173
|
-
win.flushSession('ses_a');
|
|
174
|
-
assert.equal(frames.length, 0, '这种噪声帧确实不该出站');
|
|
175
|
-
assert.equal(win.stats.droppedEmpty, 1, '静默丢帧必须计数:否则"手机没输出"永远查不出来');
|
|
176
|
-
assert.equal(win.stats.flushed, 0, '被丢弃的帧不该算进已发出数');
|
|
177
|
-
// 反面对照:同一条会话只要带 done,空文本也必须出站。
|
|
178
|
-
win.complete('ses_a', 'msg_1');
|
|
179
|
-
assert.ok(frames.length >= 1, '带 done 的空文本被一起丢了 → done 帧永不丢这条被破坏了');
|
|
180
|
-
assert.equal(win.stats.droppedEmpty, 1, 'done 帧不许进丢弃计数');
|
|
181
|
-
});
|
|
182
|
-
test('同一会话换了 messageId:上一条必须先带 done 出去,否则手机为上一条一直转圈', () => {
|
|
183
|
-
const { frames, win } = harness({ windowMs: 10_000 });
|
|
184
|
-
win.push('ses_a', 'msg_1', '前半');
|
|
185
|
-
win.push('ses_a', 'msg_2', '后半'); // 内核开始写下一条消息
|
|
186
|
-
win.stop();
|
|
187
|
-
assert.ok(frames.length >= 2, `换了 messageId 只出 ${frames.length} 帧 → msg_1 永远等不到 done`);
|
|
188
|
-
assert.equal(frames[0]?.messageId, 'msg_1');
|
|
189
|
-
assert.equal(frames[0]?.delta, '前半', '上一条的文本必须挂在它自己的 messageId 上(挂错就是两段文本拼成一段)');
|
|
190
|
-
assert.equal(frames[0]?.done, true, '上一条没有 done 就必须补一条 done:true');
|
|
191
|
-
assert.equal(frames[1]?.messageId, 'msg_2');
|
|
192
|
-
assert.equal(frames[1]?.delta, '后半');
|
|
193
|
-
});
|
|
194
|
-
test('role 必须透传:缺了它手机上无法区分助手文本与用户回声', () => {
|
|
195
|
-
const { frames, win } = harness();
|
|
196
|
-
win.push('ses_a', 'msg_1', '你好', 'assistant');
|
|
197
|
-
win.complete('ses_a', 'msg_1', 'assistant');
|
|
198
|
-
assert.equal(frames.length, 1, '同窗口内 done 与文本合并成 1 帧');
|
|
199
|
-
assert.equal(frames[0]?.role, 'assistant', 'role 丢了 → 手机把助手输出按默认气泡渲染');
|
|
200
|
-
});
|
|
201
|
-
test('stats.flushed 与实际出站帧数一致(可观测性红线:不许有"发出去了但没人知道"的帧)', () => {
|
|
202
|
-
const { frames, win } = harness({ windowMs: 10_000 });
|
|
203
|
-
for (let i = 0; i < 6; i++)
|
|
204
|
-
win.push(`ses_${i}`, 'msg_i', `片段${i}`);
|
|
205
|
-
win.flushAll();
|
|
206
|
-
assert.ok(frames.length >= 6, `预期 6 帧,实收 ${frames.length} 帧`);
|
|
207
|
-
assert.equal(win.stats.flushed, frames.length, 'flushed 计数与实际帧数分叉 → status.json 里的数字不可信');
|
|
208
|
-
assert.ok(win.stats.flushed >= 6, 'stats.flushed 必须能观察到已发出的帧数下界');
|
|
209
|
-
});
|
|
210
|
-
//# sourceMappingURL=window.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"window.test.js","sourceRoot":"","sources":["../../tests/window.test.ts"],"names":[],"mappings":"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"}
|