dsh-browser-view 0.8.0 → 0.8.1

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.
@@ -1,12 +1,29 @@
1
1
  import type { Locator, Page } from "playwright-core";
2
+ /** 精确层 = 标准层 + 库精确层(ui-library 注册表单一来源,新增 UI 库 = 追加 spec)。 */
3
+ export declare const DIALOG_PRECISE_SELECTORS: string;
4
+ /** 通用模糊层(未注册库兜底):子串词 + :not() 排除子节点。 */
5
+ export declare const DIALOG_FUZZY_SELECTORS: string;
2
6
  /**
3
- * 通用活动弹窗/对话框/抽屉选择器列表
4
- * 基于 W3C WAI-ARIA 规范 (role="dialog", aria-modal="true") 与现代 Web 通用命名规范
7
+ * 历史并集 = 精确层 + 模糊层。semantic.ts 弹窗上下文检测与 getActiveDialog 的
8
+ * domOrder 兜底消费(行为与抽取前的并集等价)。
5
9
  */
6
10
  export declare const ACTIVE_DIALOG_SELECTORS: string;
11
+ /** 活动弹窗解析结果:locator + 实际仲裁通道(诊断线索)。 */
12
+ export interface ActiveDialog {
13
+ locator: Locator;
14
+ via: "zIndex" | "domOrder";
15
+ z?: number;
16
+ tier?: "precise" | "fuzzy";
17
+ }
7
18
  /**
8
- * 获取当前页面上处于活动状态的最顶层弹窗容器 (Locator)
19
+ * 获取当前页面上处于活动状态的最顶层弹窗容器;无弹窗返回 null。
20
+ * ① 快速通道——并集零命中(绝大多数无弹窗的工具调用)直接返回 null,与旧行为
21
+ * 「空 locator + 下游 count 0」等价,零额外 evaluate 往返;
22
+ * ② 有弹窗时走分层选择器 + 页内 z-index/可见性仲裁(walker pickTopDialog,
23
+ * 页内逻辑单一来源),单次 round-trip;
24
+ * ③ evaluate 失败(极端 CSP/销毁竞态)或复核计数为 0 时回退文档序 last()
25
+ * 旧行为并标 via: "domOrder",不阻断主流程。
9
26
  */
10
- export declare function getActiveDialog(page: Page): Locator;
27
+ export declare function getActiveDialog(page: Page): Promise<ActiveDialog | null>;
11
28
  export declare function getActiveDialogSelectors(): string;
12
29
  //# sourceMappingURL=dialog.d.ts.map
@@ -1,3 +1,13 @@
1
- import type { Page } from "playwright-core";
2
- export declare function dragAndDropHelper(page: Page, sourceSelector: string, targetSelector: string): Promise<boolean>;
1
+ import type { Locator, Page } from "playwright-core";
2
+ export type DragChannel = "dragTo" | "mouse";
3
+ /**
4
+ * 核心:在两个已解析的 Locator 之间执行拖拽。
5
+ * 优先 Playwright dragTo(覆盖 HTML5 DnD 与多数组件库);
6
+ * 失败或调用方指定 preferMouse(如跨 Frame,dragTo 的已知限制)时
7
+ * 降级为物理鼠标序列。返回实际使用的通道。失败抛错(带可定位的诊断信息)。
8
+ */
9
+ export declare function dragAndDropLocators(page: Page, source: Locator, target: Locator, opts?: {
10
+ timeoutMs?: number;
11
+ preferMouse?: boolean;
12
+ }): Promise<DragChannel>;
3
13
  //# sourceMappingURL=drag.d.ts.map
@@ -1,6 +1,7 @@
1
1
  export * from "./types.js";
2
2
  export * from "./dom.js";
3
3
  export * from "./dialog.js";
4
+ export * from "./ui-library.js";
4
5
  export * from "./select.js";
5
6
  export * from "./virtual.js";
6
7
  export * from "./editor.js";
@@ -0,0 +1,72 @@
1
+ export declare const GENERIC: {
2
+ readonly dialogWords: readonly ["modal", "drawer", "dialog"];
3
+ readonly dialogExcludedParts: readonly ["mask", "wrap", "root", "header", "footer", "title", "close", "body", "btn"];
4
+ /** 下拉触发器内部件(点它展开) */
5
+ readonly dropdownTriggerParts: "[class*='selector'], [role='combobox']";
6
+ /** 下拉浮层容器的子串词(portal 挂载的面板) */
7
+ readonly dropdownFloatWords: readonly ["select-dropdown", "popper"];
8
+ /** 通用下拉选项行(select 状态机消费;库精确层另补) */
9
+ readonly dropdownOptionRows: "[class*='item-option']:not([class*='empty']), [class*='select-dropdown'] li:not([class*='empty'])";
10
+ /** 可交互「选项」枚举(elements 工具下拉选项清单消费) */
11
+ readonly dropdownOptionEnumeration: string;
12
+ /** 多选标签清除按钮 */
13
+ readonly dropdownClearButtons: "[class*='clear'], [aria-label*='clear']";
14
+ /** 多选标签移除按钮 */
15
+ readonly dropdownRemoveButtons: "[class*='remove'], [class*='close'], [aria-label*='close']";
16
+ /** 空态指示器 */
17
+ readonly emptyStates: "[class*='empty'], [class*='no-data'], [role='status'], [class*='item-empty']";
18
+ /** 表单项容器(宽松:BEM/-item 子串 + group + form 元素;label 反查主用) */
19
+ readonly formItemContainers: "[class*='form-item'], [class*='form__item'], [role='group'], form, .form-group";
20
+ /**
21
+ * 表单项容器(严格:带分隔符前缀,避免 platform-item 之类无关门类误命中;
22
+ * elements 工具页内 labelOf 消费)
23
+ */
24
+ readonly formItemContainersStrict: "[class*='-form-item'], [class*='__form-item'], form, .form-group";
25
+ /** 表单项宿主判定(目标是否处于表单语境;含 label 本身) */
26
+ readonly formItemHosts: "label, [class*='form-item'], [class*='form__item'], [class*='form-group']";
27
+ /** 表单项 label(dom 原语 label 反查消费) */
28
+ readonly formItemLabels: "[class*='form-item-label'], [class*='form-item__label'], [class*='label'], label";
29
+ /** 表单 label(简化集;elements 工具页内 labelOf 消费) */
30
+ readonly formLabelSimple: "[class*='label'], label";
31
+ };
32
+ export interface UILibrarySpec {
33
+ /** 库标识(诊断与文档)。 */
34
+ name: string;
35
+ /** 模态弹窗容器(参与顶层仲裁的容器级节点)。 */
36
+ modalContainers: string[];
37
+ /** 抽屉容器。 */
38
+ drawerContainers: string[];
39
+ /** 下拉浮层容器(portal 挂载的下拉面板)。 */
40
+ dropdownContainers: string[];
41
+ /** 下拉选项行。 */
42
+ dropdownOptions: string[];
43
+ }
44
+ /**
45
+ * 注册新库(示例:naive-ui):
46
+ * const naiveUi: UILibrarySpec = {
47
+ * name: "naive-ui",
48
+ * modalContainers: [".n-modal-container"],
49
+ * drawerContainers: [".n-drawer-container"],
50
+ * dropdownContainers: [".n-base-select-menu"],
51
+ * dropdownOptions: [".n-base-select-option"],
52
+ * };
53
+ * 追加到 UI_LIBRARIES 即可,弹窗顶层仲裁与下拉浮层发现自动获得该库精确层支持;
54
+ * 未注册的库仍由通用子串层兜底。配套要求:补一个该库真页面的 e2e
55
+ * (playground 模式照抄 test:enterprise),防止想当然的类名污染仲裁。
56
+ */
57
+ export declare const UI_LIBRARIES: readonly UILibrarySpec[];
58
+ /** 弹窗/抽屉容器(库精确层原料,未加 display:none 预过滤)。 */
59
+ export declare function dialogContainersOf(libs?: readonly UILibrarySpec[]): string[];
60
+ /** 弹窗模糊层选择器串:子串词 + 子节点排除(:not 双命名)+ display:none 预过滤。 */
61
+ export declare function composeDialogFuzzy(words?: readonly string[], excludedParts?: readonly string[]): string;
62
+ /** 下拉浮层容器选择器列表(库精确层 + 通用子串层,均带 display:none 预过滤)。 */
63
+ export declare function dropdownFloatSelectors(libs?: readonly UILibrarySpec[]): string[];
64
+ /** 下拉选项行选择器列表(标准层 role=option 由消费方自带 + 库精确层 + 通用子串层)。 */
65
+ export declare function dropdownOptionRowsOf(libs?: readonly UILibrarySpec[]): string[];
66
+ /** 预组合聚合常量(消费方直接 import)。 */
67
+ export declare const LIBRARY_DIALOG_CONTAINERS: readonly string[];
68
+ export declare const LIBRARY_DROPDOWN_CONTAINERS: readonly string[];
69
+ export declare const LIBRARY_DROPDOWN_OPTIONS: readonly string[];
70
+ /** walker 核心源里应包含的表单词表 token(drift-guard 测试用,见 test/ui-library.test.ts)。 */
71
+ export declare const WALKER_FORM_TOKENS: readonly string[];
72
+ //# sourceMappingURL=ui-library.d.ts.map
@@ -100,4 +100,16 @@ export declare function pushSnapshotVersion(cache: SnapshotCache | undefined, co
100
100
  }, capacity: unknown): SnapshotCache;
101
101
  /** 按版本号取历史条目;不在环形窗口内(更旧/未知)返回 undefined。 */
102
102
  export declare function snapshotVersionEntry(cache: SnapshotCache | undefined, version: number): SnapshotEntry | undefined;
103
+ /** 记录"最近一次成功操作"的导航代际(pageIdentity 打点,零成本)。 */
104
+ export declare function markStableNav(page: Page): void;
105
+ /** 当前代际距最近成功操作代际的差值(≥1 = 期间发生过导航)。 */
106
+ export declare function navSinceStable(page: Page): number;
107
+ export interface ExternalNavNote {
108
+ url: string;
109
+ at: number;
110
+ }
111
+ /** 记录一次疑似外部导航(非工具窗口内发生的 framenavigated)。 */
112
+ export declare function noteExternalNav(page: Page, url: string): void;
113
+ /** 读取并清空疑似外部导航记录,拼装 warning 文案;无记录返回 undefined。 */
114
+ export declare function drainExternalNavWarning(page: Page): string | undefined;
103
115
  //# sourceMappingURL=cache.d.ts.map
@@ -1,4 +1,4 @@
1
- /** 组件库下拉框的可见选项选择器并集 (基于通用 WAI-ARIA 与主流组件库规范)。 */
1
+ /** 组件库下拉框的可见选项枚举(ui-library 注册表单一来源,值与抽取前等价)。 */
2
2
  export declare const DROPDOWN_OPTION_SELECTOR: string;
3
3
  /** 读取 PNG 文件头(IHDR)中的宽高,不解码像素(导出供测试)。 */
4
4
  export declare function pngSize(buf: Buffer): {
@@ -60,8 +60,21 @@ export declare function unwrapDoubleEncodedScript(script: string): {
60
60
  };
61
61
  /** 工作区内落盘路径解析(拒绝穿越到工作区之外)。 */
62
62
  export declare function workspaceFilePath(cwd: string, file: string): string;
63
+ export type EvalWrapMode = "expression" | "statements-auto-return" | "statements";
64
+ export interface EvalWrapResult {
65
+ code: string;
66
+ mode: EvalWrapMode;
67
+ }
68
+ /**
69
+ * 把 eval 脚本包装成可直接交给 page.evaluate 的代码串,并标明实际执行形态。
70
+ * 语法非法时在 Node 侧抛出引擎原始错误(消息与页内 V8 同源,提前暴露)。
71
+ */
72
+ export declare function buildEvalScript(script: string): EvalWrapResult;
63
73
  /**
64
74
  * 规则化抽取:fields 定义抽取结构,next 选择器驱动翻页(maxPages 上限),
65
75
  * 行数超 maxRows 截断;format/file 控制序列化与落盘(json/csv/jsonl/markdown)。
66
76
  */
77
+ export declare function assertExpectedUrl(page: {
78
+ url(): string;
79
+ }, expectUrl: unknown, action: string): Promise<void>;
67
80
  //# sourceMappingURL=common.d.ts.map
@@ -2,12 +2,14 @@ import type { ToolRunContext } from "../../lib/types.js";
2
2
  import type { BrowserConfig } from "../types.js";
3
3
  import { targetLocator, resolveTargetLocator } from "../session.js";
4
4
  import { type FormFillResult } from "../primitives/index.js";
5
+ import * as primitives from "../primitives/index.js";
5
6
  export { targetLocator, resolveTargetLocator };
6
7
  export declare function isBotSensitiveUrl(url: string): boolean;
7
8
  export declare function clickTool(config: BrowserConfig, args: Record<string, any>, exec?: ToolRunContext): Promise<{
8
9
  url: string;
9
10
  title: string;
10
11
  viaBridge?: boolean | undefined;
12
+ warning?: string | undefined;
11
13
  effectHint?: string | undefined;
12
14
  clicked: string;
13
15
  effect: {
@@ -25,20 +27,24 @@ export declare function clickTool(config: BrowserConfig, args: Record<string, an
25
27
  url: string;
26
28
  title: string;
27
29
  viaBridge?: boolean | undefined;
30
+ warning?: string | undefined;
28
31
  clicked: string;
29
32
  }>;
30
33
  export declare function typeTool(config: BrowserConfig, args: Record<string, any>): Promise<{
31
34
  url: string;
32
35
  title: string;
33
36
  typed: boolean;
34
- editor: boolean;
37
+ typedVia: "editor";
35
38
  selector: string;
36
39
  } | {
37
40
  url: string;
38
41
  title: string;
39
- typed: boolean;
40
42
  selector: string;
41
43
  submit: boolean;
44
+ warning?: string | undefined;
45
+ focusedElement?: string | undefined;
46
+ typed: boolean;
47
+ typedVia: "fill" | "clicked" | "focus-kept";
42
48
  }>;
43
49
  export declare function pressTool(config: BrowserConfig, args: Record<string, any>): Promise<{
44
50
  url: string;
@@ -53,12 +59,14 @@ export declare function pressTool(config: BrowserConfig, args: Record<string, an
53
59
  export declare function selectTool(config: BrowserConfig, args: Record<string, any>): Promise<{
54
60
  url: string;
55
61
  title: string;
62
+ warning?: string | undefined;
56
63
  selected: string;
57
64
  selector: string;
58
65
  }>;
59
66
  export declare function evalTool(config: BrowserConfig, args: Record<string, any>): Promise<{
60
67
  scriptUnwrapped?: boolean | undefined;
61
68
  result: unknown;
69
+ mode: import("./common.js").EvalWrapMode;
62
70
  }>;
63
71
  export declare function downloadTool(config: BrowserConfig, args: Record<string, any>, exec?: ToolRunContext): Promise<{
64
72
  path: string;
@@ -140,10 +148,17 @@ export declare function transferTool(config: BrowserConfig, args: Record<string,
140
148
  direction: string;
141
149
  items: string[];
142
150
  }>;
151
+ /**
152
+ * browser_drag:在页面里把源元素拖到目标元素上。
153
+ * 源/目标各自走统一定位管线(selector / ref / what+scope / mark 四选一前缀),
154
+ * 支持 HTML5 原生拖放(dragTo)与鼠标拖动类控件(物理鼠标序列降级);
155
+ * 跨 Frame 拖拽自动绕过 dragTo 的同 Frame 限制。
156
+ */
143
157
  export declare function dragTool(config: BrowserConfig, args: Record<string, any>): Promise<{
144
158
  url: string;
145
159
  title: string;
146
160
  dragged: boolean;
161
+ via: primitives.DragChannel;
147
162
  source: string;
148
163
  target: string;
149
164
  }>;
@@ -24,11 +24,21 @@ declare function __walkerCore(): {
24
24
  };
25
25
  /** walker 核心注入后暴露给 entry 的 API(类型层)。 */
26
26
  export type WalkerApi = ReturnType<typeof __walkerCore>;
27
+ /** walker 核心序列化源(导出供 drift-guard 测试核对表单词表与注册表一致性)。 */
28
+ export declare const WALKER_CORE_SRC: string;
27
29
  /**
28
30
  * 把消费方 entry(自包含函数,签名 (payload, w: WalkerApi) => R)拼装成
29
31
  * 可被 page.evaluate 序列化的独立函数 (payload: P) => R。
30
32
  * 拼装发生在模块加载期(new Function 一次性),调用期零开销。
31
33
  */
32
34
  export declare function injectWalker<P, R>(entry: (payload: P, w: WalkerApi) => R): (payload: P) => R;
35
+ export declare const pickTopDialog: (payload: {
36
+ precise: string;
37
+ fuzzy: string;
38
+ }) => {
39
+ selector: string;
40
+ z: number;
41
+ tier: "precise" | "fuzzy";
42
+ } | null;
33
43
  export {};
34
44
  //# sourceMappingURL=walker.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-browser-view",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "DSH 插件:共享 Playwright 浏览器自动化(38 个 browser_* 工具,含 what 意图语义定位(一次调用替代快照→查找→点击)、SoM 标徽看图点击与零命中截图兜底、SPA ref 软失效重锚定、open Shadow DOM 组合树穿透、跨 Frame/IFrame 定位、视口感知动态快照、批量表单智能填充、点击效果验证与定位失败遥测、Playwright 规范代码导出、批处理、视觉回归、选择器自愈、增量快照)+ 人机协作(面板点选教学 browser_pick_element、人工接管等待、敏感操作审批硬拦截、人机混合录制、面板一键重跑)+ CDP 流式推流、拟人化轨迹与高斯击键、全景时光机、企业富控件矩阵。另附独立 MCP server 入口(bin dsh-browser-mcp,stdio),任意 MCP 客户端可直接调用全部工具。运行时依赖 playwright-core 与 @modelcontextprotocol/sdk(仅 MCP 入口,不进 DSH 插件加载链)。",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -43,6 +43,7 @@
43
43
  "test:enterprise": "tsx scripts/test-dev-server-enterprise.ts",
44
44
  "test:energy": "tsx scripts/test-dev-server-energy.ts",
45
45
  "test:shadow": "tsx scripts/test-dev-server-shadow.ts",
46
+ "test:drag": "tsx scripts/test-dev-server-drag.ts",
46
47
  "test:span": "tsx scripts/test-dev-server-clickable-span.ts",
47
48
  "test:pick": "tsx scripts/test-panel-pick.ts",
48
49
  "test:stream": "tsx scripts/test-panel-stream.ts",