@xnng/browser-relay 1.6.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 (79) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +445 -0
  3. package/docs/README.zh-CN.md +421 -0
  4. package/docs/benchmarks/browser-gaps-codex-ax.json +418 -0
  5. package/docs/benchmarks/browser-gaps-relay-after.json +655 -0
  6. package/docs/benchmarks/browser-gaps-relay-baseline.json +679 -0
  7. package/docs/benchmarks/browser-readiness-cost.json +106 -0
  8. package/docs/benchmarks/browser-runtime-balanced-headed.json +412 -0
  9. package/docs/benchmarks/browser-runtime-balanced-rtt50.json +412 -0
  10. package/docs/benchmarks/browser-runtime-balanced.json +412 -0
  11. package/docs/benchmarks/browser-runtime-rtt50.json +194 -0
  12. package/docs/benchmarks/browser-runtime.json +254 -0
  13. package/docs/benchmarks/browser-use-parity.json +54 -0
  14. package/docs/benchmarks/codex-extension-audit.json +131 -0
  15. package/docs/benchmarks/codex-native-protocol.md +69 -0
  16. package/docs/benchmarks/codex-native-replay.js +116 -0
  17. package/docs/benchmarks/codex-native-status.json +81 -0
  18. package/docs/benchmarks/codex-native.json +1003 -0
  19. package/docs/benchmarks/extension-sessions.png +0 -0
  20. package/docs/benchmarks/extension-tasks.png +0 -0
  21. package/docs/benchmarks/iframe-routing-regression.json +37 -0
  22. package/docs/browser-use-comparison.md +331 -0
  23. package/docs/browser-use-gap-audit.md +141 -0
  24. package/docs/browser-use-parity.md +105 -0
  25. package/docs/demo/intranet.html +103 -0
  26. package/docs/releases/v1.5.0.md +59 -0
  27. package/docs/releases/v1.5.1.md +16 -0
  28. package/docs/releases/v1.5.2.md +42 -0
  29. package/docs/releases/v1.5.3.md +33 -0
  30. package/docs/releases/v1.5.4.md +42 -0
  31. package/docs/releases/v1.6.0.md +16 -0
  32. package/docs/remote-control-hub.md +523 -0
  33. package/extension/activity.js +328 -0
  34. package/extension/automation.js +1839 -0
  35. package/extension/background.js +1854 -0
  36. package/extension/i18n.js +149 -0
  37. package/extension/icons/icon128.png +0 -0
  38. package/extension/icons/icon16.png +0 -0
  39. package/extension/icons/icon32.png +0 -0
  40. package/extension/icons/icon48.png +0 -0
  41. package/extension/manifest.json +47 -0
  42. package/extension/observations.js +109 -0
  43. package/extension/options.html +289 -0
  44. package/extension/options.js +269 -0
  45. package/extension/popup.html +74 -0
  46. package/extension/popup.js +105 -0
  47. package/extension/protocol.js +45 -0
  48. package/extension/remote-auth.js +18 -0
  49. package/extension/sessions.js +134 -0
  50. package/extension/snapshot.js +161 -0
  51. package/extension/task-groups.js +108 -0
  52. package/extension/tasks.js +186 -0
  53. package/extension/wait.js +89 -0
  54. package/hub/README.md +42 -0
  55. package/hub/package-lock.json +1544 -0
  56. package/hub/package.json +13 -0
  57. package/hub/src/rpc.js +41 -0
  58. package/hub/src/worker.js +322 -0
  59. package/hub/wrangler.example.toml +19 -0
  60. package/package.json +83 -0
  61. package/server/cdp-bridge.js +200 -0
  62. package/server/cli.js +1798 -0
  63. package/server/hub-server.js +258 -0
  64. package/server/install.js +250 -0
  65. package/server/mcp-server.js +504 -0
  66. package/server/npx-runner.js +96 -0
  67. package/server/relay-server.js +1356 -0
  68. package/server/remote-protocol.js +76 -0
  69. package/server/runtime-worker.js +166 -0
  70. package/server/script-runtime.js +189 -0
  71. package/server/sdk.js +307 -0
  72. package/server/service-state.js +103 -0
  73. package/server/snapshot.js +161 -0
  74. package/server/uninstall.js +61 -0
  75. package/server/windows-service-entry.js +58 -0
  76. package/server/windows-service.js +360 -0
  77. package/skills/browser-relay/SKILL.md +192 -0
  78. package/skills/browser-relay/references/legacy-api.md +163 -0
  79. package/skills/browser-relay/references/runtime.md +240 -0
@@ -0,0 +1,418 @@
1
+ {
2
+ "measuredAt": "2026-09-09T06:34:55.796Z",
3
+ "backend": "Codex Browser Use via CUA AX",
4
+ "scope": "Primary comparison. Interactive AX workflows on the local fixture. Session wall times excluded: research/tool scheduling intervals are uncontrolled. API time is descriptive only, one workflow trace per case, not a latency benchmark.",
5
+ "samples": [
6
+ {
7
+ "case": "delayed-enabled",
8
+ "backend": "codex-browser-use-ax",
9
+ "steps": [
10
+ {
11
+ "operation": "observe",
12
+ "elapsedMs": 118,
13
+ "state": "\t4 text Case: delayed-enabled\n\t5 container\n\t\t6 button Start enabling, ID: enable-start\n\t\t7 button (disabled) Delayed action, ID: enabled-target\n\t8 text Ready"
14
+ },
15
+ {
16
+ "operation": "Start enabling",
17
+ "elapsedMs": 17,
18
+ "error": null
19
+ },
20
+ {
21
+ "operation": "observe",
22
+ "elapsedMs": 154,
23
+ "state": "\t4 text Case: delayed-enabled\n\t5 container\n\t\t6 button Start enabling, ID: enable-start\n\t\t7 button (disabled) Delayed action, ID: enabled-target\n\t8 text Enabling"
24
+ },
25
+ {
26
+ "operation": "observe",
27
+ "elapsedMs": 24,
28
+ "state": "\t4 text Case: delayed-enabled\n\t5 container\n\t\t6 button Start enabling, ID: enable-start\n\t\t7 button Delayed action, ID: enabled-target\n\t8 text Enabling"
29
+ },
30
+ {
31
+ "operation": "Delayed action",
32
+ "elapsedMs": 14,
33
+ "error": null
34
+ },
35
+ {
36
+ "operation": "observe",
37
+ "elapsedMs": 156,
38
+ "state": "\t4 text Case: delayed-enabled\n\t5 container\n\t\t6 button Start enabling, ID: enable-start\n\t\t7 button Delayed action, ID: enabled-target\n\t8 text Enabled done"
39
+ }
40
+ ],
41
+ "outerCalls": 4,
42
+ "toolApiMs": 483,
43
+ "observations": 4,
44
+ "outcome": "completed",
45
+ "note": "等待状态启用后再操作,没有盲点 disabled 控件"
46
+ },
47
+ {
48
+ "case": "appearance",
49
+ "backend": "codex-browser-use-ax",
50
+ "steps": [
51
+ {
52
+ "operation": "observe",
53
+ "elapsedMs": 132,
54
+ "state": "\t4 text Case: appearance\n\t5 container\n\t\t6 text Expected target: Appeared action\n\t\t7 button Start appearance, ID: appear-start\n\t8 text Ready"
55
+ },
56
+ {
57
+ "operation": "Start appearance",
58
+ "elapsedMs": 20,
59
+ "error": null
60
+ },
61
+ {
62
+ "operation": "observe",
63
+ "elapsedMs": 155,
64
+ "state": "\t4 text Case: appearance\n\t5 container\n\t\t6 text Expected target: Appeared action\n\t\t7 button Start appearance, ID: appear-start\n\t8 text Waiting for appearance"
65
+ },
66
+ {
67
+ "operation": "observe",
68
+ "elapsedMs": 22,
69
+ "state": "\t4 text Case: appearance\n\t5 container\n\t\t6 text Expected target: Appeared action\n\t\t7 button Start appearance, ID: appear-start\n\t\t9 button Appeared action\n\t8 text Waiting for appearance"
70
+ },
71
+ {
72
+ "operation": "Appeared action",
73
+ "elapsedMs": 15,
74
+ "error": null
75
+ },
76
+ {
77
+ "operation": "observe",
78
+ "elapsedMs": 154,
79
+ "state": "\t4 text Case: appearance\n\t5 container\n\t\t6 text Expected target: Appeared action\n\t\t7 button Start appearance, ID: appear-start\n\t\t9 button Appeared action\n\t10 text Appeared done"
80
+ }
81
+ ],
82
+ "outerCalls": 4,
83
+ "toolApiMs": 498,
84
+ "observations": 4,
85
+ "outcome": "completed",
86
+ "note": "新控件出现后读取实际索引,再点击"
87
+ },
88
+ {
89
+ "case": "scoped",
90
+ "backend": "codex-browser-use-ax",
91
+ "steps": [
92
+ {
93
+ "operation": "observe",
94
+ "elapsedMs": 133,
95
+ "state": "\t4 text Case: scoped\n\t5 container\n\t\t6 container North\n\t\t\t7 text North\n\t\t\t8 button Save, ID: north-save\n\t\t9 container South\n\t\t\t10 text South\n\t\t\t11 button Save, ID: south-save\n\t12 text Ready"
96
+ },
97
+ {
98
+ "operation": "Save in South",
99
+ "elapsedMs": 17,
100
+ "error": null
101
+ },
102
+ {
103
+ "operation": "observe",
104
+ "elapsedMs": 155,
105
+ "state": "\t4 text Case: scoped\n\t5 container\n\t\t6 container North\n\t\t\t7 text North\n\t\t\t8 button Save, ID: north-save\n\t\t9 container South\n\t\t\t10 text South\n\t\t\t11 button Save, ID: south-save\n\t12 text South saved"
106
+ }
107
+ ],
108
+ "outerCalls": 2,
109
+ "toolApiMs": 305,
110
+ "observations": 2,
111
+ "outcome": "completed",
112
+ "note": "从 AX 父容器 South 定位同名 Save 按钮"
113
+ },
114
+ {
115
+ "case": "trusted-checkbox",
116
+ "backend": "codex-browser-use-ax",
117
+ "steps": [
118
+ {
119
+ "operation": "observe",
120
+ "elapsedMs": 129,
121
+ "state": "\t4 text Case: trusted-checkbox\n\t5 checkbox (settable, integer) Description: Trusted choice, Value: 0, ID: trusted-choice\n\t6 text Ready"
122
+ },
123
+ {
124
+ "operation": "Set Trusted choice",
125
+ "elapsedMs": 11,
126
+ "error": null
127
+ },
128
+ {
129
+ "operation": "observe",
130
+ "elapsedMs": 157,
131
+ "state": "\t4 text Case: trusted-checkbox\n\t5 checkbox (settable, integer) Description: Trusted choice, Value: 1, ID: trusted-choice\n\t6 text Ready"
132
+ }
133
+ ],
134
+ "outerCalls": 2,
135
+ "toolApiMs": 297,
136
+ "observations": 2,
137
+ "outcome": "state-only-no-click-event",
138
+ "note": "setValue 改变 checked,但 onclick 业务状态仍为 Ready;不能当作点击事件等价"
139
+ },
140
+ {
141
+ "case": "custom-checkbox",
142
+ "backend": "codex-browser-use-ax",
143
+ "steps": [
144
+ {
145
+ "operation": "observe",
146
+ "elapsedMs": 114,
147
+ "state": "\t4 text Case: custom-checkbox\n\t5 checkbox Description: Custom choice, Value: 0, ID: custom-choice\n\t6 text Ready"
148
+ },
149
+ {
150
+ "operation": "Click Custom choice",
151
+ "elapsedMs": 17,
152
+ "error": null
153
+ },
154
+ {
155
+ "operation": "observe",
156
+ "elapsedMs": 156,
157
+ "state": "\t4 text Case: custom-checkbox\n\t5 checkbox Description: Custom choice, Value: 1, ID: custom-choice\n\t6 text Custom checked=true"
158
+ }
159
+ ],
160
+ "outerCalls": 2,
161
+ "toolApiMs": 287,
162
+ "observations": 2,
163
+ "outcome": "completed",
164
+ "note": "自定义 ARIA checkbox 通过点击完成"
165
+ },
166
+ {
167
+ "case": "trusted-checkbox",
168
+ "backend": "codex-browser-use-ax",
169
+ "steps": [
170
+ {
171
+ "operation": "observe",
172
+ "elapsedMs": 114,
173
+ "state": "\t4 text Case: trusted-checkbox\n\t5 checkbox (settable, integer) Description: Trusted choice, Value: 0, ID: trusted-choice\n\t6 text Ready"
174
+ },
175
+ {
176
+ "operation": "Click Trusted choice",
177
+ "elapsedMs": 16,
178
+ "error": null
179
+ },
180
+ {
181
+ "operation": "observe",
182
+ "elapsedMs": 153,
183
+ "state": "\t4 text Case: trusted-checkbox\n\t5 checkbox (settable, integer) Description: Trusted choice, Value: 1, ID: trusted-choice\n\t6 text Checked=true; trusted=true"
184
+ }
185
+ ],
186
+ "outerCalls": 2,
187
+ "toolApiMs": 283,
188
+ "observations": 2,
189
+ "outcome": "completed",
190
+ "note": "与 setValue 对照,使用点击触发业务事件"
191
+ },
192
+ {
193
+ "case": "richtext",
194
+ "backend": "codex-browser-use-ax",
195
+ "steps": [
196
+ {
197
+ "operation": "observe",
198
+ "elapsedMs": 133,
199
+ "state": "\t4 text Case: richtext\n\t5 text entry area (settable) Description: Rich note, Value: Old note, ID: rich\n\t\t6 text Old note\n\t7 text Ready"
200
+ },
201
+ {
202
+ "operation": "Set Rich note",
203
+ "elapsedMs": 14,
204
+ "error": null
205
+ },
206
+ {
207
+ "operation": "observe",
208
+ "elapsedMs": 153,
209
+ "state": "\t4 text Case: richtext\n\t5 text entry area (settable) Description: Rich note, Value: New note, ID: rich\n\t\t6 text New note\n\t7 text Rich=New note"
210
+ }
211
+ ],
212
+ "outerCalls": 2,
213
+ "toolApiMs": 300,
214
+ "observations": 2,
215
+ "outcome": "completed",
216
+ "note": "按最终业务状态判定富文本赋值是否触发 input"
217
+ },
218
+ {
219
+ "case": "readonly",
220
+ "backend": "codex-browser-use-ax",
221
+ "steps": [
222
+ {
223
+ "operation": "observe",
224
+ "elapsedMs": 125,
225
+ "state": "\t4 text Case: readonly\n\t5 container\n\t\t6 text Read only \n\t\t7 text field Read only , Value: unchanged, ID: readonly\n\t8 text Ready"
226
+ },
227
+ {
228
+ "operation": "Attempt read-only setValue",
229
+ "elapsedMs": 7,
230
+ "error": "Error: Accessibility element 7 has no settable value"
231
+ },
232
+ {
233
+ "operation": "observe",
234
+ "elapsedMs": 19,
235
+ "state": "\t4 text Case: readonly\n\t5 container\n\t\t6 text Read only \n\t\t7 text field Read only , Value: unchanged, ID: readonly\n\t8 text Ready"
236
+ }
237
+ ],
238
+ "outerCalls": 2,
239
+ "toolApiMs": 151,
240
+ "observations": 2,
241
+ "outcome": "observed",
242
+ "note": "核对只读值是否保持 unchanged,以及工具是否明确报错"
243
+ },
244
+ {
245
+ "case": "rerender",
246
+ "backend": "codex-browser-use-ax",
247
+ "steps": [
248
+ {
249
+ "operation": "observe",
250
+ "elapsedMs": 127,
251
+ "state": "\t4 text Case: rerender\n\t5 container\n\t\t6 button Replace target, ID: replace-start\n\t\t7 button Replaceable action, ID: replace-target\n\t8 text Ready"
252
+ },
253
+ {
254
+ "operation": "Replace target",
255
+ "elapsedMs": 17,
256
+ "error": null
257
+ },
258
+ {
259
+ "operation": "observe",
260
+ "elapsedMs": 155,
261
+ "state": "\t4 text Case: rerender\n\t5 container\n\t\t6 button Replace target, ID: replace-start\n\t\t7 button Replaceable action, ID: replace-target\n\t8 text Target replaced"
262
+ },
263
+ {
264
+ "operation": "Click current replacement",
265
+ "elapsedMs": 15,
266
+ "error": null
267
+ },
268
+ {
269
+ "operation": "observe",
270
+ "elapsedMs": 154,
271
+ "state": "\t4 text Case: rerender\n\t5 container\n\t\t6 button Replace target, ID: replace-start\n\t\t7 button Replaceable action, ID: replace-target\n\t8 text Replacement done"
272
+ }
273
+ ],
274
+ "outerCalls": 3,
275
+ "toolApiMs": 468,
276
+ "observations": 3,
277
+ "outcome": "completed",
278
+ "note": "重渲染后重新观察并使用当前 AX 节点"
279
+ },
280
+ {
281
+ "case": "temporary-cover",
282
+ "backend": "codex-browser-use-ax",
283
+ "steps": [
284
+ {
285
+ "operation": "observe",
286
+ "elapsedMs": 142,
287
+ "state": "\t4 text Case: temporary-cover\n\t5 container\n\t\t6 button Start temporary cover, ID: cover-start\n\t\t7 button Covered action, ID: covered-target\n\t8 text Ready"
288
+ },
289
+ {
290
+ "operation": "Start temporary cover",
291
+ "elapsedMs": 17,
292
+ "error": null
293
+ },
294
+ {
295
+ "operation": "observe",
296
+ "elapsedMs": 154,
297
+ "state": "\t4 text Case: temporary-cover\n\t5 container\n\t\t6 button Start temporary cover, ID: cover-start\n\t\t7 button Covered action, ID: covered-target\n\t\t8 text Please wait\n\t9 text Covering"
298
+ },
299
+ {
300
+ "operation": "observe",
301
+ "elapsedMs": 5583,
302
+ "state": "\t4 text Case: temporary-cover\n\t5 container\n\t\t6 button Start temporary cover, ID: cover-start\n\t\t7 button Covered action, ID: covered-target\n\t9 text Covering"
303
+ },
304
+ {
305
+ "operation": "Covered action after overlay",
306
+ "elapsedMs": 17,
307
+ "error": null
308
+ },
309
+ {
310
+ "operation": "observe",
311
+ "elapsedMs": 154,
312
+ "state": "\t4 text Case: temporary-cover\n\t5 container\n\t\t6 button Start temporary cover, ID: cover-start\n\t\t7 button Covered action, ID: covered-target\n\t8 text Covered done"
313
+ }
314
+ ],
315
+ "outerCalls": 4,
316
+ "toolApiMs": 6067,
317
+ "observations": 4,
318
+ "outcome": "completed",
319
+ "note": "先确认覆盖层消失,再操作目标"
320
+ },
321
+ {
322
+ "case": "disabled-option",
323
+ "backend": "codex-browser-use-ax",
324
+ "steps": [
325
+ {
326
+ "operation": "observe",
327
+ "elapsedMs": 127,
328
+ "state": "\t4 text Case: disabled-option\n\t5 container\n\t\t6 text Availability \n\t\t7 pop up button (collapsed, settable) Availability , Value: Open, ID: availability, Secondary Actions: Expand\n\t\t\t8 menu\n\t\t\t\t9 (selected) Open\n\t\t\t\t10 (disabled) Closed\n\t11 text Ready"
329
+ },
330
+ {
331
+ "operation": "Attempt disabled option",
332
+ "elapsedMs": 11,
333
+ "error": "Error: Error: Select option \"Closed\" is disabled\n at HTMLSelectElement.pD (<anonymous>:1:1958)\n at HTMLSelectElement.<anonymous> (<anonymous>:1:4296)"
334
+ },
335
+ {
336
+ "operation": "observe",
337
+ "elapsedMs": 14,
338
+ "state": "\t4 text Case: disabled-option\n\t5 container\n\t\t6 text Availability \n\t\t7 pop up button (collapsed, settable) Availability , Value: Open, ID: availability, Secondary Actions: Expand\n\t\t\t8 menu\n\t\t\t\t9 (selected) Open\n\t\t\t\t10 (disabled) Closed\n\t11 text Ready"
339
+ }
340
+ ],
341
+ "outerCalls": 2,
342
+ "toolApiMs": 152,
343
+ "observations": 2,
344
+ "outcome": "observed",
345
+ "note": "专门测试 API 对禁用选项的行为,不把它当作正常用户操作"
346
+ },
347
+ {
348
+ "case": "moving",
349
+ "backend": "codex-browser-use-ax",
350
+ "steps": [
351
+ {
352
+ "operation": "observe",
353
+ "elapsedMs": 132,
354
+ "state": "\t4 text Case: moving\n\t5 container\n\t\t6 button Start movement, ID: move-start\n\t\t7 button Description: Moving action, ID: moving\n\t8 text Ready"
355
+ },
356
+ {
357
+ "operation": "Start movement and activate known target",
358
+ "elapsedMs": 28,
359
+ "error": null
360
+ },
361
+ {
362
+ "operation": "observe",
363
+ "elapsedMs": 154,
364
+ "state": "\t4 text Case: moving\n\t5 container\n\t\t6 button Start movement, ID: move-start\n\t\t7 button Description: Moving action, ID: moving\n\t8 text Moving done"
365
+ }
366
+ ],
367
+ "outerCalls": 2,
368
+ "toolApiMs": 314,
369
+ "observations": 2,
370
+ "outcome": "completed",
371
+ "note": "AX 通过控件语义激活,未依赖截图坐标追踪移动"
372
+ },
373
+ {
374
+ "case": "frame-cover",
375
+ "backend": "codex-browser-use-ax",
376
+ "steps": [
377
+ {
378
+ "operation": "observe",
379
+ "elapsedMs": 136,
380
+ "state": "\t4 text Case: frame-cover\n\t5 container\n\t\t6 container Covered frame\n\t\t\t7 AXWebArea Frame, URL: 127.0.0.1:49942/frame?covered=1\n\t\t\t\t8 button Frame action\n\t\t9 text Permanent cover\n\t10 text Ready"
381
+ },
382
+ {
383
+ "operation": "Probe covered frame action",
384
+ "elapsedMs": 62,
385
+ "error": null
386
+ },
387
+ {
388
+ "operation": "observe",
389
+ "elapsedMs": 154,
390
+ "state": "\t4 text Case: frame-cover\n\t5 container\n\t\t6 container Covered frame\n\t\t\t7 AXWebArea Frame, URL: 127.0.0.1:49942/frame?covered=1\n\t\t\t\t8 button Frame done\n\t\t9 text Permanent cover\n\t10 text Ready"
391
+ }
392
+ ],
393
+ "outerCalls": 2,
394
+ "toolApiMs": 352,
395
+ "observations": 2,
396
+ "outcome": "observed",
397
+ "note": "记录 AX 语义激活对 iframe 遮挡的处理"
398
+ }
399
+ ],
400
+ "stateFormat": "Repeated page title, heading and focus lines removed; remaining AX rows and state values preserved.",
401
+ "probes": [
402
+ {
403
+ "case": "delayed-enabled",
404
+ "backend": "native-ax",
405
+ "elapsedMs": 186,
406
+ "error": null,
407
+ "finalState": "\t3 text Case: delayed-enabled\n\t4 container\n\t\t5 button Start enabling, ID: enable-start\n\t\t6 button (disabled) Delayed action, ID: enabled-target\n\t7 text Enabling",
408
+ "success": false
409
+ },
410
+ {
411
+ "case": "shadow-cover",
412
+ "backend": "native-ax",
413
+ "elapsedMs": 211,
414
+ "error": null,
415
+ "finalState": "\t4 text Case: shadow-cover\n\t5 container\n\t\t6 button Shadow covered action\n\t\t7 text Permanent cover\n\t8 text Shadow incorrectly clicked"
416
+ }
417
+ ]
418
+ }