Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion scripts/cdp-proxy.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,14 @@ const server = http.createServer(async (req, res) => {
// 等待页面加载完成
await waitForLoad(sid);

res.end(JSON.stringify(resp.result));
// 显式透出导航错误:浏览器重启导致僵尸会话时 Page.navigate 会返回 {error}(无 result),
// 直接 JSON.stringify(resp.result) 会写出空 body,调用方无从判断。这里把错误透出来。
if (resp.error) {
res.statusCode = 502;
res.end(JSON.stringify({ error: 'Page.navigate failed', cdp: resp.error }));
return;
}
res.end(JSON.stringify(resp.result ?? { error: 'empty navigation result' }));
}

// GET /back?target=xxx - 后退
Expand Down
37 changes: 32 additions & 5 deletions scripts/check-deps.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// 持久偏好 → config.env (skill 根目录, gitignored)
// 单次覆盖 → --browser 命令行参数(全链路 argv,不碰 process.env)

import { spawn } from 'node:child_process';
import { spawn, spawnSync } from 'node:child_process';
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
Expand Down Expand Up @@ -75,9 +75,27 @@ function startProxyDetached(browserOverride) {
fs.closeSync(logFd);
}

// 功能性探针:health/targets 正常不等于会话可用。浏览器若在 proxy 运行期间重启过,
// 旧 proxy 的会话会失效——所有 Page.navigate 静默失败、tab 卡在 about:blank,但 /health 仍报 ok。
// 建一个 about:blank 测试 tab → eval → close,全过才算真健康。
async function functionalProbe(baseUrl) {
try {
const newRes = await fetch(`${baseUrl}/new`, { method: 'POST', body: 'about:blank', signal: AbortSignal.timeout(5000) });
const { targetId } = await newRes.json();
if (!targetId) return false;
const evalRes = await fetch(`${baseUrl}/eval?target=${targetId}`, { method: 'POST', body: '1+1', signal: AbortSignal.timeout(5000) });
const evalJson = await evalRes.json();
await fetch(`${baseUrl}/close?target=${targetId}`, { signal: AbortSignal.timeout(5000) }).catch(() => {});
return evalJson?.value === 2;
} catch {
return false;
}
}

async function ensureProxy(expectedBrowserId, browserOverride) {
const healthUrl = `http://127.0.0.1:${PROXY_PORT}/health`;
const targetsUrl = `http://127.0.0.1:${PROXY_PORT}/targets`;
const baseUrl = `http://127.0.0.1:${PROXY_PORT}`;
const healthUrl = `${baseUrl}/health`;
const targetsUrl = `${baseUrl}/targets`;

// 复用:proxy 已运行 + 已连接浏览器 → 校验 expected vs actual
const health = await httpGetJson(healthUrl);
Expand All @@ -89,8 +107,17 @@ async function ensureProxy(expectedBrowserId, browserOverride) {
console.log(' 请在终端运行 pkill -f cdp-proxy.mjs 重置后再试');
return false;
}
console.log(`proxy: ready (${runningLabel})`);
return true;
// 健康但未必能用:实测一遍 new/eval/close 是否真的工作;失败则判定为僵尸 proxy
// (浏览器重启后遗留的旧进程,会话失效),杀掉后走下方重启分支。
const probeOk = await functionalProbe(baseUrl);
if (probeOk) {
console.log(`proxy: ready (${runningLabel})`);
return true;
}
console.log(`proxy: stale — 健康检查通过但功能性探针失败(浏览器可能已重启),杀掉旧 proxy 重启...`);
try { spawnSync('pkill', ['-f', 'cdp-proxy.mjs']); } catch {}
await new Promise((r) => setTimeout(r, 1500));
// 落入下方 startProxyDetached 重启分支
}

console.log('proxy: connecting...');
Expand Down