dsh-remote-control 1.0.0 → 1.1.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 +6 -0
- package/dist/bundle/client.cjs +146 -0
- package/dist/bundle/index.js +667 -264
- package/package.json +13 -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,149 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* carrier-vocabulary.test — 内核会话事件 → 插件事件的**形状**映射。
|
|
3
|
-
*
|
|
4
|
-
* 这里的每一个 data 都是从本机真机 session log 里逐字抄下来的
|
|
5
|
-
* (`node scripts/read-session-log.mjs <sessionId>`,desktop profile,2026-10-02 取证)。
|
|
6
|
-
*
|
|
7
|
-
* 为什么必须拿真形状写测试:第一版的 `textOf()` 只读 `data.content`,而
|
|
8
|
-
* `assistant/message` 的正文在 `data.message.content` —— 于是助手回复被折成空串,
|
|
9
|
-
* 而手机上"⑧ 流式输出到达 / ⑨ 回合正常收尾(done:true)"两条断言**照样通过**
|
|
10
|
-
* (帧数够、done 在),屏幕上一个字都没有。判据数的是帧而不是内容,就会被这样骗过去。
|
|
11
|
-
* `tool/call` 的参数字段同理:真机叫 `arguments`,不叫 `args`。
|
|
12
|
-
*
|
|
13
|
-
* 未识别的类型(`step/start`、`request/header`、`agent/inbox/spliced`…)一律返回空数组:
|
|
14
|
-
* **不映射、不猜语义**(F1:挪用既有名字的语义才是危险的),但调用方要留痕
|
|
15
|
-
* (`kernel.unmappedEventTypes` 进 status.json)。
|
|
16
|
-
*/
|
|
17
|
-
import { test } from 'node:test';
|
|
18
|
-
import assert from 'node:assert/strict';
|
|
19
|
-
import { MAPPED_SESSION_EVENTS, sessionEventKernelEvents } from '../src/platform/carrier-services.js';
|
|
20
|
-
const asDelta = (events) => events.filter((event) => event.kind === 'delta');
|
|
21
|
-
const asTool = (events) => events.filter((event) => event.kind === 'tool');
|
|
22
|
-
test('assistant/message:正文在 data.message.content,不在顶层', () => {
|
|
23
|
-
const events = sessionEventKernelEvents({
|
|
24
|
-
sessionId: 'session-af3f',
|
|
25
|
-
type: 'assistant/message',
|
|
26
|
-
seq: 824,
|
|
27
|
-
data: {
|
|
28
|
-
turn: 9,
|
|
29
|
-
step: 2,
|
|
30
|
-
message: {
|
|
31
|
-
role: 'assistant',
|
|
32
|
-
content: [
|
|
33
|
-
{ type: 'reasoning', text: 'The bash tool is not available in this session…' },
|
|
34
|
-
{ type: 'text', text: '当前会话里没有可用的 bash 工具' },
|
|
35
|
-
],
|
|
36
|
-
id: '60ea9f79-f8f7-4895-942f-ed7535d7e6d8',
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
});
|
|
40
|
-
assert.equal(events.length, 1, `一条 assistant/message 翻成 ${events.length} 个事件`);
|
|
41
|
-
const [delta] = asDelta(events);
|
|
42
|
-
assert.equal(delta?.text, '当前会话里没有可用的 bash 工具', '回复文本丢了:手机上就是一个字都没有的空消息');
|
|
43
|
-
assert.equal(delta?.role, 'assistant', 'role 必须是 assistant,不能与用户回声混');
|
|
44
|
-
assert.equal(delta?.messageId, '60ea9f79-f8f7-4895-942f-ed7535d7e6d8', 'messageId 在 message.id 上,顶层没有');
|
|
45
|
-
assert.equal(delta?.done, true, '一条消息一条完整 delta(内核没有 token 级增量)');
|
|
46
|
-
assert.equal(delta?.text.includes('The bash tool'), false, 'reasoning 内容泄漏进正文');
|
|
47
|
-
});
|
|
48
|
-
test('assistant/message 只有 tool-call 片段时正文为空,但不许凭空造字', () => {
|
|
49
|
-
const events = sessionEventKernelEvents({
|
|
50
|
-
sessionId: 'session-af3f',
|
|
51
|
-
type: 'assistant/message',
|
|
52
|
-
seq: 819,
|
|
53
|
-
data: {
|
|
54
|
-
turn: 9,
|
|
55
|
-
step: 1,
|
|
56
|
-
message: {
|
|
57
|
-
role: 'assistant',
|
|
58
|
-
content: [{ type: 'tool-call', id: 'chatcmpl-tool-1', name: 'bash', arguments: '{"command":"echo x"}' }],
|
|
59
|
-
},
|
|
60
|
-
},
|
|
61
|
-
});
|
|
62
|
-
const [delta] = asDelta(events);
|
|
63
|
-
assert.equal(delta?.text, '', '没有 text 片段时正文就是空串(造字比空更糟)');
|
|
64
|
-
assert.ok(delta?.messageId, '即便如此也要有 messageId,否则手机把这条挂到别的消息行上');
|
|
65
|
-
});
|
|
66
|
-
test('user/message 的正文在顶层(与 assistant 不同形状,两处都要读)', () => {
|
|
67
|
-
const events = sessionEventKernelEvents({
|
|
68
|
-
sessionId: 'session-af3f',
|
|
69
|
-
type: 'user/message',
|
|
70
|
-
seq: 799,
|
|
71
|
-
data: {
|
|
72
|
-
content: [{ type: 'text', text: '只回复 ok 两个字,不要调用任何工具' }],
|
|
73
|
-
source: { kind: 'user' },
|
|
74
|
-
role: 'user',
|
|
75
|
-
id: '1957861b',
|
|
76
|
-
},
|
|
77
|
-
});
|
|
78
|
-
const [delta] = asDelta(events);
|
|
79
|
-
assert.equal(delta?.text, '只回复 ok 两个字,不要调用任何工具', '用户回声读不到顶层 content → 手机上发出去的话不显示');
|
|
80
|
-
assert.equal(delta?.role, 'user');
|
|
81
|
-
assert.equal(delta?.messageId, '1957861b');
|
|
82
|
-
});
|
|
83
|
-
test('tool/call:真机给的是 arguments 不是 args;工具名、参数预览、标题都要落到手机上', () => {
|
|
84
|
-
const events = sessionEventKernelEvents({
|
|
85
|
-
sessionId: 'session-af3f',
|
|
86
|
-
type: 'tool/call',
|
|
87
|
-
seq: 820,
|
|
88
|
-
data: {
|
|
89
|
-
turn: 9,
|
|
90
|
-
step: 1,
|
|
91
|
-
callId: 'chatcmpl-tool-9bf174521b5e2480',
|
|
92
|
-
name: 'bash',
|
|
93
|
-
arguments: '{"command":"echo drc-approval-probe"}',
|
|
94
|
-
},
|
|
95
|
-
});
|
|
96
|
-
const [tool] = asTool(events);
|
|
97
|
-
assert.equal(events.length, 1);
|
|
98
|
-
assert.equal(tool?.callId, 'chatcmpl-tool-9bf174521b5e2480', 'callId 逐字传:结果行要能对上调用行');
|
|
99
|
-
assert.equal(tool?.tool, 'bash');
|
|
100
|
-
assert.equal(tool?.phase, 'args', 'phase 停在 started 说明没读到 arguments:手机看不到参数');
|
|
101
|
-
assert.match(tool?.argsPreview ?? '', /echo drc-approval-probe/, '参数预览丢了');
|
|
102
|
-
assert.match(tool?.title ?? '', /echo drc-approval-probe/, '标题行是手机上唯一看得见的东西');
|
|
103
|
-
// 只有调用、还没参数的一代形状
|
|
104
|
-
const started = asTool(sessionEventKernelEvents({ sessionId: 'ses_1', type: 'tool/call', seq: 3, data: { callId: 'c1', name: 'bash' } }));
|
|
105
|
-
assert.equal(started[0]?.phase, 'started', '没有参数时应停在 started');
|
|
106
|
-
});
|
|
107
|
-
test('tool/result:callId 藏在 message.toolCallId,正文在 message.content', () => {
|
|
108
|
-
const events = sessionEventKernelEvents({
|
|
109
|
-
sessionId: 'session-af3f',
|
|
110
|
-
type: 'tool/result',
|
|
111
|
-
seq: 821,
|
|
112
|
-
data: {
|
|
113
|
-
turn: 9,
|
|
114
|
-
step: 1,
|
|
115
|
-
message: {
|
|
116
|
-
role: 'tool',
|
|
117
|
-
source: { kind: 'tool', callId: 'chatcmpl-tool-9bf174521b5e2480' },
|
|
118
|
-
toolCallId: 'chatcmpl-tool-9bf174521b5e2480',
|
|
119
|
-
content: [{ type: 'text', text: 'Error: unknown tool "bash"' }],
|
|
120
|
-
},
|
|
121
|
-
},
|
|
122
|
-
});
|
|
123
|
-
const [tool] = asTool(events);
|
|
124
|
-
assert.equal(tool?.callId, 'chatcmpl-tool-9bf174521b5e2480', 'callId 对不上调用行:手机上结果与调用各成一行');
|
|
125
|
-
assert.equal(tool?.phase, 'completed');
|
|
126
|
-
assert.match(tool?.resultPreview ?? '', /unknown tool/, '结果预览丢了:手机只看到工具跑完,不知道跑出了什么');
|
|
127
|
-
});
|
|
128
|
-
test('未识别的类型返回空数组且不抛(不映射、不猜语义)', () => {
|
|
129
|
-
for (const type of ['step/start', 'step/end', 'request/header', 'agent/inbox/spliced', 'internal/config']) {
|
|
130
|
-
assert.equal(MAPPED_SESSION_EVENTS.has(type), false, `${type} 被登记成已映射,但映射表里没有它`);
|
|
131
|
-
assert.deepEqual(sessionEventKernelEvents({ sessionId: 'ses_1', type, seq: 1, data: { anything: true } }), [], `${type} 被映射成了别的东西`);
|
|
132
|
-
}
|
|
133
|
-
});
|
|
134
|
-
test('approval/asked 与 approval/decided 只触发列表刷新(卡片本身走 waterfall 参与者路径)', () => {
|
|
135
|
-
for (const type of ['approval/asked', 'approval/decided']) {
|
|
136
|
-
assert.deepEqual(sessionEventKernelEvents({ sessionId: 'ses_1', type, seq: 1, data: {} }), [{ kind: 'sessions-changed', reason: type }], `${type} 的映射不对`);
|
|
137
|
-
}
|
|
138
|
-
});
|
|
139
|
-
test('session/title 只在 title 是字符串时才产出事件(否则手机上出现 undefined 标题)', () => {
|
|
140
|
-
assert.deepEqual(sessionEventKernelEvents({ sessionId: 'ses_1', type: 'session/title', seq: 1, data: { title: '新标题' } }), [{ kind: 'title', sessionId: 'ses_1', title: '新标题' }]);
|
|
141
|
-
assert.deepEqual(sessionEventKernelEvents({ sessionId: 'ses_1', type: 'session/title', seq: 1, data: { title: 42 } }), []);
|
|
142
|
-
assert.deepEqual(sessionEventKernelEvents({ sessionId: 'ses_1', type: 'session/title', seq: 1, data: {} }), []);
|
|
143
|
-
});
|
|
144
|
-
test('turn/start 只报运行态:它是手机上"正在思考…"的唯一来源', () => {
|
|
145
|
-
assert.deepEqual(sessionEventKernelEvents({ sessionId: 'ses_1', type: 'turn/start', seq: 1, data: { turn: 3 } }), [
|
|
146
|
-
{ kind: 'run-state', sessionId: 'ses_1', state: 'running' },
|
|
147
|
-
]);
|
|
148
|
-
});
|
|
149
|
-
//# sourceMappingURL=carrier-vocabulary.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"carrier-vocabulary.test.js","sourceRoot":"","sources":["../../tests/carrier-vocabulary.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* clock-probe-timers — 一次性的诊断/宽限定时器不许拖住宿主退出。
|
|
3
|
-
*
|
|
4
|
-
* 需求来源:HANDOFF.md §5 第 3 条——「`node e2e/run.mjs` 1.2s 就打完全绿,但进程约 60s
|
|
5
|
-
* 后才退出」。这一条当时把嫌疑记成"e2e 装置里某个 ~60s 的一次性定时器";用探针
|
|
6
|
-
* (包一层 global.setTimeout 记创建栈)实测后,拖尾的是 `index.ts` 里载具探测的三次复查
|
|
7
|
-
* (8s / 25s / 60s,走 `clock.setTimeout`):它们既没有 unref,也没有在 `stop()` 里撤掉,
|
|
8
|
-
* 于是 60s 那一发把事件循环钉住。
|
|
9
|
-
*
|
|
10
|
-
* 影响面比 e2e 大:**任何短命的跑法都会白等最长的那一发**(headless/CLI、CI、`dsh
|
|
11
|
-
* --profile headless "..."`)。真宿主里事件循环本来就有别的事撑着,unref 不改变取证行为
|
|
12
|
-
* ——60s 后那次复查照跑。
|
|
13
|
-
*
|
|
14
|
-
* 三条要守的:
|
|
15
|
-
* 1. 每个一次性定时器**创建后立刻 unref**("别为了我留着进程")。
|
|
16
|
-
* 2. `cancelAll()` 必须把它们**全部**撤掉,且可重复调用(stop 走两遍不该出错)。
|
|
17
|
-
* 3. 假时钟(`FakeClock` 的句柄是**数字**,没有 unref)**不许因此抛错**——那是
|
|
18
|
-
* "定时器归测试掌控"的正常场景,数字句柄上调用 unref 必须是安全的空操作。
|
|
19
|
-
*/
|
|
20
|
-
import { test } from 'node:test';
|
|
21
|
-
import assert from 'node:assert/strict';
|
|
22
|
-
import { createOneShotTimers, FakeClock, unrefTimer } from '../src/core/clock.js';
|
|
23
|
-
/** 记录"哪些句柄被 unref / 被清理"的时钟;句柄是对象,所以能验 unref 是否真被调用。 */
|
|
24
|
-
class SpyClock {
|
|
25
|
-
created = [];
|
|
26
|
-
cleared = [];
|
|
27
|
-
now() {
|
|
28
|
-
return 1_700_000_000_000;
|
|
29
|
-
}
|
|
30
|
-
setTimeout(_fn, ms) {
|
|
31
|
-
const handle = { unrefed: false, unref: () => void (handle.unrefed = true) };
|
|
32
|
-
this.created.push({ ms, handle });
|
|
33
|
-
return handle;
|
|
34
|
-
}
|
|
35
|
-
clearTimeout(handle) {
|
|
36
|
-
this.cleared.push(handle);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
test('一次性定时器创建后立刻 unref:60s 那一发不许把进程钉住', () => {
|
|
40
|
-
const clock = new SpyClock();
|
|
41
|
-
const timers = createOneShotTimers(clock);
|
|
42
|
-
for (const delayMs of [8_000, 25_000, 60_000])
|
|
43
|
-
timers.schedule(() => { }, delayMs);
|
|
44
|
-
assert.equal(clock.created.length, 3, `应当建出 3 个复查定时器,实际 ${clock.created.length}`);
|
|
45
|
-
for (const { ms, handle } of clock.created) {
|
|
46
|
-
assert.equal(handle.unrefed, true, `${ms}ms 的定时器没有 unref —— 它会把事件循环钉住到 ${ms}ms(e2e 的 ~60s 尾巴就是这么来的)`);
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
test('cancelAll 撤掉全部:任务结束后不该再有复查去写 status.json', () => {
|
|
50
|
-
const clock = new SpyClock();
|
|
51
|
-
const timers = createOneShotTimers(clock);
|
|
52
|
-
for (const delayMs of [8_000, 25_000, 60_000])
|
|
53
|
-
timers.schedule(() => { }, delayMs);
|
|
54
|
-
timers.cancelAll();
|
|
55
|
-
assert.deepEqual(clock.cleared, clock.created.map((item) => item.handle), 'cancelAll 必须把登记过的句柄逐个 clearTimeout 掉');
|
|
56
|
-
// 可重复调用:stop() 可能被 effect 与 onDispose 两条路各走一次。
|
|
57
|
-
timers.cancelAll();
|
|
58
|
-
assert.equal(clock.cleared.length, 3, '第二次 cancelAll 不该重复清理(也不该抛错)');
|
|
59
|
-
});
|
|
60
|
-
test('假时钟的数字句柄上 unref 是空操作:测试不该为了这件事改成对象句柄', () => {
|
|
61
|
-
const fake = new FakeClock();
|
|
62
|
-
const timers = createOneShotTimers(fake);
|
|
63
|
-
assert.doesNotThrow(() => timers.schedule(() => { }, 60_000), '数字句柄(FakeClock)上调用 unref 不许抛错');
|
|
64
|
-
assert.equal(fake.pending, 1, 'FakeClock 应该照常记着这个定时器');
|
|
65
|
-
timers.cancelAll();
|
|
66
|
-
assert.equal(fake.pending, 0, 'cancelAll 对假时钟同样要生效');
|
|
67
|
-
});
|
|
68
|
-
test('unrefTimer 对没有 unref 的句柄一律安静:数字、null、undefined 都不该抛', () => {
|
|
69
|
-
for (const handle of [1, 0, null, undefined, {}, 'handle']) {
|
|
70
|
-
assert.doesNotThrow(() => unrefTimer(handle), `unrefTimer(${JSON.stringify(handle)}) 抛错了`);
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
//# sourceMappingURL=clock-probe-timers.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"clock-probe-timers.test.js","sourceRoot":"","sources":["../../tests/clock-probe-timers.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* command-result.test — `/drc` 命令的返回契约(线上事故回归锁)。
|
|
3
|
-
*
|
|
4
|
-
* 事故原话(用户真机):`/drc pair报错:command "drc" returned unknown result kind "text"`。
|
|
5
|
-
* 根因:重写时 handler 返回了 `{kind:'text', text}`——这是**旧实现的形状**,而宿主只认
|
|
6
|
-
* `success`/`error` 两种 kind,别的值在**注册边界**上直接抛 TypeError,整条命令失败。
|
|
7
|
-
*
|
|
8
|
-
* 契约的权威来源(本机取证,`@deepseek-ai/dsh-commands` v0.1.0-rc.6):
|
|
9
|
-
* ~/.dsh/profiles/<profile>/node_modules/@deepseek-ai/dsh-commands/lib/types/index.js
|
|
10
|
-
* `normalizeResult(command, value)` 第 155-181 行:
|
|
11
|
-
* - 非对象 / 无 `kind` → TypeError("...handler must return a CommandResult")
|
|
12
|
-
* - kind==='success':text 可选,给了就必须是 string;sourceEventSeq 可选且须为非负安全整数
|
|
13
|
-
* - kind==='error' :text 必须是非空 string
|
|
14
|
-
* - 其余 kind → TypeError(`...returned unknown result kind "${kind}"`) ← 事故这一句
|
|
15
|
-
*
|
|
16
|
-
* 两道锁:
|
|
17
|
-
* 1. 类型锁——`packages/plugin/src/index.ts` 里 handler 标注 `Promise<CommandResult>`,
|
|
18
|
-
* 写错 kind 会被 `tsc`(本包 `pnpm build` 先跑 tsc)挡在编译期。
|
|
19
|
-
* 2. 本文件——真的走一遍 `apply()` 把 handler 注册出来,再拿结果过一遍**逐行复刻**的
|
|
20
|
-
* `normalizeResult`。复刻件自身先用 `{kind:'text'}` 做反证(见"带牙"那条),
|
|
21
|
-
* 确保它不是"永远返回 ok"的空壳。
|
|
22
|
-
*
|
|
23
|
-
* 覆盖分工:离线 `pair`(PAIR_UNAVAILABLE_TEXT)、`status`、`unpair` 三个返回点在本文件;
|
|
24
|
-
* 在线 `pair`(真的渲染二维码文本)在 `e2e/run.mjs`(那里有真中继,relay 是 online)。
|
|
25
|
-
* 四个 `kind:'success'` 返回点因此全部落到过断言。
|
|
26
|
-
*/
|
|
27
|
-
import { test } from 'node:test';
|
|
28
|
-
import assert from 'node:assert/strict';
|
|
29
|
-
import { existsSync, mkdtempSync, readFileSync, rmSync } from 'node:fs';
|
|
30
|
-
import { homedir, tmpdir } from 'node:os';
|
|
31
|
-
import path from 'node:path';
|
|
32
|
-
import { apply } from '../src/index.js';
|
|
33
|
-
import { PAIR_UNAVAILABLE_TEXT } from '../src/shell/pairing-text.js';
|
|
34
|
-
/** 一眼假的 token:仓库里不许出现真凭据,这条只验形状(同 status.test.ts)。 */
|
|
35
|
-
const FAKE_TOKEN = 'fake-host-token-not-a-real-secret-0123456789abcdef';
|
|
36
|
-
/**
|
|
37
|
-
* 逐行复刻宿主的 `normalizeResult`(来源见文件头)。
|
|
38
|
-
*
|
|
39
|
-
* 为什么是复刻而不是 import:真模块的 peerDependencies 是整条 cordis 运行时,
|
|
40
|
-
* 单测里拉进来既慢又脆。所以这里"抄"的是**被约束的那几行**,并且用下面两条
|
|
41
|
-
* 反证保证抄件有牙:(a) `{kind:'text'}` 必须被拒;(b) 若本机能找到宿主源码,
|
|
42
|
-
* 就核对抄件里的报错模板与分支关键字确实还在源码里——宿主改了契约,这条会红。
|
|
43
|
-
*/
|
|
44
|
-
function harnessNormalizeResult(command, value) {
|
|
45
|
-
if (typeof value !== 'object' || value === null || !('kind' in value)) {
|
|
46
|
-
throw new TypeError(`command "${command}" handler must return a CommandResult`);
|
|
47
|
-
}
|
|
48
|
-
const result = value;
|
|
49
|
-
if (result.kind === 'success') {
|
|
50
|
-
if (result.text !== undefined && typeof result.text !== 'string') {
|
|
51
|
-
throw new TypeError(`command "${command}" success text must be a string when supplied`);
|
|
52
|
-
}
|
|
53
|
-
if (result.sourceEventSeq !== undefined &&
|
|
54
|
-
(!Number.isSafeInteger(result.sourceEventSeq) || result.sourceEventSeq < 0)) {
|
|
55
|
-
throw new TypeError(`command "${command}" success sourceEventSeq must be a non-negative safe integer when supplied`);
|
|
56
|
-
}
|
|
57
|
-
return { kind: 'success', ...(result.text === undefined ? {} : { text: result.text }) };
|
|
58
|
-
}
|
|
59
|
-
if (result.kind === 'error') {
|
|
60
|
-
if (typeof result.text !== 'string' || result.text.trim().length === 0) {
|
|
61
|
-
throw new TypeError(`command "${command}" error text must be a non-empty string`);
|
|
62
|
-
}
|
|
63
|
-
return { kind: 'error', text: result.text };
|
|
64
|
-
}
|
|
65
|
-
throw new TypeError(`command "${command}" returned unknown result kind "${String(result.kind)}"`);
|
|
66
|
-
}
|
|
67
|
-
/** 在已安装的 profile 里找宿主命令模块(找不到就跳过差分核对,不因此判失败)。 */
|
|
68
|
-
function findHarnessTypes() {
|
|
69
|
-
const root = path.join(homedir(), '.dsh', 'profiles');
|
|
70
|
-
if (!existsSync(root))
|
|
71
|
-
return undefined;
|
|
72
|
-
for (const profile of ['desktop', 'tui']) {
|
|
73
|
-
const file = path.join(root, profile, 'node_modules', '@deepseek-ai', 'dsh-commands', 'lib', 'types', 'index.js');
|
|
74
|
-
if (existsSync(file))
|
|
75
|
-
return file;
|
|
76
|
-
}
|
|
77
|
-
return undefined;
|
|
78
|
-
}
|
|
79
|
-
/** 起一份"非 cordis"的假上下文:和 e2e/run.mjs 的 bootHost 同形状,只多一个 commands 捕获。 */
|
|
80
|
-
function bootCommandHost() {
|
|
81
|
-
const registered = {};
|
|
82
|
-
const disposers = [];
|
|
83
|
-
const statusDir = mkdtempSync(path.join(tmpdir(), 'drc-cmd-result-'));
|
|
84
|
-
const context = {
|
|
85
|
-
get: () => undefined,
|
|
86
|
-
inject: () => undefined,
|
|
87
|
-
provide: () => undefined,
|
|
88
|
-
// 假上下文直接挂 commands;真 cordis 上 `ctx.commands` 这一读是抛错(走 get/inject 两条路)。
|
|
89
|
-
commands: { register: (definition) => void (registered[definition.name] = definition) },
|
|
90
|
-
on: () => () => undefined,
|
|
91
|
-
off: () => undefined,
|
|
92
|
-
onDispose: (fn) => void disposers.push(fn),
|
|
93
|
-
};
|
|
94
|
-
apply(context, {
|
|
95
|
-
enabled: true,
|
|
96
|
-
// 故意不可达:这条测试要的就是"中继离线"这条确定分支,不许它真连上任何东西。
|
|
97
|
-
serverUrl: 'ws://127.0.0.1:1',
|
|
98
|
-
hostToken: FAKE_TOKEN,
|
|
99
|
-
hostId: 'fake-command-host',
|
|
100
|
-
statusFile: path.join(statusDir, 'status.json'),
|
|
101
|
-
mockBridge: false,
|
|
102
|
-
pairOnStartSec: 0,
|
|
103
|
-
qrImage: false,
|
|
104
|
-
qrOpen: false,
|
|
105
|
-
});
|
|
106
|
-
const definition = registered.drc;
|
|
107
|
-
assert.ok(definition, 'apply() 必须把名为 drc 的命令注册进 ctx.commands');
|
|
108
|
-
assert.equal(typeof definition.handler, 'function', 'drc 命令必须带 handler');
|
|
109
|
-
return {
|
|
110
|
-
definition,
|
|
111
|
-
dispose: () => {
|
|
112
|
-
for (const fn of disposers.splice(0)) {
|
|
113
|
-
try {
|
|
114
|
-
fn();
|
|
115
|
-
}
|
|
116
|
-
catch {
|
|
117
|
-
/* 关停失败不该污染断言结果 */
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
rmSync(statusDir, { recursive: true, force: true });
|
|
121
|
-
},
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
test('复刻件带牙:{kind:"text"} 必须被拒,且报错就是事故那一句', () => {
|
|
125
|
-
// (a) 反证 —— 若这条不抛,下面所有断言都失去意义。
|
|
126
|
-
assert.throws(() => harnessNormalizeResult('drc', { kind: 'text', text: '二维码…' }), (error) => error instanceof TypeError && /unknown result kind "text"/.test(String(error.message)), '复刻件必须拒绝 {kind:"text"},否则它不是有效判据');
|
|
127
|
-
// (b) 另外两条也要有牙:空 error text、非字符串 success text。
|
|
128
|
-
assert.throws(() => harnessNormalizeResult('drc', { kind: 'error', text: ' ' }), TypeError);
|
|
129
|
-
assert.throws(() => harnessNormalizeResult('drc', { kind: 'success', text: 42 }), TypeError);
|
|
130
|
-
assert.throws(() => harnessNormalizeResult('drc', null), TypeError);
|
|
131
|
-
// (c) 合法形状要放行 —— 免得复刻件"一律抛"也能骗过 (a)。
|
|
132
|
-
assert.deepEqual(harnessNormalizeResult('drc', { kind: 'success' }), { kind: 'success' });
|
|
133
|
-
assert.deepEqual(harnessNormalizeResult('drc', { kind: 'error', text: '不行' }), { kind: 'error', text: '不行' });
|
|
134
|
-
});
|
|
135
|
-
test('离线 pair:handler 返回的 result 过得了宿主 normalizeResult(事故点)', async (t) => {
|
|
136
|
-
const host = bootCommandHost();
|
|
137
|
-
t.after(host.dispose);
|
|
138
|
-
const raw = await host.definition.handler({ commandId: 'cmd-1', rawInput: 'pair' });
|
|
139
|
-
// 先过契约校验:这一行若红,就是用户看到的 `unknown result kind` 又回来了。
|
|
140
|
-
const result = harnessNormalizeResult('drc', raw);
|
|
141
|
-
assert.equal(result.kind, 'success', 'kind 必须是 success(旧实现写的 text 会被宿主抛错)');
|
|
142
|
-
assert.equal(result.text, PAIR_UNAVAILABLE_TEXT, '中继离线时必须是那句可操作的提示,而不是空串或栈');
|
|
143
|
-
});
|
|
144
|
-
test('status:handler 返回的 result 是 success + 可 JSON.parse 的快照', async (t) => {
|
|
145
|
-
const host = bootCommandHost();
|
|
146
|
-
t.after(host.dispose);
|
|
147
|
-
const raw = await host.definition.handler({ commandId: 'cmd-2', rawInput: 'status' });
|
|
148
|
-
const result = harnessNormalizeResult('drc', raw);
|
|
149
|
-
assert.equal(result.kind, 'success');
|
|
150
|
-
const text = result.text;
|
|
151
|
-
const snapshot = JSON.parse(text);
|
|
152
|
-
assert.equal(typeof snapshot.relay, 'string', 'status 文本必须是状态快照 JSON(relay 字段是排错入口)');
|
|
153
|
-
assert.ok(!text.includes(FAKE_TOKEN), '状态快照里绝不能出现 token 真值');
|
|
154
|
-
assert.equal(snapshot.hostToken, undefined, 'hostToken 字段必须是 undefined(只留 redact 形态)');
|
|
155
|
-
});
|
|
156
|
-
test('unpair:handler 返回的 result 过得了宿主 normalizeResult', async (t) => {
|
|
157
|
-
const host = bootCommandHost();
|
|
158
|
-
t.after(host.dispose);
|
|
159
|
-
const raw = await host.definition.handler({ commandId: 'cmd-3', rawInput: 'unpair' });
|
|
160
|
-
const result = harnessNormalizeResult('drc', raw);
|
|
161
|
-
assert.equal(result.kind, 'success');
|
|
162
|
-
assert.ok((result.text ?? '').length > 0, '成功也要有可读文本:命令面板上是空的会像卡住');
|
|
163
|
-
});
|
|
164
|
-
test('未知输入落到 status 分支:不会因为参数奇怪就返回非法 kind', async (t) => {
|
|
165
|
-
const host = bootCommandHost();
|
|
166
|
-
t.after(host.dispose);
|
|
167
|
-
for (const rawInput of ['', ' ', 'wat', 'PAIR', ' status ']) {
|
|
168
|
-
const result = harnessNormalizeResult('drc', await host.definition.handler({ commandId: 'cmd-x', rawInput }));
|
|
169
|
-
assert.equal(result.kind, 'success', `rawInput=${JSON.stringify(rawInput)} 必须落到合法分支`);
|
|
170
|
-
}
|
|
171
|
-
});
|
|
172
|
-
test('差分核对:本机宿主源码里那几行契约关键字(改了契约这条要提醒)', { skip: !findHarnessTypes() }, () => {
|
|
173
|
-
const file = findHarnessTypes();
|
|
174
|
-
assert.ok(file, 'skip 条件保证这里能找到');
|
|
175
|
-
const source = readFileSync(file, 'utf8');
|
|
176
|
-
for (const marker of [
|
|
177
|
-
'unknown result kind',
|
|
178
|
-
"result.kind === 'success'",
|
|
179
|
-
"result.kind === 'error'",
|
|
180
|
-
'must return a CommandResult',
|
|
181
|
-
]) {
|
|
182
|
-
assert.ok(source.includes(marker), `宿主源码里找不到「${marker}」:契约可能变了,复刻件要同步(${file})`);
|
|
183
|
-
}
|
|
184
|
-
});
|
|
185
|
-
//# sourceMappingURL=command-result.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"command-result.test.js","sourceRoot":"","sources":["../../tests/command-result.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|