@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.
- package/dist/atomic.d.ts +9 -0
- package/dist/atomic.js +32 -0
- package/dist/atomic.js.map +1 -0
- package/dist/bench.d.ts +57 -0
- package/dist/bench.js +112 -0
- package/dist/bench.js.map +1 -0
- package/dist/cdp/client.d.ts +70 -0
- package/dist/cdp/client.js +272 -0
- package/dist/cdp/client.js.map +1 -0
- package/dist/cdp/page.d.ts +93 -0
- package/dist/cdp/page.js +411 -0
- package/dist/cdp/page.js.map +1 -0
- package/dist/executor.d.ts +122 -0
- package/dist/executor.js +399 -0
- package/dist/executor.js.map +1 -0
- package/dist/export.d.ts +128 -0
- package/dist/export.js +234 -0
- package/dist/export.js.map +1 -0
- package/dist/gate.d.ts +56 -0
- package/dist/gate.js +144 -0
- package/dist/gate.js.map +1 -0
- package/dist/hello.d.ts +5 -0
- package/dist/hello.js +13 -0
- package/dist/hello.js.map +1 -0
- package/dist/human.d.ts +162 -0
- package/dist/human.js +506 -0
- package/dist/human.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/learning.d.ts +82 -0
- package/dist/learning.js +240 -0
- package/dist/learning.js.map +1 -0
- package/dist/mask.d.ts +32 -0
- package/dist/mask.js +70 -0
- package/dist/mask.js.map +1 -0
- package/dist/platform.d.ts +66 -0
- package/dist/platform.js +215 -0
- package/dist/platform.js.map +1 -0
- package/dist/record.d.ts +48 -0
- package/dist/record.js +42 -0
- package/dist/record.js.map +1 -0
- package/dist/schema.d.ts +130 -0
- package/dist/schema.js +93 -0
- package/dist/schema.js.map +1 -0
- package/dist/simprofile.d.ts +94 -0
- package/dist/simprofile.js +247 -0
- package/dist/simprofile.js.map +1 -0
- package/dist/storage.d.ts +63 -0
- package/dist/storage.js +138 -0
- package/dist/storage.js.map +1 -0
- package/dist/validate.d.ts +37 -0
- package/dist/validate.js +108 -0
- package/dist/validate.js.map +1 -0
- package/package.json +32 -0
package/dist/platform.js
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { mkdirSync, readFileSync, writeFileSync, readdirSync, statSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { writeJsonAtomic } from './atomic.js';
|
|
5
|
+
/** 平台客户端(无状态;每次 pkg_update 独立请求) */
|
|
6
|
+
export class PlatformClient {
|
|
7
|
+
baseUrl;
|
|
8
|
+
token;
|
|
9
|
+
constructor(baseUrl, token) {
|
|
10
|
+
this.baseUrl = baseUrl.replace(/\/+$/, '');
|
|
11
|
+
this.token = token;
|
|
12
|
+
}
|
|
13
|
+
/** 拉取包 manifest(GET /api/packages/<name>,Bearer 认证) */
|
|
14
|
+
async fetchManifest(name) {
|
|
15
|
+
const url = `${this.baseUrl}/api/packages/${name}`;
|
|
16
|
+
const body = await httpGet(url, this.token);
|
|
17
|
+
let v;
|
|
18
|
+
try {
|
|
19
|
+
v = JSON.parse(body);
|
|
20
|
+
}
|
|
21
|
+
catch (e) {
|
|
22
|
+
throw new Error(`manifest 解析失败: ${e instanceof Error ? e.message : String(e)}`);
|
|
23
|
+
}
|
|
24
|
+
const data = v && typeof v === 'object' ? v.data : undefined;
|
|
25
|
+
if (data === undefined)
|
|
26
|
+
throw new Error('响应缺少 data');
|
|
27
|
+
if (!data || typeof data !== 'object')
|
|
28
|
+
throw new Error('manifest 字段不匹配');
|
|
29
|
+
const m = data;
|
|
30
|
+
if (typeof m.name !== 'string' ||
|
|
31
|
+
typeof m.type !== 'string' ||
|
|
32
|
+
typeof m.version !== 'string' ||
|
|
33
|
+
typeof m.hash !== 'string' ||
|
|
34
|
+
!Array.isArray(m.files) ||
|
|
35
|
+
!m.files.every((f) => typeof f === 'string')) {
|
|
36
|
+
throw new Error('manifest 字段不匹配');
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
name: m.name,
|
|
40
|
+
type: m.type,
|
|
41
|
+
version: m.version,
|
|
42
|
+
hash: m.hash,
|
|
43
|
+
files: m.files,
|
|
44
|
+
signature: typeof m.signature === 'string' ? m.signature : undefined,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/** 下载包内单文件(GET /api/packages/<name>/files/<f>,Bearer 认证) */
|
|
48
|
+
async fetchFile(name, file) {
|
|
49
|
+
const url = `${this.baseUrl}/api/packages/${name}/files/${file}`;
|
|
50
|
+
const bytes = await httpGetBytes(url, this.token);
|
|
51
|
+
return bytes;
|
|
52
|
+
}
|
|
53
|
+
/** 下载整个包(按 manifest.files),返回 {文件名: 内容}(按键排序) */
|
|
54
|
+
async downloadPackage(manifest) {
|
|
55
|
+
const out = new Map();
|
|
56
|
+
for (const f of [...manifest.files].sort()) {
|
|
57
|
+
const data = await this.fetchFile(manifest.name, f);
|
|
58
|
+
out.set(f, data);
|
|
59
|
+
}
|
|
60
|
+
return out;
|
|
61
|
+
}
|
|
62
|
+
/** 计算包 hash(与 md-forge hashFiles 同口径:files 按键排序,name\0content,SHA-256 hex) */
|
|
63
|
+
static computeHash(files) {
|
|
64
|
+
const map = files instanceof Map ? files : new Map(Object.entries(files));
|
|
65
|
+
const h = createHash('sha256');
|
|
66
|
+
for (const [name, data] of [...map.entries()].sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))) {
|
|
67
|
+
h.update(name, 'utf8');
|
|
68
|
+
h.update(Buffer.from([0]));
|
|
69
|
+
h.update(data);
|
|
70
|
+
}
|
|
71
|
+
return h.digest('hex');
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* M10 D-O1:上传观察包目录到平台(POST {base}/api/observations,multipart)。
|
|
75
|
+
* bundleDir 为 outbox/<flow_id>_v<version>_<run_id>/;身份前缀 = <flow_id>_v<version>_<run_id>。
|
|
76
|
+
* 返回 { status: 'accepted' | 'duplicate', dir };网络/4xx/5xx 抛错(由调用方记台账 Failed)。
|
|
77
|
+
*/
|
|
78
|
+
async uploadObservation(bundleDir) {
|
|
79
|
+
// 目录名 = 身份前缀(flow_id_v<version>_<run_id>)
|
|
80
|
+
const identity = bundleDir.split(/[\\/]/).filter(Boolean).pop() ?? '';
|
|
81
|
+
const files = readdirSync(bundleDir)
|
|
82
|
+
.filter((f) => statSync(join(bundleDir, f)).isFile())
|
|
83
|
+
.sort();
|
|
84
|
+
// 必选文件检查(D-O1:manifest/run/dom_snapshot 必选)
|
|
85
|
+
const names = new Set(files);
|
|
86
|
+
for (const req of ['manifest.json', 'run.json', 'dom_snapshot.json']) {
|
|
87
|
+
if (!names.has(req))
|
|
88
|
+
throw new Error(`观察包缺必选文件 ${req}(${bundleDir})`);
|
|
89
|
+
}
|
|
90
|
+
// multipart 组装:字段名 files;originalname = <identity>_<file>
|
|
91
|
+
const boundary = `----flow-rpa-${Date.now().toString(36)}`;
|
|
92
|
+
const chunks = [];
|
|
93
|
+
for (const f of files) {
|
|
94
|
+
const content = readFileSync(join(bundleDir, f));
|
|
95
|
+
chunks.push(Buffer.from(`--${boundary}\r\nContent-Disposition: form-data; name="files"; filename="${identity}_${f}"\r\nContent-Type: application/octet-stream\r\n\r\n`, 'utf8'));
|
|
96
|
+
chunks.push(content);
|
|
97
|
+
chunks.push(Buffer.from('\r\n', 'utf8'));
|
|
98
|
+
}
|
|
99
|
+
chunks.push(Buffer.from(`--${boundary}--\r\n`, 'utf8'));
|
|
100
|
+
const body = Buffer.concat(chunks);
|
|
101
|
+
const resp = await fetch(`${this.baseUrl}/api/observations`, {
|
|
102
|
+
method: 'POST',
|
|
103
|
+
signal: AbortSignal.timeout(60_000),
|
|
104
|
+
headers: {
|
|
105
|
+
Authorization: `Bearer ${this.token}`,
|
|
106
|
+
'Content-Type': `multipart/form-data; boundary=${boundary}`,
|
|
107
|
+
},
|
|
108
|
+
body,
|
|
109
|
+
});
|
|
110
|
+
const text = await resp.text();
|
|
111
|
+
let v;
|
|
112
|
+
try {
|
|
113
|
+
v = JSON.parse(text);
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
throw new Error(`上传响应非 JSON: HTTP ${resp.status} ${text.slice(0, 120)}`);
|
|
117
|
+
}
|
|
118
|
+
if (!(resp.status >= 200 && resp.status < 300)) {
|
|
119
|
+
const msg = v && typeof v === 'object' ? v.error : undefined;
|
|
120
|
+
const detail = msg && typeof msg === 'object' ? JSON.stringify(msg).slice(0, 200) : String(msg ?? text).slice(0, 200);
|
|
121
|
+
throw new Error(`上传失败 HTTP ${resp.status}: ${detail}`);
|
|
122
|
+
}
|
|
123
|
+
const data = v && typeof v === 'object' ? v.data : undefined;
|
|
124
|
+
if (!data || typeof data !== 'object')
|
|
125
|
+
throw new Error('上传响应缺少 data');
|
|
126
|
+
const d = data;
|
|
127
|
+
if (typeof d.status !== 'string' || typeof d.dir !== 'string')
|
|
128
|
+
throw new Error('上传响应 data 字段不匹配');
|
|
129
|
+
return { status: d.status, dir: d.dir };
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/** 哈希校验:下载的包文件重新计算 hash,与 manifest.hash 比对 */
|
|
133
|
+
export function verifyHash(manifest, files) {
|
|
134
|
+
const actual = PlatformClient.computeHash(files);
|
|
135
|
+
if (actual !== manifest.hash) {
|
|
136
|
+
throw new Error(`哈希校验失败: 期望 ${manifest.hash} 实际 ${actual}(包可能损坏或被篡改)`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/** 本地 flows/ 目录中某 flow 的当前版本(读 flow.json 的 version 字段;不存在返回 undefined) */
|
|
140
|
+
export function localFlowVersion(flowsDir, name) {
|
|
141
|
+
const flowPath = join(flowsDir, name, 'flow.json');
|
|
142
|
+
try {
|
|
143
|
+
const v = JSON.parse(readFileSync(flowPath, 'utf8'));
|
|
144
|
+
if (typeof v.version === 'number')
|
|
145
|
+
return v.version;
|
|
146
|
+
throw new Error('本地 flow.json 缺 version');
|
|
147
|
+
}
|
|
148
|
+
catch (e) {
|
|
149
|
+
if (e instanceof Error && e.message === '本地 flow.json 缺 version')
|
|
150
|
+
throw e;
|
|
151
|
+
return undefined; // 文件不存在 → undefined
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* 执行 pkg_update:拉 manifest → 比版本 → 有更新下载 → 哈希校验 → 替换 flows/。
|
|
156
|
+
* 校验失败抛错(不落盘)。
|
|
157
|
+
*/
|
|
158
|
+
export async function pkgUpdate(client, flowsDir, name) {
|
|
159
|
+
// 1. 拉 manifest
|
|
160
|
+
const manifest = await client.fetchManifest(name);
|
|
161
|
+
const platformVersion = Number.parseInt(manifest.version, 10);
|
|
162
|
+
if (Number.isNaN(platformVersion)) {
|
|
163
|
+
throw new Error(`平台版本号非数字: ${manifest.version}`);
|
|
164
|
+
}
|
|
165
|
+
// 2. 本地版本比对
|
|
166
|
+
const local = localFlowVersion(flowsDir, name);
|
|
167
|
+
const mkResult = (status, msg) => ({
|
|
168
|
+
name,
|
|
169
|
+
status,
|
|
170
|
+
localVersion: local,
|
|
171
|
+
platformVersion,
|
|
172
|
+
hash: manifest.hash,
|
|
173
|
+
dir: undefined,
|
|
174
|
+
message: msg,
|
|
175
|
+
});
|
|
176
|
+
if (local !== undefined && local >= platformVersion) {
|
|
177
|
+
// 已是最新或本地更新(不回退)
|
|
178
|
+
return mkResult(local > platformVersion ? 'newer' : 'up_to_date', local > platformVersion ? '本地版本高于平台,不更新' : '已是最新版本');
|
|
179
|
+
}
|
|
180
|
+
// 3. 下载 + 哈希校验(校验失败抛错,不落盘)
|
|
181
|
+
const files = await client.downloadPackage(manifest);
|
|
182
|
+
verifyHash(manifest, files);
|
|
183
|
+
// 4. 替换本地 flows/<name>/
|
|
184
|
+
const pkgDir = join(flowsDir, name);
|
|
185
|
+
mkdirSync(pkgDir, { recursive: true });
|
|
186
|
+
for (const [f, data] of files) {
|
|
187
|
+
// 包文件直接写(flow.json / scenes.json / thesaurus.json 等)
|
|
188
|
+
writeFileSync(join(pkgDir, f), data);
|
|
189
|
+
}
|
|
190
|
+
// 本地记录一份 manifest.json(= 拉到的平台 manifest;不在 files 列表里)
|
|
191
|
+
writeJsonAtomic(join(pkgDir, 'manifest.json'), manifest);
|
|
192
|
+
return mkResult('updated', `流程包已更新到 v${platformVersion}(${files.size} 个文件)`);
|
|
193
|
+
}
|
|
194
|
+
/** 简单 HTTP GET(原生 fetch,Node 24 内置) */
|
|
195
|
+
async function httpGet(url, token) {
|
|
196
|
+
const bytes = await httpGetBytes(url, token);
|
|
197
|
+
return new TextDecoder().decode(bytes);
|
|
198
|
+
}
|
|
199
|
+
async function httpGetBytes(url, token) {
|
|
200
|
+
const resp = await fetch(url, {
|
|
201
|
+
signal: AbortSignal.timeout(30_000),
|
|
202
|
+
headers: {
|
|
203
|
+
Accept: 'application/json',
|
|
204
|
+
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
|
205
|
+
},
|
|
206
|
+
});
|
|
207
|
+
const status = resp.status;
|
|
208
|
+
const body = new Uint8Array(await resp.arrayBuffer());
|
|
209
|
+
if (!(status >= 200 && status < 300)) {
|
|
210
|
+
const text = new TextDecoder().decode(body);
|
|
211
|
+
throw new Error(`HTTP ${status}: ${[...text].slice(0, 200).join('')}`);
|
|
212
|
+
}
|
|
213
|
+
return body;
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=platform.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"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"}
|
package/dist/record.d.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { FlowResult } from './executor.js';
|
|
2
|
+
/**
|
|
3
|
+
* 执行记录(run.json)—— L2 学习的唯一输入(移植自 Rust `record.rs`)。
|
|
4
|
+
* 契约见 docs/FLOW-SCHEMA-v1.md「执行记录」:每步一条结构化记录。
|
|
5
|
+
* executor 产出结构化 FlowResult 后,经本模块转换为可序列化的 RunRecord。
|
|
6
|
+
*/
|
|
7
|
+
export interface RunRecord {
|
|
8
|
+
runId: string;
|
|
9
|
+
flowId: string;
|
|
10
|
+
flowVersion: number;
|
|
11
|
+
/** done / failed(整体) */
|
|
12
|
+
status: 'done' | 'failed';
|
|
13
|
+
error?: string;
|
|
14
|
+
/** ISO 时间(如 2026-08-24T00:00:00Z) */
|
|
15
|
+
startedAt: string;
|
|
16
|
+
steps: StepRecord[];
|
|
17
|
+
}
|
|
18
|
+
export interface StepRecord {
|
|
19
|
+
stepId: string;
|
|
20
|
+
/** 步骤类型(navigate/click/...),与 schema 的 type 一致 */
|
|
21
|
+
type?: string;
|
|
22
|
+
/** done / failed */
|
|
23
|
+
status: 'done' | 'failed';
|
|
24
|
+
error?: string;
|
|
25
|
+
verify?: VerifyRecord;
|
|
26
|
+
/** 步骤耗时(节奏学习/冷却的输入) */
|
|
27
|
+
durationMs: number;
|
|
28
|
+
/** 输入值(input 步骤;落盘时刻已掩码 —— 掩码前移,ARCHITECTURE #6) */
|
|
29
|
+
inputValueMasked?: string;
|
|
30
|
+
/** 提取字段标签 / 是否落盘明细 / 命中元素数 / 实际生效选择器(M4 扩展,记录进 run.json) */
|
|
31
|
+
field?: string;
|
|
32
|
+
saved?: boolean;
|
|
33
|
+
count?: number;
|
|
34
|
+
selectorHit?: string;
|
|
35
|
+
/** 冷却锚点(D-C1:wait 步骤 coolKey;server 层据此记账) */
|
|
36
|
+
cooldownKey?: string;
|
|
37
|
+
}
|
|
38
|
+
export interface VerifyRecord {
|
|
39
|
+
waitSelector?: string;
|
|
40
|
+
passed: boolean;
|
|
41
|
+
durationMs: number;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* 从 executor 的结构化结果构建 run.json(run_id/started_at 由调用方提供)。
|
|
45
|
+
* 掩码前移:`keywords` 为本次执行的敏感词集合,落盘时刻对步骤/流程 error 掩码
|
|
46
|
+
* (明文不落盘)。只替换关键词原文,不动失败类别短语(类别判定不受影响)。
|
|
47
|
+
*/
|
|
48
|
+
export declare function fromFlowResult(runId: string, flowId: string, flowVersion: number, r: FlowResult, startedAt: string, keywords: string[]): RunRecord;
|
package/dist/record.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { maskKeywords } from './mask.js';
|
|
2
|
+
/**
|
|
3
|
+
* 从 executor 的结构化结果构建 run.json(run_id/started_at 由调用方提供)。
|
|
4
|
+
* 掩码前移:`keywords` 为本次执行的敏感词集合,落盘时刻对步骤/流程 error 掩码
|
|
5
|
+
* (明文不落盘)。只替换关键词原文,不动失败类别短语(类别判定不受影响)。
|
|
6
|
+
*/
|
|
7
|
+
export function fromFlowResult(runId, flowId, flowVersion, r, startedAt, keywords) {
|
|
8
|
+
return {
|
|
9
|
+
runId,
|
|
10
|
+
flowId,
|
|
11
|
+
flowVersion,
|
|
12
|
+
status: r.status,
|
|
13
|
+
error: r.error ? maskKeywords(r.error, keywords) : undefined,
|
|
14
|
+
startedAt,
|
|
15
|
+
steps: r.steps.map((s) => stepToRecord(s, keywords)),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function stepToRecord(s, keywords) {
|
|
19
|
+
return {
|
|
20
|
+
stepId: s.stepId,
|
|
21
|
+
type: s.kind,
|
|
22
|
+
status: s.status,
|
|
23
|
+
error: s.error ? maskKeywords(s.error, keywords) : undefined,
|
|
24
|
+
verify: s.verify ? verifyToRecord(s.verify) : undefined,
|
|
25
|
+
durationMs: s.durationMs,
|
|
26
|
+
inputValueMasked: s.inputValueMasked,
|
|
27
|
+
field: s.field,
|
|
28
|
+
saved: s.saved,
|
|
29
|
+
count: s.count,
|
|
30
|
+
selectorHit: s.selectorHit,
|
|
31
|
+
cooldownKey: s.cooldownKey,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function verifyToRecord(v) {
|
|
35
|
+
// wait_selector 字段在契约示例中是具体的选择器;这里取 detail(验证点内容)
|
|
36
|
+
return {
|
|
37
|
+
waitSelector: v.detail,
|
|
38
|
+
passed: v.passed,
|
|
39
|
+
durationMs: v.durationMs,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=record.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record.js","sourceRoot":"","sources":["../src/record.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAgDxC;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAC5B,KAAa,EACb,MAAc,EACd,WAAmB,EACnB,CAAa,EACb,SAAiB,EACjB,QAAkB;IAElB,OAAO;QACL,KAAK;QACL,MAAM;QACN,WAAW;QACX,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS;QAC5D,SAAS;QACT,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;KACrD,CAAA;AACH,CAAC;AAED,SAAS,YAAY,CACnB,CAAmP,EACnP,QAAkB;IAElB,OAAO;QACL,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS;QAC5D,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS;QACvD,UAAU,EAAE,CAAC,CAAC,UAAU;QACxB,gBAAgB,EAAE,CAAC,CAAC,gBAAgB;QACpC,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,WAAW,EAAE,CAAC,CAAC,WAAW;QAC1B,WAAW,EAAE,CAAC,CAAC,WAAW;KAC3B,CAAA;AACH,CAAC;AAED,SAAS,cAAc,CAAC,CAAgB;IACtC,kDAAkD;IAClD,OAAO;QACL,YAAY,EAAE,CAAC,CAAC,MAAM;QACtB,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,UAAU,EAAE,CAAC,CAAC,UAAU;KACzB,CAAA;AACH,CAAC"}
|
package/dist/schema.d.ts
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* 流程定义 schema v1(移植自 Rust `engine/src/lib.rs`,语义逐条对应)。
|
|
4
|
+
*
|
|
5
|
+
* 契约要点(与 Rust 版一致):
|
|
6
|
+
* - 顶层字段 camelCase 序列化;`platform`/`trigger`/`version` 有默认值
|
|
7
|
+
* - 步骤类型 `type` 为 snake_case;`params` 是自由键值(动作参数由执行器解释)
|
|
8
|
+
* - `verify` 可选(缺省 = 执行器无法判定成败,schema 铁律;校验层面不强制)
|
|
9
|
+
* - 字段默认值:version=1、trigger.mode=manual、verify.timeoutMs=15000
|
|
10
|
+
*
|
|
11
|
+
* TS 扩展(Rust 版无,EXECUTION-SPEC 定案):
|
|
12
|
+
* - `inputs`(D-R6):顶层可选参数声明,供 list_flows 返回 / run_flow 必填校验
|
|
13
|
+
* - `envCheck`(D-V1):顶层可选环境风险检测配置(verifyUrls/dialogs),随流程包分发
|
|
14
|
+
* (zod 默认 strip 未知键 —— 这两个字段必须显式声明,否则被丢弃)
|
|
15
|
+
*
|
|
16
|
+
* 注意:这里不做「嵌套 loop 拒绝」——那是 EXECUTION-SPEC M4 的扩展语义,
|
|
17
|
+
* 到 M4 时在 validate 层加(避免现在加验证与基线行为分叉)。
|
|
18
|
+
* 结构错误(解析失败)走 zod 错误信息;语义校验在 validate.ts。
|
|
19
|
+
*/
|
|
20
|
+
export declare const TriggerSchema: z.ZodDefault<z.ZodObject<{
|
|
21
|
+
mode: z.ZodOptional<z.ZodString>;
|
|
22
|
+
}, z.core.$strip>>;
|
|
23
|
+
export type Trigger = {
|
|
24
|
+
mode: string;
|
|
25
|
+
};
|
|
26
|
+
export declare const StepTypeSchema: z.ZodEnum<{
|
|
27
|
+
input: "input";
|
|
28
|
+
navigate: "navigate";
|
|
29
|
+
click: "click";
|
|
30
|
+
extract: "extract";
|
|
31
|
+
next_page: "next_page";
|
|
32
|
+
loop: "loop";
|
|
33
|
+
wait: "wait";
|
|
34
|
+
finalize: "finalize";
|
|
35
|
+
}>;
|
|
36
|
+
/** 步骤类型(与 Rust `StepType` 枚举一一对应) */
|
|
37
|
+
export type StepType = z.infer<typeof StepTypeSchema>;
|
|
38
|
+
export declare const VerifySchema: z.ZodObject<{
|
|
39
|
+
waitSelector: z.ZodOptional<z.ZodString>;
|
|
40
|
+
urlContains: z.ZodOptional<z.ZodString>;
|
|
41
|
+
textContains: z.ZodOptional<z.ZodString>;
|
|
42
|
+
timeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
43
|
+
}, z.core.$loose>;
|
|
44
|
+
export type Verify = z.infer<typeof VerifySchema>;
|
|
45
|
+
export declare const StepSchema: z.ZodObject<{
|
|
46
|
+
id: z.ZodString;
|
|
47
|
+
type: z.ZodEnum<{
|
|
48
|
+
input: "input";
|
|
49
|
+
navigate: "navigate";
|
|
50
|
+
click: "click";
|
|
51
|
+
extract: "extract";
|
|
52
|
+
next_page: "next_page";
|
|
53
|
+
loop: "loop";
|
|
54
|
+
wait: "wait";
|
|
55
|
+
finalize: "finalize";
|
|
56
|
+
}>;
|
|
57
|
+
params: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
58
|
+
verify: z.ZodOptional<z.ZodObject<{
|
|
59
|
+
waitSelector: z.ZodOptional<z.ZodString>;
|
|
60
|
+
urlContains: z.ZodOptional<z.ZodString>;
|
|
61
|
+
textContains: z.ZodOptional<z.ZodString>;
|
|
62
|
+
timeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
63
|
+
}, z.core.$loose>>;
|
|
64
|
+
}, z.core.$strip>;
|
|
65
|
+
export type Step = z.infer<typeof StepSchema>;
|
|
66
|
+
/** 流程参数声明(D-R6,2026-08-25 定案):name 必填;required 默认 false;description 可选 */
|
|
67
|
+
export declare const InputSchema: z.ZodObject<{
|
|
68
|
+
name: z.ZodString;
|
|
69
|
+
required: z.ZodOptional<z.ZodBoolean>;
|
|
70
|
+
description: z.ZodOptional<z.ZodString>;
|
|
71
|
+
}, z.core.$strip>;
|
|
72
|
+
export type FlowInput = z.infer<typeof InputSchema>;
|
|
73
|
+
/** 环境风险检测配置(D-V1):verifyUrls=风险 URL 子串;dialogs=弹窗(selector + 关闭按钮链) */
|
|
74
|
+
export declare const EnvCheckSchema: z.ZodObject<{
|
|
75
|
+
verifyUrls: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
76
|
+
dialogs: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
77
|
+
selector: z.ZodString;
|
|
78
|
+
closeSelectors: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
79
|
+
}, z.core.$strip>>>;
|
|
80
|
+
}, z.core.$strip>;
|
|
81
|
+
export type EnvCheck = z.infer<typeof EnvCheckSchema>;
|
|
82
|
+
export declare const FlowSchema: z.ZodObject<{
|
|
83
|
+
id: z.ZodString;
|
|
84
|
+
name: z.ZodString;
|
|
85
|
+
platform: z.ZodDefault<z.ZodString>;
|
|
86
|
+
version: z.ZodDefault<z.ZodNumber>;
|
|
87
|
+
trigger: z.ZodDefault<z.ZodObject<{
|
|
88
|
+
mode: z.ZodOptional<z.ZodString>;
|
|
89
|
+
}, z.core.$strip>>;
|
|
90
|
+
inputs: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
91
|
+
name: z.ZodString;
|
|
92
|
+
required: z.ZodOptional<z.ZodBoolean>;
|
|
93
|
+
description: z.ZodOptional<z.ZodString>;
|
|
94
|
+
}, z.core.$strip>>>;
|
|
95
|
+
envCheck: z.ZodOptional<z.ZodObject<{
|
|
96
|
+
verifyUrls: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
97
|
+
dialogs: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
98
|
+
selector: z.ZodString;
|
|
99
|
+
closeSelectors: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
100
|
+
}, z.core.$strip>>>;
|
|
101
|
+
}, z.core.$strip>>;
|
|
102
|
+
steps: z.ZodArray<z.ZodObject<{
|
|
103
|
+
id: z.ZodString;
|
|
104
|
+
type: z.ZodEnum<{
|
|
105
|
+
input: "input";
|
|
106
|
+
navigate: "navigate";
|
|
107
|
+
click: "click";
|
|
108
|
+
extract: "extract";
|
|
109
|
+
next_page: "next_page";
|
|
110
|
+
loop: "loop";
|
|
111
|
+
wait: "wait";
|
|
112
|
+
finalize: "finalize";
|
|
113
|
+
}>;
|
|
114
|
+
params: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
115
|
+
verify: z.ZodOptional<z.ZodObject<{
|
|
116
|
+
waitSelector: z.ZodOptional<z.ZodString>;
|
|
117
|
+
urlContains: z.ZodOptional<z.ZodString>;
|
|
118
|
+
textContains: z.ZodOptional<z.ZodString>;
|
|
119
|
+
timeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
120
|
+
}, z.core.$loose>>;
|
|
121
|
+
}, z.core.$strip>>;
|
|
122
|
+
}, z.core.$strip>;
|
|
123
|
+
export type Flow = z.infer<typeof FlowSchema>;
|
|
124
|
+
/** 步骤类型全集(供执行器 / 记录器使用) */
|
|
125
|
+
export declare const STEP_TYPES: readonly StepType[];
|
|
126
|
+
/**
|
|
127
|
+
* 反序列化(结构校验)。等价 Rust `serde_json::from_str::<Flow>`。
|
|
128
|
+
* 只做结构,不做语义校验(validate.ts 的 validate 负责)。
|
|
129
|
+
*/
|
|
130
|
+
export declare function parseFlowJson(raw: unknown): Flow;
|
package/dist/schema.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* 流程定义 schema v1(移植自 Rust `engine/src/lib.rs`,语义逐条对应)。
|
|
4
|
+
*
|
|
5
|
+
* 契约要点(与 Rust 版一致):
|
|
6
|
+
* - 顶层字段 camelCase 序列化;`platform`/`trigger`/`version` 有默认值
|
|
7
|
+
* - 步骤类型 `type` 为 snake_case;`params` 是自由键值(动作参数由执行器解释)
|
|
8
|
+
* - `verify` 可选(缺省 = 执行器无法判定成败,schema 铁律;校验层面不强制)
|
|
9
|
+
* - 字段默认值:version=1、trigger.mode=manual、verify.timeoutMs=15000
|
|
10
|
+
*
|
|
11
|
+
* TS 扩展(Rust 版无,EXECUTION-SPEC 定案):
|
|
12
|
+
* - `inputs`(D-R6):顶层可选参数声明,供 list_flows 返回 / run_flow 必填校验
|
|
13
|
+
* - `envCheck`(D-V1):顶层可选环境风险检测配置(verifyUrls/dialogs),随流程包分发
|
|
14
|
+
* (zod 默认 strip 未知键 —— 这两个字段必须显式声明,否则被丢弃)
|
|
15
|
+
*
|
|
16
|
+
* 注意:这里不做「嵌套 loop 拒绝」——那是 EXECUTION-SPEC M4 的扩展语义,
|
|
17
|
+
* 到 M4 时在 validate 层加(避免现在加验证与基线行为分叉)。
|
|
18
|
+
* 结构错误(解析失败)走 zod 错误信息;语义校验在 validate.ts。
|
|
19
|
+
*/
|
|
20
|
+
// ---- 顶层 ----
|
|
21
|
+
export const TriggerSchema = z
|
|
22
|
+
.object({
|
|
23
|
+
// zod 4:trigger 整体缺省时应用 { mode: 'manual' }(对齐 Rust #[serde(default)] + default_trigger_mode)。
|
|
24
|
+
// 内层 mode 允许缺省(输入 { } 也通过),输出恒有 mode。
|
|
25
|
+
mode: z.string().optional(),
|
|
26
|
+
})
|
|
27
|
+
.default({ mode: 'manual' });
|
|
28
|
+
export const StepTypeSchema = z.enum([
|
|
29
|
+
'navigate',
|
|
30
|
+
'click',
|
|
31
|
+
'input',
|
|
32
|
+
'extract',
|
|
33
|
+
'next_page',
|
|
34
|
+
'loop',
|
|
35
|
+
'wait',
|
|
36
|
+
'finalize',
|
|
37
|
+
]);
|
|
38
|
+
export const VerifySchema = z
|
|
39
|
+
.object({
|
|
40
|
+
waitSelector: z.string().optional(),
|
|
41
|
+
urlContains: z.string().optional(),
|
|
42
|
+
textContains: z.string().optional(),
|
|
43
|
+
timeoutMs: z.number().default(15_000),
|
|
44
|
+
})
|
|
45
|
+
.passthrough();
|
|
46
|
+
export const StepSchema = z.object({
|
|
47
|
+
id: z.string(),
|
|
48
|
+
type: StepTypeSchema,
|
|
49
|
+
params: z.record(z.string(), z.unknown()).default({}),
|
|
50
|
+
verify: VerifySchema.optional(),
|
|
51
|
+
});
|
|
52
|
+
/** 流程参数声明(D-R6,2026-08-25 定案):name 必填;required 默认 false;description 可选 */
|
|
53
|
+
export const InputSchema = z.object({
|
|
54
|
+
name: z.string(),
|
|
55
|
+
required: z.boolean().optional(),
|
|
56
|
+
description: z.string().optional(),
|
|
57
|
+
});
|
|
58
|
+
/** 环境风险检测配置(D-V1):verifyUrls=风险 URL 子串;dialogs=弹窗(selector + 关闭按钮链) */
|
|
59
|
+
export const EnvCheckSchema = z.object({
|
|
60
|
+
verifyUrls: z.array(z.string()).optional(),
|
|
61
|
+
dialogs: z
|
|
62
|
+
.array(z.object({ selector: z.string(), closeSelectors: z.array(z.string()).optional() }))
|
|
63
|
+
.optional(),
|
|
64
|
+
});
|
|
65
|
+
export const FlowSchema = z.object({
|
|
66
|
+
id: z.string(),
|
|
67
|
+
name: z.string(),
|
|
68
|
+
platform: z.string().default(''),
|
|
69
|
+
version: z.number().default(1),
|
|
70
|
+
trigger: TriggerSchema,
|
|
71
|
+
inputs: z.array(InputSchema).optional(),
|
|
72
|
+
envCheck: EnvCheckSchema.optional(),
|
|
73
|
+
steps: z.array(StepSchema),
|
|
74
|
+
});
|
|
75
|
+
/** 步骤类型全集(供执行器 / 记录器使用) */
|
|
76
|
+
export const STEP_TYPES = [
|
|
77
|
+
'navigate',
|
|
78
|
+
'click',
|
|
79
|
+
'input',
|
|
80
|
+
'extract',
|
|
81
|
+
'next_page',
|
|
82
|
+
'loop',
|
|
83
|
+
'wait',
|
|
84
|
+
'finalize',
|
|
85
|
+
];
|
|
86
|
+
/**
|
|
87
|
+
* 反序列化(结构校验)。等价 Rust `serde_json::from_str::<Flow>`。
|
|
88
|
+
* 只做结构,不做语义校验(validate.ts 的 validate 负责)。
|
|
89
|
+
*/
|
|
90
|
+
export function parseFlowJson(raw) {
|
|
91
|
+
return FlowSchema.parse(raw);
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 模拟参数差异化层(sim profile)—— 从 hr-rpa-mcp `src/core/simprofile.mjs`
|
|
3
|
+
* 完整移植(Rust `simprofile.rs` 已 1:1 复刻原版,TS 直接按 Rust 语义翻译,三者一致)。
|
|
4
|
+
*
|
|
5
|
+
* 目的:让每台机器/每个实例的拟人行为参数「基准」互不相同。首次运行时用机器指纹
|
|
6
|
+
* 生成稳定的 ±15% 乘性扰动,缓存到本地 sim-profile.json,之后每次运行读同一份缓存。
|
|
7
|
+
*
|
|
8
|
+
* 原则:
|
|
9
|
+
* - BASE_SIM 的值 = human.mjs 原硬编码值(勿改,作基准)
|
|
10
|
+
* - 只扰动「行为风格」参数;不扰动「结构边界」
|
|
11
|
+
* - 纯本地,无服务器依赖
|
|
12
|
+
*/
|
|
13
|
+
/** 扰动幅度(±百分比) */
|
|
14
|
+
export declare const PERTURB_PCT = 0.15;
|
|
15
|
+
/** 统一 PRNG 接口:next() 返回 [0,1) 浮点(对应 JS `rng()`) */
|
|
16
|
+
export type Rng = () => number;
|
|
17
|
+
/**
|
|
18
|
+
* 确定性 PRNG:xorshift32(对应 hr-rpa-mcp `createRng`)。
|
|
19
|
+
* `t ^= t<<13; t ^= t>>>17; t ^= t<<5; t>>>0; return (t%1e6)/1e6`
|
|
20
|
+
*/
|
|
21
|
+
export declare class XorShift32 {
|
|
22
|
+
private s;
|
|
23
|
+
constructor(seed: number);
|
|
24
|
+
/** 无种子默认随机(等价 Rust `XorShift32::time_seeded`):取高精度时钟低 32 位作种子 */
|
|
25
|
+
static timeSeeded(): XorShift32;
|
|
26
|
+
next(): number;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* mulberry32:确定性 PRNG(hr-rpa-mcp simprofile 的机器指纹扰动用)。
|
|
30
|
+
* 全部为 32 位有符号整数运算(|0 / Math.imul / >>> 0),TS 用 >>>0 保证无符号。
|
|
31
|
+
*/
|
|
32
|
+
export declare function mulberry32(a: number): Rng;
|
|
33
|
+
/** 拟人参数配置(对应 JS BASE_SIM 全字段,camelCase) */
|
|
34
|
+
export interface SimProfile {
|
|
35
|
+
jitter: number;
|
|
36
|
+
moveMedianMs: number;
|
|
37
|
+
moveSigma: number;
|
|
38
|
+
startOffsetRange: [number, number];
|
|
39
|
+
clickJitter: number;
|
|
40
|
+
hoverRangeMs: [number, number];
|
|
41
|
+
overshootProbability: number;
|
|
42
|
+
overshootPx: [number, number];
|
|
43
|
+
overshootMedianMs: number;
|
|
44
|
+
overshootSigma: number;
|
|
45
|
+
pressMedianMs: number;
|
|
46
|
+
pressSigma: number;
|
|
47
|
+
doubleClickRangeMs: [number, number];
|
|
48
|
+
wheelRatioRange: [number, number];
|
|
49
|
+
wheelInertiaStepsRange: [number, number];
|
|
50
|
+
wheelUniformStepsRange: [number, number];
|
|
51
|
+
wheelIntervalMs: [number, number];
|
|
52
|
+
dragJitter: number;
|
|
53
|
+
pressDelayMs: [number, number];
|
|
54
|
+
releaseDelayMs: [number, number];
|
|
55
|
+
dragPreMedianMs: number;
|
|
56
|
+
dragPreSigma: number;
|
|
57
|
+
dragMoveMedianMs: number;
|
|
58
|
+
dragMoveSigma: number;
|
|
59
|
+
wpmRange: [number, number];
|
|
60
|
+
errorRate: number;
|
|
61
|
+
thinkPauseChance: number;
|
|
62
|
+
thinkPauseRangeMs: [number, number];
|
|
63
|
+
finalPauseMs: number;
|
|
64
|
+
typeSigma: number;
|
|
65
|
+
typeErrSigma: number;
|
|
66
|
+
typeBackspaceSigma: number;
|
|
67
|
+
randomClickMaxClicks: number;
|
|
68
|
+
randomClickIntervalMs: number;
|
|
69
|
+
}
|
|
70
|
+
export declare const BASE_SIM: SimProfile;
|
|
71
|
+
/** 机器指纹 → 稳定 seed:用户名/主机名/域/工作目录(不含绝对时间,同机稳定) */
|
|
72
|
+
export declare function machineSeed(): number;
|
|
73
|
+
/** 由 BASE_SIM 生成一份扰动后的 profile(对应 JS `perturbBase`) */
|
|
74
|
+
export declare function perturbBase(rng: Rng): SimProfile;
|
|
75
|
+
/** 带版本号标识的缓存文件格式(与 Rust / hr-rpa-mcp 一致:`__v` 顶键) */
|
|
76
|
+
export interface ProfileFile {
|
|
77
|
+
__v: number;
|
|
78
|
+
[key: string]: unknown;
|
|
79
|
+
}
|
|
80
|
+
/** 加载后的 profile:带 __v(与 Rust `load_sim_profile` 返回的结构一致) */
|
|
81
|
+
export interface LoadedSimProfile {
|
|
82
|
+
__v: number;
|
|
83
|
+
profile: SimProfile;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* 加载本机模拟参数:首次生成扰动并缓存,之后读缓存(同机稳定)。
|
|
87
|
+
* 任何异常都回退到 BASE_SIM(未扰动基准),绝不阻断主流程。
|
|
88
|
+
* 等价 Rust `load_sim_profile(profile_file)`。
|
|
89
|
+
*/
|
|
90
|
+
export declare function loadSimProfile(profileFile: string): LoadedSimProfile;
|
|
91
|
+
/** 从任意对象解析 SimProfile(字段缺失/类型不符 → null,等价 Rust from_value 的 ok()) */
|
|
92
|
+
export declare function parseProfile(v: unknown): SimProfile | null;
|
|
93
|
+
/** 默认缓存路径:由 app 层注入数据目录(测试传临时文件,隔离真实拟人参数) */
|
|
94
|
+
export declare function defaultProfileFile(dataDir: string): string;
|