@qing3a/flow-rpa-engine 0.1.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 (55) hide show
  1. package/dist/atomic.d.ts +9 -0
  2. package/dist/atomic.js +32 -0
  3. package/dist/atomic.js.map +1 -0
  4. package/dist/bench.d.ts +57 -0
  5. package/dist/bench.js +112 -0
  6. package/dist/bench.js.map +1 -0
  7. package/dist/cdp/client.d.ts +70 -0
  8. package/dist/cdp/client.js +272 -0
  9. package/dist/cdp/client.js.map +1 -0
  10. package/dist/cdp/page.d.ts +93 -0
  11. package/dist/cdp/page.js +411 -0
  12. package/dist/cdp/page.js.map +1 -0
  13. package/dist/executor.d.ts +122 -0
  14. package/dist/executor.js +399 -0
  15. package/dist/executor.js.map +1 -0
  16. package/dist/export.d.ts +128 -0
  17. package/dist/export.js +234 -0
  18. package/dist/export.js.map +1 -0
  19. package/dist/gate.d.ts +56 -0
  20. package/dist/gate.js +144 -0
  21. package/dist/gate.js.map +1 -0
  22. package/dist/hello.d.ts +5 -0
  23. package/dist/hello.js +13 -0
  24. package/dist/hello.js.map +1 -0
  25. package/dist/human.d.ts +162 -0
  26. package/dist/human.js +506 -0
  27. package/dist/human.js.map +1 -0
  28. package/dist/index.d.ts +20 -0
  29. package/dist/index.js +16 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/learning.d.ts +82 -0
  32. package/dist/learning.js +240 -0
  33. package/dist/learning.js.map +1 -0
  34. package/dist/mask.d.ts +32 -0
  35. package/dist/mask.js +70 -0
  36. package/dist/mask.js.map +1 -0
  37. package/dist/platform.d.ts +66 -0
  38. package/dist/platform.js +215 -0
  39. package/dist/platform.js.map +1 -0
  40. package/dist/record.d.ts +48 -0
  41. package/dist/record.js +42 -0
  42. package/dist/record.js.map +1 -0
  43. package/dist/schema.d.ts +130 -0
  44. package/dist/schema.js +93 -0
  45. package/dist/schema.js.map +1 -0
  46. package/dist/simprofile.d.ts +94 -0
  47. package/dist/simprofile.js +247 -0
  48. package/dist/simprofile.js.map +1 -0
  49. package/dist/storage.d.ts +63 -0
  50. package/dist/storage.js +138 -0
  51. package/dist/storage.js.map +1 -0
  52. package/dist/validate.d.ts +37 -0
  53. package/dist/validate.js +108 -0
  54. package/dist/validate.js.map +1 -0
  55. package/package.json +32 -0
@@ -0,0 +1,9 @@
1
+ /**
2
+ * A5 原子写(吸收自 hr-rpa-mcp `experience.mjs` 的 write tmp + rename 原子写模式)。
3
+ * storage 层统一 JSON 落盘走 `writeJsonAtomic`:进程中断不产生半写文件。
4
+ * 语义:tmp 同目录 + rename(同目录保证 rename 原子性;跨盘 rename 会失败)。
5
+ */
6
+ /** 原子写文本文件:先写同目录 tmp,再 rename 覆盖目标 */
7
+ export declare function writeFileAtomic(file: string, content: string): void;
8
+ /** 原子写 JSON(pretty 2 空格,与 Rust serde_json::to_string_pretty 同风格) */
9
+ export declare function writeJsonAtomic(file: string, value: unknown): void;
package/dist/atomic.js ADDED
@@ -0,0 +1,32 @@
1
+ import { mkdirSync, renameSync, rmSync, writeFileSync } from 'node:fs';
2
+ import { dirname } from 'node:path';
3
+ /**
4
+ * A5 原子写(吸收自 hr-rpa-mcp `experience.mjs` 的 write tmp + rename 原子写模式)。
5
+ * storage 层统一 JSON 落盘走 `writeJsonAtomic`:进程中断不产生半写文件。
6
+ * 语义:tmp 同目录 + rename(同目录保证 rename 原子性;跨盘 rename 会失败)。
7
+ */
8
+ /** 原子写文本文件:先写同目录 tmp,再 rename 覆盖目标 */
9
+ export function writeFileAtomic(file, content) {
10
+ const dir = dirname(file);
11
+ mkdirSync(dir, { recursive: true });
12
+ const tmp = `${file}.${process.pid}.${Date.now()}.tmp`;
13
+ writeFileSync(tmp, content, 'utf8');
14
+ try {
15
+ renameSync(tmp, file);
16
+ }
17
+ catch (e) {
18
+ // rename 失败(如跨设备)时清理 tmp 并重抛,不留半写
19
+ try {
20
+ rmSync(tmp, { force: true });
21
+ }
22
+ catch {
23
+ // 清理失败不影响主错误
24
+ }
25
+ throw e;
26
+ }
27
+ }
28
+ /** 原子写 JSON(pretty 2 空格,与 Rust serde_json::to_string_pretty 同风格) */
29
+ export function writeJsonAtomic(file, value) {
30
+ writeFileAtomic(file, JSON.stringify(value, null, 2));
31
+ }
32
+ //# sourceMappingURL=atomic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"atomic.js","sourceRoot":"","sources":["../src/atomic.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AACtE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAEnC;;;;GAIG;AAEH,sCAAsC;AACtC,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,OAAe;IAC3D,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACzB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACnC,MAAM,GAAG,GAAG,GAAG,IAAI,IAAI,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,MAAM,CAAA;IACtD,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,CAAA;IACnC,IAAI,CAAC;QACH,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;IACvB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,kCAAkC;QAClC,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QAC9B,CAAC;QAAC,MAAM,CAAC;YACP,aAAa;QACf,CAAC;QACD,MAAM,CAAC,CAAA;IACT,CAAC;AACH,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,KAAc;IAC1D,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;AACvD,CAAC"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * 端到端性能基准 —— 平均耗时/调用数质量门(移植自 Rust `bench.rs`)。
3
+ * 质量门:每个流程记录历史样本的平均耗时与平均步骤数(步骤数 = 调用数代理);
4
+ * 样本 ≥ 门槛后,本次耗时超过基线均值 × `PERF_ALARM_RATIO` → 告警。
5
+ * 基准持久化(benchmarks/perf-baseline.json),A5 原子写。
6
+ */
7
+ /** 质量门告警阈值:本次耗时 > 基线均值 × 此值 → 告警 */
8
+ export declare const PERF_ALARM_RATIO = 2;
9
+ /** 质量门判定的最小样本数:不足不判定 */
10
+ export declare const PERF_MIN_SAMPLES = 3;
11
+ /** 单流程性能基线 */
12
+ export interface FlowPerf {
13
+ flowId: string;
14
+ sampleCount: number;
15
+ /** 平均耗时(毫秒) */
16
+ avgDurationMs: number;
17
+ /** 平均步骤数(调用数代理) */
18
+ avgSteps: number;
19
+ /** 最近一次耗时 */
20
+ lastDurationMs: number;
21
+ /** 最近更新时间(ISO) */
22
+ lastUpdated: string;
23
+ }
24
+ /** 性能基线(持久化) */
25
+ export interface PerfBaseline {
26
+ flows: Record<string, FlowPerf>;
27
+ }
28
+ /** 质量门检查结果 */
29
+ export interface PerfCheck {
30
+ passed: boolean;
31
+ /** 质量门说明(告警信息 / 样本不足 / 通过) */
32
+ message: string;
33
+ avgDurationMs: number;
34
+ thisDurationMs: number;
35
+ /** 本次耗时 / 基线均值 */
36
+ ratio: number;
37
+ sampleCount: number;
38
+ }
39
+ /** 性能基准与质量门 */
40
+ export declare class PerfGate {
41
+ private readonly path;
42
+ constructor(root: string);
43
+ private load;
44
+ private save;
45
+ /**
46
+ * 记录一次 run 并更新基线;返回本次质量门检查结果(用更新前的历史基线判定,
47
+ * 避免本次异常样本稀释告警;样本不足时 passed=true 且说明样本不足)。
48
+ */
49
+ record(flowId: string, durationMs: number, stepCount: number): PerfCheck;
50
+ /** 只检查质量门(不更新基线) */
51
+ check(flowId: string, durationMs: number): PerfCheck;
52
+ private checkInner;
53
+ /** 查询基线(诊断/展示) */
54
+ baseline(flowId: string): FlowPerf | undefined;
55
+ /** 全部基线(按 flowId 排序) */
56
+ all(): FlowPerf[];
57
+ }
package/dist/bench.js ADDED
@@ -0,0 +1,112 @@
1
+ import { mkdirSync, readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { writeJsonAtomic } from './atomic.js';
4
+ import { nowIso } from './storage.js';
5
+ /**
6
+ * 端到端性能基准 —— 平均耗时/调用数质量门(移植自 Rust `bench.rs`)。
7
+ * 质量门:每个流程记录历史样本的平均耗时与平均步骤数(步骤数 = 调用数代理);
8
+ * 样本 ≥ 门槛后,本次耗时超过基线均值 × `PERF_ALARM_RATIO` → 告警。
9
+ * 基准持久化(benchmarks/perf-baseline.json),A5 原子写。
10
+ */
11
+ /** 质量门告警阈值:本次耗时 > 基线均值 × 此值 → 告警 */
12
+ export const PERF_ALARM_RATIO = 2.0;
13
+ /** 质量门判定的最小样本数:不足不判定 */
14
+ export const PERF_MIN_SAMPLES = 3;
15
+ /** 性能基准与质量门 */
16
+ export class PerfGate {
17
+ path;
18
+ constructor(root) {
19
+ this.path = join(root, 'benchmarks', 'perf-baseline.json');
20
+ mkdirSync(join(root, 'benchmarks'), { recursive: true });
21
+ }
22
+ load() {
23
+ try {
24
+ const v = JSON.parse(readFileSync(this.path, 'utf8'));
25
+ if (v && typeof v === 'object' && typeof v.flows === 'object')
26
+ return v;
27
+ return { flows: {} };
28
+ }
29
+ catch {
30
+ return { flows: {} };
31
+ }
32
+ }
33
+ save(b) {
34
+ writeJsonAtomic(this.path, b);
35
+ }
36
+ /**
37
+ * 记录一次 run 并更新基线;返回本次质量门检查结果(用更新前的历史基线判定,
38
+ * 避免本次异常样本稀释告警;样本不足时 passed=true 且说明样本不足)。
39
+ */
40
+ record(flowId, durationMs, stepCount) {
41
+ const b = this.load();
42
+ const check = this.checkInner(b, flowId, durationMs);
43
+ const entry = b.flows[flowId] ?? {
44
+ flowId,
45
+ sampleCount: 0,
46
+ avgDurationMs: 0,
47
+ avgSteps: 0,
48
+ lastDurationMs: 0,
49
+ lastUpdated: nowIso(),
50
+ };
51
+ const prevN = entry.sampleCount;
52
+ entry.sampleCount += 1;
53
+ entry.avgDurationMs = Math.floor((entry.avgDurationMs * prevN + durationMs) / entry.sampleCount);
54
+ entry.avgSteps = Math.floor((entry.avgSteps * prevN + stepCount) / entry.sampleCount);
55
+ entry.lastDurationMs = durationMs;
56
+ entry.lastUpdated = nowIso();
57
+ b.flows[flowId] = entry;
58
+ this.save(b);
59
+ return check;
60
+ }
61
+ /** 只检查质量门(不更新基线) */
62
+ check(flowId, durationMs) {
63
+ return this.checkInner(this.load(), flowId, durationMs);
64
+ }
65
+ checkInner(b, flowId, durationMs) {
66
+ const p = b.flows[flowId];
67
+ if (p && p.sampleCount >= PERF_MIN_SAMPLES) {
68
+ const avg = Math.max(1, p.avgDurationMs);
69
+ const ratio = durationMs / avg;
70
+ const passed = ratio <= PERF_ALARM_RATIO;
71
+ return {
72
+ passed,
73
+ message: passed
74
+ ? `性能正常:本次 ${durationMs}ms vs 基线均值 ${avg}ms(${ratio.toFixed(2)}x)`
75
+ : `质量门告警:本次耗时 ${durationMs}ms 超过基线均值 ${avg}ms 的 ${ratio.toFixed(2)}x(阈值 ${PERF_ALARM_RATIO.toFixed(1)}x),流程可能变慢(选择器退化/页面改版/网络异常)`,
76
+ avgDurationMs: avg,
77
+ thisDurationMs: durationMs,
78
+ ratio,
79
+ sampleCount: p.sampleCount,
80
+ };
81
+ }
82
+ if (p) {
83
+ return {
84
+ passed: true,
85
+ message: `样本不足(${p.sampleCount}/${PERF_MIN_SAMPLES}),暂不判定质量门`,
86
+ avgDurationMs: p.avgDurationMs,
87
+ thisDurationMs: durationMs,
88
+ ratio: 0,
89
+ sampleCount: p.sampleCount,
90
+ };
91
+ }
92
+ return {
93
+ passed: true,
94
+ message: '无历史基线,首个样本',
95
+ avgDurationMs: 0,
96
+ thisDurationMs: durationMs,
97
+ ratio: 0,
98
+ sampleCount: 0,
99
+ };
100
+ }
101
+ /** 查询基线(诊断/展示) */
102
+ baseline(flowId) {
103
+ return this.load().flows[flowId];
104
+ }
105
+ /** 全部基线(按 flowId 排序) */
106
+ all() {
107
+ const v = Object.values(this.load().flows);
108
+ v.sort((a, b) => (a.flowId < b.flowId ? -1 : a.flowId > b.flowId ? 1 : 0));
109
+ return v;
110
+ }
111
+ }
112
+ //# sourceMappingURL=bench.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bench.js","sourceRoot":"","sources":["../src/bench.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ import type { InputSink } from '../human.js';
2
+ /**
3
+ * CDP 客户端 —— 从 Rust `cdp.rs` 移植(原生 WebSocket 手写客户端,对照 hr-rpa-mcp `cdp.mjs`)。
4
+ *
5
+ * 背景(EXECUTION-SPEC-M11 第九节 CDP 诊断):chrome-remote-interface 库与 Edge 122
6
+ * 消息层不兼容(WebSocket 连接建立但 Runtime.evaluate 命令无响应);hr-rpa-mcp 手写
7
+ * 原生 ws 客户端数百次真实执行正常。故弃 CRI,改原生 WebSocket + 手写消息分发,
8
+ * 并补连接超时(诊断步骤 3:connect 无超时 = 真实健壮性缺口)。
9
+ *
10
+ * 职责:
11
+ * - 连接浏览器调试端口(HTTP /json/list、/json/new PUT→GET 回退)+ 标签页 CDP 会话
12
+ * - 发送 CDP 命令(带超时)与页面求值(Runtime.evaluate)
13
+ * - 实现 `InputSink`(human.rs 拟人层事件出口)
14
+ * - 多 tab:新建/关闭/激活标签页(Target.*)
15
+ *
16
+ * 命令超时默认 60s(对齐 cdp.mjs / Rust CMD_TIMEOUT)。
17
+ */
18
+ /** 调试端口默认 9222(对齐 cdp.mjs) */
19
+ export declare const CDP_PORT = 9222;
20
+ /** 标签页描述(/json/list 返回项) */
21
+ export interface Target {
22
+ id: string;
23
+ title: string;
24
+ url: string;
25
+ wsUrl: string;
26
+ }
27
+ /** 列出所有 page 类型标签页 */
28
+ export declare function listTargets(port: number): Promise<Target[]>;
29
+ /**
30
+ * 新建标签页(Chromium 122+ 禁用 GET /json/new 防 CSRF → 405,必须 PUT;极旧版回退 GET)。
31
+ * 先 PUT,405/失败时回退 GET。
32
+ */
33
+ export declare function openTarget(url: string, port: number): Promise<Target>;
34
+ /** 极简 URL 编码(仅用于 /json/new 的 url 参数;空格/中文等需编码) */
35
+ export declare function urlEncoding(s: string): string;
36
+ /** 关闭标签页(Target.closeTarget) */
37
+ export declare function closeTarget(targetId: string, port: number): Promise<unknown>;
38
+ /** 激活/前置标签页(Target.activateTarget) */
39
+ export declare function activateTarget(targetId: string, port: number): Promise<unknown>;
40
+ /** 命令超时(默认 60s,对齐 cdp.mjs / Rust CMD_TIMEOUT) */
41
+ export declare const CMD_TIMEOUT_MS = 60000;
42
+ /** WebSocket 连接超时(诊断步骤 3:connect 无超时 = 真实健壮性缺口) */
43
+ export declare const CONNECT_TIMEOUT_MS = 10000;
44
+ /** 页面 CDP 会话(原生 WebSocket 手写客户端,对照 hr-rpa-mcp cdp.mjs) */
45
+ export declare class CdpClient {
46
+ private nextId;
47
+ private readonly pending;
48
+ private closed;
49
+ private ws?;
50
+ private constructor();
51
+ /** 连接页面 WebSocket 调试 URL(如 ws://127.0.0.1:9222/devtools/page/xxx);带连接超时 */
52
+ static connect(wsUrl: string): Promise<CdpClient>;
53
+ /**
54
+ * 发送 CDP 命令,等待响应(带超时;无响应则清理 pending 并报错)。
55
+ * 返回 result;命令 error 时抛 HumanError.sink(error.message)。
56
+ */
57
+ send(method: string, params: Record<string, unknown>): Promise<unknown>;
58
+ /** 页面求值(Runtime.evaluate;返回 byValue,awaitPromise;异常抛错) */
59
+ evaluate(expression: string): Promise<unknown>;
60
+ /** 关闭连接 */
61
+ close(): Promise<void>;
62
+ }
63
+ /** 把 CdpClient 适配为拟人层的事件出口(InputSink) */
64
+ export declare class CdpInputSink implements InputSink {
65
+ private readonly client;
66
+ constructor(client: CdpClient);
67
+ send(method: string, params: Record<string, unknown>): Promise<void>;
68
+ evaluate(expr: string): Promise<unknown>;
69
+ viewport(): Promise<[number, number]>;
70
+ }
@@ -0,0 +1,272 @@
1
+ import { HumanError } from '../human.js';
2
+ /**
3
+ * CDP 客户端 —— 从 Rust `cdp.rs` 移植(原生 WebSocket 手写客户端,对照 hr-rpa-mcp `cdp.mjs`)。
4
+ *
5
+ * 背景(EXECUTION-SPEC-M11 第九节 CDP 诊断):chrome-remote-interface 库与 Edge 122
6
+ * 消息层不兼容(WebSocket 连接建立但 Runtime.evaluate 命令无响应);hr-rpa-mcp 手写
7
+ * 原生 ws 客户端数百次真实执行正常。故弃 CRI,改原生 WebSocket + 手写消息分发,
8
+ * 并补连接超时(诊断步骤 3:connect 无超时 = 真实健壮性缺口)。
9
+ *
10
+ * 职责:
11
+ * - 连接浏览器调试端口(HTTP /json/list、/json/new PUT→GET 回退)+ 标签页 CDP 会话
12
+ * - 发送 CDP 命令(带超时)与页面求值(Runtime.evaluate)
13
+ * - 实现 `InputSink`(human.rs 拟人层事件出口)
14
+ * - 多 tab:新建/关闭/激活标签页(Target.*)
15
+ *
16
+ * 命令超时默认 60s(对齐 cdp.mjs / Rust CMD_TIMEOUT)。
17
+ */
18
+ /** 调试端口默认 9222(对齐 cdp.mjs) */
19
+ export const CDP_PORT = 9222;
20
+ const versionUrl = (port) => `http://127.0.0.1:${port}/json/version`;
21
+ const listUrl = (port) => `http://127.0.0.1:${port}/json/list`;
22
+ /** HTTP 请求并解析 JSON(原生 fetch;仅用于浏览器调试端点的短请求) */
23
+ async function httpJsonWith(method, url) {
24
+ let resp;
25
+ try {
26
+ resp = await fetch(url, {
27
+ method,
28
+ signal: AbortSignal.timeout(3_000),
29
+ });
30
+ }
31
+ catch (e) {
32
+ throw HumanError.sink(`HTTP 请求失败 ${url}: ${e instanceof Error ? e.message : String(e)}`);
33
+ }
34
+ const body = await resp.text();
35
+ try {
36
+ return JSON.parse(body);
37
+ }
38
+ catch (e) {
39
+ throw HumanError.sink(`JSON 解析失败 ${url}: ${e instanceof Error ? e.message : String(e)}`);
40
+ }
41
+ }
42
+ const httpJson = (url) => httpJsonWith('GET', url);
43
+ /** 列出所有 page 类型标签页 */
44
+ export async function listTargets(port) {
45
+ const v = await httpJson(listUrl(port));
46
+ if (!Array.isArray(v))
47
+ throw HumanError.sink('调试端点返回非数组');
48
+ const targets = [];
49
+ for (const t of v) {
50
+ if (t && typeof t === 'object' && t.type === 'page') {
51
+ const id = t.id;
52
+ const ws = t.webSocketDebuggerUrl;
53
+ if (typeof id === 'string' && typeof ws === 'string') {
54
+ targets.push({
55
+ id,
56
+ title: typeof t.title === 'string' ? t.title : '',
57
+ url: typeof t.url === 'string' ? t.url : '',
58
+ wsUrl: ws,
59
+ });
60
+ }
61
+ }
62
+ }
63
+ return targets;
64
+ }
65
+ /**
66
+ * 新建标签页(Chromium 122+ 禁用 GET /json/new 防 CSRF → 405,必须 PUT;极旧版回退 GET)。
67
+ * 先 PUT,405/失败时回退 GET。
68
+ */
69
+ export async function openTarget(url, port) {
70
+ const base = listUrl(port).replace(/\/json\/list$/, '');
71
+ const u = `${base}/json/new?${urlEncoding(url)}`;
72
+ let v;
73
+ try {
74
+ v = await httpJsonWith('PUT', u);
75
+ }
76
+ catch {
77
+ // 旧版 Chromium GET 回退(/json/new 尚未禁 GET)
78
+ v = await httpJson(u);
79
+ }
80
+ const o = v;
81
+ if (typeof o.id !== 'string') {
82
+ throw HumanError.sink(`创建标签页失败: ${JSON.stringify(v)}`);
83
+ }
84
+ return {
85
+ id: o.id,
86
+ title: typeof o.title === 'string' ? o.title : '',
87
+ url: typeof o.url === 'string' ? o.url : '',
88
+ wsUrl: typeof o.webSocketDebuggerUrl === 'string' ? o.webSocketDebuggerUrl : '',
89
+ };
90
+ }
91
+ /** 极简 URL 编码(仅用于 /json/new 的 url 参数;空格/中文等需编码) */
92
+ export function urlEncoding(s) {
93
+ let out = '';
94
+ for (const b of Buffer.from(s, 'utf8')) {
95
+ const c = b;
96
+ if ((c >= 0x41 && c <= 0x5a) || (c >= 0x61 && c <= 0x7a) || (c >= 0x30 && c <= 0x39) ||
97
+ c === 0x2d || c === 0x5f || c === 0x2e || c === 0x7e || c === 0x2f || c === 0x3a ||
98
+ c === 0x3f || c === 0x26 || c === 0x3d || c === 0x25 || c === 0x23) {
99
+ out += String.fromCharCode(c);
100
+ }
101
+ else {
102
+ out += `%${c.toString(16).toUpperCase().padStart(2, '0')}`;
103
+ }
104
+ }
105
+ return out;
106
+ }
107
+ /** 通过 browser 级会话执行 Target.* 命令 */
108
+ async function browserCommand(port, method, params) {
109
+ const v = (await httpJson(versionUrl(port)));
110
+ const ws = v.webSocketDebuggerUrl;
111
+ if (typeof ws !== 'string') {
112
+ throw HumanError.sink('浏览器版本端点缺少 webSocketDebuggerUrl');
113
+ }
114
+ const client = await CdpClient.connect(ws);
115
+ try {
116
+ return await client.send(method, params);
117
+ }
118
+ finally {
119
+ await client.close();
120
+ }
121
+ }
122
+ /** 关闭标签页(Target.closeTarget) */
123
+ export function closeTarget(targetId, port) {
124
+ return browserCommand(port, 'Target.closeTarget', { targetId });
125
+ }
126
+ /** 激活/前置标签页(Target.activateTarget) */
127
+ export function activateTarget(targetId, port) {
128
+ return browserCommand(port, 'Target.activateTarget', { targetId });
129
+ }
130
+ /** 命令超时(默认 60s,对齐 cdp.mjs / Rust CMD_TIMEOUT) */
131
+ export const CMD_TIMEOUT_MS = 60_000;
132
+ /** WebSocket 连接超时(诊断步骤 3:connect 无超时 = 真实健壮性缺口) */
133
+ export const CONNECT_TIMEOUT_MS = 10_000;
134
+ /** 页面 CDP 会话(原生 WebSocket 手写客户端,对照 hr-rpa-mcp cdp.mjs) */
135
+ export class CdpClient {
136
+ nextId = 0;
137
+ pending = new Map();
138
+ closed = false;
139
+ ws;
140
+ constructor() { }
141
+ /** 连接页面 WebSocket 调试 URL(如 ws://127.0.0.1:9222/devtools/page/xxx);带连接超时 */
142
+ static async connect(wsUrl) {
143
+ const client = new CdpClient();
144
+ const ws = new WebSocket(wsUrl);
145
+ await new Promise((resolve, reject) => {
146
+ const timer = setTimeout(() => {
147
+ ws.close();
148
+ reject(HumanError.sink(`CDP WebSocket 连接超时(${CONNECT_TIMEOUT_MS}ms): ${wsUrl}`));
149
+ }, CONNECT_TIMEOUT_MS);
150
+ ws.onopen = () => {
151
+ clearTimeout(timer);
152
+ resolve();
153
+ };
154
+ ws.onerror = () => {
155
+ clearTimeout(timer);
156
+ reject(HumanError.sink(`CDP WebSocket 连接失败: ${wsUrl}`));
157
+ };
158
+ });
159
+ client.ws = ws;
160
+ ws.onmessage = (ev) => {
161
+ let m;
162
+ try {
163
+ m = JSON.parse(String(ev.data));
164
+ }
165
+ catch {
166
+ return; // 非 JSON 帧忽略
167
+ }
168
+ if (typeof m?.id === 'number' && client.pending.has(m.id)) {
169
+ const resolve = client.pending.get(m.id);
170
+ client.pending.delete(m.id);
171
+ if (m.error) {
172
+ resolve({ __cdpError: m.error.message ?? 'CDP error' });
173
+ }
174
+ else {
175
+ resolve(m.result ?? null);
176
+ }
177
+ }
178
+ };
179
+ return client;
180
+ }
181
+ /**
182
+ * 发送 CDP 命令,等待响应(带超时;无响应则清理 pending 并报错)。
183
+ * 返回 result;命令 error 时抛 HumanError.sink(error.message)。
184
+ */
185
+ async send(method, params) {
186
+ if (this.closed)
187
+ throw HumanError.sink('CDP 连接已关闭');
188
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
189
+ throw HumanError.sink('CDP WebSocket 未连接');
190
+ }
191
+ const id = ++this.nextId;
192
+ return new Promise((resolve, reject) => {
193
+ const timer = setTimeout(() => {
194
+ this.pending.delete(id);
195
+ reject(HumanError.sink(`CDP 命令超时(${CMD_TIMEOUT_MS}ms): ${method}`));
196
+ }, CMD_TIMEOUT_MS);
197
+ this.pending.set(id, (v) => {
198
+ clearTimeout(timer);
199
+ if (v && typeof v === 'object' && '__cdpError' in v) {
200
+ reject(HumanError.sink(v.__cdpError));
201
+ }
202
+ else {
203
+ resolve(v);
204
+ }
205
+ });
206
+ try {
207
+ this.ws.send(JSON.stringify({ id, method, params }));
208
+ }
209
+ catch (e) {
210
+ clearTimeout(timer);
211
+ this.pending.delete(id);
212
+ reject(HumanError.sink(`CDP 发送失败: ${e instanceof Error ? e.message : String(e)}`));
213
+ }
214
+ });
215
+ }
216
+ /** 页面求值(Runtime.evaluate;返回 byValue,awaitPromise;异常抛错) */
217
+ async evaluate(expression) {
218
+ const r = (await this.send('Runtime.evaluate', {
219
+ expression,
220
+ returnByValue: true,
221
+ awaitPromise: true,
222
+ }));
223
+ if (r && typeof r === 'object' && 'exceptionDetails' in r) {
224
+ const ex = r.exceptionDetails;
225
+ const desc = ex.exception?.description ??
226
+ ex.text ??
227
+ 'eval error';
228
+ throw HumanError.sink(`页面求值异常: ${desc}`);
229
+ }
230
+ const result = r?.result;
231
+ return result && typeof result === 'object' ? result.value : null;
232
+ }
233
+ /** 关闭连接 */
234
+ async close() {
235
+ if (this.closed)
236
+ return;
237
+ this.closed = true;
238
+ // 拒绝所有未决命令(避免调用方永久挂起)
239
+ for (const reject of this.pending.values()) {
240
+ reject({ __cdpError: 'CDP 连接已关闭' });
241
+ }
242
+ this.pending.clear();
243
+ try {
244
+ this.ws?.close();
245
+ }
246
+ catch {
247
+ // 关闭失败不抛出
248
+ }
249
+ }
250
+ }
251
+ /** 把 CdpClient 适配为拟人层的事件出口(InputSink) */
252
+ export class CdpInputSink {
253
+ client;
254
+ constructor(client) {
255
+ this.client = client;
256
+ }
257
+ async send(method, params) {
258
+ await this.client.send(method, params);
259
+ }
260
+ async evaluate(expr) {
261
+ return this.client.evaluate(expr);
262
+ }
263
+ async viewport() {
264
+ const m = (await this.client.send('Page.getLayoutMetrics', {}));
265
+ const v = m && typeof m === 'object' ? m.visualViewport : undefined;
266
+ const vv = v && typeof v === 'object' ? v : undefined;
267
+ const w = typeof vv?.clientWidth === 'number' ? vv.clientWidth : 1440;
268
+ const h = typeof vv?.clientHeight === 'number' ? vv.clientHeight : 900;
269
+ return [Math.floor(w), Math.floor(h)];
270
+ }
271
+ }
272
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/cdp/client.ts"],"names":[],"mappings":"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"}