dsh-browser-view 0.1.1 → 0.2.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/README.md +109 -15
- package/lib/client.js +1 -1
- package/lib/index.js +1913 -105
- package/lib/types/browser/extract.d.ts +13 -0
- package/lib/types/browser/recordings.d.ts +4 -9
- package/lib/types/browser/reports.d.ts +42 -0
- package/lib/types/browser/session.d.ts +16 -7
- package/lib/types/browser/tools.d.ts +222 -24
- package/lib/types/browser/types.d.ts +36 -0
- package/lib/types/client/index.d.ts +17 -7
- package/lib/types/lib/tools.d.ts +11 -0
- package/lib/types/lib/types.d.ts +2 -0
- package/package.json +2 -2
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare function toCsv(rows: Record<string, unknown>[]): string;
|
|
2
|
+
export declare function toJsonl(rows: Record<string, unknown>[]): string;
|
|
3
|
+
export declare function toMarkdownTable(rows: Record<string, unknown>[]): string;
|
|
4
|
+
/** 按格式序列化抽取结果(json 为 pretty JSON 字符串)。 */
|
|
5
|
+
export declare function serializeRows(rows: Record<string, unknown>[], format: string): string;
|
|
6
|
+
/** 由文件扩展名推断序列化格式(显式 format 优先)。 */
|
|
7
|
+
export declare function formatFromFile(file: string): string | null;
|
|
8
|
+
/**
|
|
9
|
+
* 解析 CSV 文本为行对象数组(首行为表头;支持引号包裹、双引号转义、
|
|
10
|
+
* 逗号/换行内嵌)。供 browser_replay 的 dataFile 使用。
|
|
11
|
+
*/
|
|
12
|
+
export declare function parseCsv(text: string): Record<string, string>[];
|
|
13
|
+
//# sourceMappingURL=extract.d.ts.map
|
|
@@ -1,14 +1,12 @@
|
|
|
1
|
+
import type { ReplayStep } from "./types.js";
|
|
1
2
|
/** 录制存储目录($DSH_HOME/.dsh-browser/recordings)。 */
|
|
2
3
|
export declare function recordingsDir(): string;
|
|
3
4
|
/** 名字安全化:只保留字母数字 . _ -,连续点压成下划线防路径穿越。 */
|
|
4
5
|
export declare function safeName(name: string): string;
|
|
5
6
|
/** 加载目录下所有 .json 录制进内存表;返回加载数量。坏文件静默跳过。 */
|
|
6
7
|
export declare function loadRecordings(): number;
|
|
7
|
-
/** 写一个录制到磁盘(原子替换);返回文件路径。 */
|
|
8
|
-
export declare function saveRecordingFile(name: string, steps:
|
|
9
|
-
tool: string;
|
|
10
|
-
args: any;
|
|
11
|
-
}[]): string;
|
|
8
|
+
/** 写一个录制到磁盘(原子替换);返回文件路径。formatVersion 2 起步骤可带 meta(选择器指纹)与 {{var}} 占位符。 */
|
|
9
|
+
export declare function saveRecordingFile(name: string, steps: ReplayStep[]): string;
|
|
12
10
|
/** 删除磁盘上的录制文件;返回是否存在并删除。 */
|
|
13
11
|
export declare function deleteRecordingFile(name: string): boolean;
|
|
14
12
|
/** 录制列表(面板 / browser_record list 共用)。 */
|
|
@@ -21,10 +19,7 @@ export declare function listRecordings(): Array<{
|
|
|
21
19
|
/** 录制详情(面板展开查看步骤)。 */
|
|
22
20
|
export declare function recordingDetail(name: string): {
|
|
23
21
|
name: string;
|
|
24
|
-
steps:
|
|
25
|
-
tool: string;
|
|
26
|
-
args: any;
|
|
27
|
-
}[];
|
|
22
|
+
steps: ReplayStep[];
|
|
28
23
|
} | undefined;
|
|
29
24
|
/** 删除录制(内存 + 磁盘同步);返回是否存在并删除。 */
|
|
30
25
|
export declare function deleteRecording(name: string): boolean;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/** 一步的执行结果(与 runReplay results 条目同形,外加自愈标记)。 */
|
|
2
|
+
export interface RunStepResult {
|
|
3
|
+
index: number;
|
|
4
|
+
tool: string;
|
|
5
|
+
ok: boolean;
|
|
6
|
+
error?: string;
|
|
7
|
+
healed?: boolean;
|
|
8
|
+
via?: string;
|
|
9
|
+
resolved?: string;
|
|
10
|
+
}
|
|
11
|
+
/** 一次 replay/batch 的运行记录。 */
|
|
12
|
+
export interface RunRecord {
|
|
13
|
+
runId: string;
|
|
14
|
+
ts: number;
|
|
15
|
+
kind: "replay" | "batch";
|
|
16
|
+
source: string;
|
|
17
|
+
total: number;
|
|
18
|
+
passed: number;
|
|
19
|
+
failed: number;
|
|
20
|
+
healedCount: number;
|
|
21
|
+
durationMs: number;
|
|
22
|
+
/** data 数据集模式时的行号(单次运行为 undefined)。 */
|
|
23
|
+
row?: number;
|
|
24
|
+
results: RunStepResult[];
|
|
25
|
+
}
|
|
26
|
+
/** 报告存储目录($DSH_HOME/.dsh-browser/reports)。 */
|
|
27
|
+
export declare function reportsDir(): string;
|
|
28
|
+
/** 生成 runId:YYYYMMDD-HHmmss-随机4位。 */
|
|
29
|
+
export declare function makeRunId(ts: number): string;
|
|
30
|
+
/** 追加一条运行记录;超限时截断旧行(原子替换)。 */
|
|
31
|
+
export declare function appendRun(record: RunRecord): void;
|
|
32
|
+
/** 读取全部运行记录(按时间倒序);坏行静默跳过。 */
|
|
33
|
+
export declare function listRuns(limit?: number): RunRecord[];
|
|
34
|
+
/** 最近一次运行(无记录返回 null)。 */
|
|
35
|
+
export declare function latestRun(): RunRecord | null;
|
|
36
|
+
/** 按 runId 取单条记录。 */
|
|
37
|
+
export declare function getRun(runId: string): RunRecord | null;
|
|
38
|
+
/** 生成 Markdown 回归报告。 */
|
|
39
|
+
export declare function renderMarkdownReport(runs: RunRecord[], source?: string): string;
|
|
40
|
+
/** 生成自包含 HTML 回归报告(内联样式,无外部资源)。 */
|
|
41
|
+
export declare function renderHtmlReport(runs: RunRecord[], source?: string): string;
|
|
42
|
+
//# sourceMappingURL=reports.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Page } from "playwright-core";
|
|
2
|
-
import type { BrowserConfig, ProfileState, DownloadEntry, FormField, NavEntry } from "./types.js";
|
|
2
|
+
import type { BrowserConfig, ProfileState, DownloadEntry, FormField, NavEntry, RefEntry, ReplayStep, SelectorHint } from "./types.js";
|
|
3
3
|
/** 当前活动 profile 名(默认 "default")。 */
|
|
4
4
|
export declare let currentProfile: string;
|
|
5
5
|
/** 多配置文件浏览器会话:name → 会话状态。 */
|
|
@@ -8,12 +8,15 @@ export declare const profileStates: Map<string, ProfileState>;
|
|
|
8
8
|
export declare const savedForms: Map<string, FormField[]>;
|
|
9
9
|
/** 最近一次 browser_form 填充的字段(供 browser_form_save 无参保存)。 */
|
|
10
10
|
export declare let lastFormFields: FormField[];
|
|
11
|
+
/** 记录一次 aria 快照分配的 ref(整表替换)。 */
|
|
12
|
+
export declare function setPageRefs(page: Page, refs: Map<string, RefEntry>): void;
|
|
13
|
+
/** 查询某个 ref 的定位信息;未注册返回 undefined。 */
|
|
14
|
+
export declare function pageRef(page: Page, ref: string): RefEntry | undefined;
|
|
15
|
+
/** 清空页面的 ref 表(导航/新快照时调用)。 */
|
|
16
|
+
export declare function clearPageRefs(page: Page): void;
|
|
11
17
|
/** 已保存的录制脚本:name → 步骤数组。 */
|
|
12
18
|
export declare const savedRecordings: Map<string, {
|
|
13
|
-
steps:
|
|
14
|
-
tool: string;
|
|
15
|
-
args: any;
|
|
16
|
-
}[];
|
|
19
|
+
steps: ReplayStep[];
|
|
17
20
|
savedAt: number;
|
|
18
21
|
}>;
|
|
19
22
|
/** 一次工具调用的记录(操作轨迹 / 录制 / 回放共用)。 */
|
|
@@ -24,12 +27,18 @@ export interface TestCall {
|
|
|
24
27
|
ms: number;
|
|
25
28
|
ts: number;
|
|
26
29
|
error?: string;
|
|
30
|
+
/** 录制时采集的选择器指纹(回放自愈用;register 包装层异步补齐)。 */
|
|
31
|
+
meta?: {
|
|
32
|
+
hint?: SelectorHint;
|
|
33
|
+
};
|
|
27
34
|
}
|
|
28
35
|
export declare function isRecording(): boolean;
|
|
29
36
|
export declare function startRecording(): void;
|
|
30
37
|
export declare function stopRecording(): TestCall[];
|
|
31
|
-
/**
|
|
32
|
-
export declare function
|
|
38
|
+
/** 最近一次完整录制(start→stop)的 buffer;从未录制过返回 null。 */
|
|
39
|
+
export declare function lastRecordingOf(): TestCall[] | null;
|
|
40
|
+
/** 操作轨迹追加(同时写入录制 buffer,排除 record/replay 自身)。返回存入的调用对象(供调用方补 meta)。 */
|
|
41
|
+
export declare function recordCall(call: TestCall): TestCall;
|
|
33
42
|
/** 操作轨迹(按时间倒序,最新在前)。 */
|
|
34
43
|
export declare function testLogOf(): TestCall[];
|
|
35
44
|
export declare function clearTestLog(): void;
|
|
@@ -1,12 +1,49 @@
|
|
|
1
|
-
import type { Page } from "playwright-core";
|
|
1
|
+
import type { Locator, Page } from "playwright-core";
|
|
2
2
|
import type { ToolRunContext } from "../lib/types.js";
|
|
3
|
-
import type { BrowserConfig } from "./types.js";
|
|
3
|
+
import type { BrowserConfig, ReplayStep, SelectorHint } from "./types.js";
|
|
4
|
+
import { type RunRecord } from "./reports.js";
|
|
5
|
+
/** 读取 PNG 文件头(IHDR)中的宽高,不解码像素(导出供测试)。 */
|
|
6
|
+
export declare function pngSize(buf: Buffer): {
|
|
7
|
+
width: number;
|
|
8
|
+
height: number;
|
|
9
|
+
};
|
|
10
|
+
/** 按缩放比例换算 mask 矩形(导出供测试;与页内比对共用同一套坐标语义)。 */
|
|
11
|
+
export declare function scaleRects(rects: {
|
|
12
|
+
x: number;
|
|
13
|
+
y: number;
|
|
14
|
+
width: number;
|
|
15
|
+
height: number;
|
|
16
|
+
}[], scale: number): {
|
|
17
|
+
x: number;
|
|
18
|
+
y: number;
|
|
19
|
+
width: number;
|
|
20
|
+
height: number;
|
|
21
|
+
}[];
|
|
4
22
|
export declare function openTool(config: BrowserConfig, args: Record<string, any>): Promise<{
|
|
5
23
|
url: string;
|
|
6
24
|
title: string;
|
|
7
25
|
status: string;
|
|
8
26
|
}>;
|
|
27
|
+
/**
|
|
28
|
+
* 快照文本压缩(导出供测试):
|
|
29
|
+
* - 去掉首尾空白行;
|
|
30
|
+
* - 连续空白行折叠为 1 行;
|
|
31
|
+
* - 连续重复的非空行(表格空单元格/占位行产生的噪音)折叠为「首行 + …(重复 N 行)」。
|
|
32
|
+
* 只折叠完全相同的相邻行,不重排、不删改非重复内容。
|
|
33
|
+
*/
|
|
34
|
+
export declare function compressText(text: string): string;
|
|
9
35
|
export declare function snapshotTool(config: BrowserConfig, args: Record<string, any>): Promise<{
|
|
36
|
+
url: string;
|
|
37
|
+
title: string;
|
|
38
|
+
tree: string;
|
|
39
|
+
truncated: boolean;
|
|
40
|
+
refs: number;
|
|
41
|
+
text?: undefined;
|
|
42
|
+
links?: undefined;
|
|
43
|
+
inputs?: undefined;
|
|
44
|
+
} | {
|
|
45
|
+
url: string;
|
|
46
|
+
title: string;
|
|
10
47
|
text: string;
|
|
11
48
|
truncated: boolean;
|
|
12
49
|
links: {
|
|
@@ -14,9 +51,15 @@ export declare function snapshotTool(config: BrowserConfig, args: Record<string,
|
|
|
14
51
|
href: string;
|
|
15
52
|
}[];
|
|
16
53
|
inputs: number;
|
|
17
|
-
|
|
18
|
-
|
|
54
|
+
tree?: undefined;
|
|
55
|
+
refs?: undefined;
|
|
19
56
|
}>;
|
|
57
|
+
/**
|
|
58
|
+
* 解析点击/输入目标为 Locator:selector 直译;ref 走注册表——
|
|
59
|
+
* 先试快照时的 CSS 路径并校验 role/name 仍一致(防 ref 漂移误点),
|
|
60
|
+
* 不一致则降级 getByRole(role, {name}),均失败报「ref 已失效」。
|
|
61
|
+
*/
|
|
62
|
+
export declare function targetLocator(page: Page, args: Record<string, any>): Promise<Locator>;
|
|
20
63
|
export declare function clickTool(config: BrowserConfig, args: Record<string, any>): Promise<{
|
|
21
64
|
url: string;
|
|
22
65
|
title: string;
|
|
@@ -34,6 +77,17 @@ export declare function pressTool(config: BrowserConfig, args: Record<string, an
|
|
|
34
77
|
title: string;
|
|
35
78
|
pressed: string;
|
|
36
79
|
}>;
|
|
80
|
+
/**
|
|
81
|
+
* 下拉选择原语:原生 <select> 走 selectOption;组件库下拉(antd/element/listbox)
|
|
82
|
+
* 走「点击触发框 → 等待可见选项 → 按文本点击」。找不到选项时抛出错误并附当前可见
|
|
83
|
+
* 选项清单,agent 可直接据此修正,无需再手写 eval 探查。
|
|
84
|
+
*/
|
|
85
|
+
export declare function selectTool(config: BrowserConfig, args: Record<string, any>): Promise<{
|
|
86
|
+
url: string;
|
|
87
|
+
title: string;
|
|
88
|
+
selected: string;
|
|
89
|
+
selector: string;
|
|
90
|
+
}>;
|
|
37
91
|
export declare function evalTool(config: BrowserConfig, args: Record<string, any>): Promise<{
|
|
38
92
|
result: unknown;
|
|
39
93
|
}>;
|
|
@@ -42,6 +96,13 @@ export declare function screenshotTool(config: BrowserConfig, args: Record<strin
|
|
|
42
96
|
bytes: number;
|
|
43
97
|
width: number;
|
|
44
98
|
height: number;
|
|
99
|
+
baseline: string;
|
|
100
|
+
} | {
|
|
101
|
+
path: string;
|
|
102
|
+
bytes: number;
|
|
103
|
+
width: number;
|
|
104
|
+
height: number;
|
|
105
|
+
baseline?: undefined;
|
|
45
106
|
}>;
|
|
46
107
|
export declare function waitTool(config: BrowserConfig, args: Record<string, any>): Promise<{
|
|
47
108
|
url: string;
|
|
@@ -189,6 +250,7 @@ export declare function profileTool(config: BrowserConfig, args: Record<string,
|
|
|
189
250
|
export declare function elementsTool(config: BrowserConfig, args: Record<string, any>): Promise<{
|
|
190
251
|
count: number;
|
|
191
252
|
elements: Record<string, unknown>[];
|
|
253
|
+
dropdownOptions: string[];
|
|
192
254
|
}>;
|
|
193
255
|
export declare function closeTool(): Promise<{
|
|
194
256
|
closed: boolean;
|
|
@@ -231,24 +293,48 @@ export declare function waitForLoginTool(config: BrowserConfig, args: Record<str
|
|
|
231
293
|
title: string;
|
|
232
294
|
loggedIn: boolean;
|
|
233
295
|
}>;
|
|
234
|
-
/** 断言:条件在 timeoutMs 内成立则通过,否则失败并自动截图存证据。 */
|
|
296
|
+
/** 断言:条件在 timeoutMs 内成立则通过,否则失败并自动截图存证据。visual 断言走像素比对。 */
|
|
235
297
|
export declare function assertTool(config: BrowserConfig, args: Record<string, any>, exec?: ToolRunContext): Promise<{
|
|
236
298
|
url: string;
|
|
237
299
|
title: string;
|
|
238
300
|
passed: boolean;
|
|
301
|
+
visual: {
|
|
302
|
+
baseline: string;
|
|
303
|
+
diffRatio: number;
|
|
304
|
+
diffPixels: number;
|
|
305
|
+
};
|
|
306
|
+
} | {
|
|
307
|
+
url: string;
|
|
308
|
+
title: string;
|
|
309
|
+
passed: boolean;
|
|
239
310
|
}>;
|
|
240
311
|
/** 网络记录查询:list / failed / wait / clear。 */
|
|
241
312
|
export declare function networkTool(args: Record<string, any>): Promise<{
|
|
242
313
|
cleared: boolean;
|
|
243
|
-
entries:
|
|
314
|
+
entries: never[];
|
|
244
315
|
matched?: undefined;
|
|
245
316
|
waitMs?: undefined;
|
|
317
|
+
stats?: undefined;
|
|
246
318
|
failed?: undefined;
|
|
247
319
|
} | {
|
|
248
320
|
matched: import("./session.js").NetworkEntry;
|
|
249
321
|
waitMs: number;
|
|
250
322
|
cleared?: undefined;
|
|
251
323
|
entries?: undefined;
|
|
324
|
+
stats?: undefined;
|
|
325
|
+
failed?: undefined;
|
|
326
|
+
} | {
|
|
327
|
+
stats: {
|
|
328
|
+
host: string;
|
|
329
|
+
total: number;
|
|
330
|
+
failed: number;
|
|
331
|
+
avgMs: number | null;
|
|
332
|
+
byStatus: Record<string, number>;
|
|
333
|
+
}[];
|
|
334
|
+
cleared?: undefined;
|
|
335
|
+
entries?: undefined;
|
|
336
|
+
matched?: undefined;
|
|
337
|
+
waitMs?: undefined;
|
|
252
338
|
failed?: undefined;
|
|
253
339
|
} | {
|
|
254
340
|
failed: import("./session.js").NetworkEntry[];
|
|
@@ -256,20 +342,32 @@ export declare function networkTool(args: Record<string, any>): Promise<{
|
|
|
256
342
|
entries?: undefined;
|
|
257
343
|
matched?: undefined;
|
|
258
344
|
waitMs?: undefined;
|
|
345
|
+
stats?: undefined;
|
|
259
346
|
} | {
|
|
260
347
|
entries: import("./session.js").NetworkEntry[];
|
|
261
348
|
cleared?: undefined;
|
|
262
349
|
matched?: undefined;
|
|
263
350
|
waitMs?: undefined;
|
|
351
|
+
stats?: undefined;
|
|
264
352
|
failed?: undefined;
|
|
265
353
|
}>;
|
|
354
|
+
/** 使用 args.selector 定位的工具集合(自愈与录制指纹的作用范围)。 */
|
|
355
|
+
export declare const SELECTOR_STEP_TOOLS: Set<string>;
|
|
356
|
+
/**
|
|
357
|
+
* 采集选择器指向元素的指纹(页内 evaluate;找不到元素返回 null)。
|
|
358
|
+
* 指纹是回放自愈的降级候选来源:testid / role+name / text / id / tag+text。
|
|
359
|
+
*/
|
|
360
|
+
export declare function captureSelectorHint(page: Page, selector: string): Promise<SelectorHint | null>;
|
|
361
|
+
/** 由指纹生成自愈降级候选(按优先级排序;导出供测试)。 */
|
|
362
|
+
export declare function healCandidates(hint: SelectorHint): {
|
|
363
|
+
via: string;
|
|
364
|
+
selector: string;
|
|
365
|
+
}[];
|
|
266
366
|
/** 录制管理:start / stop / save / list / delete。 */
|
|
267
367
|
export declare function recordTool(args: Record<string, any>): Promise<{
|
|
268
368
|
recording: boolean;
|
|
269
369
|
hint: string;
|
|
270
370
|
steps?: undefined;
|
|
271
|
-
saved?: undefined;
|
|
272
|
-
file?: undefined;
|
|
273
371
|
recordings?: undefined;
|
|
274
372
|
deleted?: undefined;
|
|
275
373
|
name?: undefined;
|
|
@@ -277,16 +375,18 @@ export declare function recordTool(args: Record<string, any>): Promise<{
|
|
|
277
375
|
recording: boolean;
|
|
278
376
|
steps: number;
|
|
279
377
|
hint?: undefined;
|
|
280
|
-
saved?: undefined;
|
|
281
|
-
file?: undefined;
|
|
282
378
|
recordings?: undefined;
|
|
283
379
|
deleted?: undefined;
|
|
284
380
|
name?: undefined;
|
|
285
381
|
} | {
|
|
382
|
+
hint: string;
|
|
383
|
+
warnings?: string[] | undefined;
|
|
384
|
+
varsApplied?: number | undefined;
|
|
385
|
+
stripped?: number | undefined;
|
|
286
386
|
saved: string;
|
|
287
387
|
steps: number;
|
|
388
|
+
source: string;
|
|
288
389
|
file: string;
|
|
289
|
-
hint: string;
|
|
290
390
|
recording?: undefined;
|
|
291
391
|
recordings?: undefined;
|
|
292
392
|
deleted?: undefined;
|
|
@@ -301,8 +401,6 @@ export declare function recordTool(args: Record<string, any>): Promise<{
|
|
|
301
401
|
recording?: undefined;
|
|
302
402
|
hint?: undefined;
|
|
303
403
|
steps?: undefined;
|
|
304
|
-
saved?: undefined;
|
|
305
|
-
file?: undefined;
|
|
306
404
|
deleted?: undefined;
|
|
307
405
|
name?: undefined;
|
|
308
406
|
} | {
|
|
@@ -311,29 +409,129 @@ export declare function recordTool(args: Record<string, any>): Promise<{
|
|
|
311
409
|
recording?: undefined;
|
|
312
410
|
hint?: undefined;
|
|
313
411
|
steps?: undefined;
|
|
314
|
-
saved?: undefined;
|
|
315
|
-
file?: undefined;
|
|
316
412
|
recordings?: undefined;
|
|
317
413
|
}>;
|
|
318
|
-
/**
|
|
319
|
-
export
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
}
|
|
414
|
+
/** 回放选项(自愈开关与单次尝试超时,来自 config)。 */
|
|
415
|
+
export interface ReplayOptions {
|
|
416
|
+
healing?: boolean;
|
|
417
|
+
healTimeoutMs?: number;
|
|
418
|
+
}
|
|
419
|
+
/** 回放执行器(步骤 → 工具调用),由 register.ts 注入实现 map。支持选择器自愈。 */
|
|
420
|
+
export declare function runReplay(steps: ReplayStep[], impls: Record<string, (args: any) => Promise<unknown>>, failFast: boolean, opts?: ReplayOptions): Promise<{
|
|
323
421
|
total: number;
|
|
324
422
|
passed: number;
|
|
325
423
|
failed: number;
|
|
326
|
-
|
|
424
|
+
healedCount: number;
|
|
425
|
+
stoppedAt?: number;
|
|
327
426
|
results: any[];
|
|
328
427
|
}>;
|
|
329
|
-
|
|
330
|
-
|
|
428
|
+
export interface ExtractField {
|
|
429
|
+
name: string;
|
|
430
|
+
selector: string;
|
|
431
|
+
attr?: string;
|
|
432
|
+
multiple?: boolean;
|
|
433
|
+
fields?: ExtractField[];
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* 把单页抽取结果规整为行数组:恰好一个顶层 multiple 字段时,其数组即行
|
|
437
|
+
* (行内嵌套对象为行,标量包装成 { [name]: value });否则整页算一行。
|
|
438
|
+
*/
|
|
439
|
+
export declare function rowsOfExtract(result: Record<string, any>, fields: ExtractField[]): Record<string, any>[];
|
|
440
|
+
/** 工作区内落盘路径解析(拒绝穿越到工作区之外)。 */
|
|
441
|
+
export declare function workspaceFilePath(cwd: string, file: string): string;
|
|
442
|
+
/**
|
|
443
|
+
* 规则化抽取:fields 定义抽取结构,next 选择器驱动翻页(maxPages 上限),
|
|
444
|
+
* 行数超 maxRows 截断;format/file 控制序列化与落盘(json/csv/jsonl/markdown)。
|
|
445
|
+
*/
|
|
446
|
+
export declare function extractTool(config: BrowserConfig, args: Record<string, any>, exec?: ToolRunContext): Promise<{
|
|
447
|
+
url: string;
|
|
448
|
+
title: string;
|
|
449
|
+
file?: string | undefined;
|
|
450
|
+
bytes?: number | undefined;
|
|
451
|
+
truncated: boolean;
|
|
452
|
+
rows: Record<string, any>[];
|
|
453
|
+
count: number;
|
|
454
|
+
pages: number;
|
|
455
|
+
format: string;
|
|
456
|
+
}>;
|
|
457
|
+
/**
|
|
458
|
+
* 回归报告:list 列出最近运行,show 看单条详情,
|
|
459
|
+
* export 聚合生成 Markdown/HTML 报告落盘工作区。
|
|
460
|
+
*/
|
|
461
|
+
export declare function reportTool(config: BrowserConfig, args: Record<string, any>, exec?: ToolRunContext): Promise<{
|
|
462
|
+
runs: {
|
|
463
|
+
row?: number | undefined;
|
|
464
|
+
runId: string;
|
|
465
|
+
ts: number;
|
|
466
|
+
kind: "replay" | "batch";
|
|
467
|
+
source: string;
|
|
468
|
+
total: number;
|
|
469
|
+
passed: number;
|
|
470
|
+
failed: number;
|
|
471
|
+
healedCount: number;
|
|
472
|
+
durationMs: number;
|
|
473
|
+
}[];
|
|
474
|
+
run?: undefined;
|
|
475
|
+
file?: undefined;
|
|
476
|
+
bytes?: undefined;
|
|
477
|
+
format?: undefined;
|
|
478
|
+
} | {
|
|
479
|
+
run: RunRecord;
|
|
480
|
+
runs?: undefined;
|
|
481
|
+
file?: undefined;
|
|
482
|
+
bytes?: undefined;
|
|
483
|
+
format?: undefined;
|
|
484
|
+
} | {
|
|
485
|
+
file: string;
|
|
486
|
+
bytes: number;
|
|
487
|
+
runs: number;
|
|
488
|
+
format: string;
|
|
489
|
+
run?: undefined;
|
|
490
|
+
}>;
|
|
491
|
+
/**
|
|
492
|
+
* 动作批处理:一次调用顺序执行多个浏览器步骤(内核复用 runReplay),
|
|
493
|
+
* 减少「点击→等待→输入」类固定小序列的工具往返。步骤内禁止嵌套
|
|
494
|
+
* batch/replay/record;批整体在操作轨迹里记为一条 browser_batch。
|
|
495
|
+
*/
|
|
496
|
+
export declare function batchTool(args: Record<string, any>, impls: Record<string, (args: any) => Promise<unknown>>, config?: BrowserConfig): Promise<{
|
|
497
|
+
summary: string;
|
|
498
|
+
total: number;
|
|
499
|
+
passed: number;
|
|
500
|
+
failed: number;
|
|
501
|
+
healedCount: number;
|
|
502
|
+
stoppedAt?: number;
|
|
503
|
+
results: any[];
|
|
504
|
+
}>;
|
|
505
|
+
/** 收集步骤中所有 {{var}} 占位符名(导出供测试)。 */
|
|
506
|
+
export declare function findPlaceholders(steps: ReplayStep[]): string[];
|
|
507
|
+
/**
|
|
508
|
+
* 深拷贝步骤并替换字符串叶子里的 {{var}} 占位符(导出供测试)。
|
|
509
|
+
* vars 缺失的占位符保留原样(由调用方先 findPlaceholders 校验)。
|
|
510
|
+
*/
|
|
511
|
+
export declare function substituteVars(steps: ReplayStep[], vars: Record<string, unknown>): ReplayStep[];
|
|
512
|
+
/**
|
|
513
|
+
* 回放入口:name(已保存录制)或 steps(数组)二选一。
|
|
514
|
+
* vars 注入 {{占位符}};data/dataFile 数据集模式逐行运行并聚合。
|
|
515
|
+
*/
|
|
516
|
+
export declare function replayTool(args: Record<string, any>, impls: Record<string, (args: any) => Promise<unknown>>, config?: BrowserConfig, exec?: ToolRunContext): Promise<{
|
|
517
|
+
source: string;
|
|
518
|
+
rows: number;
|
|
519
|
+
passedRows: number;
|
|
520
|
+
failedRows: number;
|
|
521
|
+
runs: any[];
|
|
522
|
+
summary: string;
|
|
523
|
+
} | {
|
|
331
524
|
summary: string;
|
|
332
525
|
total: number;
|
|
333
526
|
passed: number;
|
|
334
527
|
failed: number;
|
|
335
|
-
|
|
528
|
+
healedCount: number;
|
|
529
|
+
stoppedAt?: number;
|
|
336
530
|
results: any[];
|
|
337
531
|
source: string;
|
|
532
|
+
rows?: undefined;
|
|
533
|
+
passedRows?: undefined;
|
|
534
|
+
failedRows?: undefined;
|
|
535
|
+
runs?: undefined;
|
|
338
536
|
}>;
|
|
339
537
|
//# sourceMappingURL=tools.d.ts.map
|
|
@@ -8,6 +8,8 @@ export interface BrowserConfig {
|
|
|
8
8
|
profiles?: Record<string, Partial<BrowserConfig>>;
|
|
9
9
|
screenshotDir?: string;
|
|
10
10
|
downloadDir?: string;
|
|
11
|
+
/** 截图/下载/上传的落盘基准目录(默认探测会话 cwd;显式指定后优先)。 */
|
|
12
|
+
workspaceDir?: string;
|
|
11
13
|
/** 截图保留天数(0 = 不按时间清理)。 */
|
|
12
14
|
screenshotMaxAgeDays?: number;
|
|
13
15
|
/** 截图保留数量上限(0 = 不按数量清理)。 */
|
|
@@ -19,6 +21,16 @@ export interface BrowserConfig {
|
|
|
19
21
|
maxTextChars?: number;
|
|
20
22
|
maxLinks?: number;
|
|
21
23
|
timeoutMs?: number;
|
|
24
|
+
/** 视觉回归基线截图目录(默认 .dsh-browser/baselines,不受截图清理策略约束)。 */
|
|
25
|
+
baselineDir?: string;
|
|
26
|
+
/** 回放/批处理时的选择器自愈(默认 true;只作用于失败路径,live 工具不受影响)。 */
|
|
27
|
+
selectorHealing?: boolean;
|
|
28
|
+
/** 自愈时单次尝试的超时毫秒(默认 3000,避免等满全局超时)。 */
|
|
29
|
+
healTimeoutMs?: number;
|
|
30
|
+
/** ARIA 快照每次分配的最大 ref 数(默认 200)。 */
|
|
31
|
+
maxRefs?: number;
|
|
32
|
+
/** browser_extract 单次最多聚合的行数(默认 1000)。 */
|
|
33
|
+
maxRows?: number;
|
|
22
34
|
}
|
|
23
35
|
/** 一个命名 profile 的会话状态。 */
|
|
24
36
|
export interface ProfileState {
|
|
@@ -52,4 +64,28 @@ export interface FormField {
|
|
|
52
64
|
label?: string;
|
|
53
65
|
value?: string;
|
|
54
66
|
}
|
|
67
|
+
/** ARIA 快照分配的 ref 注册项(ref → 定位信息)。 */
|
|
68
|
+
export interface RefEntry {
|
|
69
|
+
role: string;
|
|
70
|
+
name: string;
|
|
71
|
+
/** 生成快照时计算的稳定 CSS 路径(优先 #id / [data-testid] / nth-of-type 链)。 */
|
|
72
|
+
selector: string;
|
|
73
|
+
}
|
|
74
|
+
/** 录制时采集的选择器指纹(回放自愈的降级候选来源)。 */
|
|
75
|
+
export interface SelectorHint {
|
|
76
|
+
testid?: string;
|
|
77
|
+
role?: string;
|
|
78
|
+
name?: string;
|
|
79
|
+
id?: string;
|
|
80
|
+
text?: string;
|
|
81
|
+
tag?: string;
|
|
82
|
+
}
|
|
83
|
+
/** 录制/回放的一步(formatVersion 2 起支持 meta.hint 选择器指纹)。 */
|
|
84
|
+
export interface ReplayStep {
|
|
85
|
+
tool: string;
|
|
86
|
+
args: any;
|
|
87
|
+
meta?: {
|
|
88
|
+
hint?: SelectorHint;
|
|
89
|
+
};
|
|
90
|
+
}
|
|
55
91
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1,16 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* dsh-browser
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
2
|
+
* dsh-browser-view client half:
|
|
3
|
+
* 1. "settings.section" -> A "🌐 浏览器" page in the official dsh settings
|
|
4
|
+
* dialog managing saved browser recordings with polished header & icon.
|
|
5
|
+
* 2. "shell.overlay" -> Universal floating widget (FAB + live screenshot
|
|
6
|
+
* thumbnail panel + full-size inspection modal) rendered natively in both
|
|
7
|
+
* Electron desktop and web client.
|
|
7
8
|
*/
|
|
8
9
|
import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
|
|
10
|
+
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
11
|
+
interface SlotMap {
|
|
12
|
+
'shell.overlay': {
|
|
13
|
+
kind: 'list';
|
|
14
|
+
scope: 'root';
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
}
|
|
9
18
|
/** Required services (cordis fiber inject). */
|
|
10
19
|
export declare const inject: string[];
|
|
11
20
|
/**
|
|
12
|
-
* Register the
|
|
13
|
-
*
|
|
21
|
+
* Register the browser extension components:
|
|
22
|
+
* 1. settings.section -> "🌐 浏览器" page in settings
|
|
23
|
+
* 2. shell.overlay -> Universal floating live screenshot widget (Desktop & Web)
|
|
14
24
|
*/
|
|
15
25
|
export declare function apply(ctx: ClientContext): void;
|
|
16
26
|
//# sourceMappingURL=index.d.ts.map
|
package/lib/types/lib/tools.d.ts
CHANGED
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
import type { PlainToolDefinition, ToolRunContext } from "./types.js";
|
|
2
|
+
/** 注入日志函数(插件 apply 时调用一次)。 */
|
|
3
|
+
export declare function setToolsLogger(fn: ((message: string) => void) | null): void;
|
|
2
4
|
/**
|
|
3
5
|
* Resolve the workspace working directory for one tool execution.
|
|
4
6
|
* Prefers the calling agent's session cwd; falls back to the host process cwd.
|
|
5
7
|
*/
|
|
6
8
|
export declare function workspaceCwd(exec: ToolRunContext | undefined): string;
|
|
9
|
+
/**
|
|
10
|
+
* 截图/下载/上传等文件的落盘基准目录:
|
|
11
|
+
* 1. config.workspaceDir 显式指定(相对路径按 process.cwd() 解析)——最高优先;
|
|
12
|
+
* 2. 会话 cwd 探测链(workspaceCwd);
|
|
13
|
+
* 首次解析打一次日志,记录来源,便于诊断「文件落错位置」类问题。
|
|
14
|
+
*/
|
|
15
|
+
export declare function workspaceBaseDir(config: {
|
|
16
|
+
workspaceDir?: string;
|
|
17
|
+
}, exec: ToolRunContext | undefined): string;
|
|
7
18
|
/** definePlainTool 的输入选项。 */
|
|
8
19
|
export interface PlainToolOptions {
|
|
9
20
|
name: string;
|
package/lib/types/lib/types.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-browser-view",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "DSH 插件:共享 Playwright 浏览器自动化(
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "DSH 插件:共享 Playwright 浏览器自动化(31 个 browser_* 工具,含 ARIA ref 交互、批处理、视觉回归、选择器自愈、参数化回放、结构化抽取与回归报告)+ 原生界面实时画面面板 + 官方设置弹窗内的浏览器录制管理。仅依赖 playwright-core,不依赖任何 @deepseek-ai 运行时包。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
7
7
|
"types": "./lib/types/index.d.ts",
|