virlen-remote 0.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.
Files changed (99) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/LICENSE +21 -0
  3. package/README.md +192 -0
  4. package/dist/index.d.ts +44 -0
  5. package/dist/index.d.ts.map +1 -0
  6. package/dist/index.js +34 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/protocol/answer.d.ts +48 -0
  9. package/dist/protocol/answer.d.ts.map +1 -0
  10. package/dist/protocol/answer.js +65 -0
  11. package/dist/protocol/answer.js.map +1 -0
  12. package/dist/protocol/api.d.ts +576 -0
  13. package/dist/protocol/api.d.ts.map +1 -0
  14. package/dist/protocol/api.js +38 -0
  15. package/dist/protocol/api.js.map +1 -0
  16. package/dist/protocol/endpoint.d.ts +76 -0
  17. package/dist/protocol/endpoint.d.ts.map +1 -0
  18. package/dist/protocol/endpoint.js +307 -0
  19. package/dist/protocol/endpoint.js.map +1 -0
  20. package/dist/protocol/errors.d.ts +32 -0
  21. package/dist/protocol/errors.d.ts.map +1 -0
  22. package/dist/protocol/errors.js +56 -0
  23. package/dist/protocol/errors.js.map +1 -0
  24. package/dist/protocol/frame.d.ts +51 -0
  25. package/dist/protocol/frame.d.ts.map +1 -0
  26. package/dist/protocol/frame.js +154 -0
  27. package/dist/protocol/frame.js.map +1 -0
  28. package/dist/protocol/hello.d.ts +73 -0
  29. package/dist/protocol/hello.d.ts.map +1 -0
  30. package/dist/protocol/hello.js +37 -0
  31. package/dist/protocol/hello.js.map +1 -0
  32. package/dist/protocol/host.d.ts +116 -0
  33. package/dist/protocol/host.d.ts.map +1 -0
  34. package/dist/protocol/host.js +52 -0
  35. package/dist/protocol/host.js.map +1 -0
  36. package/dist/protocol/identity.d.ts +107 -0
  37. package/dist/protocol/identity.d.ts.map +1 -0
  38. package/dist/protocol/identity.js +143 -0
  39. package/dist/protocol/identity.js.map +1 -0
  40. package/dist/protocol/ids.d.ts +2 -0
  41. package/dist/protocol/ids.d.ts.map +1 -0
  42. package/dist/protocol/ids.js +20 -0
  43. package/dist/protocol/ids.js.map +1 -0
  44. package/dist/protocol/pairing.d.ts +43 -0
  45. package/dist/protocol/pairing.d.ts.map +1 -0
  46. package/dist/protocol/pairing.js +78 -0
  47. package/dist/protocol/pairing.js.map +1 -0
  48. package/dist/testing/index.d.ts +6 -0
  49. package/dist/testing/index.d.ts.map +1 -0
  50. package/dist/testing/index.js +5 -0
  51. package/dist/testing/index.js.map +1 -0
  52. package/dist/testing/mock-host.d.ts +66 -0
  53. package/dist/testing/mock-host.d.ts.map +1 -0
  54. package/dist/testing/mock-host.js +573 -0
  55. package/dist/testing/mock-host.js.map +1 -0
  56. package/dist/transport/broadcast.d.ts +26 -0
  57. package/dist/transport/broadcast.d.ts.map +1 -0
  58. package/dist/transport/broadcast.js +71 -0
  59. package/dist/transport/broadcast.js.map +1 -0
  60. package/dist/transport/ice.d.ts +130 -0
  61. package/dist/transport/ice.d.ts.map +1 -0
  62. package/dist/transport/ice.js +338 -0
  63. package/dist/transport/ice.js.map +1 -0
  64. package/dist/transport/memory.d.ts +52 -0
  65. package/dist/transport/memory.d.ts.map +1 -0
  66. package/dist/transport/memory.js +135 -0
  67. package/dist/transport/memory.js.map +1 -0
  68. package/dist/transport/rtc.d.ts +76 -0
  69. package/dist/transport/rtc.d.ts.map +1 -0
  70. package/dist/transport/rtc.js +310 -0
  71. package/dist/transport/rtc.js.map +1 -0
  72. package/dist/transport/signaling.d.ts +101 -0
  73. package/dist/transport/signaling.d.ts.map +1 -0
  74. package/dist/transport/signaling.js +235 -0
  75. package/dist/transport/signaling.js.map +1 -0
  76. package/dist/transport/types.d.ts +41 -0
  77. package/dist/transport/types.d.ts.map +1 -0
  78. package/dist/transport/types.js +11 -0
  79. package/dist/transport/types.js.map +1 -0
  80. package/package.json +69 -0
  81. package/src/index.ts +155 -0
  82. package/src/protocol/answer.ts +89 -0
  83. package/src/protocol/api.ts +517 -0
  84. package/src/protocol/endpoint.ts +405 -0
  85. package/src/protocol/errors.ts +90 -0
  86. package/src/protocol/frame.ts +196 -0
  87. package/src/protocol/hello.ts +112 -0
  88. package/src/protocol/host.ts +150 -0
  89. package/src/protocol/identity.ts +184 -0
  90. package/src/protocol/ids.ts +20 -0
  91. package/src/protocol/pairing.ts +95 -0
  92. package/src/testing/index.ts +5 -0
  93. package/src/testing/mock-host.ts +691 -0
  94. package/src/transport/broadcast.ts +81 -0
  95. package/src/transport/ice.ts +402 -0
  96. package/src/transport/memory.ts +164 -0
  97. package/src/transport/rtc.ts +344 -0
  98. package/src/transport/signaling.ts +317 -0
  99. package/src/transport/types.ts +50 -0
@@ -0,0 +1,573 @@
1
+ /**
2
+ * Mock 宿主数据源 —— 供「浏览器 harness」与单测使用。
3
+ *
4
+ * 行为:`send` 立即回投递确认(`messageId`),随后**异步**推送
5
+ * `message.added`(用户消息)→ `runtime.changed`(working)→ 多次 `message.stream`
6
+ * → `message.added`(AI 完整消息)+ `runtime.changed`(空闲)。
7
+ *
8
+ * 流式帧的形状**由客户端在 `hello` 里声明**(`streamMode`,默认 `full`):`delta` 时只发新增后缀
9
+ * (带 `offset`),规则与真实电脑侧(`store-bridge.ts` 的 `pushStream`)**逐条对齐**:
10
+ * 消息首帧 / 正文被改写 / `final` 收尾帧都发**整段**,只有「新正文以已发出内容为前缀」时才发增量。
11
+ * 两边不一致的后果很具体:mock 宽松 = 用例对着假行为发绿灯(§24 的教训)。
12
+ *
13
+ * 这正是 §3.3「RPC 只做投递确认、过程走事件」的可运行样例。
14
+ *
15
+ * ⚠️ **订阅门(§24,2026-09-29)**:消息 / 流式 / 运行时 / 占用这四类事件**只推已订阅的会话**
16
+ * (`host.event.session.list.changed` 与交互事件恒推)——与真实电脑侧(`store-bridge` 的
17
+ * `subscriptions.has(s.id)`)**同一条规则**。
18
+ *
19
+ * 为何必须一致:mock 过去无条件推送,于是「客户端忘了 `host.session.subscribe`」这类缺陷在
20
+ * 联调 / 单测里**完全看不见**,真机上才表现为「新建会话的标题更新了,但消息永远是空的」。
21
+ * mock 比真机宽松 = 测试对着假行为发绿灯,这条闸是故意的:宁可让用例早失败。
22
+ */
23
+ import { BridgeError } from '../protocol/errors.js';
24
+ import { answerActionError, normalizeChoiceAnswer } from '../protocol/answer.js';
25
+ import { COMPRESS_MIN_RATIO, DEFAULT_CONTEXT_WINDOW_TOKENS } from '../protocol/api.js';
26
+ /** 演示用模型服务(与 `sessions` 里的 provider 字段一致)。 */
27
+ const DEMO_PROVIDERS = [
28
+ { id: 'p-openai', name: 'OpenAI(演示)', models: ['gpt-4o', 'gpt-4o-mini'] },
29
+ { id: 'p-anthropic', name: 'Anthropic(演示)', models: ['claude-sonnet-4'] },
30
+ ];
31
+ /** 演示用工作目录候选集(新建会话只能从这里选)。 */
32
+ const DEMO_WORKSPACES = ['E:/code/virlen-demo', 'E:/code/another-project'];
33
+ export function createMockHostDataSource(options = {}) {
34
+ const streamSteps = options.streamSteps ?? 3;
35
+ const streamDelayMs = options.streamDelayMs ?? 40;
36
+ let emit = null;
37
+ /**
38
+ * 已订阅的会话(与真实电脑侧的 `SubscriptionRegistry` 同语义)。
39
+ *
40
+ * 未订阅的会话:只有会话列表(`session.list.changed`)与交互事件会推给对端 ——
41
+ * 消息 / 流式 / 运行时 / 占用一律不推(见文件头「订阅门」)。
42
+ */
43
+ const subscribed = new Set();
44
+ /** 会话维度的事件推送(受订阅门约束)。 */
45
+ function emitFor(sessionId, topic, payload) {
46
+ if (!subscribed.has(sessionId))
47
+ return;
48
+ emit?.(topic, payload);
49
+ }
50
+ /** RPC 方法名流水(见 `MockHostDataSource.calls`)。 */
51
+ const calls = [];
52
+ const sessions = [
53
+ {
54
+ id: 'demo-1',
55
+ title: '演示:手机控制',
56
+ updatedAt: Date.now(),
57
+ working: false,
58
+ agentId: 'agent-virlen',
59
+ agentName: 'Virlen',
60
+ workspace: DEMO_WORKSPACES[0],
61
+ providerConfigId: 'p-openai',
62
+ providerName: 'OpenAI(演示)',
63
+ modelId: 'gpt-4o',
64
+ },
65
+ {
66
+ id: 'demo-2',
67
+ title: '空会话',
68
+ updatedAt: Date.now() - 60000,
69
+ working: false,
70
+ agentId: 'agent-reviewer',
71
+ agentName: '代码评审员',
72
+ workspace: DEMO_WORKSPACES[1],
73
+ providerConfigId: 'p-anthropic',
74
+ providerName: 'Anthropic(演示)',
75
+ modelId: 'claude-sonnet-4',
76
+ },
77
+ ];
78
+ const messages = new Map();
79
+ const demoCount = options.demoMessageCount ?? 2;
80
+ messages.set('demo-1', demoCount <= 2
81
+ ? [
82
+ { id: 'm1', role: 'user', text: '你好,帮我看下今天的安排', createdAt: Date.now() - 120000 },
83
+ { id: 'm2', role: 'assistant', text: '好的,我来看看。', createdAt: Date.now() - 110000 },
84
+ ]
85
+ : Array.from({ length: demoCount }, (_, i) => ({
86
+ id: `m${i}`,
87
+ role: i % 2 === 0 ? 'user' : 'assistant',
88
+ text: `演示消息 #${i}`,
89
+ createdAt: Date.now() - (demoCount - i) * 1000,
90
+ })));
91
+ messages.set('demo-2', []);
92
+ if (options.demoToolMessage) {
93
+ messages.get('demo-1')?.push({
94
+ id: 'tool-1',
95
+ role: 'tool',
96
+ text: 'src/index.ts\nsrc/store.ts\nsrc/ui/pages/Chat.tsx',
97
+ createdAt: Date.now() - 105000,
98
+ toolName: 'list_files',
99
+ }, {
100
+ id: 'empty-assistant',
101
+ role: 'assistant',
102
+ text: '',
103
+ createdAt: Date.now() - 100000,
104
+ });
105
+ }
106
+ /**
107
+ * 上下文占用(模拟电脑侧口径:最后一条带 usage / contextTokens 的消息)。
108
+ *
109
+ * `demo-2` 特意给一个很低的占用 —— 让手机端「上下文充裕时不显示压缩」的分支可验证。
110
+ */
111
+ const contextTokens = new Map([
112
+ ['demo-1', 120000],
113
+ ['demo-2', 1000],
114
+ ]);
115
+ let counter = 0;
116
+ const nextId = (prefix) => `${prefix}-${++counter}-${Date.now().toString(36)}`;
117
+ /**
118
+ * 待应答交互(模拟电脑侧的交互注册表)。
119
+ */
120
+ const interactions = new Map();
121
+ /**
122
+ * 手机在 `hello` 里声明的流式偏好(§32)。默认 `full` —— 不声明就按整帧发,
123
+ * 与真实电脑侧同一条规则(旧客户端收到增量帧会把一帧当全文,正文就错位了)。
124
+ */
125
+ let peerStreamMode = 'full';
126
+ /** 被「暂存」而暂停的会话(模拟电脑侧的 paused 运行态,供 resume 演示 / 测试)。 */
127
+ const pausedSessions = new Set();
128
+ function emitList() {
129
+ emit?.('host.event.session.list.changed', { sessions: sessions.map((s) => ({ ...s })) });
130
+ }
131
+ /**
132
+ * 发一帧流式正文(按客户端的 `streamMode` 声明决定整帧还是增量)。
133
+ *
134
+ * `sent` = 上一步**已发出**的正文;首帧传 `''` → 必然走 `full`(客户端还没有基准)。
135
+ * 与真实电脑侧一样:写改(非前缀增长)时回落整帧,而不是硬发一个错的增量。
136
+ */
137
+ function emitStreamFrame(sessionId, messageId, seq, text, sent) {
138
+ const delta = peerStreamMode === 'delta' && sent !== '' && text.startsWith(sent);
139
+ emitFor(sessionId, 'host.event.message.stream', {
140
+ sessionId,
141
+ messageId,
142
+ seq,
143
+ mode: delta ? 'delta' : 'full',
144
+ text: delta ? text.slice(sent.length) : text,
145
+ ...(delta ? { offset: sent.length } : {}),
146
+ final: false,
147
+ });
148
+ }
149
+ async function streamReply(sessionId, list) {
150
+ const messageId = nextId('a');
151
+ let text = '';
152
+ // 模拟生成过程中的积压:内容真实增长 → 流式帧逐次变长(与真实电脑侧同规则)
153
+ list.push({ id: messageId, role: 'assistant', text: '', createdAt: Date.now() });
154
+ for (let i = 0; i < streamSteps; i++) {
155
+ await delay(streamDelayMs);
156
+ const sent = text;
157
+ text += `这是模拟流式的第 ${i + 1} 段。`;
158
+ emitStreamFrame(sessionId, messageId, i + 1, text, sent);
159
+ }
160
+ await delay(streamDelayMs);
161
+ const finalMessage = {
162
+ id: messageId,
163
+ role: 'assistant',
164
+ text,
165
+ createdAt: Date.now(),
166
+ };
167
+ // 定稿:就地替换那条临时消息(与电脑侧「流式期间不发 message.updated」的语义对齐)
168
+ const idx = list.findIndex((m) => m.id === messageId);
169
+ if (idx >= 0)
170
+ list[idx] = finalMessage;
171
+ else
172
+ list.push(finalMessage);
173
+ // 收尾帧同样是**整段**(定稿全文可能被回填/修复改写,增量已经不可靠)
174
+ emitFor(sessionId, 'host.event.message.stream', {
175
+ sessionId,
176
+ messageId,
177
+ seq: streamSteps + 1,
178
+ mode: 'full',
179
+ text,
180
+ final: true,
181
+ });
182
+ emitFor(sessionId, 'host.event.message.added', { sessionId, message: finalMessage });
183
+ emitFor(sessionId, 'host.event.session.runtime.changed', { sessionId, runtime: { working: false } });
184
+ // 生成一轮 → 上下文占用增长(手机端可看到实时变化)
185
+ bumpContext(sessionId, (contextTokens.get(sessionId) ?? 0) + 2000);
186
+ const session = sessions.find((s) => s.id === sessionId);
187
+ if (session) {
188
+ session.working = false;
189
+ session.updatedAt = Date.now();
190
+ }
191
+ }
192
+ /** 推一次上下文变化(内部与 harness 共用)—— 同样受订阅门约束。 */
193
+ function bumpContext(sessionId, tokens) {
194
+ contextTokens.set(sessionId, tokens);
195
+ emitFor(sessionId, 'host.event.session.context.changed', { sessionId, context: contextOf(sessionId) });
196
+ }
197
+ /** 推一次工具参数生成进度(§27)—— 同上,受订阅门约束。 */
198
+ function setToolProgress(sessionId, progress) {
199
+ emitFor(sessionId, 'host.event.session.runtime.changed', {
200
+ sessionId,
201
+ // 参数累积期一定是 working(真实链路里两者同源);progress=null 即清空
202
+ runtime: { working: true, ...(progress ? { toolProgress: progress } : {}) },
203
+ });
204
+ }
205
+ function contextOf(sessionId) {
206
+ const tokens = contextTokens.get(sessionId);
207
+ return {
208
+ tokens: tokens ?? null,
209
+ windowTokens: DEFAULT_CONTEXT_WINDOW_TOKENS,
210
+ };
211
+ }
212
+ const host = {
213
+ calls,
214
+ bind(fn) {
215
+ emit = fn;
216
+ },
217
+ /**
218
+ * 模拟配对校验 + 授权凭证签发(M6 口径,见 docs/phone-control-bridge.md §30):
219
+ *
220
+ * - 无 token → 拒(`invalid`)
221
+ * - `token === 'expired'` → 凭证过期(`data.reason='expired'`)
222
+ * - `token === 'removed'` → 手机已被电脑端移除(`data.reason='revoked'`)
223
+ * - `token === 'ticket-old'` → 二维码已过期(`data.reason='ticket-expired'`)
224
+ * - 其它非空 token → 通过,并**回传一条授权凭证**(手机端存的应该是它,不是手上那张票)
225
+ */
226
+ async hello(params) {
227
+ const token = params.token;
228
+ // §32:记下手机声明的流式偏好(后续 `message.stream` 按它决定整帧/增量)
229
+ peerStreamMode = params.streamMode === 'delta' ? 'delta' : 'full';
230
+ if (!token) {
231
+ throw new BridgeError('E_DENIED', '缺少配对令牌', { data: { reason: 'invalid' } });
232
+ }
233
+ if (token === 'expired') {
234
+ throw new BridgeError('E_DENIED', '令牌已过期', { data: { reason: 'expired' } });
235
+ }
236
+ if (token === 'removed') {
237
+ throw new BridgeError('E_DENIED', '该设备已被电脑端移除', { data: { reason: 'revoked' } });
238
+ }
239
+ if (token === 'ticket-old') {
240
+ throw new BridgeError('E_DENIED', '二维码已过期', { data: { reason: 'ticket-expired' } });
241
+ }
242
+ const now = Date.now();
243
+ return {
244
+ protocolVersion: params.protocolVersion,
245
+ host: { platform: 'web-harness', appVersion: '0.0.0' },
246
+ capabilities: [
247
+ 'session.list',
248
+ 'session.send',
249
+ 'session.cancel',
250
+ 'session.resume',
251
+ 'session.create',
252
+ 'session.rename',
253
+ 'session.pin',
254
+ 'session.delete',
255
+ 'interaction.answer',
256
+ 'stream.delta',
257
+ 'session.model',
258
+ 'session.workspace',
259
+ 'session.context',
260
+ 'session.compress',
261
+ ],
262
+ paired: true,
263
+ deviceName: 'Virlen 电脑(演示)',
264
+ deviceId: 'demo-host',
265
+ // M6:派发授权凭证(30 天)—— 手机端应把它存起来,下次直接连
266
+ grant: {
267
+ token: 'gt-demo',
268
+ issuedAt: now,
269
+ expiresAt: now + 30 * 24 * 60 * 60 * 1000,
270
+ lastSeenAt: now,
271
+ },
272
+ };
273
+ },
274
+ async listSessions() {
275
+ return sessions.map((s) => ({ ...s }));
276
+ },
277
+ async getMessages(params) {
278
+ calls.push(params.fromRowid != null ? 'host.session.messages(older)' : 'host.session.messages');
279
+ const list = messages.get(params.sessionId) ?? [];
280
+ const limit = params.limit ?? 50;
281
+ // 游标 = 已返回窗口中最旧一条的下标(与真实电脑侧的 rowid 同形:不透明、原样回传)
282
+ if (params.fromRowid != null) {
283
+ const end = Math.max(0, Math.min(params.fromRowid, list.length));
284
+ const start = Math.max(0, end - limit);
285
+ return {
286
+ messages: list.slice(start, end).map((m) => ({ ...m })),
287
+ hasMore: start > 0,
288
+ cursor: start > 0 ? start : null,
289
+ };
290
+ }
291
+ const start = Math.max(0, list.length - limit);
292
+ return {
293
+ messages: list.slice(start).map((m) => ({ ...m })),
294
+ hasMore: start > 0,
295
+ cursor: start > 0 ? start : null,
296
+ };
297
+ },
298
+ async getMessage(params) {
299
+ const list = messages.get(params.sessionId) ?? [];
300
+ const found = list.find((m) => m.id === params.messageId);
301
+ if (!found)
302
+ throw new BridgeError('E_NOT_FOUND', `message not found: ${params.messageId}`);
303
+ return { ...found };
304
+ },
305
+ async send(params) {
306
+ calls.push('host.session.send');
307
+ const list = messages.get(params.sessionId);
308
+ if (!list)
309
+ throw new BridgeError('E_NOT_FOUND', `session not found: ${params.sessionId}`);
310
+ const userMessage = {
311
+ id: nextId('u'),
312
+ role: 'user',
313
+ text: params.text,
314
+ createdAt: Date.now(),
315
+ };
316
+ list.push(userMessage);
317
+ emitFor(params.sessionId, 'host.event.message.added', { sessionId: params.sessionId, message: userMessage });
318
+ emitFor(params.sessionId, 'host.event.session.runtime.changed', {
319
+ sessionId: params.sessionId,
320
+ runtime: { working: true },
321
+ });
322
+ const session = sessions.find((s) => s.id === params.sessionId);
323
+ if (session) {
324
+ session.working = true;
325
+ session.updatedAt = Date.now();
326
+ }
327
+ void streamReply(params.sessionId, list);
328
+ return { messageId: userMessage.id };
329
+ },
330
+ async cancel() {
331
+ calls.push('host.session.cancel');
332
+ return { ok: true };
333
+ },
334
+ async resume(params) {
335
+ calls.push('host.session.resume');
336
+ if (!sessions.some((s) => s.id === params.sessionId)) {
337
+ throw new BridgeError('E_NOT_FOUND', `session not found: ${params.sessionId}`);
338
+ }
339
+ pausedSessions.delete(params.sessionId);
340
+ emitFor(params.sessionId, 'host.event.session.runtime.changed', {
341
+ sessionId: params.sessionId,
342
+ runtime: { working: true },
343
+ });
344
+ return { ok: true };
345
+ },
346
+ /**
347
+ * 记录订阅(与真实电脑侧同语义:只推已订阅会话的会话维度事件)。
348
+ *
349
+ * ⚠️ 真实电脑侧还会先 `requireSession`(未知名会话 → `E_NOT_FOUND`),mock 保持一致:
350
+ * 否则「客户端订阅了一个不存在的会话」这类接线错误在单测里喑默通过。
351
+ */
352
+ async subscribe(params) {
353
+ calls.push('host.session.subscribe');
354
+ if (!sessions.some((s) => s.id === params.sessionId)) {
355
+ throw new BridgeError('E_NOT_FOUND', `session not found: ${params.sessionId}`);
356
+ }
357
+ subscribed.add(params.sessionId);
358
+ return { ok: true };
359
+ },
360
+ /**
361
+ * 模拟「终端内确认」(`presentation:'terminal'`):
362
+ * 手机只能原样放行 / 拒绝;电脑侧落点是 `terminalConfirmSubmit/Cancel`(§16.4)。
363
+ */
364
+ triggerInteraction(spec = {}) {
365
+ const interactionId = nextId('it');
366
+ const kind = spec.kind ?? 'authorization';
367
+ const interaction = {
368
+ interactionId,
369
+ sessionId: spec.sessionId ?? 'demo-1',
370
+ toolCallId: nextId('tc'),
371
+ kind,
372
+ createdAt: Date.now(),
373
+ tier: spec.tier ?? 'low',
374
+ question: spec.question,
375
+ options: spec.options,
376
+ multi: spec.multi,
377
+ permName: spec.permName,
378
+ title: spec.title ?? (kind === 'authorization' ? '执行命令' : undefined),
379
+ subTitle: spec.subTitle,
380
+ desc: spec.desc,
381
+ hint: spec.hint,
382
+ risk: spec.risk,
383
+ sandboxBypass: spec.sandboxBypass,
384
+ presentation: spec.presentation ?? 'modal',
385
+ };
386
+ interactions.set(interactionId, interaction);
387
+ emit?.('host.event.interaction.requested', { interaction });
388
+ return interactionId;
389
+ },
390
+ /**
391
+ * 应答:与真实电脑侧同样的**独立校验**(高风险批准必须带 `confirmed`;
392
+ * 选择结果必须能规范化成非空回执)—— 演示 / 测试才能真实反映「手机 UI 漏改不算放行」。
393
+ */
394
+ async answer(params) {
395
+ const interaction = interactions.get(params.interactionId);
396
+ if (!interaction)
397
+ return { accepted: false, reason: 'not-found' };
398
+ // 动作合法性:与真实电脑侧(`interaction-registry`)**共用同一份**判据 ——
399
+ // mock 偏宽松会让「手机 UI 的动作与交互类型不匹配」这类缺陷测不出来(§18.6)。
400
+ const actionError = answerActionError(interaction, params.action);
401
+ if (actionError)
402
+ return { accepted: false, reason: actionError };
403
+ if (params.action === 'allow' && interaction.tier === 'high' && params.confirmed !== true) {
404
+ return { accepted: false, reason: 'confirm-required' };
405
+ }
406
+ if (params.action === 'choose' && !normalizeChoiceAnswer(params.value)) {
407
+ return { accepted: false, reason: 'invalid-value' };
408
+ }
409
+ interactions.delete(params.interactionId);
410
+ // 暂存 → 会话进入「暂停运行」态(供手机端显示「继续」,与电脑侧 paused 语义一致)
411
+ if (params.action === 'shelve') {
412
+ pausedSessions.add(interaction.sessionId);
413
+ emitFor(interaction.sessionId, 'host.event.session.runtime.changed', {
414
+ sessionId: interaction.sessionId,
415
+ runtime: { working: false, paused: true },
416
+ });
417
+ }
418
+ emit?.('host.event.interaction.resolved', {
419
+ interactionId: params.interactionId,
420
+ by: 'mobile',
421
+ outcome: params.action === 'allow' ? 'allow' : params.action === 'shelve' ? 'shelve' : 'deny',
422
+ });
423
+ return { accepted: true };
424
+ },
425
+ pendingInteractions() {
426
+ return [...interactions.keys()];
427
+ },
428
+ async listInteractions() {
429
+ return [...interactions.values()].map((i) => ({ ...i }));
430
+ },
431
+ // ── M4 写操作 ──
432
+ async createSession(params) {
433
+ calls.push('host.session.create');
434
+ const id = nextId('s');
435
+ // 工作目录:**与真实电脑侧同一条防线** —— 候选集由电脑侧给出,手机不能自造(§22.3)
436
+ let workspace;
437
+ if (params.workspace != null) {
438
+ const match = DEMO_WORKSPACES.find((w) => w === params.workspace);
439
+ if (!match) {
440
+ throw new BridgeError('E_BAD_REQUEST', `工作目录不在电脑侧既有目录内:${params.workspace}`);
441
+ }
442
+ workspace = match;
443
+ }
444
+ const model = resolveModel(params.providerConfigId, params.modelId);
445
+ sessions.unshift({
446
+ id,
447
+ title: params.title || '手机新建的会话',
448
+ updatedAt: Date.now(),
449
+ working: false,
450
+ agentId: 'agent-virlen',
451
+ agentName: 'Virlen',
452
+ workspace: workspace ?? DEMO_WORKSPACES[0],
453
+ ...model,
454
+ });
455
+ messages.set(id, []);
456
+ contextTokens.set(id, 0);
457
+ // 与真实电脑侧同一条兜底(§24):**自建的会话直接纳入订阅集合** ——
458
+ // 客户端创建会话的意图就是要马上看它,订阅不该押在它记得再调一次 RPC 上。
459
+ subscribed.add(id);
460
+ emitList();
461
+ return { sessionId: id };
462
+ },
463
+ async renameSession(params) {
464
+ const session = sessions.find((s) => s.id === params.sessionId);
465
+ if (!session)
466
+ throw new BridgeError('E_NOT_FOUND', `session not found: ${params.sessionId}`);
467
+ session.title = params.title;
468
+ session.updatedAt = Date.now();
469
+ emitList();
470
+ return { ok: true };
471
+ },
472
+ async setPinned(params) {
473
+ const session = sessions.find((s) => s.id === params.sessionId);
474
+ if (!session)
475
+ throw new BridgeError('E_NOT_FOUND', `session not found: ${params.sessionId}`);
476
+ session.pinned = params.pinned;
477
+ emitList();
478
+ return { ok: true };
479
+ },
480
+ async deleteSession(params) {
481
+ if (params.confirm !== true) {
482
+ throw new BridgeError('E_CONFIRM_REQUIRED', '删除会话需二次确认');
483
+ }
484
+ const idx = sessions.findIndex((s) => s.id === params.sessionId);
485
+ if (idx === -1)
486
+ throw new BridgeError('E_NOT_FOUND', `session not found: ${params.sessionId}`);
487
+ sessions.splice(idx, 1);
488
+ messages.delete(params.sessionId);
489
+ contextTokens.delete(params.sessionId);
490
+ emitList();
491
+ return { ok: true };
492
+ },
493
+ // ── §22:模型 / 工作目录 / 上下文 ──
494
+ async listModels() {
495
+ calls.push('host.model.list');
496
+ return DEMO_PROVIDERS.map((p) => ({ ...p, models: [...p.models] }));
497
+ },
498
+ async setModel(params) {
499
+ calls.push('host.session.setModel');
500
+ const session = sessions.find((s) => s.id === params.sessionId);
501
+ if (!session)
502
+ throw new BridgeError('E_NOT_FOUND', `session not found: ${params.sessionId}`);
503
+ Object.assign(session, resolveModel(params.providerConfigId, params.modelId));
504
+ emitList();
505
+ return { ok: true };
506
+ },
507
+ async listWorkspaces() {
508
+ calls.push('host.workspace.list');
509
+ return DEMO_WORKSPACES.map((path) => ({
510
+ path,
511
+ name: path.split('/').pop() ?? path,
512
+ sessionCount: sessions.filter((s) => s.workspace === path).length,
513
+ }));
514
+ },
515
+ async getContext(params) {
516
+ calls.push('host.session.context');
517
+ if (!sessions.some((s) => s.id === params.sessionId)) {
518
+ throw new BridgeError('E_NOT_FOUND', `session not found: ${params.sessionId}`);
519
+ }
520
+ return contextOf(params.sessionId);
521
+ },
522
+ /**
523
+ * 压缩上下文:**与真实电脑侧同判据**(confirm + 最小占用比例),
524
+ * 然后把消息换成一条 summary,并推 `messages.reset`(手机重拉窗口)。
525
+ */
526
+ async compress(params) {
527
+ calls.push('host.session.compress');
528
+ if (params.confirm !== true) {
529
+ throw new BridgeError('E_CONFIRM_REQUIRED', '压缩上下文需二次确认(confirm:true)');
530
+ }
531
+ if (!sessions.some((s) => s.id === params.sessionId)) {
532
+ throw new BridgeError('E_NOT_FOUND', `session not found: ${params.sessionId}`);
533
+ }
534
+ const context = contextOf(params.sessionId);
535
+ const tokens = context.tokens ?? 0;
536
+ if (tokens < context.windowTokens * COMPRESS_MIN_RATIO) {
537
+ throw new BridgeError('E_BAD_REQUEST', '当前上下文很充裕,无需压缩');
538
+ }
539
+ const summary = {
540
+ id: nextId('sum'),
541
+ role: 'system',
542
+ text: '[上下文摘要] 之前的内容已压缩为摘要。',
543
+ createdAt: Date.now(),
544
+ };
545
+ messages.set(params.sessionId, [summary]);
546
+ emitFor(params.sessionId, 'host.event.session.messages.reset', { sessionId: params.sessionId });
547
+ emitFor(params.sessionId, 'host.event.message.added', { sessionId: params.sessionId, message: summary });
548
+ bumpContext(params.sessionId, 2000);
549
+ return { ok: true };
550
+ },
551
+ /** 手动推一次占用变化(harness 按钮 / 测试用)。 */
552
+ bumpContext,
553
+ setToolProgress,
554
+ };
555
+ return host;
556
+ }
557
+ function delay(ms) {
558
+ return new Promise((resolve) => setTimeout(resolve, ms));
559
+ }
560
+ /** 把 `providerConfigId` / `modelId` 解析成会话上的三个展示 / 切换字段(非法组合 → E_BAD_REQUEST)。 */
561
+ function resolveModel(providerConfigId, modelId) {
562
+ if (providerConfigId == null && modelId == null) {
563
+ return { providerConfigId: DEMO_PROVIDERS[0].id, providerName: DEMO_PROVIDERS[0].name, modelId: DEMO_PROVIDERS[0].models[0] };
564
+ }
565
+ const provider = DEMO_PROVIDERS.find((p) => p.id === providerConfigId);
566
+ if (!provider)
567
+ throw new BridgeError('E_BAD_REQUEST', `模型服务不存在或未启用:${providerConfigId}`);
568
+ if (!modelId || !provider.models.includes(modelId)) {
569
+ throw new BridgeError('E_BAD_REQUEST', `该服务下没有模型:${modelId}`);
570
+ }
571
+ return { providerConfigId: provider.id, providerName: provider.name, modelId };
572
+ }
573
+ //# sourceMappingURL=mock-host.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock-host.js","sourceRoot":"","sources":["../../src/testing/mock-host.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * BroadcastChannel transport —— 同源跨上下文(两个 tab)直连。
3
+ *
4
+ * 用途:M2 的**浏览器联调**。宿主 harness 与手机页放在同一源的两个 tab,
5
+ * 用同名 `BroadcastChannel` 直连 —— **不依赖 WebRTC、不依赖信令服务器**(docs/phone-control-bridge.md §9-M2)。
6
+ *
7
+ * 约束:**仅同源**。生产不可用(生产走 RTC transport,M3)。
8
+ * 同一上下文内创建两个同名实例也能互通(BroadcastChannel 不会回声给发送者自身)。
9
+ */
10
+ import type { Transport, TransportState } from './types.js';
11
+ export declare class BroadcastTransport implements Transport {
12
+ private readonly channel;
13
+ private _state;
14
+ private readonly messageListeners;
15
+ private readonly stateListeners;
16
+ constructor(channelName: string);
17
+ get state(): TransportState;
18
+ get bufferedAmount(): number;
19
+ send(bytes: Uint8Array): void;
20
+ close(): void;
21
+ onMessage(listener: (bytes: Uint8Array) => void): () => void;
22
+ onStateChange(listener: (state: TransportState) => void): () => void;
23
+ }
24
+ /** 建立一对同名 channel 的 transport(同上下文互通用)。 */
25
+ export declare function createBroadcastPair(channelName: string): [BroadcastTransport, BroadcastTransport];
26
+ //# sourceMappingURL=broadcast.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"broadcast.d.ts","sourceRoot":"","sources":["../../src/transport/broadcast.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAExD,qBAAa,kBAAmB,YAAW,SAAS;IAClD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkB;IAC1C,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAyC;IAC1E,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA6C;IAE5E,YAAY,WAAW,EAAE,MAAM,EAY9B;IAED,IAAI,KAAK,IAAI,cAAc,CAE1B;IAED,IAAI,cAAc,IAAI,MAAM,CAE3B;IAED,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAI5B;IAED,KAAK,IAAI,IAAI,CASZ;IAED,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,GAAG,MAAM,IAAI,CAK3D;IAED,aAAa,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,GAAG,MAAM,IAAI,CAKnE;CACF;AAQD,2CAA2C;AAC3C,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,CAAC,kBAAkB,EAAE,kBAAkB,CAAC,CAEjG"}