feat: 外接浏览器支持阶段一+二(Edge/Chrome 打开与基础自动化)
- 新增 browser/transport.ts: CdpTransport 抽象(Embedded=webContents.debugger / External=ws 直连调试端口) - 新增 browser/external.ts: Chrome/Edge 路径探测(常见目录+注册表App Paths)、带独立 user-data-dir 与调试端口拉起、端口占用自增、/json/version 就绪轮询、远程连接模式 - session.ts: BrowserSession 改为传输层注入, navigate/currentUrl/download/弹窗/网络监听双模式适配; 外部会话按 (mode,type,port) 缓存复用; pickElement 外部模式明确报不支持(阶段四) - capabilities/browser.ts: WebBrowser_Create/V2/V3/CreateBackground 读取 type/isRemote/ipAddress/port/arguments; type=chrome/edge 或 isRemote=1 走外部浏览器, 缺省仍走内置兜底 - 依赖: +ws ^8.22.0 - 冒烟已验证: Edge 156 拉起→CDP 连接→Page.navigate+loadEventFired→取标题→截图→setDownloadBehavior→关闭 全通过 - 内置浏览器行为不变(browser.test.ts 21 项回归通过)
This commit is contained in:
1 parent
a25f8c76b6
commit
ccfd82e894
6 files changed
+786
-74
No files matched your search
@@ -1,6 +1,6 @@
|
||||
import { register } from "../engine/registry";
|
||||
import { RuntimeError } from "../engine/types";
|
||||
import { browserSession } from "../browser/session";
|
||||
import { browserSession, externalBrowserSession } from "../browser/session";
|
||||
import type { BrowserLike, RunContext } from "../engine/types";
|
||||
|
||||
async function session(ctx: RunContext): Promise<BrowserLike> {
|
||||
@@ -8,6 +8,56 @@ async function session(ctx: RunContext): Promise<BrowserLike> {
|
||||
return ctx.browser;
|
||||
}
|
||||
|
||||
function isTruthyFlag(value: unknown): boolean {
|
||||
const text = String(value ?? "").trim().toLowerCase();
|
||||
return text === "1" || text === "true" || text === "yes";
|
||||
}
|
||||
|
||||
/**
|
||||
* 「打开网页」浏览器选择:
|
||||
* - type 填 chrome / edge → 拉起本机对应浏览器(带独立 profile + 调试端口)并接管
|
||||
* - isRemote 填 1/true → 直连 ipAddress:port 上已监听调试端口的实例(不拉起进程)
|
||||
* - type 缺省或其他值 → 内置运行浏览器(现状行为,兜底)
|
||||
*/
|
||||
async function resolveSession(ctx: RunContext, args: Record<string, unknown>): Promise<{ browser: BrowserLike; label: string }> {
|
||||
if (ctx.browser) return { browser: ctx.browser, label: "" };
|
||||
const type = String(args.type ?? "").trim().toLowerCase();
|
||||
const isRemote = isTruthyFlag(args.isRemote);
|
||||
if (isRemote) {
|
||||
const host = String(args.ipAddress ?? "127.0.0.1");
|
||||
const port = Number(args.port ?? 9222);
|
||||
const browser = await externalBrowserSession({ mode: "remote", host, port });
|
||||
ctx.browser = browser;
|
||||
return { browser, label: browser.label };
|
||||
}
|
||||
if (type === "chrome" || type === "edge") {
|
||||
const extraArgs = String(args.arguments ?? "")
|
||||
.split(/\s+/)
|
||||
.map((item) => item.trim())
|
||||
.filter(Boolean);
|
||||
const browser = await externalBrowserSession({
|
||||
mode: "launch",
|
||||
browserType: type === "edge" ? "edge" : "chrome",
|
||||
port: Number(args.port ?? 9222) || 9222,
|
||||
extraArgs
|
||||
});
|
||||
ctx.browser = browser;
|
||||
return { browser, label: browser.label };
|
||||
}
|
||||
return { browser: await session(ctx), label: "内置运行浏览器" };
|
||||
}
|
||||
|
||||
register(["WebBrowser_CreateV3", "WebBrowser_CreateV2", "WebBrowser_Create", "WebBrowser_CreateBackground"], async (ctx, node, args) => {
|
||||
const { browser, label } = await resolveSession(ctx, args);
|
||||
const url = String(args.url ?? "");
|
||||
if (url) {
|
||||
const result = await browser.navigate(url);
|
||||
ctx.log(`已使用${label}打开 ${result.url}`, "info", node.id);
|
||||
return result;
|
||||
}
|
||||
return { url: await browser.currentUrl(), title: "" };
|
||||
});
|
||||
|
||||
function selectorOf(args: Record<string, unknown>): unknown {
|
||||
const selector = args.uiSelector ?? args.selector ?? args.target ?? args.uiWindowSelector;
|
||||
if (selector === undefined || selector === null || selector === "") {
|
||||
@@ -18,17 +68,6 @@ function selectorOf(args: Record<string, unknown>): unknown {
|
||||
return selector;
|
||||
}
|
||||
|
||||
register(["WebBrowser_CreateV3", "WebBrowser_CreateV2", "WebBrowser_Create", "WebBrowser_CreateBackground"], async (ctx, node, args) => {
|
||||
const browser = await session(ctx);
|
||||
const url = String(args.url ?? "");
|
||||
if (url) {
|
||||
const result = await browser.navigate(url);
|
||||
ctx.log(`已打开 ${result.url}`, "info", node.id);
|
||||
return result;
|
||||
}
|
||||
return { url: await browser.currentUrl(), title: "" };
|
||||
});
|
||||
|
||||
register(["WebBrowser_GoUrl", "WebBrowser_Navigate"], async (ctx, node, args) => {
|
||||
const browser = await session(ctx);
|
||||
const url = String(args.url ?? "");
|
||||
|
||||
Reference in new issue
Block a user