mooncat-browser 0.2.3 → 0.2.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mooncat-browser",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "浏览器自动化工具包:可独立启动的本地服务(browserd)+ JS/TS client。双路由(WebPlater 扩展 / CDP),不依赖 mooncat 总发行体。",
5
5
  "type": "module",
6
6
  "main": "./dist/client.js",
@@ -93,9 +93,11 @@ await browser.operate({ pageHandle: tab.pageHandle, action: "click", params: { s
93
93
  快速开个页面看 Chrome 能不能起、扩展连没连。**不是程序化自动化的方式**;
94
94
  正经自动化用上面的 BrowserClient。open 的 `--route-mode` 必填(无 auto)。
95
95
 
96
- **操作清单不在本 skill 列**——`operate` 40+ 个 action(导航/交互/读取/等待/存储/截图)
97
- 是公开契约,查包内 `README.md` "operate 的 action 清单" 或
98
- `browser-op/backend/browserd.cjs``rpcOperate`(始终权威)。
96
+ **SDK 能力清单见** [references/operate-actions.md](references/operate-actions.md) —— 分两段:
97
+ BrowserClient **直接方法**(`reuseTab`/`listDownloads`/`waitFor`/`waitForDownload` 等,不走 operate)
98
+ + **operate(action)** 40+ 个 action(导航/交互/读取/等待/存储/截图)。
99
+ **两套是不同入口,别把 operate 表当全集**——reuseTab/listFrames 这些是 client 直接方法,不在 operate 表里。
100
+ 始终权威源:`browser-op/backend/browserd.cjs` 的 `rpcOperate`(action) + `src/client.ts`(直接方法)。
99
101
 
100
102
  ## 步进式 co-work 的标准节奏
101
103
 
@@ -147,4 +149,4 @@ await browser.operate({ pageHandle: tab.pageHandle, action: "click", params: { s
147
149
  - [references/collect.md](references/collect.md) — **★标准采集工作流**:三件套范式(复用 tab / 清弹窗 / 等就绪),SPA 采集必读
148
150
  - [references/probing.md](references/probing.md) — **★探查方法论**:frame 意识(元素查不到怎么系统性枚举)/ 同名消歧(位置 context)/ SOP 截图识图纪律
149
151
  - [references/high-risk.md](references/high-risk.md) — 高危平台专题(淘宝/京东/银行):扩展路由 + 验证码 + 拟人化
150
- - [references/operate-actions.md](references/operate-actions.md) — operate 40+ 个 action 速查(按导航/交互/读取/等待/存储/截图分组)
152
+ - [references/operate-actions.md](references/operate-actions.md) — **★SDK 能力清单**:BrowserClient 直接方法(reuseTab/listDownloads/waitFor 等,不走 operate)+ operate(action) 40+ 个 action。**两套分开看,别把 operate 表当全集**
@@ -1,92 +1,128 @@
1
- # operate 的 action 速查
1
+ # SDK 能力清单
2
2
 
3
- `browser.operate({ pageHandle, action, params })` 支持 40+ 个 action,覆盖导航/交互/读取/等待/存储/截图。
4
- 这是内核公开契约的速查表;完整说明见包内 `dist/actions.md`。
3
+ `BrowserClient` 有**两套**入口,不要混:
4
+
5
+ 1. **直接方法**(`browser.xxx()`)— 生命周期 / tab / cookie / 下载 / 通用等待。不走 operate。
6
+ 2. **operate(action)**(`browser.operate({ pageHandle, action, params })`)— 页面内动作(导航/交互/读取/存储/截图),40+ 个 action。
7
+
8
+ 下面两段分开列。表里没有 ≠ 工具没有 —— 先看另一段。
9
+
10
+ ## 一、BrowserClient 直接方法(不走 operate)
11
+
12
+ ### 生命周期 / tab
13
+
14
+ | 方法 | 签名 | 说明 |
15
+ | --- | --- | --- |
16
+ | `health` | `health(timeoutMs?)` → `/health` body 或 null | 探测 browserd 是否就绪 + browser 是否 open。返回 null = 连不上 |
17
+ | `open` | `open({ routeMode: "cdp"\|"extension", headless? })` → BrowserHandle | 打开/复用浏览器(幂等)。routeMode 必填(无 auto) |
18
+ | `close` | `close()` → `{ ok, closed }` | graceful 关浏览器(保留登录态)。用户满意前不要 close |
19
+ | `newTab` | `newTab({ url?, force? })` → TabInfo | 新建 tab(或复用同 url 的 tab)。返回含 `pageHandle` |
20
+ | `listTabs` | `listTabs()` → TabInfo[] | 列所有 tab(每项含 pageHandle) |
21
+ | `reuseTab` | `reuseTab({ url?, urlMatch? })` → TabInfo & { reused } | 按 url/urlMatch 找已有 tab 复用;没有才 newTab。**高危平台频繁重开触发风控,已开的 tab 应复用** |
22
+
23
+ ### cookie
24
+
25
+ | 方法 | 签名 | 说明 |
26
+ | --- | --- | --- |
27
+ | `getCookies` | `getCookies({ url?, domain? })` → `{ cookies }` | 读 cookie(按 url 或 domain 过滤) |
28
+ | `setCookies` | `setCookies(cookies[])` → `{ ok, count }` | 写 cookie |
29
+ | `clearCookies` | `clearCookies({ url? \| domain? })` | 清 cookie(按 url 或 domain;不传清该域全部) |
30
+
31
+ ### 下载(仅 extension 路,chrome.downloads API)
32
+
33
+ | 方法 | 签名 | 说明 |
34
+ | --- | --- | --- |
35
+ | `listDownloads` | `listDownloads(limit?)` → `{ downloads }` | 列最近下载(默认 20) |
36
+ | `getDownload` | `getDownload(id)` → `{ download }` | 查单个下载状态 |
37
+ | `waitForDownload` | `waitForDownload({ filenameRegex?, sinceMs?, timeoutMs?, intervalMs? })` → `{ download, reason }` | 轮询等下载完成(reason=complete 成功,timeout 超时)。**点了下载按钮后调用** |
38
+
39
+ ### 通用等待(轮询页面,复用 operate(evaluate))
40
+
41
+ | 方法 | 签名 | 说明 |
42
+ | --- | --- | --- |
43
+ | `waitFor` | `waitFor({ tab, selector?, text?, pollTimeoutMs?, intervalMs?, maxRefresh?, refreshSettleMs?, frameId? })` → `{ ok, matched, refreshCount, elapsedMs }` | 等 DOM 节点(selector)或文本(text)出现。延迟重试 + 刷新重试。SPA 异步加载用,比 sleep 固定等待稳 |
44
+
45
+ > `waitFor` 内部用 operate(evaluate) 轮询,但它本身是直接方法(语义封装,不让你手写 operate+evaluate 循环)。
46
+
47
+ ## 二、operate(action) 清单
48
+
49
+ `browser.operate({ pageHandle, action, params })` 的 40+ 个 action。**都要传 pageHandle**(从 newTab/listTabs/reuseTab 拿)。
50
+
51
+ ### 导航
52
+
53
+ | action | params | returns | 说明 | ext |
54
+ | --- | --- | --- | --- | --- |
55
+ | `goto` | `url`:string | {ok,url} | 导航到 URL,等待 DOMContentLoaded | ✓ |
56
+ | `goBack` | `timeout?`:number=15000 | {ok,url} | 后退一页 | ✓ |
57
+ | `goForward` | `timeout?`:number=15000 | {ok,url} | 前进一页 | ✓ |
58
+ | `reload` | `timeout?`:number=15000 | {ok,url} | 刷新当前页 | ✓ |
59
+ | `status` | — | {ok,url,title,readyState,textLength} | 读当前页状态 | ✓ |
5
60
 
6
61
  ### 交互
7
62
 
8
- | action | params | returns | description | ext |
63
+ | action | params | returns | 说明 | ext |
9
64
  | --- | --- | --- | --- | --- |
10
- | `clickAt` | `x`:number, `y`:number, `button`?:string=left, `clickCount`?:number=1 | {ok,x,y,route} | 坐标点击(绕过selector,CDP路真实鼠标/扩展路合成事件) | ✓ |
11
- | `clickByText` | `text`:string, `exact`?:boolean=false, `index`?:number=0, `offsetX`?:number=0, `offsetY`?:number=0 | {ok,text,x,y,match,route} | 定位可见文本后立即点击(原子,防DOM重渲染) | ✓ |
12
- | `click` | `selector`:string, `x`?:number, `y`?:number | {ok,selector} | 点击元素(或坐标x,y) | ✓ |
13
- | `fill` | `selector`:string, `value`:string | {ok,selector,value} | 在selector元素填入文本(先清空) | ✓ |
14
- | `type` | `selector`:string, `value`:string, `delay`?:number=0 | {ok,selector} | 逐字输入(带延迟,模拟键盘) | ✓ |
65
+ | `click` | `selector`:string, `x`?, `y`? | {ok,selector} | 点击元素(或坐标 x,y) | ✓ |
66
+ | `clickAt` | `x`:number, `y`:number, `button?`=left, `clickCount?`=1 | {ok,x,y,route} | 坐标点击(绕过 selector) | ✓ |
67
+ | `clickByText` | `text`:string, `exact?`=false, `index?`=0, `offsetX?`, `offsetY?` | {ok,text,x,y,match,route} | 定位可见文本后立即点击(原子,防 DOM 重渲染) | ✓ |
68
+ | `fill` | `selector`:string, `value`:string | {ok,selector,value} | 在 selector 元素填文本(先清空) | ✓ |
69
+ | `type` | `selector`:string, `value`:string, `delay?`=0 | {ok,selector} | 逐字输入(带延迟,模拟键盘) | ✓ |
15
70
  | `press` | `selector`:string, `key`:string | {ok,selector,key} | 在元素上按键 | ✓ |
16
- | `hover` | `selector`:string, `x`?:number, `y`?:number | {ok,selector} | 悬停元素(或坐标) | ✓ |
71
+ | `hover` | `selector`:string, `x`?, `y`? | {ok,selector} | 悬停(或坐标) | ✓ |
17
72
  | `focus` | `selector`:string | {ok,selector} | 聚焦元素 | ✓ |
18
- | `check` | `selector`:string | {ok,selector} | 勾选checkbox/radio | ✓ |
73
+ | `check` | `selector`:string | {ok,selector} | 勾选 checkbox/radio | ✓ |
19
74
  | `uncheck` | `selector`:string | {ok,selector} | 取消勾选 | ✓ |
20
- | `selectOption` | `selector`:string, `value`:string | {ok,selector,value} | 选择option | ✓ |
75
+ | `selectOption` | `selector`:string, `value`:string | {ok,selector,value} | 选择 option | ✓ |
21
76
  | `dblclick` | `selector`:string | {ok,selector} | 双击元素 | ✓ |
22
77
  | `mouseMove` | `x`:number, `y`:number | {ok,x,y} | 移动鼠标到坐标 | ✓ |
23
- | `clickAt` | `x`:number, `y`:number, `button`?:string=left, `clickCount`?:number=1 | {ok,x,y,route} | 坐标点击(CDP路page.mouse真实鼠标) | ✓ |
24
- | `clickByText` | `text`:string, `exact`?:boolean=false, `index`?:number=0, `offsetX`?:number=0, `offsetY`?:number=0 | {ok,text,x,y,match,route} | 定位可见文本后立即点击(CDP路原子) | ✓ |
25
- | `dragTo` | `source`:string, `target`:string | {ok,source,target} | 拖拽source到target(双兼容mouse+HTML5) | ✓ |
78
+ | `dragTo` | `source`:string, `target`:string | {ok,source,target} | 拖拽 source 到 target | ✓ |
79
+ | `setInputFiles` | `selector`:string, `files`:array, `timeout?`=10000 | {ok,selector,count} | 上传文件到 file input | ✓ |
26
80
 
27
81
  ### 读取
28
82
 
29
- | action | params | returns | description | ext |
83
+ | action | params | returns | 说明 | ext |
30
84
  | --- | --- | --- | --- | --- |
31
- | `locateVisibleText` | `text`:string, `exact`?:boolean=false, `index`?:number=0 | {ok,matches:[{text,x,y,width,height,centerX,centerY,visible}]} | 定位可见文本节点返回bbox(不返回DOM handle) | ✓ |
32
- | `locateVisibleText` | `text`:string, `exact`?:boolean=false, `index`?:number=0 | {ok,matches:[{text,x,y,width,height,centerX,centerY,visible}]} | 定位可见文本节点返回bbox | ✓ |
33
- | `innerHTML` | `selector`:string | {ok,selector,value} | 读元素innerHTML | ✓ |
34
- | `innerText` | `selector`:string | {ok,selector,value} | 读元素innerText | ✓ |
35
- | `textContent` | `selector`:string | {ok,selector,value} | 读元素textContent | ✓ |
85
+ | `snapshot` | `depth?`, `timeout?`=15000, `rootSelector?`, `interactiveOnly?`, `chunkId?`, `chunkSize?`, `refresh?` | {ok,yaml,...} | aria 无障碍快照(返回 yaml,可分块) | ✓ |
86
+ | `innerHTML` | `selector`:string | {ok,selector,value} | innerHTML | ✓ |
87
+ | `innerText` | `selector`:string | {ok,selector,value} | innerText | ✓ |
88
+ | `textContent` | `selector`:string | {ok,selector,value} | textContent | ✓ |
36
89
  | `getAttribute` | `selector`:string, `name`:string | {ok,selector,name,value} | 读元素属性 | ✓ |
37
- | `inputValue` | `selector`:string, `timeout`?:number=10000 | {ok,selector,value} | 读input/select当前值 | ✓ |
38
- | `boundingBox` | `selector`:string | {ok,selector,x,y,width,height} | 读元素包围盒(坐标+尺寸) | ✓ |
39
- | `count` | `selector`:string | {ok,selector,count} | 统计selector匹配数 | ✓ |
40
- | `snapshot` | `depth`?:number, `timeout`?:number=15000 | {ok,yaml,totalChars} | aria无障碍快照(返回yaml) | ✓ |
41
-
42
- ### 进阶
43
-
44
- | action | params | returns | description | ext |
45
- | --- | --- | --- | --- | --- |
46
- | `operateSequence` | `steps`:array | {ok,results} | 原子序列执行(locate/click/wait在同一页面上下文串行) | ✓ |
47
- | `setDialogHandler` | `handler`:string | {ok} | 设置JS对话框处理 | 仅 ext |
48
- | `operateSequence` | `steps`:array | {ok,results} | 原子序列执行 | ✓ |
49
- | `evaluate` | `source`:string, `args`?:any | 由函数返回值决定 | 执行页面JS函数(返回其结果) | ✓ |
50
- | `setInputFiles` | `selector`:string, `files`:array, `timeout`?:number=10000 | {ok,selector,count} | 上传文件到file input | ✓ |
51
-
52
- ### 导航
53
-
54
- | action | params | returns | description | ext |
55
- | --- | --- | --- | --- | --- |
56
- | `goto` | `url`:string | {ok,url} | 导航到URL,等待DOMContentLoaded | ✓ |
57
- | `goBack` | `timeout`?:number=15000 | {ok,url} | 后退一页 | ✓ |
58
- | `goForward` | `timeout`?:number=15000 | {ok,url} | 前进一页 | ✓ |
59
- | `reload` | `timeout`?:number=15000 | {ok,url} | 刷新当前页 | ✓ |
60
- | `status` | — | {ok,url,title,readyState,textLength} | 读当前页状态(url/title/readyState) | ✓ |
90
+ | `inputValue` | `selector`:string, `timeout?`=10000 | {ok,selector,value} | 读 input/select 当前值 | ✓ |
91
+ | `boundingBox` | `selector`:string | {ok,selector,x,y,width,height} | 读元素包围盒 | ✓ |
92
+ | `count` | `selector`:string | {ok,selector,count} | 统计 selector 匹配数 | ✓ |
93
+ | `locateVisibleText` | `text`:string, `exact?`=false, `index?`=0 | {ok,matches:[{text,x,y,width,height,centerX,centerY,visible}]} | 定位可见文本节点返回 bbox(不返回 DOM handle) | ✓ |
94
+ | `evaluate` | `source`:string, `args?`:any | 函数返回值 | 执行页面 JS 函数,返回其结果 | ✓ |
95
+ | `listFrames` | — | [{frameId,url,parentFrameId}] | 列当前 tab 的所有 frame(iframe 结构) | ✓ |
61
96
 
62
97
  ### 等待
63
98
 
64
- | action | params | returns | description | ext |
99
+ | action | params | returns | 说明 | ext |
65
100
  | --- | --- | --- | --- | --- |
66
- | `waitForLoadState` | `state`?:string=load, `timeout`?:number=30000 | {ok} | 等待指定加载状态 | ✓ |
67
- | `waitForSelector` | `selector`:string, `timeout`?:number=30000 | {ok,selector,visible,inViewport} | 等待selector元素可见 | ✓ |
68
- | `waitForFunction` | `source`:string, `timeout`?:number=30000 | 由函数返回值决定 | 等待页面函数返回truthy | (extension路CSP拦截eval) |
69
- | `waitForURL` | `url`:string, `timeout`?:number=30000 | {ok,url} | 等待URL匹配 | ✓ |
70
- | `waitForTimeout` | `ms`?:number=1000 | {ok,ms} | 固定等待 | ✓ |
101
+ | `waitForLoadState` | `state?`=load, `timeout?`=30000 | {ok} | 等待指定加载状态(load/domcontentloaded/networkidle) | ✓ |
102
+ | `waitForSelector` | `selector`:string, `timeout?`=30000 | {ok,selector,visible,inViewport} | selector 元素可见 | ✓ |
103
+ | `waitForFunction` | `source`:string, `timeout?`=30000 | 函数返回值 | 等页面函数返回 truthy | ✗(extension CSPeval |
104
+ | `waitForURL` | `url`:string, `timeout?`=30000 | {ok,url} | URL 匹配 | ✓ |
105
+ | `waitForTimeout` | `ms?`=1000 | {ok,ms} | 固定等待 | ✓ |
71
106
 
72
- ### 标签页
107
+ ### 存储(localStorage)
73
108
 
74
- | action | params | returns | description | ext |
109
+ | action | params | returns | 说明 | ext |
75
110
  | --- | --- | --- | --- | --- |
76
- | `closeTab` | | {ok} | 关闭当前page | ✓ |
77
- | `activate` | | {ok} | 切到最前(仅可视) | ✓ |
111
+ | `getLocalStorage` | `keys?`:array | {ok,storage} | localStorage(不传读全部) | ✓ |
112
+ | `setLocalStorage` | `items`:object | {ok,count} | localStorage | ✓ |
113
+ | `removeLocalStorage` | `keys?`:array | {ok,count} | 删 localStorage(不传删全部) | ✓ |
114
+ | `clearLocalStorage` | — | {ok} | 清空 localStorage | ✓ |
78
115
 
79
- ### 截图
116
+ ### 标签页 / 截图 / 对话框
80
117
 
81
- | action | params | returns | description | ext |
118
+ | action | params | returns | 说明 | ext |
82
119
  | --- | --- | --- | --- | --- |
83
- | `screenshot` | — | {ok,format,dataUrl} | 截整页PNG(返回dataUrl) | ✓ |
120
+ | `closeTab` | — | {ok} | 关闭当前 page | ✓ |
121
+ | `activate` | — | {ok} | 切到最前(仅可视) | ✓ |
122
+ | `screenshot` | — | {ok,format,dataUrl} | 截整页 PNG(返回 dataUrl;extension 模式需先 activate) | ✓ |
123
+ | `setDialogHandler` | `handler`:string | {ok} | 设置 JS 对话框处理 | 仅 ext |
124
+ | `operateSequence` | `steps`:array | {ok,results} | 原子序列执行(locate/click/wait 在同页面上下文串行) | ✓ |
84
125
 
85
- ### 存储
126
+ ## ext 列说明
86
127
 
87
- | action | params | returns | description | ext |
88
- | --- | --- | --- | --- | --- |
89
- | `getLocalStorage` | `keys`?:array | {ok,storage} | 读localStorage(不传keys读全部) | ✓ |
90
- | `setLocalStorage` | `items`:object | {ok,count} | 写localStorage | ✓ |
91
- | `removeLocalStorage` | `keys`?:array | {ok,count} | 删localStorage(不传keys删全部) | ✓ |
92
- | `clearLocalStorage` | — | {ok} | 清空localStorage | ✓ |
128
+ `ext=✓` 表示 action extension 路和 CDP 路行为一致。`✗` 或"仅 ext"见注释。多数 action 双路由统一(路由不泄漏原则)。