lasso-mcp 1.20.0 → 1.22.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/ARCHITECTURE.md +2 -2
- package/README.en.md +10 -4
- package/README.md +10 -4
- package/dist/browse/upstream-response.d.ts +7 -0
- package/dist/browse/upstream-response.d.ts.map +1 -1
- package/dist/browse/upstream-response.js +11 -1
- package/dist/browse/upstream-response.js.map +1 -1
- package/dist/browse/upstream-wedge.d.ts +36 -0
- package/dist/browse/upstream-wedge.d.ts.map +1 -0
- package/dist/browse/upstream-wedge.js +40 -0
- package/dist/browse/upstream-wedge.js.map +1 -0
- package/dist/channels/BrowseChannel.d.ts +55 -0
- package/dist/channels/BrowseChannel.d.ts.map +1 -1
- package/dist/channels/BrowseChannel.js +288 -29
- package/dist/channels/BrowseChannel.js.map +1 -1
- package/dist/channels/LoggedInChannel.d.ts +20 -0
- package/dist/channels/LoggedInChannel.d.ts.map +1 -1
- package/dist/channels/LoggedInChannel.js +97 -1
- package/dist/channels/LoggedInChannel.js.map +1 -1
- package/dist/doctor/chrome-status.d.ts +129 -0
- package/dist/doctor/chrome-status.d.ts.map +1 -0
- package/dist/doctor/chrome-status.js +467 -0
- package/dist/doctor/chrome-status.js.map +1 -0
- package/dist/doctor/doctor.d.ts +33 -1
- package/dist/doctor/doctor.d.ts.map +1 -1
- package/dist/doctor/doctor.js +102 -12
- package/dist/doctor/doctor.js.map +1 -1
- package/dist/index.js +66 -17
- package/dist/index.js.map +1 -1
- package/dist/launcher/chrome-hide.d.ts +65 -0
- package/dist/launcher/chrome-hide.d.ts.map +1 -1
- package/dist/launcher/chrome-hide.js +121 -0
- package/dist/launcher/chrome-hide.js.map +1 -1
- package/dist/launcher/chrome-hideshow-cli.d.ts +4 -1
- package/dist/launcher/chrome-hideshow-cli.d.ts.map +1 -1
- package/dist/launcher/chrome-hideshow-cli.js +14 -2
- package/dist/launcher/chrome-hideshow-cli.js.map +1 -1
- package/dist/launcher/chrome-idle-reaper.d.ts.map +1 -1
- package/dist/launcher/chrome-idle-reaper.js +6 -0
- package/dist/launcher/chrome-idle-reaper.js.map +1 -1
- package/dist/launcher/chrome-ledger.d.ts +81 -1
- package/dist/launcher/chrome-ledger.d.ts.map +1 -1
- package/dist/launcher/chrome-ledger.js +110 -1
- package/dist/launcher/chrome-ledger.js.map +1 -1
- package/dist/launcher/chrome-stop.d.ts +49 -2
- package/dist/launcher/chrome-stop.d.ts.map +1 -1
- package/dist/launcher/chrome-stop.js +79 -10
- package/dist/launcher/chrome-stop.js.map +1 -1
- package/dist/launcher/desired-hide-enforcer.d.ts +92 -3
- package/dist/launcher/desired-hide-enforcer.d.ts.map +1 -1
- package/dist/launcher/desired-hide-enforcer.js +147 -15
- package/dist/launcher/desired-hide-enforcer.js.map +1 -1
- package/dist/launcher/desired-hide-watchdog.d.ts +16 -9
- package/dist/launcher/desired-hide-watchdog.d.ts.map +1 -1
- package/dist/launcher/desired-hide-watchdog.js +75 -5
- package/dist/launcher/desired-hide-watchdog.js.map +1 -1
- package/dist/launcher/launch-chrome.d.ts +33 -2
- package/dist/launcher/launch-chrome.d.ts.map +1 -1
- package/dist/launcher/launch-chrome.js +179 -12
- package/dist/launcher/launch-chrome.js.map +1 -1
- package/dist/logged-in/TabRegistry.d.ts.map +1 -1
- package/dist/logged-in/TabRegistry.js +19 -0
- package/dist/logged-in/TabRegistry.js.map +1 -1
- package/dist/runtime/runtime-types.d.ts +1 -1
- package/dist/runtime/runtime-types.d.ts.map +1 -1
- package/dist/tools/admin.d.ts +9 -1
- package/dist/tools/admin.d.ts.map +1 -1
- package/dist/tools/admin.js +21 -0
- package/dist/tools/admin.js.map +1 -1
- package/dist/tools/browse.d.ts.map +1 -1
- package/dist/tools/browse.js +4 -0
- package/dist/tools/browse.js.map +1 -1
- package/dist/tools/descriptions.d.ts.map +1 -1
- package/dist/tools/descriptions.js +33 -8
- package/dist/tools/descriptions.js.map +1 -1
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/doc/bugs/03-2026-09-07-hidden/346/241/243/345/212/253/346/214/201/347/224/250/346/210/267Chrome/346/277/200/346/264/273.md +302 -0
- package/doc/bugs/04-2026-09-08-/351/200/211/344/270/255/351/241/265/346/255/273/351/224/201/344/270/216/345/275/222/345/261/236/351/211/264/345/256/232chrome-status.md +229 -0
- package/doc/bugs/04-/351/231/204/345/275/225E-cc-control/347/255/224/345/244/215/344/270/216hook/344/272/244/344/273/230/345/214/205.md +216 -0
- package/doc//345/257/271/346/216/245/345/256/236/346/226/275/350/257/264/346/230/216-/346/270/262/346/237/223/346/241/243x-media-gen-mcp.md +12 -6
- package/doc//347/231/273/350/256/260/351/227/256/351/242/230-timing/345/201/207/347/272/242/344/270/216/351/200/200/345/207/272/345/245/221/347/272/246/344/270/216/351/200/232/347/224/250/345/214/226.md +206 -0
- package/package.json +1 -1
- package/src/browse/upstream-response.ts +11 -1
- package/src/browse/upstream-wedge.ts +43 -0
- package/src/channels/BrowseChannel.ts +291 -37
- package/src/channels/LoggedInChannel.ts +94 -1
- package/src/doctor/chrome-status.ts +607 -0
- package/src/doctor/doctor.ts +115 -12
- package/src/index.ts +66 -17
- package/src/invariants/check-invariants.mjs +548 -9
- package/src/launcher/chrome-hide.ts +168 -0
- package/src/launcher/chrome-hideshow-cli.ts +19 -3
- package/src/launcher/chrome-idle-reaper.ts +5 -0
- package/src/launcher/chrome-ledger.ts +149 -2
- package/src/launcher/chrome-stop.ts +150 -16
- package/src/launcher/desired-hide-enforcer.ts +233 -15
- package/src/launcher/desired-hide-watchdog.ts +90 -10
- package/src/launcher/launch-chrome.ts +220 -13
- package/src/logged-in/TabRegistry.ts +19 -0
- package/src/runtime/runtime-types.ts +6 -1
- package/src/tools/admin.ts +29 -0
- package/src/tools/browse.ts +4 -0
- package/src/tools/descriptions.ts +33 -8
- package/src/types.ts +9 -0
package/ARCHITECTURE.md
CHANGED
|
@@ -148,10 +148,10 @@ outcome = worked | didnt | unknown
|
|
|
148
148
|
### 3.6 生命周期与稳定性(v1.9 → v1.13)
|
|
149
149
|
|
|
150
150
|
- **无头浏览器**:空闲 5 分钟自动回收(`LASSO_HEADLESS_IDLE_MS`,v1.9;touchKeepalive 防误杀)
|
|
151
|
-
- **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;v1.17.1 修复恒 no-op 缺陷,双 targetId 守卫)。**bug02 修复 2(v1.18.6,doc/bugs/02):CLI 显式拉起默认 `idleMs:0`**——用户/工作流手敲命令要的 Chrome 不被后台 server reaper 60s 静默收割(外部 CDP 直连消费者误杀根因);显式配置(env / config.json `LASSO_LAUNCH_IDLE_MS`)与 argv `--idle-ms`
|
|
151
|
+
- **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;v1.17.1 修复恒 no-op 缺陷,双 targetId 守卫)。**bug02 修复 2(v1.18.6,doc/bugs/02):CLI 显式拉起默认 `idleMs:0`**——用户/工作流手敲命令要的 Chrome 不被后台 server reaper 60s 静默收割(外部 CDP 直连消费者误杀根因);显式配置(env / config.json `LASSO_LAUNCH_IDLE_MS`)与 argv `--idle-ms` 仍最高优先。**BUG-03 决议 A1/A2/B2(doc/bugs/03):CLI 默认翻 30min(`CLI_LAUNCH_IDLE_DEFAULT_MS` 单一真源)+ 停机三维谓词(modes × ownerPid × userTakenAt 豁免——任何进程退出只许收自己拉起的 Chrome,消费方「连坐死」根治)+ 端口占用归因(自家挂死 Chrome 收尸重拉 `ledger_zombie_collected`;用户资产永不代杀 `never_kill_user_asset`;🔴 对抗复审 r2-F1:**用户拥有记录**(`userTakenAt` 已认领 / visible 登录窗,`isUserOwnedRecord`)同样永不进程序化收尸——唯一出口 = 用户关闭或用户本人显式 chrome-stop,`user_taken_asset` token 如实拒绝)+ `--mode headless` 可选档(零窗口/零 AX 纯抓取形态;🔴 对抗复审 r1 真机证伪原「不占 Dock 槽位」声明——macOS 激活仍被同 bundle id 吸收,无人值守机器专用)**
|
|
152
152
|
- **hide 粘滞复隐看门狗**(v1.18.3,P27):`chrome-hide` 转后台的窗口被任何来源掀出(含上游页面自己弹的)约 1.5s 内自动压回;`chrome-show` 明示解除;粘滞状态跨重启保留(`desired-hide-state.ts`);`chrome-hide/--pid` 台账缺条目时按进程号直达(只认 lasso 自己的 profile);hide 原语异步化(Chrome 正忙时不拖慢并行操作)
|
|
153
153
|
- **chrome-touch 外部活动信号**(v1.18.6 bug02 闭环,`chrome-touch.ts`):约定文件 `~/.cache/lasso/chrome-touch-<port>` 的 **mtime 即活动信号**——任何第二消费者(外部 CDP 工具 / shell 工作流)一行 `touch` 即续命,不需要 lasso API、不改 reaper 写路径;reaper 每 tick 顺带 stat(`chromeTouchMtimeSync`)。修的是 R-INT-07 活案例:touch 活动源曾唯一(LoggedInChannel browse 回调),外部 CDP 直连消费者对 reaper 完全不可见、台账 Chrome 60s 被误收割
|
|
154
|
-
- **desired-hide-enforcer 独立执守**(v1.18.6 bug02,`desired-hide-enforcer.ts`):粘滞看门狗「只活在 server 进程」而 Chrome 是 detached+unref 的失配(server 崩溃 / 3s race 失败 / 纯 CLI 拉起三种窗口)由**独立执守进程**兜底——chrome-hide 成功 / launch-chrome hidden 记账后 `ensureHideEnforcerRunning()`(pidfile + ps cmdline 标记双复验的 detached 单例);执守体复用 `startDesiredHideWatchdog` 单一调度真源 + 账空 2 tick 自退(不留常驻 node);与 server 内看门狗并发安全(reassert
|
|
154
|
+
- **desired-hide-enforcer 独立执守**(v1.18.6 bug02,`desired-hide-enforcer.ts`):粘滞看门狗「只活在 server 进程」而 Chrome 是 detached+unref 的失配(server 崩溃 / 3s race 失败 / 纯 CLI 拉起三种窗口)由**独立执守进程**兜底——chrome-hide 成功 / launch-chrome hidden 记账后 `ensureHideEnforcerRunning()`(pidfile + ps cmdline 标记双复验的 detached 单例);执守体复用 `startDesiredHideWatchdog` 单一调度真源 + 账空 2 tick 自退(不留常驻 node);与 server 内看门狗并发安全(reassert「可见才压回」幂等)。**BUG-03 A1/B1:执守扩双职责**——粘滞复隐 + 日常档(hidden/headless)idle 收割(`startEnforcerIdleReaper`,server 不在时收割宿主;双职责自退闩——两账都空才 exit);**压回决策接入用户激活让位门**(`reassertChromeHiddenGatedAsync`:hidSystemState 年龄 <10s AND 本 Chrome frontmost 双判据在单次 osascript 内判定且先于压回;判据不可得整体跳过零副作用;看门狗确认窗连续 20 tick 才落台账 `userTakenAt`——认领后执守退位/idle 禁收/停机豁免,唯一清除路径 = 显式 chrome-hide 重武装;chrome-show 同标 userTakenAt)。INV-85/86 守
|
|
155
155
|
- **stdin-EOF 收尾**(v1.12):CC 异常退出 → 父进程死 → stdin EOF → 复用幂等 shutdown;受管子进程不再孤儿到 zombie reaper 1h 阈值(上游 SDK #2002 的进程侧缓解)
|
|
156
156
|
- **停机链全路径有界**(v1.13):Steel 会话释放双层 3s 上界(停机链 race 3s + fetch `AbortSignal.timeout(3s)`)——自托管 Steel 停摆/endpoint 悬挂(实测可挂 ~301s)不再拖死退出
|
|
157
157
|
- **`LASSO_PROXY` 出口代理**(v1.11):headless 经 `--proxy-server`、Steel 经 session `proxyUrl`;**`browse_logged_in` 永不读取**(用户真实 Chrome 出口原样,铁律);doctor `proxy_config` 回显
|
package/README.en.md
CHANGED
|
@@ -206,7 +206,7 @@ Goes to the Internet Archive (Wayback Machine) to find the last archived copy of
|
|
|
206
206
|
|
|
207
207
|
## Install
|
|
208
208
|
|
|
209
|
-
**Current version v1.
|
|
209
|
+
**Current version v1.22.0** (changelog in the collapsed block at the end of this section).
|
|
210
210
|
|
|
211
211
|
Prerequisites: Node.js ≥ 20 + Claude Code (or any MCP-capable client).
|
|
212
212
|
|
|
@@ -223,6 +223,8 @@ Restart Claude Code → `/mcp` → `lasso ✓ Connected`. **That's the one line
|
|
|
223
223
|
<details>
|
|
224
224
|
<summary>📋 Changelog (v1.8 → v1.18.6 — click to see what each version changed)</summary>
|
|
225
225
|
|
|
226
|
+
- **v1.22.0**: ownership-verdict & channel-self-heal batch (BUG-04, consumer-field driven) — ① new subcommand **`chrome-status [--port N]`**: takes "who occupies this port and may I touch it" out of the AI's hands — lasso classifies it directly in ten categories (ledger zombie / stale / suspected user asset …) and outputs a human decision message + machine-readable directives (`allowed_commands` / `must_report` — on a "suspected user asset" verdict the AI is explicitly told it has **zero allowed actions and must report to you**) + a paste-ready report pack; companion `chrome-stop --zombie-gate` is the only machine kill exit (in-ledger + fingerprint match + ledger re-read at kill time — triple gate). Existing commands unchanged. ② fixes the `browse_logged_in` **selected-page wedge** (P1, channel-level): root cause is a structural flaw in the upstream engine — once the selected page closes, every later navigate/evaluate/snapshot fails forever until restart; the wedge signature is now detected and healed by quietly taking over with a background page of our own, with an honest prefix when healing fails. ③ `evaluate` accepts the `(async () => {...})()` form (previously "fn is not a function"); ④ your own bad JS no longer trips the fallback chain (script errors vs channel errors classified); ⑤ doctor port-probe wording made honest ("HTTP 404" → four real outcome shapes). Two clean adversarial rounds: 5/5 mutations killed + live-machine sovereignty checks against a real user Chrome + report-pack weaponization tests. For heavy automation users: a PreToolUse hook sample (hard-blocking AI killing browsers via Bash) is in doc/bugs/04 appendix E.
|
|
227
|
+
- **v1.21.0**: browser-sovereignty & lifecycle root-fix batch (BUG-03, driven by a live-machine incident) — ① 🔴 **behavior change**: `launch-chrome` CLI default idle reaping changes from "never reap" to **auto-reap after 30 minutes** (the old never-reap behavior is restored explicitly with `--idle-ms 0`); ② **user-activation yielding gate**: when you un-hide lasso's hidden Chrome via Dock/Spotlight, lasso recognizes it as a **human at the machine** via a dual predicate (HID idle + frontmost window) — lets it through, then steps aside after a 30-second confirmation window (page-spawned popups are still pressed back; the v1.18.3 silence contract is unchanged); ③ **no collateral kill on shutdown**: fixes a P0 — any lasso server process exiting used to sweep-kill **every hidden Chrome** in the global ledger (violating the `--idle-ms 0` keep-alive promise); collection is now filtered by ownership in three dimensions, so CLI-launched instances survive server exits and are still reaped on idle; ④ **zombie-port self-healing**: when 9222 is occupied by lasso's own hung instance, it is no longer misreported as "a non-CDP process" — the ledger is consulted, the zombie collected, and a fresh instance relaunched; doctor classifies port occupiers three ways (own zombie / stale / user asset) and **never suggests killing a user asset** (forged ledger entries and impersonating pids are also refused; new invariants INV-85/86/87); ⑤ consumer-field fixes (cc-control feedback): `browse` screenshot upstream-contract adaptation (filePath direct-write for large images + Access-denied fallback retry, closing the in-session screenshot gap), `evaluate` always-returning-undefined fixed (dual-form function-expression passthrough), session rotation classified as retryable `session_rotated`; ⑥ optional `launch-chrome --mode headless` tier (for unattended use — honest caveat: headless still shares the Chrome bundle slot). Three adversarial rounds closed: 28/28 mutations killed + 3 CRITICALs fixed and re-verified PASS; tests 2595→2676 / invariants 84→87.
|
|
226
228
|
- **v1.20.0**: render-tier parallel-safety batch (stop/doctor port scoping) — ① 🔴 **behavior change**: `render-chrome --stop` previously ignored `LASSO_RENDER_PORT` and killed **every render tier on the machine** (the #1 entry point for parallel acceptance agents killing each other's instances); now, **an explicitly set `LASSO_RENDER_PORT` stops only that port** (symmetric with `--ensure`/`--status`), unset = collect-all unchanged, an invalid value exits 1 as a usage error. Old scripts that set the port yet expect a full sweep should switch to `chrome-stop --modes render`; the `--stop` output shape is unchanged (idempotent `{"stopped":[...]}`). ② `render-chrome doctor` orphan judgment is scoped the same way with double exemption: an explicit port scans only that port, and other namespaces' in-use instances are no longer misjudged as orphans (out-of-scope port + touch heartbeat within 10 minutes, both exempt — `--clean` no longer kills in-use instances). ③ the **multi-agent parallel acceptance** three-env recipe (`LASSO_RENDER_PORT` + `LASSO_LAUNCHED_CHROMES_PATH` + `LASSO_RENDER_GUARDIAN_PID_PATH`) verified on a live machine: two terminals tearing down concurrently, mutually invisible, zero cross-kills. Consumers like media-gen-mcp only call `--ensure` and are unaffected (verified at source level).
|
|
227
229
|
- **v1.19.0**: deterministic render tier + performance/accuracy batch — ① new `lasso-mcp render-chrome`: a **deterministic rendering browser** for other AI tools (e.g. media-gen-mcp) — one `--ensure` line launches a headless Chrome with a frozen flag snapshot (the browser survives consumer kills; auto-reclaimed after 10 min idle with profile cleanup; see README render section); ② perf: handshake budget on engine cold start (fast-fail instead of 60s hangs, tunable via `LASSO_MCP_HANDSHAKE_TIMEOUT_MS`), first-install npx tax removed, 2FA probe made idempotent, fast-path for truncated large evaluations; ③ accuracy: SERP layout-change detection chain live (selector rot auto-detected with baseline recording). Tool interfaces unchanged (purely additive subcommand and flags).
|
|
228
230
|
- **v1.18.8**: doctor & CLI polish — ① `doctor` no longer reports "unhealthy" due to **ad-hoc signing** (previously a false `ready:false`: ad-hoc is Apple's free legitimate scheme, fully functional — the only cost is re-granting system permissions after rebuilds; a proper Developer ID signature still passes); ② `lasso launch-chrome --help` fixed (previously it actually launched a Chrome; now prints usage); ③ architecture doc fully aligned + 20 legacy cleanups (tests up to 2471 / invariants 84).
|
|
@@ -300,7 +302,7 @@ lasso launch-chrome
|
|
|
300
302
|
The first time, log in to your accounts in that window (handle 2FA yourself) — **the login state is reused from then on**. Afterwards, just say "open my logged-in Jira" to Claude.
|
|
301
303
|
|
|
302
304
|
- Works **silently with zero window** by default — never steals focus, always muted; add `--mode visible` to watch it work
|
|
303
|
-
- CLI-launched Chrome **no
|
|
305
|
+
- CLI-launched Chrome **auto-collects after 30 min of no activity by default** (BUG-03 A1 — "stays alive while in use, auto-collected when idle"; external tools keep it alive with one `touch ~/.cache/lasso/chrome-touch-<port>`; long sessions opt out with `--idle-ms 0`); `lasso chrome-stop` closes it manually at any time
|
|
304
306
|
- Tabs it opens in your Chrome are restored to the original list when you say `admin {action:"tab_restore", reason:"done"}` after a task (the same happens automatically on server exit)
|
|
305
307
|
|
|
306
308
|
> 🔴 **Red line**: 2FA / verification codes / CAPTCHA — Lasso doesn't solve these for you; pass them manually once in the window.
|
|
@@ -310,13 +312,17 @@ The first time, log in to your accounts in that window (handle 2FA yourself) —
|
|
|
310
312
|
|
|
311
313
|
- Since v1.8, a dedicated Lasso profile is used by default (Chrome 136+ forbids opening a debug port on the default profile — the old way would exit instantly); to reuse an existing profile, use `lasso launch-chrome --profile <dir>`.
|
|
312
314
|
- After launch, the debug port is probed automatically; if Chrome didn't come up or the port is taken, it fails loudly instead of faking success.
|
|
313
|
-
- Auto-close threshold: `LASSO_LAUNCH_IDLE_MS` (default 60000; `300000` reverts to 5 minutes; `0` disables). To let a single long task through: `--idle-ms 3600000`. Since
|
|
314
|
-
- **Keep-alive for external CDP consumers** (v1.18.5): when other tools (chrome-devtools-mcp, automation scripts, …) connect straight to this Chrome's debug port, a single `touch ~/.cache/lasso/chrome-touch-<port>` counts as "just used"
|
|
315
|
+
- Auto-close threshold: `LASSO_LAUNCH_IDLE_MS` (default 60000; `300000` reverts to 5 minutes; `0` disables). To let a single long task through: `--idle-ms 3600000`. Since BUG-03 an **explicit CLI launch defaults to `--idle-ms 1800000` (30 min)** — a server exit never guilt-by-associates CLI-launched Chromes (owner filtering), and the enforcer process (alive even without a server) collects on expiry; explicit env / config.json still wins.
|
|
316
|
+
- **Keep-alive for external CDP consumers** (v1.18.5; wording revised in BUG-03): when other tools (chrome-devtools-mcp, automation scripts, …) connect straight to this Chrome's debug port, a single `touch ~/.cache/lasso/chrome-touch-<port>` counts as "just used" (the promise is now **stays alive while in use** — only silent expiry collects); no resident Chrome is needed (hidden-tier cold start reaches a usable CDP in ~1.5 s measured); for a whole working session launch with `--idle-ms 0` (explicit opt-out of auto-collect) or touch periodically.
|
|
315
317
|
- The headless browser auto-recycles after 5 minutes idle (`LASSO_HEADLESS_IDLE_MS` to tune or disable).
|
|
316
318
|
- Honest boundary: running `lasso launch-chrome` standalone (outside the server) has no idle auto-close — the exit is `chrome-stop`; `browse_logged_in` connecting to **your own visible Chrome** is "low-disturbance, not zero-disturbance" (a macOS platform-level limitation — occasional operations may steal focus once) — for pure silence use the hidden tier or `browse_headless`; `desktop` simulates a real human's keyboard and mouse, so it occupies the physical keyboard/mouse by design — there is no silent form.
|
|
317
319
|
- chrome-stop only closes the Chromes Lasso itself launched, with verified ownership — it never touches your manually-opened browsers.
|
|
318
320
|
- `chrome-hide` / `chrome-show` likewise only touch ledger-registered Chromes (pid-targeted, never your manually-opened browsers); hide only hides the window — process / login state / CDP all stay. If the ledger has no entry, target by process id with `--pid N` (see above; anything that isn't Lasso's own profile is refused).
|
|
319
321
|
- Hide is **sticky** (v1.18.3; full lifecycle in v1.18.5): a hidden window un-hidden by any source (an upstream page popping itself, a tab opened by an external tool, a system focus switch) is pressed back into the background within ~1.5 s; use `chrome-show` when you want to look at it (explicit release, no more pressing back). The sticky state survives restarts; since v1.18.5 the hidden tier is **protected from birth** (the launch itself writes the sticky ledger), and a standalone enforcer process backs it — **even when the Claude session / server is gone, an un-hidden Chrome gets pressed back** (the enforcer is a short-lived process that self-exits on an empty ledger — no resident overhead).
|
|
322
|
+
- **When YOU open it by hand, the enforcer yields** (BUG-03 B1): the press-back decision has a user-activation yield gate — a Dock click / your manual activation (detected as this Chrome being frontmost + recent HID input, confirmed over ~30 s) gets claimed: no more pressing back, no idle collection; the only close exits are you closing it or an explicit `chrome-stop`. Programmatic pop-ups still get pressed back as before. Re-arm anytime with `lasso chrome-hide`.
|
|
323
|
+
- **Port taken by your own Chrome? Lasso never touches it** (BUG-03 C): on `port_in_use_non_cdp`, a Lasso-owned dead instance that is **not user-owned** self-heals automatically (`ledger_zombie_collected`); one the user has taken over (`user_taken_asset` claimed / visible login window) is **never auto-cleared** — its only exits are the user closing it or running `chrome-stop` themselves; if the occupier is your manually-opened Chrome or another program, the error says so honestly — "user asset, will not kill, decide yourself or pick another port" — Lasso provides no kill escape hatch for non-ledger assets.
|
|
324
|
+
- **Want to know WHO occupies a port? `lasso chrome-status [--port N] [--json]`** (BUG-04 A, read-only): Lasso does the ownership attribution for you — real listener pid, process name, uptime, cmdline, ledger and CDP probe in one shot, answering in 10 classifications (free / lasso-live / still-starting / ledger zombie / user-claimed / stale ledger / suspected lasso orphan / suspected user asset / external process / insufficient-evidence), plus a **user-facing decision pack** (`user_paste_pack` listing YOUR exits: close it yourself / run `chrome-stop --port N` yourself / have the agent pick another port). For agents it **never outputs any kill command** (the only cleanup directive is the gated `chrome-stop --zombie-gate --port N` variant — re-evaluating your claim state at kill time, zombie branch only); failed/empty probes honestly report "insufficient evidence, report only" — empty output does NOT mean unoccupied. MCP-side equivalent: `admin {action:"chrome_status"}`.
|
|
325
|
+
- For pure scraping without login state on an **unattended** machine, `--mode headless` (BUG-03 B2) gives a zero-window, zero-AX footprint. Real-machine correction (BUG-03 adversarial review): on macOS it does **not** free the Dock slot — while it runs, clicking the Chrome icon produces no visible response (the activation is absorbed by the headless instance, which has no window to show); on machines a human may use, prefer the default hidden mode (its yield gate lets you take the window over). The tradeoffs: no window, `chrome-show` ineffective — use hidden/visible for login flows.
|
|
320
326
|
|
|
321
327
|
</details>
|
|
322
328
|
|
package/README.md
CHANGED
|
@@ -215,7 +215,7 @@ macOS 上能控 Finder / Mail / Safari / Notes / 系统设置等任何原生 app
|
|
|
215
215
|
|
|
216
216
|
## 安装
|
|
217
217
|
|
|
218
|
-
**当前版本 v1.
|
|
218
|
+
**当前版本 v1.22.0**(更新日志见本节末尾折叠块)。
|
|
219
219
|
|
|
220
220
|
前提:Node.js ≥ 20 + Claude Code(或任何支持 MCP 的客户端)。
|
|
221
221
|
|
|
@@ -232,6 +232,8 @@ claude mcp add lasso -- npx -y lasso-mcp
|
|
|
232
232
|
<details>
|
|
233
233
|
<summary>📋 更新日志(v1.8 → v1.18.6,点开看每版改了什么)</summary>
|
|
234
234
|
|
|
235
|
+
- **v1.22.0**:归属鉴定与通道自愈批(BUG-04,消费方实战驱动)——① 新子命令 **`chrome-status [--port N]`**:把「这个端口被谁占着、我能不能动它」的鉴定权从 AI 手里收走——lasso 直接十分类(账本僵尸/陈留/疑似用户资产…),输出人类决策文案 + 机器可读指令(`allowed_commands` / `must_report`——AI 拿到「疑似用户资产」分类时被明确告知**零允许操作、必须上报你**)+ 可直接粘贴的上报包;配套 `chrome-stop --zombie-gate` 唯一机器代杀出口(台账在案+指纹对+kill 时刻重读台账三重门)。旧命令行为零变化。② 修复 `browse_logged_in` **选中页死锁**(P1 通道级):根因是上游引擎的结构性缺陷——选中页一旦被关闭,后续 navigate/evaluate/snapshot 永久报错只能重启;现在自动检测楔死签名并后台自建页接管自愈,修不掉时如实前缀上报。③ `evaluate` 兼容 `(async () => {...})()` 形态(此前报 fn is not a function);④ 调用方自己写错 JS 不再拉响备用通道(脚本错误与通道错误分类);⑤ doctor 端口探测措辞如实化(「HTTP 404」→ 四形态真实归因)。对抗两轮 clean:5 变异全杀 + 真实用户 Chrome 主权实机验证 + 上报包武器化测试不破防。给重度自动化用户的配套:PreToolUse hook 硬拦样例(拦 AI 经 Bash kill 浏览器)见 doc/bugs/04-附录E。
|
|
236
|
+
- **v1.21.0**:浏览器主权与生命周期根治批(BUG-03,真机事故驱动)——① 🔴 **行为变更**:`launch-chrome` CLI 默认空闲回收从「永不回收」改为 **30 分钟自动回收**(旧永不回收行为用 `--idle-ms 0` 显式恢复);② **用户激活让位门**:你点 Dock/Spotlight 掀出 lasso 隐藏的 Chrome 时,lasso 以「HID 空闲 + 前置窗口」双判据识别这是**人在操作**——放行、30 秒确认窗后退位(页面自弹的窗口照常压回,v1.18.3 静默契约零回归);③ **停机不连坐**:修复一个 P0——此前任意 lasso server 进程退出会按全局台账**扫杀全部隐藏 Chrome**(违背 `--idle-ms 0` 保活承诺);现在按归属三维过滤,CLI 拉起的实例在 server 退出后照常存活、照常被回收;④ **僵尸占位自愈**:9222 被自家挂死实例占用时不再误报「非 CDP 进程」,自动按台账归因收尸重拉;doctor 端口占用三分类(自家僵尸/陈留/用户资产),**永不建议代杀用户资产**(台账伪造 + pid 冒名也拒杀,新不变量 INV-85/86/87);⑤ 消费方实战修复(cc-control 反馈):`browse` 截图上游契约适配(大图 filePath 直写 + Access-denied 降级重试,会话内截图通路补齐)、`evaluate` 恒返 undefined 根治(函数表达式双形态透传)、会话轮换归类为可重试的 `session_rotated`;⑥ `launch-chrome --mode headless` 可选档(无人值守专用——诚实声明:headless 也共享 Chrome bundle 槽位)。对抗三轮闭环:28 变异全杀 + 3 个 CRITICAL 当场修复复核 PASS;测试 2595→2676 / 不变量 84→87。
|
|
235
237
|
- **v1.20.0**:渲染档并行安全批(stop/doctor 端口作用域化)——① 🔴 **行为变更**:`render-chrome --stop` 此前无视 `LASSO_RENDER_PORT`、会收掉**全机**渲染档(同机多 agent 并行验收时互杀对方实例的第一入口);现在**显式设了 `LASSO_RENDER_PORT` 只收该 port**(与 `--ensure`/`--status` 对称),未设=维持全收不变,非法值 exit 1 报用法错。设了 port 却想全收的旧脚本请改用 `chrome-stop --modes render`;`--stop` 输出形状不变(幂等 `{"stopped":[...]}`)。② `render-chrome doctor` 孤儿判定同样作用域化 + 双豁免:显式 port 只判该 port,他人命名空间实例不再被误判孤儿(范围外 port + touch 心跳 10 分钟内新鲜双重豁免,`--clean` 不再误杀在用实例)。③ 配套**同机多 agent 并行验收**三 env 隔离配方(`LASSO_RENDER_PORT` + `LASSO_LAUNCHED_CHROMES_PATH` + `LASSO_RENDER_GUARDIAN_PID_PATH`)真机验证:双终端并发各自清场,并行互不可见零互杀。media-gen-mcp 等消费方只调 `--ensure` 不受影响(已源码级实证)。
|
|
236
238
|
- **v1.19.0**:确定性渲染档 + 性能/准确率批——① 新增 `lasso-mcp render-chrome`:给其它 AI 工具(如 media-gen-mcp)当**确定性渲染浏览器**——`--ensure` 一行拉起带冻结旗标快照的 headless Chrome(消费方进程被强杀浏览器照常存活,空闲 10 分钟自动回收并清理 profile),详见 README 渲染档节;② 性能:浏览器引擎冷启动握手加预算(卡死快速失败不再挂 60 秒,`LASSO_MCP_HANDSHAKE_TIMEOUT_MS` 可调)、首装 npx 下载税消除、2FA 探测幂等化、大求值截断快路;③ 准确率:搜索页改版检测链上线(选择器失效自动发现并记录基线)。工具接口零变化(纯新增子命令与旗标)。
|
|
237
239
|
- **v1.18.8**:doctor 与 CLI 打磨——① `doctor` 不再因 **ad-hoc 签名**报「不健康」(此前 `ready:false` 误报:ad-hoc 是官方免费合法方案,功能正常,唯一代价是重编译后需重新系统授权;Developer ID 正签仍 pass)② `lasso launch-chrome --help` 修复(此前会误启动一个 Chrome,现在正确打印用法说明)③ 架构文档全量对齐 + 20 项历史遗留清理(测试增至 2471 / 不变量 84)。
|
|
@@ -320,7 +322,7 @@ lasso launch-chrome
|
|
|
320
322
|
以后对 Claude 说「打开我已登录的 Jira」就行。想再看窗口随时 `lasso chrome-show`(可逆,登录态不动)。
|
|
321
323
|
|
|
322
324
|
- 默认**零窗口静默**干活、不抢焦点、永远静音;想看着它干加 `--mode visible`
|
|
323
|
-
- 命令行拉起的 Chrome
|
|
325
|
+
- 命令行拉起的 Chrome **默认 30 分钟无活动自动收**(BUG-03 A1——「有活动就活,无消费者到期自动收」;外部工具 `touch ~/.cache/lasso/chrome-touch-<端口>` 一行续命;长会话显式 `--idle-ms 0` 永不自动收),手动关随时 `lasso chrome-stop`
|
|
324
326
|
- 它在你 Chrome 里开的 tab,任务后说 `admin {action:"tab_restore", reason:"完成"}` 恢复原列表(server 退出也会自动做)
|
|
325
327
|
|
|
326
328
|
> 🔴 **红线**:2FA / 验证码 / CAPTCHA——Lasso 不替你解,你在窗口里手动过一次。
|
|
@@ -330,14 +332,18 @@ lasso launch-chrome
|
|
|
330
332
|
|
|
331
333
|
- v1.8 起默认用 Lasso 独立 profile(Chrome 136+ 禁止对默认 profile 开调试端口,老办法会秒退);复用已有 profile 用 `lasso launch-chrome --profile <目录>`。
|
|
332
334
|
- 启动后自动探活调试端口,Chrome 没起来 / 端口被占会明确报错,不假报成功。
|
|
333
|
-
- 自动关阈值:`LASSO_LAUNCH_IDLE_MS`(默认 60000;`300000` 回退 5 分钟;`0` 禁用)。单次长任务放行:`--idle-ms 3600000`。
|
|
334
|
-
- **外部 CDP 消费者续命**(v1.18.5
|
|
335
|
+
- 自动关阈值:`LASSO_LAUNCH_IDLE_MS`(默认 60000;`300000` 回退 5 分钟;`0` 禁用)。单次长任务放行:`--idle-ms 3600000`。BUG-03 轮起**命令行显式拉起默认 `--idle-ms 1800000`(30 分钟)**——server 退出不再连坐任何 CLI 拉起的 Chrome(归属过滤),执守进程(server 不在也活着)负责到期收割;显式配置 env / config.json 仍最高优先。
|
|
336
|
+
- **外部 CDP 消费者续命**(v1.18.5,BUG-03 口径修订):其他工具(chrome-devtools-mcp、自动化脚本等)直连这条 Chrome 的调试端口时,一行 `touch ~/.cache/lasso/chrome-touch-<端口>` 即视为「刚用过」(承诺口径 = **在用就一直活**,无信号才到期收);不需要常驻(hidden 档冷启动实测 1.5s 内 CDP 可用),一整段会话要用就拉起时配 `--idle-ms 0`(显式退出自动收)或定期 touch。
|
|
335
337
|
- 登录后自动收窗:`LASSO_AUTO_HIDE_AFTER_LOGIN`(默认 false;开启后只在「见过登录页 → 登录页消失 → 等 10 秒 → Claude 没在用」四关全过时才收,收错方向保守——拿不准就不收)。等待时长 `LASSO_AUTO_HIDE_AFTER_LOGIN_DELAY_MS`(默认 10000)。只在 server 会话运行期间生效(CLI 单独 `launch-chrome` 没有调度器,仍走手动 `chrome-hide`)。
|
|
336
338
|
- 无头浏览器空闲 5 分钟自动回收(`LASSO_HEADLESS_IDLE_MS` 可调/禁用)。
|
|
337
339
|
- 诚实边界:单独跑 `lasso launch-chrome`(不经 server)没有 idle 自动关,出口是 `chrome-stop`;它起的 Chrome 在 Dock / 任务栏会多一个图标(浏览器有头进程的注册行为,lasso 控制不了),要零图标用 `browse_headless`;`browse_logged_in` 连**你自己开的可见 Chrome** 时会在你的 Chrome 里临时开一个后台 tab 干活(不抢焦点不发声,结束自动关,v1.17.2 起你的 tab 一律不被改写)——但你的 Chrome 本身不静音(lasso 不改写你的浏览器参数),浏览到自动播放页面会真出声;`desktop` 模拟真人键鼠,设计上就占用物理键鼠,没有静默形态。
|
|
338
340
|
- chrome-stop 只关 Lasso 自己起的、验证过归属的 Chrome,不会误伤你手动开的浏览器。
|
|
339
341
|
- `chrome-hide` / `chrome-show` 同样只动台账在案的 Chrome(按 pid 定向,永不碰你手动开的浏览器);hide 只隐藏窗口,进程/登录态/CDP 全保留。台账缺条目时按 `--pid N` 直达(见上文;归属不满足会明确拒绝)。
|
|
340
342
|
- hide 是**粘滞**的(v1.18.3,v1.18.5 补全生命周期):已 hide 的窗口无论被什么来源掀出(上游页面自己弹的、外部工具开的 tab、系统焦点切换),约 1.5 秒内自动压回后台;想看窗口用 `chrome-show`(明示解除,不再压回)。粘滞状态跨重启保留;v1.18.5 起 hidden 档**出生即受保护**(拉起落账即写粘滞),且由独立执守进程兜底——**即使 Claude 会话/server 不在,隐藏的 Chrome 被掀出也会被压回**(执守是账空自退的短命进程,不留常驻开销)。
|
|
343
|
+
- **你亲手点开它时,执守会让位**(BUG-03 B1):压回决策带「用户激活让位门」——Dock 点击 / 你手动点开的激活(判定 = 本 Chrome 处于前台 + 键鼠刚有输入,连续约 30 秒确认)会被认领:不再压回、不再自动收,关它只剩你自己关或显式 `chrome-stop`。程序掀出(页面自己弹的)照常压回。误认领可用 `lasso chrome-hide` 重新武装。
|
|
344
|
+
- **端口被你自己的 Chrome 占了?lasso 永不动它**(BUG-03 C):报 `port_in_use_non_cdp` 时,自家挂死且**未被用户使用**的实例会自动清掉重拉(`ledger_zombie_collected`);已被用户拿去用的实例(已认领 `user_taken_asset` / visible 登录窗)**绝不自动清理**——唯一出口是你自己关掉或你本人跑 `chrome-stop`;是你手开的 Chrome / 其他程序占用则明确说「用户资产,不会 kill,请自行裁决或换口」——lasso 不提供任何针对非自家资产的 kill 出口。
|
|
345
|
+
- **端口被占了想知道是谁?`lasso chrome-status [--port N] [--json]`**(BUG-04 A,只读):lasso 直接替你做「归属鉴定」——真实监听 pid / 进程名 / 已运行时长 / 命令行 / 台账 / CDP 探测一次查清,分 10 类作答(空闲 / lasso 在用 / 慢启动中 / 台账僵尸 / 用户已认领 / 台账陈留 / 疑似 lasso 无主实例 / 疑似用户资产 / 外部进程 / 证据不足),并给出**给你看的裁决包**(`user_paste_pack`,含你能走的出口:自己关 / 本人跑 `chrome-stop --port N` / 让 Claude 换口)。对 Claude/agent 侧它**永不输出任何 kill 命令**(唯一的清账指引是 `chrome-stop --zombie-gate --port N` 门槛变体——kill 时刻重估你的认领状态,且仅限 lasso 自家僵尸分支);探针失败/空输出一律如实报「证据不足、只上报」——空输出≠没占用。MCP 侧等价入口:`admin {action:"chrome_status"}`。
|
|
346
|
+
- 纯抓取不需要登录态时可用 `--mode headless`(BUG-03 B2):无头实例零窗口/零打扰,适合**无人值守**机器的纯抓取。🔴 真机复核订正(BUG-03 对抗复审):macOS 上它**并不**让出 Dock 槽位——它活着时你点 Chrome 图标不会有任何反应(激活被无头实例吸收、没有窗口可显示);有人会用的机器请用默认 hidden(有让位门,你点开它会让位)。代价:没有窗口、`chrome-show` 无效,登录流用 hidden/visible。
|
|
341
347
|
|
|
342
348
|
</details>
|
|
343
349
|
|
|
@@ -28,6 +28,13 @@ export declare function firstText(r: UpstreamContentResult | undefined): string
|
|
|
28
28
|
/**
|
|
29
29
|
* 提取 evaluate_script 响应里 ``` 围栏内的文本(去掉 ```json 语言标)。
|
|
30
30
|
* 无围栏(上游形状漂移)返回 undefined。
|
|
31
|
+
*
|
|
32
|
+
* E④(BUG-03 决议 E④,doc/bugs/03 §4 E):贪婪围栏——非贪婪 `[\s\S]*?` 会在
|
|
33
|
+
* **返回值内部含 ``` 的字符串**(如页面源码片段)处提前截断(实测形态:脚本
|
|
34
|
+
* 返回含三反引号的文本 → 围栏在值内部提前闭合 → parseEvalResult 拿到半截)。
|
|
35
|
+
* 上游契约是单围栏形态("# evaluate_script response\n...\n```json\n<值>\n```"),
|
|
36
|
+
* 惰性组 + 负向前瞻 `(?![\s\S]*```)` 把闭合锚定到**最后一个**围栏——值内部的
|
|
37
|
+
* ``` 不再截断,且不把闭合围栏前的换行并入值尾。
|
|
31
38
|
*/
|
|
32
39
|
export declare function evalFence(r: UpstreamContentResult | undefined): string | undefined;
|
|
33
40
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upstream-response.d.ts","sourceRoot":"","sources":["../../src/browse/upstream-response.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,MAAM,SAAS,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AACxD,MAAM,MAAM,UAAU,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAC7E,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,GAAG,UAAU,CAAC,CAAC;IACxC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,0DAA0D;AAC1D,wBAAgB,SAAS,CACvB,CAAC,EAAE,qBAAqB,GAAG,SAAS,GACnC,MAAM,GAAG,SAAS,CAMpB;AAED
|
|
1
|
+
{"version":3,"file":"upstream-response.d.ts","sourceRoot":"","sources":["../../src/browse/upstream-response.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,MAAM,SAAS,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AACxD,MAAM,MAAM,UAAU,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAC7E,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,GAAG,UAAU,CAAC,CAAC;IACxC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,0DAA0D;AAC1D,wBAAgB,SAAS,CACvB,CAAC,EAAE,qBAAqB,GAAG,SAAS,GACnC,MAAM,GAAG,SAAS,CAMpB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CACvB,CAAC,EAAE,qBAAqB,GAAG,SAAS,GACnC,MAAM,GAAG,SAAS,CAQpB;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,CAAC,EAAE,qBAAqB,GAAG,SAAS,GACnC,OAAO,CAgBT;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,CAAC,EAAE,qBAAqB,GAAG,SAAS,GACnC,MAAM,GAAG,SAAS,CAKpB;AAED,kEAAkE;AAClE,wBAAgB,UAAU,CACxB,CAAC,EAAE,qBAAqB,GAAG,SAAS,GACnC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAQhD"}
|
|
@@ -23,12 +23,22 @@ export function firstText(r) {
|
|
|
23
23
|
/**
|
|
24
24
|
* 提取 evaluate_script 响应里 ``` 围栏内的文本(去掉 ```json 语言标)。
|
|
25
25
|
* 无围栏(上游形状漂移)返回 undefined。
|
|
26
|
+
*
|
|
27
|
+
* E④(BUG-03 决议 E④,doc/bugs/03 §4 E):贪婪围栏——非贪婪 `[\s\S]*?` 会在
|
|
28
|
+
* **返回值内部含 ``` 的字符串**(如页面源码片段)处提前截断(实测形态:脚本
|
|
29
|
+
* 返回含三反引号的文本 → 围栏在值内部提前闭合 → parseEvalResult 拿到半截)。
|
|
30
|
+
* 上游契约是单围栏形态("# evaluate_script response\n...\n```json\n<值>\n```"),
|
|
31
|
+
* 惰性组 + 负向前瞻 `(?![\s\S]*```)` 把闭合锚定到**最后一个**围栏——值内部的
|
|
32
|
+
* ``` 不再截断,且不把闭合围栏前的换行并入值尾。
|
|
26
33
|
*/
|
|
27
34
|
export function evalFence(r) {
|
|
28
35
|
const text = firstText(r);
|
|
29
36
|
if (!text)
|
|
30
37
|
return undefined;
|
|
31
|
-
|
|
38
|
+
// 贪婪语义经「惰性组 + 负向前瞻锚定最后一个围栏」实现:惰性组照常最短匹配,
|
|
39
|
+
// 但闭合围栏后不允许再出现 ``` ——若值内部还有 ```,引擎回溯到真正的闭合围栏。
|
|
40
|
+
// (纯贪婪 `[\s\S]*` 也能匹配到最后围栏,但会把闭合围栏前的换行并入值尾。)
|
|
41
|
+
const m = text.match(/```(?:json)?\s*\n([\s\S]*?)\n?```(?![\s\S]*```)/);
|
|
32
42
|
return m?.[1];
|
|
33
43
|
}
|
|
34
44
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upstream-response.js","sourceRoot":"","sources":["../../src/browse/upstream-response.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AASH,0DAA0D;AAC1D,MAAM,UAAU,SAAS,CACvB,CAAoC;IAEpC,IAAI,CAAC,CAAC,EAAE,OAAO;QAAE,OAAO,SAAS,CAAC;IAClC,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;QAC1B,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,IAAI;YAAE,OAAO,CAAC,CAAC,IAAI,CAAC;IACjD,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"upstream-response.js","sourceRoot":"","sources":["../../src/browse/upstream-response.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AASH,0DAA0D;AAC1D,MAAM,UAAU,SAAS,CACvB,CAAoC;IAEpC,IAAI,CAAC,CAAC,EAAE,OAAO;QAAE,OAAO,SAAS,CAAC;IAClC,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;QAC1B,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,IAAI;YAAE,OAAO,CAAC,CAAC,IAAI,CAAC;IACjD,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,SAAS,CACvB,CAAoC;IAEpC,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;IAC1B,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC;IAC5B,yCAAyC;IACzC,8CAA8C;IAC9C,6CAA6C;IAC7C,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACxE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAChB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAC7B,CAAoC;IAEpC,MAAM,KAAK,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;IAC3B,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO,SAAS,CAAC;IACpC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC/B,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC7B,IAAI,CAAC;gBACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC1B,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,IAAI,CAAC,CAAC,gCAAgC;YAC/C,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAC3B,CAAoC;IAEpC,MAAM,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;IAC7B,IAAI,CAAC,IAAI,IAAI;QAAE,OAAO,SAAS,CAAC;IAChC,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,CAAC,CAAC;IACpC,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;AACnB,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,UAAU,CACxB,CAAoC;IAEpC,IAAI,CAAC,CAAC,EAAE,OAAO;QAAE,OAAO,SAAS,CAAC;IAClC,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;QAC1B,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;YACjC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,WAAW,EAAE,CAAC;QAC/D,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* upstream-wedge.ts(BUG-04 决议 B,doc/bugs/04 §5,2026-09-08)
|
|
3
|
+
*
|
|
4
|
+
* 上游 chrome-devtools-mcp@1.7.0「选中页死锁」签名单一真源。
|
|
5
|
+
*
|
|
6
|
+
* 根因(npm tarball 逐行复核,doc/bugs/04 §2):上游 ToolHandler.js 的
|
|
7
|
+
* `const targetPage = page ?? context.getSelectedMcpPage()`(:189)无条件执行——
|
|
8
|
+
* 选中页被关(用户手关 / 页面 window.close / 会话收尾关自建 tab)后,**任何**
|
|
9
|
+
* 工具调用(含 list_pages 自身)都在此处 throw 落入外层 catch,绕过唯一自愈点
|
|
10
|
+
* `createPagesSnapshot()`——通道级死锁,MCP 进程重启才解。
|
|
11
|
+
*
|
|
12
|
+
* 本模块只放签名常量 + 判定函数(零依赖叶子,BrowseChannel / TabRegistry /
|
|
13
|
+
* LoggedInChannel 三方共用——签名定义不允许第二处漂移)。
|
|
14
|
+
*
|
|
15
|
+
* INV-89 机械锚。
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* 上游 McpContext.getSelectedMcpPage() 的整串错误子串(build/src/McpContext.js:253):
|
|
19
|
+
* `The selected page has been closed. Call list_pages to see open pages.`
|
|
20
|
+
*
|
|
21
|
+
* 窄匹配(只用前半句)防误伤:页面正文/标题正常场景不会以这个精确短语出现;
|
|
22
|
+
* 若未来页面内容真含此串,被动检测面(错误文本)不受影响——只有主动
|
|
23
|
+
* reconcile 面(list_pages 全响应)可能命中,而该响应在健康通道上恒为页列表。
|
|
24
|
+
*/
|
|
25
|
+
export declare const UPSTREAM_WEDGE_SIGNATURE: RegExp;
|
|
26
|
+
/** 判定错误/响应文本是否上游选中页死锁签名。 */
|
|
27
|
+
export declare function isUpstreamWedgeError(text: string): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* reconcile 类型化信号前缀(doc/bugs/04 §5 主动接入点):
|
|
30
|
+
* `TabRegistry.reconcile` 命中签名 → throw `upstream_wedge:<原文摘录>`;
|
|
31
|
+
* LoggedInChannel.getMcpClient 捕获该前缀 → 返回 client 前触发 heal。
|
|
32
|
+
*/
|
|
33
|
+
export declare const UPSTREAM_WEDGE_SIGNAL_PREFIX = "upstream_wedge:";
|
|
34
|
+
/** 判定是否 reconcile 抛出的类型化楔死信号(区别于普通 reconcile 失败)。 */
|
|
35
|
+
export declare function isUpstreamWedgeTypedSignal(msg: string): boolean;
|
|
36
|
+
//# sourceMappingURL=upstream-wedge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upstream-wedge.d.ts","sourceRoot":"","sources":["../../src/browse/upstream-wedge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,QAAsC,CAAC;AAE5E,4BAA4B;AAC5B,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,oBAAoB,CAAC;AAE9D,qDAAqD;AACrD,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE/D"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* upstream-wedge.ts(BUG-04 决议 B,doc/bugs/04 §5,2026-09-08)
|
|
3
|
+
*
|
|
4
|
+
* 上游 chrome-devtools-mcp@1.7.0「选中页死锁」签名单一真源。
|
|
5
|
+
*
|
|
6
|
+
* 根因(npm tarball 逐行复核,doc/bugs/04 §2):上游 ToolHandler.js 的
|
|
7
|
+
* `const targetPage = page ?? context.getSelectedMcpPage()`(:189)无条件执行——
|
|
8
|
+
* 选中页被关(用户手关 / 页面 window.close / 会话收尾关自建 tab)后,**任何**
|
|
9
|
+
* 工具调用(含 list_pages 自身)都在此处 throw 落入外层 catch,绕过唯一自愈点
|
|
10
|
+
* `createPagesSnapshot()`——通道级死锁,MCP 进程重启才解。
|
|
11
|
+
*
|
|
12
|
+
* 本模块只放签名常量 + 判定函数(零依赖叶子,BrowseChannel / TabRegistry /
|
|
13
|
+
* LoggedInChannel 三方共用——签名定义不允许第二处漂移)。
|
|
14
|
+
*
|
|
15
|
+
* INV-89 机械锚。
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* 上游 McpContext.getSelectedMcpPage() 的整串错误子串(build/src/McpContext.js:253):
|
|
19
|
+
* `The selected page has been closed. Call list_pages to see open pages.`
|
|
20
|
+
*
|
|
21
|
+
* 窄匹配(只用前半句)防误伤:页面正文/标题正常场景不会以这个精确短语出现;
|
|
22
|
+
* 若未来页面内容真含此串,被动检测面(错误文本)不受影响——只有主动
|
|
23
|
+
* reconcile 面(list_pages 全响应)可能命中,而该响应在健康通道上恒为页列表。
|
|
24
|
+
*/
|
|
25
|
+
export const UPSTREAM_WEDGE_SIGNATURE = /The selected page has been closed/;
|
|
26
|
+
/** 判定错误/响应文本是否上游选中页死锁签名。 */
|
|
27
|
+
export function isUpstreamWedgeError(text) {
|
|
28
|
+
return UPSTREAM_WEDGE_SIGNATURE.test(text);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* reconcile 类型化信号前缀(doc/bugs/04 §5 主动接入点):
|
|
32
|
+
* `TabRegistry.reconcile` 命中签名 → throw `upstream_wedge:<原文摘录>`;
|
|
33
|
+
* LoggedInChannel.getMcpClient 捕获该前缀 → 返回 client 前触发 heal。
|
|
34
|
+
*/
|
|
35
|
+
export const UPSTREAM_WEDGE_SIGNAL_PREFIX = "upstream_wedge:";
|
|
36
|
+
/** 判定是否 reconcile 抛出的类型化楔死信号(区别于普通 reconcile 失败)。 */
|
|
37
|
+
export function isUpstreamWedgeTypedSignal(msg) {
|
|
38
|
+
return msg.startsWith(UPSTREAM_WEDGE_SIGNAL_PREFIX);
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=upstream-wedge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upstream-wedge.js","sourceRoot":"","sources":["../../src/browse/upstream-wedge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,mCAAmC,CAAC;AAE5E,4BAA4B;AAC5B,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,OAAO,wBAAwB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC7C,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,iBAAiB,CAAC;AAE9D,qDAAqD;AACrD,MAAM,UAAU,0BAA0B,CAAC,GAAW;IACpD,OAAO,GAAG,CAAC,UAAU,CAAC,4BAA4B,CAAC,CAAC;AACtD,CAAC"}
|
|
@@ -115,6 +115,20 @@ export declare abstract class BrowseChannel extends UiChannel {
|
|
|
115
115
|
* 成功返 true → browseSingle 原样重试一次该 action。
|
|
116
116
|
*/
|
|
117
117
|
protected recoverNoPageSelected(_c: McpClient): Promise<boolean>;
|
|
118
|
+
/**
|
|
119
|
+
* BUG-04 决议 B(doc/bugs/04 §5):上游选中页死锁("The selected page has
|
|
120
|
+
* been closed"——上游 ToolHandler.js:189 结构性死锁,通道级)自愈钩子。
|
|
121
|
+
* 默认 null(HeadlessChannel 同样可能楔死但通过 spec 自管 respawn 兜底,
|
|
122
|
+
* 行为零变化);LoggedInChannel override 两层:
|
|
123
|
+
* 层 1 `new_page {background:true}`——上游 pages.js handler 内
|
|
124
|
+
* `context.newPage → selectPage`(McpContext.js:212)先于 :189 执行,
|
|
125
|
+
* 结构性逃逸口;成功返回**原 client**(选中页已重置)。
|
|
126
|
+
* 层 2 respawn upstream spec(SubprocessManager.restart——只杀 npx 上游
|
|
127
|
+
* 子进程,**永不触碰 Chrome**);成功返回**新 client**。
|
|
128
|
+
* 返 null = 自愈失败 → 调用方走 `upstream_wedge_selected_page_closed`
|
|
129
|
+
* 透明错误(unknown:通道错,fallback 语义正确)。
|
|
130
|
+
*/
|
|
131
|
+
protected healUpstreamWedge(_c: McpClient): Promise<McpClient | null>;
|
|
118
132
|
/**
|
|
119
133
|
* P10(v1.18.1):上游工具缺失探测(带 per-client 缓存——同一上游子进程
|
|
120
134
|
* 生命周期内工具集不变;listTools 抛错 → false 放行,让真实调用浮出错误)。
|
|
@@ -187,6 +201,47 @@ export declare abstract class BrowseChannel extends UiChannel {
|
|
|
187
201
|
*/
|
|
188
202
|
private persistState;
|
|
189
203
|
}
|
|
204
|
+
/**
|
|
205
|
+
* E④(BUG-03 决议 E④)+ BUG-04 决议 C1(doc/bugs/04 §7):evaluate 的 js 入参 →
|
|
206
|
+
* 上游 function 参数归一(导出供测试)。
|
|
207
|
+
*
|
|
208
|
+
* 三形态兼容:
|
|
209
|
+
* - **函数表达式**(起手 `(` / `function` / `async`,或单标识符箭头 `x => x`)
|
|
210
|
+
* → 原样透传——上游 evaluate_script 契约本就吃函数表达式并自调用;旧 wrapper
|
|
211
|
+
* 会把它包成「函数体内的函数表达式语句」(求值不 return → 恒 undefined 静默
|
|
212
|
+
* 错值——消费方④实战毒点)。
|
|
213
|
+
* - **IIFE 立即执行式**(`(async () => {...})()` / `(() => {...})()` /
|
|
214
|
+
* `(function () { ... })()`)→ 包成表达式体箭头 `() => (\n${t}\n)`——上游
|
|
215
|
+
* performEvaluation(script.js:158-165)= `evaluateHandle('(' + fnString + ')')`
|
|
216
|
+
* 后 `fn(...args)`:IIFE 串求值成**结果**而非函数 → `fn is not a function`
|
|
217
|
+
* (报告 §9-②a)。包裹成 `() => (iife)` 后外层箭头求值即得 IIFE 结果
|
|
218
|
+
* (Promise 由上游 await fn() 解开,语义不变)。
|
|
219
|
+
* - **语句体**(`return ...` / 声明 / 多语句 / 裸表达式)→ 维持包裹
|
|
220
|
+
* `() => { ... }`(W1-DEF-1b:直接透传 `return` 会被当函数表达式语法错,
|
|
221
|
+
* wave2 smoke 实证 "Unexpected token 'return'")。
|
|
222
|
+
*
|
|
223
|
+
* IIFE 判定(C1 结构化规则,防误伤尾调用箭头):起手函数表达式 token + 剥尾 `;`
|
|
224
|
+
* 后以 `()` 收尾 + 其前一字符属于平衡的 `)`/`}` 组。反例锚:
|
|
225
|
+
* - `() => document.getElementById('x').click()`(箭头尾调用)——末尾 `()` 前是
|
|
226
|
+
* 标识符 → 透传(上游直接自调用该箭头,语义正确);
|
|
227
|
+
* - `() => (foo)(x)` —— 尾参非空括号组(`(x)` 而非 `()`)→ 维持透传
|
|
228
|
+
* (文档化取向:静默变更风险大于响亮报错——若真是 IIFE 形态,调用方改写
|
|
229
|
+
* 起手 `(` 形态即可)。
|
|
230
|
+
* 判定规则刻意保守:误判方向 = 语句体被透传(上游报语法错,响亮可修),优于
|
|
231
|
+
* 函数表达式被包裹(静默 undefined,毒中之毒)。IIFE 误包裹方向同样安全——
|
|
232
|
+
* 表达式位置包 `() => (expr)` 求值不变。
|
|
233
|
+
*/
|
|
234
|
+
export declare function evaluateFunctionArg(js: string): string;
|
|
235
|
+
/**
|
|
236
|
+
* BUG-04 决议 C1:IIFE 立即执行式结构化判定(导出供测试)。
|
|
237
|
+
*
|
|
238
|
+
* 规则(三条全中才判 IIFE):
|
|
239
|
+
* 1. 剥尾 `;`(含尾随空白)后以空参调用 `()` 收尾;
|
|
240
|
+
* 2. 其前一字符是 `)` 或 `}`(闭合的函数体/括号组——排除 `fn()` / `.click()`
|
|
241
|
+
* 等标识符尾调用);
|
|
242
|
+
* 3. 全串括号/花括号平衡(排除截断/畸形输入——畸形按响亮上游错误处理)。
|
|
243
|
+
*/
|
|
244
|
+
export declare function isIifeString(t: string): boolean;
|
|
190
245
|
/**
|
|
191
246
|
* v1.17(doc/governance/06 verify ⑤,真机实证):refs 附录感知截断——长页正文超
|
|
192
247
|
* PREVIEW_MAX_CHARS 时朴素 truncatePreview 会把**缀在末尾**的
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BrowseChannel.d.ts","sourceRoot":"","sources":["../../src/channels/BrowseChannel.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"BrowseChannel.d.ts","sourceRoot":"","sources":["../../src/channels/BrowseChannel.ts"],"names":[],"mappings":"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"}
|