lasso-mcp 1.13.0 → 1.14.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 (76) hide show
  1. package/ARCHITECTURE.md +144 -74
  2. package/README.de.md +106 -79
  3. package/README.en.md +82 -95
  4. package/README.es.md +106 -79
  5. package/README.fr.md +108 -81
  6. package/README.ja.md +109 -83
  7. package/README.md +77 -111
  8. package/README.pt.md +108 -81
  9. package/README.ru.md +107 -80
  10. package/dist/channels/BingChannel.d.ts +2 -1
  11. package/dist/channels/BingChannel.d.ts.map +1 -1
  12. package/dist/channels/BingChannel.js +2 -1
  13. package/dist/channels/BingChannel.js.map +1 -1
  14. package/dist/channels/BraveChannel.d.ts +4 -2
  15. package/dist/channels/BraveChannel.d.ts.map +1 -1
  16. package/dist/channels/BraveChannel.js +4 -2
  17. package/dist/channels/BraveChannel.js.map +1 -1
  18. package/dist/channels/BrowseChannel.d.ts.map +1 -1
  19. package/dist/channels/BrowseChannel.js +6 -0
  20. package/dist/channels/BrowseChannel.js.map +1 -1
  21. package/dist/config/providers.d.ts +7 -3
  22. package/dist/config/providers.d.ts.map +1 -1
  23. package/dist/config/providers.js +18 -11
  24. package/dist/config/providers.js.map +1 -1
  25. package/dist/config/quota-ledger.d.ts.map +1 -1
  26. package/dist/config/quota-ledger.js +2 -1
  27. package/dist/config/quota-ledger.js.map +1 -1
  28. package/dist/doctor/doctor-cli.d.ts +9 -4
  29. package/dist/doctor/doctor-cli.d.ts.map +1 -1
  30. package/dist/doctor/doctor-cli.js +15 -3
  31. package/dist/doctor/doctor-cli.js.map +1 -1
  32. package/dist/doctor/doctor.d.ts +19 -1
  33. package/dist/doctor/doctor.d.ts.map +1 -1
  34. package/dist/doctor/doctor.js +166 -4
  35. package/dist/doctor/doctor.js.map +1 -1
  36. package/dist/index.js +9 -5
  37. package/dist/index.js.map +1 -1
  38. package/dist/search/FreeTierRouter.d.ts +4 -3
  39. package/dist/search/FreeTierRouter.d.ts.map +1 -1
  40. package/dist/search/FreeTierRouter.js.map +1 -1
  41. package/dist/serp/extract.d.ts +18 -3
  42. package/dist/serp/extract.d.ts.map +1 -1
  43. package/dist/serp/extract.js +49 -8
  44. package/dist/serp/extract.js.map +1 -1
  45. package/dist/serp/selectors.d.ts +12 -2
  46. package/dist/serp/selectors.d.ts.map +1 -1
  47. package/dist/serp/selectors.js +27 -2
  48. package/dist/serp/selectors.js.map +1 -1
  49. package/dist/tools/search.d.ts +7 -1
  50. package/dist/tools/search.d.ts.map +1 -1
  51. package/dist/tools/search.js +25 -6
  52. package/dist/tools/search.js.map +1 -1
  53. package/dist/types.d.ts +4 -3
  54. package/dist/types.d.ts.map +1 -1
  55. package/doc/08-media-interact-/345/212/237/350/203/275/346/236/266/346/236/204.md +442 -0
  56. package/doc/09-media-interact-/345/256/236/346/226/275/346/216/222/346/234/237.md +312 -0
  57. package/doc/20-/346/226/207/346/241/243/345/220/214/346/255/245/345/256/241/350/256/241.md +280 -0
  58. package/doc/21-/346/220/234/347/264/242/346/226/271/346/241/210/351/207/215/345/256/241/rca-/344/270/272/344/273/200/344/271/210/346/274/217.md +154 -0
  59. package/doc/21-/346/220/234/347/264/242/346/226/271/346/241/210/351/207/215/345/256/241/verdict.md +113 -0
  60. package/doc/21-/346/220/234/347/264/242/346/226/271/346/241/210/351/207/215/345/256/241/verify.md +130 -0
  61. package/doc/KEY-GUIDE.md +74 -54
  62. package/doc/TROUBLESHOOTING.md +61 -11
  63. package/package.json +1 -1
  64. package/src/channels/BingChannel.ts +2 -1
  65. package/src/channels/BraveChannel.ts +4 -2
  66. package/src/channels/BrowseChannel.ts +6 -0
  67. package/src/config/providers.ts +19 -12
  68. package/src/config/quota-ledger.ts +2 -1
  69. package/src/doctor/doctor-cli.ts +22 -5
  70. package/src/doctor/doctor.ts +190 -4
  71. package/src/index.ts +9 -5
  72. package/src/search/FreeTierRouter.ts +4 -3
  73. package/src/serp/extract.ts +83 -14
  74. package/src/serp/selectors.ts +27 -3
  75. package/src/tools/search.ts +29 -6
  76. package/src/types.ts +4 -3
package/ARCHITECTURE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Lasso 架构
2
2
 
3
- > 本文是 Lasso v1.0 的架构概览(user-first;深度架构基线见 [`doc/08`](./../doc/08-media-interact-功能架构.md);实施排期与决策记录见 [`doc/09`](./../doc/09-media-interact-实施排期.md))。
3
+ > 本文是 Lasso v1.13 的架构概览(user-first;深度架构基线见 [`doc/08`](./../doc/08-media-interact-功能架构.md);实施排期与决策记录见 [`doc/09`](./../doc/09-media-interact-实施排期.md);五轮最优性审查全记录见 [`doc/19`](./doc/19-最优性审查轮次/00-总结.md))。
4
4
 
5
5
  ## 1. 项目定位
6
6
 
@@ -9,7 +9,7 @@ Lasso 是 Claude Code 的**全交互**对外抓手 MCP(浏览器 + 桌面)
9
9
  - media-gen-mcp:「所有图像操作归一个 MCP」(生成 + 识别)
10
10
  - **Lasso**:「所有外部交互归一个 MCP」(浏览器 + 桌面)
11
11
 
12
- 四通道:`search` / `browse_headless` / `browse_logged_in` / `desktop`。所有通道共享同一套 fallback 范式 / 状态模型 / 工具风格(R-CI-02 红线:禁第二套做法)。
12
+ 四通道:`search` / `browse_headless` / `browse_logged_in` / `desktop`(+ 条件解锁的 `browse_cloud_steel` 云通道)。所有通道共享同一套 fallback 范式 / 状态模型 / 工具风格(R-CI-02 红线:禁第二套做法)。
13
13
 
14
14
  ## 2. 整体分层
15
15
 
@@ -25,15 +25,16 @@ Lasso 是 Claude Code 的**全交互**对外抓手 MCP(浏览器 + 桌面)
25
25
  │ ┌──────────────────────────────────────────────────────────┐ │
26
26
  │ │ Tool Layer(src/tools/) │ │
27
27
  │ │ search / browse_headless / browse_logged_in │ │
28
- │ │ desktop / admin / doctor │ │
28
+ │ │ desktop / admin / doctor / fetch_url / network / ... │ │
29
29
  │ │ 每工具 Zod inputSchema + ToolAnnotations 完整 │ │
30
30
  │ └────────────────────────┬─────────────────────────────────┘ │
31
31
  │ │ typed call │
32
32
  │ ┌────────────────────────▼─────────────────────────────────┐ │
33
33
  │ │ Channel Layer(src/channels/ + src/browse/ + src/desktop/│ │
34
34
  │ │ + src/search/ + src/logged-in/) │ │
35
- │ │ BaseChannel ← UiChannel ← BrowseChannel / DesktopChannel│ │
36
- │ │ SearchChannel / LoggedInChannel │ │
35
+ │ │ BaseChannel ← UiChannel ← BrowseChannel │ │
36
+ │ │ HeadlessChannel / LoggedInChannel / SteelChannel │ │
37
+ │ │ ← SearchChannel / DesktopChannel │ │
37
38
  │ └────────────────────────┬─────────────────────────────────┘ │
38
39
  │ │ FallbackDecider + tri-state │
39
40
  │ ┌────────────────────────▼─────────────────────────────────┐ │
@@ -44,19 +45,32 @@ Lasso 是 Claude Code 的**全交互**对外抓手 MCP(浏览器 + 桌面)
44
45
  │ ┌────────────────────────▼─────────────────────────────────┐ │
45
46
  │ │ Subprocess Layer(src/subprocess/) │ │
46
47
  │ │ SubprocessManager + RustBridge │ │
47
- │ │ chrome-devtools-mcp ×2(headless / logged_in│ │
48
- │ │ lasso-rust-helper(AXAPI/UIA/AT-SPI + screenshot + TCC) │ │
48
+ │ │ chrome-devtools-mcp@1.7.0(headless / logged_in / │ │
49
+ │ │ Steel / browserbase 各自 registerSpec) │ │
50
+ │ │ lasso-rust-helper(AXAPI/UIA/AT-SPI + cgEvent │ │
51
+ │ │ + screenshot + TCC) │ │
49
52
  │ └──────────────────────────────────────────────────────────┘ │
50
53
  └──────────────────────────────┬─────────────────────────────────┘
51
54
  ┌───────────────────────┼───────────────────────┐
52
55
  ▼ ▼ ▼
53
- chrome-devtools-mcp 智谱/Brave/Bing/Wayback lasso-rust-helper
54
- (--headless (search multi-engine (macOS AXAPI
55
- / --browser-url via HTTP) Windows UIA
56
- :9222) Linux AT-SPI
57
- + screenshot + TCC)
56
+ chrome-devtools-mcp 智谱/Brave/Bing/SERP lasso-rust-helper
57
+ @1.7.0(--headless / 兜底(search 多引擎 macOS AXAPI +
58
+ --browser-url / Steel 经 HTTP;machine_mcp cgEvent;Windows UIA
59
+ CDP / --wsEndpoint) 复用打头) Linux AT-SPI
58
60
  ```
59
61
 
62
+ ### 2.1 浏览器驱动契约锁:chrome-devtools-mcp 1.7.0(v1.11 迁移)
63
+
64
+ `src/subprocess/SubprocessManager.ts` 的 `LOCKED_CDP_MCP_VERSION = "1.7.0"` 是唯一真源,启动时经 `npx -y chrome-devtools-mcp@1.7.0` 自动拉取。v1.11 从 0.3.0 → 1.7.0 的一次性迁移(11 个月 / 57 个上游版本)要点:
65
+
66
+ - `--chromeArg` 透传机制解锁:launch 级 `--user-agent` / `--viewport` / `--accept-lang` 直达 Chromium(stealth 与反节流都靠它)
67
+ - 全部 spec 显式 `--no-usage-statistics`(1.7.0 默认采集使用统计,Lasso 关掉——隐私不倒退,INV-79(b) 守)
68
+ - Browserbase 改 `--wsEndpoint`(与 `--browser-url` 互斥,wss 语义保障,INV-79(c) 守)
69
+ - **network 原生化**:`network` 工具从 JS 层 PerformanceObserver 注入改为原生 `list_network_requests`(CDP Network 域)——fake-ip / TUN 代理网络「抓不全」的限制关闭;per-request `method/status/reqid`
70
+ - **console 实装**:`list_console_messages`(原生工具,v1.11 前是占位)
71
+
72
+ 迁移守护 = INV-79(版本锁 / 遥测关 / wsEndpoint / launch 级 stealth / 零哑 flag 回潮五面)。
73
+
60
74
  ## 3. 核心抽象
61
75
 
62
76
  ### 3.1 BaseChannel / UiChannel 分层
@@ -65,9 +79,10 @@ Lasso 是 Claude Code 的**全交互**对外抓手 MCP(浏览器 + 桌面)
65
79
  BaseChannel (src/channels/BaseChannel.ts)
66
80
  ├── SearchChannel (只通用层;不进 UI)
67
81
  └── UiChannel (src/channels/UiChannel.ts)
68
- ├── BrowseChannel (browse_headless + browse_logged_in 复用)
82
+ ├── BrowseChannel (browse_headless + browse_logged_in + cloud 复用)
69
83
  ├── HeadlessChannel
70
84
  ├── LoggedInChannel
85
+ ├── SteelChannel (v1.6 自托管云浏览器;extends BrowseChannel 平级兄弟)
71
86
  └── DesktopChannel (desktop 4 档 fallback:ax → appleScript → cgEvent → screenshotVlm)
72
87
  ```
73
88
 
@@ -75,7 +90,7 @@ UI 通道共享 UiChannel 的状态写盘 / LRU / output envelope 机制;Searc
75
90
 
76
91
  ### 3.2 CapabilityBag(运行时动态启停)
77
92
 
78
- `src/runtime/CapabilityBag.ts`(v0.6+):通道运行时可 enable/disable,无需重启进程。`admin` tool 提供 `channel_health` / `reset` action。**INV-37 守:admin tool 必经 toolManager.register(不直调 server.tool)**。
93
+ `src/runtime/CapabilityBag.ts`(v0.6+):通道运行时可 enable/disable,无需重启进程。`admin` tool 提供 `channel_health` / `reset` action;v1.12 起动态注册工具的时延/错误入 metrics 观测窗(`toolManager.setMetrics` 接线)。**INV-37 守:admin tool 必经 toolManager.register(不直调 server.tool)**。
79
94
 
80
95
  ### 3.3 FallbackPlan + tri-state outcome
81
96
 
@@ -91,19 +106,37 @@ outcome = worked | didnt | unknown
91
106
  └──────────────────────┘
92
107
  ```
93
108
 
94
- 铁律:**event delivery ≠ semantic success**(INV-13)。例如 `desktop act` 调用 AXPress 不报错(event delivered),但目标按钮没有真的被点(disabled / obscured)→ 必须 `expect` 验证后置条件,failed 时 `outcome=didnt` 终止链。
109
+ 铁律:**event delivery ≠ semantic success**(INV-13)。例如 `desktop act` 调用 AXPress 不报错(event delivered),但目标按钮没有真的被点(disabled / obscured)→ 必须 `expect` 验证后置条件,failed 时 `outcome=didnt` 终止链。v1.11 起 expect 真接线(schema 早承诺、v1.0 零消费);v1.12 起 **wait / expect 需连续 2 次命中才算**(稳定性采样——加载闪现元素不再假成功)。
95
110
 
96
111
  ### 3.4 StateStore LRU(128)
97
112
 
98
- 页面 DOM / 桌面 OutlineNode 不灌 CC 上下文,而是写本地磁盘(`~/.cache/lasso/state/`),返回 `state_id`。CC 后续 `act` / `find` 经 `state_id` 引用 → **4× token 效率**。LRU(128) 自动淘汰旧状态。
113
+ 页面 DOM / 桌面 OutlineNode 不灌 CC 上下文,而是写本地磁盘(`~/.cache/lasso/state/`),返回 `state_id`。CC 后续 `act` / `find` 经 `state_id` 引用 → **4× token 效率**。LRU(128) 自动淘汰旧状态。desktop 侧另有 `skeleton:true` 树剪枝(v1.11:被 max_depth 剪掉的子树折叠为边界节点 + childrenCount)与顶层 `truncated:true` 诚实信号(v1.12:仅真剪掉子树时出现)。
114
+
115
+ ### 3.5 stealth 体系(v1.5 → v1.13 演进)
116
+
117
+ `src/browse/StealthEngine.ts` + `src/browse/stealth-profiles.ts`:
118
+
119
+ - **v1.5**:16 路 evasions(12 路 vendored from puppeteer-extra-plugin-stealth@2.11.2,MIT 头保留)+ profile 附 header 集(secChUa / secFetch* / accept*;UA↔secChUa↔userAgentData.brands 三方一致,INV-73 守)
120
+ - **v1.11**:launch 级 stealth——经 `--chromeArg` 下发 `--user-agent` / `--viewport`,网络层 HTTP 头与 JS 层 `navigator.*` 同源同值;值域刷新到 2026-07 stable 时代(Chrome 151 / Safari 27 冻结 token / Firefox 153,profile key 名不动)
121
+ - **v1.12**:`mac_chrome` profile + `defaultHeadlessProfileForHost()`——darwin 默认指纹与宿主系统对齐(消除「UA 说 Windows、低熵 client hints 招供 macOS」)
122
+ - **v1.13**:`--accept-lang` 透传 + `navigator.languages` 档案感知——HTTP 头与 JS 层语言同源同值(消除「头 zh-CN ↔ 页面 en-US」自矛盾指纹)
123
+ - **回归门禁**:doctor #38 `stealth_creepjs_regression`(opt-in `--stealth-check`,creepjs lies 基线零容忍退化,INV-75 守)+ self-check 的宿主 Chrome 版本 skew hint(|skew|≥2 建议刷新)与 UA 年龄提示
124
+
125
+ ### 3.6 生命周期与稳定性(v1.9 → v1.13)
126
+
127
+ - **无头浏览器**:空闲 5 分钟自动回收(`LASSO_HEADLESS_IDLE_MS`,v1.9;touchKeepalive 防误杀)
128
+ - **launch-chrome**:台账(`launched-chromes.json`)+ `lasso chrome-stop`(只杀 cmdline 验证归属的 pid,防 pid 复用误杀,v1.9);hidden 档默认 + 最后使用后 ~60s 自动关(`LASSO_LAUNCH_MODE` / `LASSO_LAUNCH_IDLE_MS`,v1.10);`admin tab_restore` 恢复用户原 tab(红线:不关用户原有 tab)
129
+ - **stdin-EOF 收尾**(v1.12):CC 异常退出 → 父进程死 → stdin EOF → 复用幂等 shutdown;受管子进程不再孤儿到 zombie reaper 1h 阈值(上游 SDK #2002 的进程侧缓解)
130
+ - **停机链全路径有界**(v1.13):Steel 会话释放双层 3s 上界(停机链 race 3s + fetch `AbortSignal.timeout(3s)`)——自托管 Steel 停摆/endpoint 悬挂(实测可挂 ~301s)不再拖死退出
131
+ - **`LASSO_PROXY` 出口代理**(v1.11):headless 经 `--proxy-server`、Steel 经 session `proxyUrl`;**`browse_logged_in` 永不读取**(用户真实 Chrome 出口原样,铁律);doctor `proxy_config` 回显
99
132
 
100
- ## 4. desktop 跨平台(v1.0 落地)
133
+ ## 4. desktop:四档新实现(v1.11 v1.13,从「能看」到「能点」)
101
134
 
102
135
  ```
103
136
  AxBackend interface(三平台同构 OutlineNode 契约)
104
- ├── MacAxBackend → rust.call("ax_snapshot") → rust-helper/src/ax.rs [cfg(macos)]
105
- ├── WinUiaBackend → rust.call("uia_snapshot") → rust-helper/src/uia.rs [cfg(windows)]
106
- └── LinuxAtspiBackend → rust.call("atspi_snapshot") → rust-helper/src/atspi.rs [cfg(linux)]
137
+ ├── MacAxBackend → rust.call("ax_*") → rust-helper/src/ax.rs [cfg(macos)]
138
+ ├── WinUiaBackend → rust.call("uia_*") → rust-helper/src/uia.rs [cfg(windows)]
139
+ └── LinuxAtspiBackend → rust.call("atspi_*") → rust-helper/src/atspi.rs [cfg(linux)]
107
140
 
108
141
 
109
142
  AxBackendFactory.create() ← platform-detect.ts (process.platform)
@@ -118,14 +151,26 @@ AxBackend interface(三平台同构 OutlineNode 契约)
118
151
  OutlineNode(同形异源;INV-19 守:类型无 surface 字段)
119
152
  ```
120
153
 
154
+ 四档 fallback(`DesktopChannel` 内):
155
+
156
+ 1. **tier-1 ax(AXAPI 语义)**:v1.11 真实现(v0.3.5 起的 invoke 占位废除)——click / type / press / scroll / hotkey 经 AXAPI 语义执行 + **写后读回验证**(secure 字段豁免);逐项结果 `actions_and_results`;全败且含 stale_ref → `didnt`(UI 已变,引导重新 observe)。type 语义 = **整值替换**(AXSetValue,非追加)。
157
+ 2. **tier-2 appleScript**:白名单脚本档(INV-27 守)。
158
+ 3. **tier-3 cgEvent(坐标鼠标)**:v1.11 新——`click{x,y,button}` / `drag{from→to}` / `move{x,y}` / `scroll{dx,dy[,x,y]}`;坐标 = snapshot rect 中心;canvas / Electron 自绘 UI 兜底,@wN 透传链同样支持坐标形态。v1.12 拖拽物理质量:按下 200ms + 12 点线性插值轨迹(每点 16ms)+ 100ms 沉淀 + clickState(`rust-helper/src/cgevent.rs`)。macOS 15+ 需 Event Synthesizing TCC 授权(缺失 → `tcc_event_synthesis_denied` 明确报错,doctor #21 专查)。
159
+ 4. **tier-4 screenshotVlm(VLM 链尾)**:截图推断 → 容错解析为坐标动作 → `cgevent_dispatch` **真执行**(v1.12 闭环);不可解析 / 执行失败 → 诚实 `unknown`(`vlm_inference_only:*`,推断原文附 data 不浪费)——不再「调用成功即 worked」假成功。v1.13 起 `screenshot_region` 场景 VLM 区域相对坐标平移回全局坐标(修系统性偏移)。
160
+
161
+ **Electron 输入兜底**(v1.12,档内降级):AX 不可用(Electron 吞 AXSetValue,Slack / VSCode 典型)时「聚焦 + cmd+a 全选 + 逐字符键盘合成」(ASCII);`ax_verify_failed` 不兜底(保持失败诚实)。
162
+
163
+ **find 语义**(v1.12/v1.13):命中节点附 `actions:[...]`(AX 动作名);`where` 只认 text / role——纯 ref 查询双端夹击报 `invalid_params`(TS zod 删字段 + Rust 兜底,防绕过 zod 直发 wire;此前静默退化成全树命中 + token 爆炸还装成功)。
164
+
165
+ **跨平台边界**:macOS 真机验证;Win/Linux 编译可证(cfg-gate + `cargo check --target`)+ 契约可证,真机完整手测待社区反馈(不伪造)。
166
+
121
167
  **关键设计决策**(守简单性 02 §5 R-CI-02 + §6.1 R-FF-01):
122
168
 
123
- 1. **不重写 AxBackend interface**。v0.3.5 已定义 `snapshot / find / act` 三方法;v1.0 只加 backend 实现,不破契约。
124
- 2. **不在 TS 层做平台分支**。`AxProvider` 不 `if (platform === 'win32')`;而是 `AxBackendFactory.create()` 经 `platform-detect.ts` 路由。**INV-21 守:src/**/*.ts 无平台字面量**(AXUIElement / CGEvent / libatspi 都隔离在 rust-helper/*.rs)。
125
- 3. **不渗 OutlineMapper 到 backend 内**。OutlineMapper 三平台共享同一个(INV-61 守:mapper 是纯数据变换,不感知 backend 实现选择);Rust 端三平台都返同形 AxNode JSON。
126
- 4. **不引 electron / tauri 跨平台 AX 抽象**。它们抽象太厚(带 IPC / window management),Lasso 只需"读 AX 树 + act 节点",薄壳足够(02 §5 R-ABS-01 错误抽象警惕)。
127
- 5. **Windows UIA 用官方 `windows` crate(microsoft/windows-rs)**。微软长期维护 + auto-generated from Win32 metadata + 完整覆盖(社区 uiautomation crate 维护风险高,不选)。
128
- 6. **Linux AT-SPI 用 `atspi` crate(odilia-app)**。pure Rust via zbus D-Bus,无 C 依赖,CI Linux headless 可编。
169
+ 1. **不重写 AxBackend interface**。`snapshot / find / act` 三方法契约自 v0.3.5 稳定至今;升级只加实现细节(skeleton / 坐标动作 / 读回验证),不破契约。
170
+ 2. **不在 TS 层做平台分支**。`AxProvider` 不 `if (platform === 'win32')`;`AxBackendFactory.create()` 经 `platform-detect.ts` 路由。**INV-21 守:src/**/*.ts 无平台字面量**(AXUIElement / CGEvent / libatspi 都隔离在 rust-helper/*.rs)。
171
+ 3. **不渗 OutlineMapper 到 backend 内**。OutlineMapper 三平台共享同一个(INV-61 守);Rust 端三平台都返同形 AxNode JSON。
172
+ 4. **不引 electron / tauri 跨平台 AX 抽象**。它们抽象太厚(带 IPC / window management),Lasso 只需「读 AX 树 + act 节点」,薄壳足够(02 §5 R-ABS-01 错误抽象警惕)。
173
+ 5. **Windows UIA 用官方 `windows` crate(microsoft/windows-rs)**;**Linux AT-SPI 用 `atspi` crate(odilia-app)**(pure Rust via zbus D-Bus,无 C 依赖,CI Linux headless 可编)。
129
174
 
130
175
  ## 5. 设计原则(08 §0)
131
176
 
@@ -133,10 +178,10 @@ AxBackend interface(三平台同构 OutlineNode 契约)
133
178
  2. **页面/界面状态写磁盘**:4× token 效率
134
179
  3. **减少推理调用**:多步链式(如 search → click → extract)一次工具调用完成
135
180
  4. **fallback 对 CC 透明**:CC 只看到 `worked / didnt`,不感知降级细节
136
- 5. **诚实三态交付**:`worked / didnt / unknown`(unknown 是 fallback 触发器)
137
- 6. **零侵入跟随上游**:chrome-devtools-mcp 升级时 Lasso 不改业务(契约锁版本)
181
+ 5. **诚实三态交付**:`worked / didnt / unknown`(unknown 是 fallback 触发器);假成功零容忍(expect 稳定性采样 / VLM 链尾诚实化 / find 拒纯 ref 同族)
182
+ 6. **零侵入跟随上游**:chrome-devtools-mcp 升级时 Lasso 不改业务(契约锁版本,当前 1.7.0)
138
183
  7. **第二套做法红线**(R-CI-02):横切关注点变体只允许一套(fallback 范式 / state 模型 / dispatch Map / provider registry 等)
139
- 8. **不变量脚本化**(CI 守门):65 条 INV 静态 grep + 形状测,防 refactor 回退
184
+ 8. **不变量脚本化**(CI 守门):**79 条 INV** 静态 grep + 形状测,防 refactor 回退;另有 `inv-selftest`(见 §7)
140
185
  9. **平台差异隔离在 backend 内部**:AxBackend 三平台同构 OutlineNode 契约;TS 层零平台字面量
141
186
 
142
187
  ## 6. 边界(08 §7)
@@ -144,25 +189,26 @@ AxBackend interface(三平台同构 OutlineNode 契约)
144
189
  Lasso 明确**不做**以下事情:
145
190
 
146
191
  - **不解 2FA**:站点要求 2FA 时返 `NEEDS_MANUAL_2FA`(red line;不让 CC 尝试绕过)
147
- - **不做坐标 grounding**:desktop 走语义 AX tree,不 click (x, y) 坐标(坐标方案脆弱)
192
+ - **不做「全坐标 grounding」方案**:desktop 以语义 AX tree 为主路径(tier-1);坐标形态 `{x,y}`(取 snapshot rect 中心)只是 tier-3 cgEvent 的**兜底**,服务 canvas / Electron 自绘 UI 与 VLM 链尾(v1.11 T7)——不采用「截图 + 坐标识别」为主路径的脆弱方案
148
193
  - **不做 RRF 融合 / corpus 持久化**:search 是 hit + wayback 兜底,不是 RAG
149
194
  - **不导出 cookie**:`browse_logged_in` 的 cookie 留本机 Chrome(除用户显式 opt-in `admin` action 且经 AES-256-GCM 加密)
150
- - **不引云浏览器**:cloud 浏览器通道(Browserbase / Stagehand)必经 `LASSO_ALLOW_CLOUD_BROWSER=true` manual-switch + API key 双重解锁(INV-25 守)
151
- - **macOS-only 开发**:Win/Linux backend 编译可证(cfg-gate + `cargo check --target`),真机执行待社区反馈(不伪造)
195
+ - **托管型云浏览器默认关**:cloud 通道必经 `LASSO_ALLOW_CLOUD_BROWSER=true` manual-switch + 端点/key 双重解锁(INV-25/74 守)。其中 **Steel 是自托管**(Apache-2.0 开源、本地 Docker、零 per-session 费、cookie 不出本地,v1.6)——与托管型(browserbase / stagehand,付费)区分;stagehand 是程序化实验通道(无 MCP 工具入口,doctor #39 探测 REST 契约)
196
+ - **macOS 先行**:Win/Linux backend 编译可证(cfg-gate + `cargo check --target`),真机执行待社区反馈(不伪造)
152
197
 
153
198
  ## 7. 测试策略
154
199
 
155
- | 层 | 工具 | 覆盖 | 规模 |
200
+ | 层 | 工具 | 覆盖 | 规模(v1.13 终态) |
156
201
  |---|---|---|---|
157
- | 架构不变量 | `check-invariants.mjs`(自写) | INV-1..65 静态 grep + 形状测 | 65 |
158
- | TS 单测 | vitest | channel / fallback / forest / doctor / launcher / outline-contract / replay-baseline | ≈1400 测试 |
159
- | Rust 单测 | cargo test | macOS 路径(ax / applescript / cgevent / screenshot / tcc / windows) | ≈180 测试 |
202
+ | 架构不变量 | `check-invariants.mjs`(自写) | INV-1..79 静态 grep + 形状测 | **79 条** |
203
+ | INV 自测 | `inv-selftest.mjs`(`npm run inv-selftest`) | 抽样 INV 做「注入违规 必红」复证(外部契约类全覆盖:INV-68/71/76/79 等) | **14 样本**(v1.13 10 扩;未验证的其余 pin 显性化报告——按需补样) |
204
+ | TS 单测 | vitest | channel / fallback / forest / doctor / launcher / outline-contract / replay-baseline / stealth / lifecycle / cdp-actions | **1961 测试**(122 文件,1960 passed + 1 skipped) |
205
+ | Rust 单测 | cargo test | ax / applescript / cgevent(+keymap) / screenshot / tcc / windows / protocol / role-map | **207 测试** |
160
206
  | 跨平台编译 | cargo check --target | Windows (x86_64-pc-windows-msvc) + Linux (x86_64-unknown-linux-gnu) | CI Linux runner |
161
207
  | 录制回放回归 | npm run replay-baseline | fixtures/serp-baseline/ × 三引擎 × 多 query | 12+ fixtures |
162
208
  | 故障注入 | vitest | fallback 链 / 限流 / 政策 gate / SERP 改版 | ~20 场景 |
163
- | 契约锁 | chrome-devtools-mcp version pin | 上游小版本升级不破 Lasso | package.json |
209
+ | 契约锁 | chrome-devtools-mcp@**1.7.0** version pin(`LOCKED_CDP_MCP_VERSION` 单一真源) | 上游小版本升级不破 Lasso;迁移要点见 §2.1 | SubprocessManager.ts |
164
210
 
165
- ## 8. 不变量(65 条)分类
211
+ ## 8. 不变量(79 条)分类
166
212
 
167
213
  | 范畴 | INV 编号 | 守的是什么 |
168
214
  |---|---|---|
@@ -173,44 +219,56 @@ Lasso 明确**不做**以下事情:
173
219
  | 安全红线 | INV-14 / 25 / 27 / 30 / 31 / 32 | HIGH_RISK_PATTERNS / cloud 双重解锁 / appleScript 白名单 / stealth profiles / SSRF / 连接池 |
174
220
  | 诚实交付 | INV-13 / 19 | expect failed 必须 didnt + 终止 / OutlineNode 同形异源 |
175
221
  | v1.0 release polish | INV-63 / 64 / 65 | version 三处一致 / launcher 不引新 npm dep / README+ARCHITECTURE 必引用 08+09 |
222
+ | v1.1 LLM 友好抽取 | INV-66..69 | raw 默认 byte-identical / extractor 内部件封装 / markdown 引擎禁第三运行期 / 引用角标零 crawl4ai 依赖 |
223
+ | v1.2-v1.4 配置与复用 | INV-70 / 71 / 72 | interactiveOnly opt-in 剪枝 byte-identical / config 文件机制(扁平 JSON + env 覆盖)/ 机器 MCP 复用安全(只读不写、永不 log Authorization) |
224
+ | v1.5-v1.7 反检测与云通道 | INV-73 / 74 / 75 | stealth 16 路一致性 + Headless 接线 / Steel 通道零回归(单独导出 + 双重解锁 + mutex)/ creepjs 门禁纯 doctor 侧零回归 |
225
+ | v1.8 wave 修复守护 | INV-76 | 上游 0.3.0 契约适配与接线回归(截图落盘 / launch 探活 / read_text 续页等) |
226
+ | v1.9 浏览器生命周期 | INV-77 | 台账 + chrome-stop 归属验证 / tab 快照恢复三守卫 / 树杀原语单一真源 |
227
+ | v1.10 静默启动与回收 | INV-78 | hidden 档 flag 集不漂移 / idle reaper 零第二 kill 原语 / 激活路径禁令 |
228
+ | v1.11 1.7.0 迁移守护 | INV-79 | 版本锁 1.7.0 / 遥测关 / --wsEndpoint / launch 级 stealth / 零哑 flag 形态 |
176
229
 
177
230
  完整 INV 列表 + 释义见 `src/invariants/check-invariants.mjs` 顶部注释。
178
231
 
179
232
  ## 9. 数据流(典型场景)
180
233
 
181
- ### 9.1 search(多引擎 fallback
234
+ ### 9.1 search(多引擎 fallback,v1.4/v1.11 后)
182
235
 
183
236
  ```
184
- CC → search("rust async", engine="auto")
237
+ CC → search("rust async 最新动态", freshness="week")
185
238
  → SearchChannel.run()
186
- → FallbackChain: 智谱 Brave → Bing → Wayback → RecordingStore replay
187
- 任一 worked 即止;全 didnt + 有录制 recording_replay_miss 兜底
188
- { outcome: "worked", entries: [...], engine: "zhipu" }
239
+ → FallbackChain: machine_mcp(本机已配智谱 MCP 自动复用,最高优先)
240
+ 智谱 BraveBing
241
+ SERP 实搜兜底(query 语言分流:CJK→百度,非 CJK→DuckDuckGo HTML 端点,零 Key;
242
+ DDG 跳转壳 uddg= 自动解包)
243
+ → Wayback → RecordingStore replay
244
+ → freshness(day/week/month/year)全链透传且入 cache key(不同时效不互相污染)
245
+ → 返 { outcome: "worked", entries: [...], engine: "..." }
189
246
  ```
190
247
 
191
248
  ### 9.2 browse_logged_in(2FA 场景)
192
249
 
193
250
  ```
194
251
  CC → browse_logged_in("https://app.example.com", action="snapshot")
195
- → LoggedInChannel.run() → chrome-devtools-mcp (:9222 CDP)
252
+ → LoggedInChannel.run() → chrome-devtools-mcp@1.7.0 (:9222 CDP)
196
253
  → 站点返 302 to /login/2fa
197
254
  → outcome="didnt" + error="NEEDS_MANUAL_2FA"
198
255
  → 链止(不 fallback;2FA 是红线)
199
256
  → CC 提示用户本机 Chrome 完成 2FA
200
257
  ```
201
258
 
202
- ### 9.3 desktop(macOS ax → screenshotVlm 兜底)
259
+ ### 9.3 desktop(macOS 四档:语义优先、坐标兜底)
203
260
 
204
261
  ```
205
262
  CC → desktop(action="act", actions=[{ref:"@e7", type:"click"}])
206
263
  → DesktopChannel.act()
207
- FallbackPlan: ax appleScript → cgEvent → screenshotVlm
208
- ax.invoke(@e7) → expect 视觉验证
209
- worked链止,返成功
210
- unknown(按钮未响应)→ 下一档 appleScript
211
- ...
212
- → screenshotVlm 兜底(最后一次)
213
- { outcome: "worked"|"didnt", provider: "desktop.ax"|"desktop.cgEvent"|"desktop.vlm" }
264
+ tier-1 ax:AXPress 语义执行 + 写后读回验证
265
+ worked链止,返成功(expect 后置条件连续 2 次命中才确认)
266
+ stale_ref 全败 didnt(UI 已变,引导重新 observe)
267
+ tier-2 appleScript(白名单脚本)
268
+ tier-3 cgEvent:坐标动作 {x,y}(snapshot rect 中心)/ drag 12 点插值轨迹
269
+ tier-4 screenshotVlm:截图推断 → 解析为坐标动作 → cgevent_dispatch 真执行
270
+ 不可解析/执行失败 unknown(vlm_inference_only:*,触发降级或人接管)
271
+ → 返 { outcome, provider: "desktop.ax"|"desktop.appleScript"|"desktop.cgEvent"|"desktop.vlm" }
214
272
  ```
215
273
 
216
274
  ### 9.4 launch-chrome(跨平台子命令)
@@ -221,47 +279,59 @@ $ lasso launch-chrome
221
279
  → macOS: /Applications/Google Chrome.app/...
222
280
  → Linux: /usr/bin/google-chrome
223
281
  → Windows: C:\Program Files\Google\Chrome\...
224
- → spawn chrome --remote-debugging-port=9222 ...
225
- 输出 "Chrome ready at http://127.0.0.1:9222"
282
+ → spawn chrome --remote-debugging-port=9222 ...(hidden 档 + 反节流三件套 + 静音)
283
+ 探活 CDP /json/version 台账登记 → server 运行期最后使用后 ~60s 自动关
226
284
  ```
227
285
 
228
286
  ## 10. 关键路径文件索引
229
287
 
230
- | 模块 | 主文件 | 行数 |
288
+ | 模块 | 主文件 | 行数(v1.13 量级) |
231
289
  |---|---|---|
232
- | Tool 注册 | src/index.ts | ~1000 |
233
- | Tool handler | src/tools/{search,browse,desktop,admin,doctor}.ts | — |
290
+ | Tool 注册 / 生命周期 | src/index.ts(stdin-EOF 收尾 / reaper / Steel 3s 上界) | ~1400 |
291
+ | Tool handler | src/tools/{search,browse,desktop,admin,doctor,network,fetch-url}.ts | — |
234
292
  | Channel 层 | src/channels/{BaseChannel,UiChannel}.ts | — |
235
- | BrowseChannel | src/browse/BrowseChannel.ts | — |
236
- | DesktopChannel | src/desktop/AxProvider.ts | ~250 |
237
- | AxBackend 契约 | src/desktop/AxBackend.ts(含三平台 backend class) | ~250 |
238
- | AxBackendFactory | src/desktop/AxBackendFactory.ts(INV-60 单一真源) | ~110 |
239
- | OutlineMapper | src/desktop/OutlineMapper.ts(三平台共享,INV-61) | ~120 |
293
+ | BrowseChannel | src/browse/BrowseChannel.ts;HeadlessChannel(launch 级 stealth + 宿主对齐 profile);SteelChannel(session mutex + proxyUrl) | — |
294
+ | stealth | src/browse/{StealthEngine,stealth-profiles}.ts(16 路 + 4 profile + 值域 2026-07) | |
295
+ | markdown 抽取 | src/browse/markdown-extractor.ts(defuddle 双激活 + turndown 降级保底) | |
296
+ | desktop 四档 | src/desktop/{AxProvider,AxBackend,AxBackendFactory,OutlineMapper,CGEventProvider,ScreenshotVlmProvider}.ts | AxProvider ~330 |
240
297
  | FallbackDecider | src/fallback/FallbackDecider.ts | ~280 |
241
- | Forest 调度 | src/forest/RootRegistry.ts(INV-24) | — |
242
- | RecordingStore | src/serp/RecordingStore.ts(v0.9;v1.0 不改) | ~260 |
243
- | replay-baseline | src/serp/replay-baseline.ts(v1.0 录制回放回归) | ~280 |
298
+ | 搜索 | src/search/{SearchCache,MultiSourceFanout}.ts;src/channels/{ZhipuChannel,BraveChannel,BingChannel}.ts;src/serp/extract.tsDDG→Brave 级联/百度兜底,v1.14 S-4) | — |
244
299
  | Launcher | src/launcher/{launch-chrome,chrome-paths}.ts(INV-64 不引新 npm dep) | ~200 |
245
- | Doctor | src/doctor/doctor.ts(v1.0 32 项 check) | ~1800 |
246
- | Invariants | src/invariants/check-invariants.mjs(65 条 INV) | ~2700 |
247
- | Rust helper | rust-helper/src/{ax,uia,atspi,applescript,cgevent,screenshot,tcc,windows,main,ax_role_map}.rs | ~3500 |
300
+ | Doctor | src/doctor/doctor.ts(39 项 check;#21 event-synthesis / #36 machine_mcp / #37 steel / #38 creepjs / #39 stagehand / proxy_config) | ~2900 |
301
+ | Invariants | src/invariants/check-invariants.mjs(79 条 INV) | ~4200 |
302
+ | INV 自测 | scripts/inv-selftest.mjs(14 样本红转复证) | ~280 |
303
+ | Subprocess | src/subprocess/SubprocessManager.ts(`LOCKED_CDP_MCP_VERSION = "1.7.0"`) | ~730 |
304
+ | Rust helper | rust-helper/src/{ax,uia,atspi,applescript,cgevent,cgevent_keymap,screenshot,tcc,windows,protocol,main,ax_role_map,app_bundle_map}.rs | ~5000 |
248
305
 
249
306
  ## 11. 版本与发布
250
307
 
251
- - **当前版本**:`1.0.0`(v1.0 稳定发布;2026-07-22
308
+ - **当前版本**:`1.13.0`(v1.13 最优性审查第 3-5 轮收敛;2026-08-17 发布 npm latest
252
309
  - **version 真源**:`package.json` + `src/index.ts:LASSO_SERVER_VERSION` + `src/doctor/doctor.ts:LASSO_VERSION`(INV-63 守:三处必字面量一致)
253
- - **doctor readiness**:32 项 check 全 pass → `ready: true`
254
- - **跨平台 backend**:macOS 本机全证;Win/Linux 编译可证 + 契约可证,真机执行待社区反馈(parse11-acceptance.md 手测清单)
310
+ - **doctor readiness**:39 项 check 全 pass → `ready: true`(检查项随版本增长,以实跑为准)
311
+ - **跨平台 backend**:macOS 本机全证;Win/Linux 编译可证 + 契约可证,真机执行待社区反馈
312
+ - **门禁四链**:`npm run build` / `npm test`(1961)/ `npm run check-invariants`(79)/ `npm run inv-selftest`(14)+ `cargo test`(207)
313
+
314
+ ## 12. 五轮最优性审查(doc/19,v1.10 → v1.13 的质量主线)
315
+
316
+ 2026-08-15 → 08-17 对全仓做了五轮「四域(arch / browser / desktop / search)白盒复审 → 裁决 → 实施 → 独立审查」循环,候选调优项轨迹 **16 → 14 → 7 → 1 → 0 单调收敛**(round5 终裁 ROUND-CLEAN)。四维结论:**技术选型 / 架构 / 范围 / 实施全部最优**(五轮零翻案零漂移)。
317
+
318
+ - **落地量**:38 项调优(round1 16 + round2 14 + round3 7 + round4 1)+ 2 rider + W-3 分桶 + 2 处审查修复,全部经独立审查验收(round1 ROUND-PASS 修 2🔴+4 次要;round2/3/4 zero-issues-pass)
319
+ - **版本轨迹**:v1.10.0(1801 TS / 78 INV)→ v1.11.0(1906 / 79 / 193 Rust,commit `0b07536`)→ v1.12.0(1941 / 79 / 202,工作树)→ v1.13.0(**1961 / 79 / 207 / selftest 14**,commit `a9eb106`,npm latest)
320
+ - **量级修复代表**:chrome-devtools-mcp 0.3.0→1.7.0 迁移、desktop 从「能看」到「能点」(ax_act 真实现 + 坐标鼠标 + VLM 真执行)、stealth launch 级一致性、network 原生化、stdin-EOF 收尾、Steel 3s 上界、假成功族清零(VLM 链尾 / wait 采样 / find 拒纯 ref / VLM region 偏移)
321
+ - **方法学沉淀**(供复用):裁决官不采信文档(关键声称白盒双源亲验,五轮零虚报);证据阶梯 L0-L3(注释不得承载运行时结论);mutation 即验收(删守卫 → 旧实现仍绿 = 缺陷坐实);「先拿事实再加参数」(上游实证失败 ≠ 本侧实测失败);收敛协议前置(round4 写死终止条件防「为找事而立项」)
322
+
323
+ 全记录:[`doc/19-最优性审查轮次/`](./doc/19-最优性审查轮次/00-总结.md)(30 份在档:四域调研 / 裁决 / 实施 / 审查 / 手测清单 / 冒烟脚本)。
255
324
 
256
- ## 12. 相关文档
325
+ ## 13. 相关文档
257
326
 
258
327
  - [README.md](./README.md) — 用户手册(安装 / 配置 / 工具列表 / 隐私 / 故障排查)
259
328
  - [doc/08 功能架构](./../doc/08-media-interact-功能架构.md) — 权威架构基线(F 编号、能力矩阵)
260
- - [doc/09 实施排期](./../doc/09-media-interact-实施排期.md) — v0.1 → v1.0 能力跃升路径与决策记录
329
+ - [doc/09 实施排期](./../doc/09-media-interact-实施排期.md) — v0.1 → v1.13 能力跃升路径与决策记录
330
+ - [doc/19 最优性审查轮次](./doc/19-最优性审查轮次/00-总结.md) — 五轮审查全记录(v1.10 → v1.13 质量主线)
261
331
  - [doc/13 全交互重设计](./../doc/13-全交互抓手重设计.md) — 桌面演进设计
262
332
  - [doc/TROUBLESHOOTING.md](./doc/TROUBLESHOOTING.md) — FAQ + error_kind 释义
263
333
  - [doc/SELECTOR-MAINTENANCE.md](./doc/SELECTOR-MAINTENANCE.md) — selector 债维护手册
264
334
 
265
335
  ---
266
336
 
267
- 本文档是 Lasso v1.0 架构概览(user-first;2026-07-22)。深度架构基线(含 F 编号 / 不变量推导链 / 测试策略)见 [`doc/08`](./../doc/08-media-interact-功能架构.md);v0.1 → v1.0 实施排期(含每 phase 决策记录)见 [`doc/09`](./../doc/09-media-interact-实施排期.md)。
337
+ 本文档是 Lasso v1.13 架构概览(user-first;2026-08-17 同步)。深度架构基线(含 F 编号 / 不变量推导链 / 测试策略)见 [`doc/08`](./../doc/08-media-interact-功能架构.md);v0.1 → v1.13 实施排期(含每 phase 决策记录)见 [`doc/09`](./../doc/09-media-interact-实施排期.md)。