bb-browser 0.3.0 → 0.4.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 +106 -130
- package/README.zh-CN.md +169 -0
- package/dist/chunk-CWLDHQGR.js +60 -0
- package/dist/chunk-CWLDHQGR.js.map +1 -0
- package/dist/cli.js +4205 -22
- package/dist/cli.js.map +1 -1
- package/dist/daemon.js +1 -1
- package/dist/mcp.js +21240 -0
- package/dist/mcp.js.map +1 -0
- package/extension/dist/background.js +700 -543
- package/extension/dist/background.js.map +1 -1
- package/extension/dist/manifest.json +1 -1
- package/package.json +12 -7
- package/dist/chunk-TUO443YI.js +0 -21
- package/dist/chunk-TUO443YI.js.map +0 -1
package/README.md
CHANGED
|
@@ -2,192 +2,168 @@
|
|
|
2
2
|
|
|
3
3
|
# bb-browser
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
### BadBoy Browser
|
|
6
|
+
|
|
7
|
+
**Your browser is the API. No keys. No bots. No scrapers.**
|
|
6
8
|
|
|
7
9
|
[](https://www.npmjs.com/package/bb-browser)
|
|
8
10
|
[](https://nodejs.org)
|
|
9
11
|
[](LICENSE)
|
|
10
12
|
|
|
13
|
+
[English](README.md) · [中文](README.zh-CN.md)
|
|
14
|
+
|
|
11
15
|
</div>
|
|
12
16
|
|
|
13
17
|
---
|
|
14
18
|
|
|
15
|
-
|
|
19
|
+
You're already logged into Gmail, Twitter, Reddit, Xiaohongshu — bb-browser lets AI agents use that. Not by stealing cookies or faking fingerprints. By **being** the browser.
|
|
16
20
|
|
|
17
21
|
```
|
|
18
|
-
AI Agent (Claude,
|
|
19
|
-
│ CLI
|
|
22
|
+
AI Agent (Claude Code, Codex, etc.)
|
|
23
|
+
│ CLI commands
|
|
20
24
|
▼
|
|
21
25
|
bb-browser CLI ──HTTP──▶ Daemon ──SSE──▶ Chrome Extension
|
|
22
26
|
│
|
|
23
27
|
▼ chrome.debugger (CDP)
|
|
24
|
-
|
|
25
|
-
(
|
|
28
|
+
Your Real Browser
|
|
29
|
+
(logged-in sites, cookies, sessions)
|
|
26
30
|
```
|
|
27
31
|
|
|
28
|
-
##
|
|
32
|
+
## Why
|
|
29
33
|
|
|
30
|
-
|
|
31
|
-
|---|---|---|
|
|
32
|
-
| 浏览器环境 | 独立的无头浏览器 | 用户的真实浏览器 |
|
|
33
|
-
| 登录态 | 没有,需要手动登录 | 复用已有的 Cookies 和会话 |
|
|
34
|
-
| 自动化检测 | 容易被识别和拦截 | `chrome.debugger` API,无指纹 |
|
|
35
|
-
| 内部系统 | 需要额外配置 VPN/代理 | 用户能访问的,它都能访问 |
|
|
34
|
+
Every scraping tool tries to **pretend** it's a browser. bb-browser **is** the browser.
|
|
36
35
|
|
|
37
|
-
|
|
36
|
+
| | Playwright / Selenium | Scraping libs | bb-browser |
|
|
37
|
+
|---|---|---|---|
|
|
38
|
+
| Browser | Headless, isolated | No browser | Your real Chrome |
|
|
39
|
+
| Login state | None, must re-login | Cookie extraction | Already there |
|
|
40
|
+
| Anti-bot | Detected easily | Cat-and-mouse game | Invisible — it IS the user |
|
|
41
|
+
| Internal sites | Need VPN/proxy setup | Can't reach | If you can see it, so can the agent |
|
|
38
42
|
|
|
39
|
-
|
|
43
|
+
## What it can do
|
|
40
44
|
|
|
41
|
-
|
|
45
|
+
### Browser Automation
|
|
42
46
|
|
|
43
47
|
```bash
|
|
44
48
|
bb-browser open https://example.com
|
|
45
|
-
bb-browser snapshot -i
|
|
46
|
-
bb-browser click @0
|
|
47
|
-
bb-browser fill @2 "
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
### 接入 Epiral Agent
|
|
51
|
-
|
|
52
|
-
通过 [Epiral CLI](https://github.com/epiral/cli) 的 Browser Bridge 接入 [Epiral Agent](https://github.com/epiral/agent),让 Agent 远程控制浏览器:
|
|
53
|
-
|
|
54
|
-
```
|
|
55
|
-
Epiral Agent → gRPC → Epiral CLI (Browser Bridge) → SSE → Chrome 扩展 → 浏览器
|
|
49
|
+
bb-browser snapshot -i # interactive elements only
|
|
50
|
+
bb-browser click @0 # click by ref
|
|
51
|
+
bb-browser fill @2 "hello" # fill input
|
|
52
|
+
bb-browser press Enter
|
|
53
|
+
bb-browser screenshot
|
|
56
54
|
```
|
|
57
55
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
## 安装
|
|
56
|
+
### Authenticated Fetch
|
|
61
57
|
|
|
62
|
-
|
|
58
|
+
Like `curl`, but with your browser's login state. No API keys, no tokens.
|
|
63
59
|
|
|
64
60
|
```bash
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
### 从源码构建
|
|
61
|
+
# Reddit — you're logged in, just fetch
|
|
62
|
+
bb-browser fetch https://www.reddit.com/api/me.json
|
|
69
63
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
cd bb-browser
|
|
73
|
-
pnpm install && pnpm build
|
|
64
|
+
# Any website's internal API — the browser handles auth
|
|
65
|
+
bb-browser fetch https://api.example.com/user/profile --json
|
|
74
66
|
```
|
|
75
67
|
|
|
76
|
-
###
|
|
77
|
-
|
|
78
|
-
1. 打开 Chrome → `chrome://extensions/`
|
|
79
|
-
2. 开启「开发者模式」
|
|
80
|
-
3. 点击「加载已解压的扩展程序」
|
|
81
|
-
4. 选择扩展目录:
|
|
82
|
-
- npm 安装:`node_modules/bb-browser/extension/`
|
|
83
|
-
- 源码构建:`packages/extension/dist/`
|
|
84
|
-
|
|
85
|
-
## 使用
|
|
68
|
+
### Network Capture
|
|
86
69
|
|
|
87
|
-
|
|
70
|
+
See what any website sends and receives — request headers, bodies, response data. Like Chrome DevTools Network tab, but from CLI.
|
|
88
71
|
|
|
89
72
|
```bash
|
|
90
|
-
bb-browser
|
|
91
|
-
|
|
73
|
+
bb-browser network requests --filter "api.example.com" --with-body --json
|
|
74
|
+
# → Full request headers (including auth/signing), full response body
|
|
75
|
+
# → See exactly how a website's API works — then build an adapter for it
|
|
92
76
|
```
|
|
93
77
|
|
|
94
|
-
###
|
|
95
|
-
|
|
96
|
-
```bash
|
|
97
|
-
# 打开网页
|
|
98
|
-
bb-browser open https://example.com
|
|
78
|
+
### Site Adapters
|
|
99
79
|
|
|
100
|
-
|
|
101
|
-
bb-browser snapshot -i
|
|
102
|
-
# 输出:
|
|
103
|
-
# - link "Learn more" [ref=0]
|
|
104
|
-
# - button "Submit" [ref=1]
|
|
105
|
-
# - textbox "Search" [ref=2]
|
|
80
|
+
Pre-built commands for popular websites. Community-driven via [bb-sites](https://github.com/epiral/bb-sites).
|
|
106
81
|
|
|
107
|
-
|
|
108
|
-
bb-browser
|
|
109
|
-
bb-browser
|
|
110
|
-
bb-browser
|
|
82
|
+
```bash
|
|
83
|
+
bb-browser site update # install adapters
|
|
84
|
+
bb-browser site reddit/thread https://reddit.com/r/... # Reddit discussion tree
|
|
85
|
+
bb-browser site twitter/user yan5xu # Twitter profile
|
|
86
|
+
bb-browser site xiaohongshu/feed # Xiaohongshu feed
|
|
87
|
+
bb-browser site hackernews/top # HN front page
|
|
111
88
|
```
|
|
112
89
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|------|------|------|
|
|
117
|
-
| **导航** | `open <url>` | 打开 URL |
|
|
118
|
-
| | `back` / `forward` / `refresh` | 导航操作 |
|
|
119
|
-
| | `close` | 关闭标签页 |
|
|
120
|
-
| **快照** | `snapshot` | 完整 DOM 树 |
|
|
121
|
-
| | `snapshot -i` | 只看可交互元素 |
|
|
122
|
-
| **交互** | `click <ref>` | 点击 |
|
|
123
|
-
| | `fill <ref> <text>` | 清空后填入 |
|
|
124
|
-
| | `type <ref> <text>` | 逐字符追加 |
|
|
125
|
-
| | `hover <ref>` | 悬停 |
|
|
126
|
-
| | `press <key>` | 按键 |
|
|
127
|
-
| | `scroll <dir> [px]` | 滚动 |
|
|
128
|
-
| | `check` / `uncheck <ref>` | 复选框 |
|
|
129
|
-
| | `select <ref> <val>` | 下拉框 |
|
|
130
|
-
| **信息** | `get text <ref>` | 元素文本 |
|
|
131
|
-
| | `get url` / `get title` | 页面信息 |
|
|
132
|
-
| | `screenshot [path]` | 截图 |
|
|
133
|
-
| | `eval "<js>"` | 执行 JavaScript |
|
|
134
|
-
| **Tab** | `tab` | 列出标签页 |
|
|
135
|
-
| | `tab new <url>` | 新标签页 |
|
|
136
|
-
| | `tab <n>` | 切换标签页 |
|
|
137
|
-
| | `tab close` | 关闭标签页 |
|
|
138
|
-
| **Frame** | `frame "<selector>"` | 进入 iframe |
|
|
139
|
-
| | `frame main` | 回到主 frame |
|
|
140
|
-
| **对话框** | `dialog accept [text]` | 接受 |
|
|
141
|
-
| | `dialog dismiss` | 拒绝 |
|
|
142
|
-
| **网络** | `network requests [filter]` | 查看请求 |
|
|
143
|
-
| | `network route "<pattern>" --abort` | 拦截 |
|
|
144
|
-
| | `network unroute` | 取消拦截 |
|
|
145
|
-
| **调试** | `console` / `errors` | 控制台/错误 |
|
|
146
|
-
| **Daemon** | `daemon` / `start` / `stop` / `status` | 管理 |
|
|
147
|
-
|
|
148
|
-
### JSON 输出
|
|
149
|
-
|
|
150
|
-
所有命令支持 `--json` 参数:
|
|
90
|
+
> Xiaohongshu has request signing (X-s headers). Our adapters call the page's own Vue/Pinia store actions — the page signs the requests itself. Zero reverse engineering needed.
|
|
91
|
+
|
|
92
|
+
## Install
|
|
151
93
|
|
|
152
94
|
```bash
|
|
153
|
-
bb-browser
|
|
154
|
-
# {"success":true,"data":"https://example.com"}
|
|
95
|
+
npm install -g bb-browser
|
|
155
96
|
```
|
|
156
97
|
|
|
157
|
-
|
|
98
|
+
Then load the Chrome extension:
|
|
158
99
|
|
|
159
|
-
|
|
100
|
+
1. `chrome://extensions/` → Enable Developer Mode
|
|
101
|
+
2. "Load unpacked" → select `node_modules/bb-browser/extension/`
|
|
102
|
+
3. Done.
|
|
160
103
|
|
|
161
104
|
```bash
|
|
162
|
-
bb-browser
|
|
163
|
-
bb-browser
|
|
164
|
-
bb-browser snapshot -i --tab 123 # 操作 site-a
|
|
165
|
-
bb-browser click @0 --tab 456 # 操作 site-b
|
|
105
|
+
bb-browser daemon # start the daemon
|
|
106
|
+
bb-browser status # verify connection
|
|
166
107
|
```
|
|
167
108
|
|
|
168
|
-
##
|
|
109
|
+
## Command Reference
|
|
110
|
+
|
|
111
|
+
| Category | Command | Description |
|
|
112
|
+
|----------|---------|-------------|
|
|
113
|
+
| **Navigate** | `open <url>` | Open URL |
|
|
114
|
+
| | `back` / `forward` / `refresh` | Navigate |
|
|
115
|
+
| | `close` | Close tab |
|
|
116
|
+
| **Snapshot** | `snapshot` | Full DOM tree |
|
|
117
|
+
| | `snapshot -i` | Interactive elements only |
|
|
118
|
+
| **Interact** | `click <ref>` | Click element |
|
|
119
|
+
| | `fill <ref> <text>` | Clear and fill |
|
|
120
|
+
| | `type <ref> <text>` | Append text |
|
|
121
|
+
| | `hover <ref>` | Hover |
|
|
122
|
+
| | `press <key>` | Keyboard (Enter, Tab, Control+a) |
|
|
123
|
+
| | `scroll <dir> [px]` | Scroll |
|
|
124
|
+
| | `check` / `uncheck <ref>` | Checkbox |
|
|
125
|
+
| | `select <ref> <val>` | Dropdown |
|
|
126
|
+
| **Data** | `get text <ref>` | Element text |
|
|
127
|
+
| | `get url` / `get title` | Page info |
|
|
128
|
+
| | `screenshot [path]` | Screenshot |
|
|
129
|
+
| | `eval "<js>"` | Run JavaScript |
|
|
130
|
+
| **Fetch** | `fetch <url> [--json]` | Authenticated HTTP fetch |
|
|
131
|
+
| **Site** | `site list` | List site adapters |
|
|
132
|
+
| | `site <name> [args]` | Run adapter |
|
|
133
|
+
| | `site update` | Update community adapters |
|
|
134
|
+
| **Network** | `network requests [filter]` | View requests |
|
|
135
|
+
| | `network requests --with-body` | Include headers & body |
|
|
136
|
+
| | `network route "<url>" --abort` | Block requests |
|
|
137
|
+
| | `network clear` | Clear records |
|
|
138
|
+
| **Tab** | `tab` | List tabs |
|
|
139
|
+
| | `tab new [url]` | New tab |
|
|
140
|
+
| | `tab <n>` | Switch tab |
|
|
141
|
+
| **Debug** | `console` / `errors` | Console & JS errors |
|
|
142
|
+
| | `trace start` / `trace stop` | Record user actions |
|
|
143
|
+
| **Daemon** | `daemon` / `stop` / `status` | Manage daemon |
|
|
144
|
+
|
|
145
|
+
All commands support `--json` for structured output and `--tab <id>` for multi-tab operations.
|
|
146
|
+
|
|
147
|
+
## Architecture
|
|
169
148
|
|
|
170
149
|
```
|
|
171
150
|
bb-browser/
|
|
172
151
|
├── packages/
|
|
173
|
-
│ ├── cli/ # CLI
|
|
174
|
-
│ ├── daemon/ # HTTP
|
|
175
|
-
│ ├── extension/ # Chrome
|
|
176
|
-
│ └── shared/ #
|
|
177
|
-
├──
|
|
178
|
-
|
|
179
|
-
└── extension/ # 构建好的扩展(npm 发布)
|
|
152
|
+
│ ├── cli/ # CLI (TypeScript, argument parsing, HTTP client)
|
|
153
|
+
│ ├── daemon/ # HTTP daemon (SSE bridge, request-response matching)
|
|
154
|
+
│ ├── extension/ # Chrome extension (Manifest V3, chrome.debugger CDP)
|
|
155
|
+
│ └── shared/ # Shared types and protocol definitions
|
|
156
|
+
├── dist/ # Build output (npm publish)
|
|
157
|
+
└── extension/ # Built extension (npm publish)
|
|
180
158
|
```
|
|
181
159
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
|
185
|
-
|
|
186
|
-
|
|
|
187
|
-
|
|
|
188
|
-
| Extension | Chrome Manifest V3 + `chrome.debugger` API |
|
|
189
|
-
| 构建 | pnpm monorepo + Turborepo + tsup + Vite |
|
|
160
|
+
| Layer | Tech |
|
|
161
|
+
|-------|------|
|
|
162
|
+
| CLI | TypeScript, zero dependencies |
|
|
163
|
+
| Daemon | Node.js HTTP + SSE |
|
|
164
|
+
| Extension | Chrome MV3 + `chrome.debugger` API |
|
|
165
|
+
| Build | pnpm monorepo + Turborepo + tsup + Vite |
|
|
190
166
|
|
|
191
|
-
##
|
|
167
|
+
## License
|
|
192
168
|
|
|
193
169
|
[MIT](LICENSE)
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# bb-browser
|
|
4
|
+
|
|
5
|
+
### 坏孩子浏览器 BadBoy Browser
|
|
6
|
+
|
|
7
|
+
**你的浏览器就是 API。不需要密钥,不需要爬虫,不需要模拟。**
|
|
8
|
+
|
|
9
|
+
[](https://www.npmjs.com/package/bb-browser)
|
|
10
|
+
[](https://nodejs.org)
|
|
11
|
+
[](LICENSE)
|
|
12
|
+
|
|
13
|
+
[English](README.md) · [中文](README.zh-CN.md)
|
|
14
|
+
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
你已经登录了 Gmail、Twitter、Reddit、小红书 — bb-browser 让 AI Agent 直接用你的浏览器。不是偷 Cookie,不是伪造指纹。是**成为**浏览器本身。
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
AI Agent (Claude Code, Codex 等)
|
|
23
|
+
│ CLI 命令
|
|
24
|
+
▼
|
|
25
|
+
bb-browser CLI ──HTTP──▶ Daemon ──SSE──▶ Chrome 扩展
|
|
26
|
+
│
|
|
27
|
+
▼ chrome.debugger (CDP)
|
|
28
|
+
你的真实浏览器
|
|
29
|
+
(已登录的网站、Cookie、会话)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## 为什么
|
|
33
|
+
|
|
34
|
+
所有爬虫工具都在**假装**是浏览器。bb-browser **就是**浏览器。
|
|
35
|
+
|
|
36
|
+
| | Playwright / Selenium | 爬虫库 | bb-browser |
|
|
37
|
+
|---|---|---|---|
|
|
38
|
+
| 浏览器 | 无头、隔离环境 | 没有浏览器 | 你的真实 Chrome |
|
|
39
|
+
| 登录态 | 没有,要重新登录 | 偷 Cookie | 已经在了 |
|
|
40
|
+
| 反爬检测 | 容易被识别 | 猫鼠游戏 | 无法检测 — 它就是用户 |
|
|
41
|
+
| 内部系统 | 需要配 VPN/代理 | 访问不了 | 你能看到的,Agent 都能用 |
|
|
42
|
+
|
|
43
|
+
## 能做什么
|
|
44
|
+
|
|
45
|
+
### 浏览器自动化
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
bb-browser open https://example.com
|
|
49
|
+
bb-browser snapshot -i # 只看可交互元素
|
|
50
|
+
bb-browser click @0 # 按 ref 点击
|
|
51
|
+
bb-browser fill @2 "hello" # 填写输入框
|
|
52
|
+
bb-browser press Enter
|
|
53
|
+
bb-browser screenshot
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### 带登录态的 Fetch
|
|
57
|
+
|
|
58
|
+
像 `curl`,但自动带上浏览器里的 Cookie 和会话。不需要 API key,不需要 token。
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# Reddit — 你已经登录了,直接 fetch
|
|
62
|
+
bb-browser fetch https://www.reddit.com/api/me.json
|
|
63
|
+
|
|
64
|
+
# 任何网站的内部 API — 浏览器自动处理认证
|
|
65
|
+
bb-browser fetch https://api.example.com/user/profile --json
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 网络抓包
|
|
69
|
+
|
|
70
|
+
查看任何网站发送和接收的完整数据 — 请求头、请求体、响应体。相当于 Chrome DevTools 的 Network 面板,但在命令行里。
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
bb-browser network requests --filter "api.example.com" --with-body --json
|
|
74
|
+
# → 完整的请求头(包括签名 header)、完整的响应体
|
|
75
|
+
# → 看清一个网站的 API 是怎么工作的 — 然后为它写 adapter
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Site Adapters — 网站 CLI 化
|
|
79
|
+
|
|
80
|
+
为热门网站预置的命令,社区驱动,通过 [bb-sites](https://github.com/epiral/bb-sites) 维护。
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
bb-browser site update # 安装/更新 adapter
|
|
84
|
+
bb-browser site reddit/thread https://reddit.com/r/... # Reddit 讨论树
|
|
85
|
+
bb-browser site twitter/user yan5xu # Twitter 用户资料
|
|
86
|
+
bb-browser site xiaohongshu/feed # 小红书推荐 Feed
|
|
87
|
+
bb-browser site hackernews/top # HN 首页
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
> 小红书有请求签名(X-s header)。我们的 adapter 通过调用页面自己的 Vue/Pinia store action 发请求 — 页面自己签名,零逆向。
|
|
91
|
+
|
|
92
|
+
## 安装
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
npm install -g bb-browser
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
加载 Chrome 扩展:
|
|
99
|
+
|
|
100
|
+
1. 打开 `chrome://extensions/` → 开启开发者模式
|
|
101
|
+
2. 点击「加载已解压的扩展程序」→ 选 `node_modules/bb-browser/extension/`
|
|
102
|
+
3. 完成。
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
bb-browser daemon # 启动 daemon
|
|
106
|
+
bb-browser status # 确认连接
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## 命令速查
|
|
110
|
+
|
|
111
|
+
| 分类 | 命令 | 说明 |
|
|
112
|
+
|------|------|------|
|
|
113
|
+
| **导航** | `open <url>` | 打开 URL |
|
|
114
|
+
| | `back` / `forward` / `refresh` | 导航 |
|
|
115
|
+
| | `close` | 关闭标签页 |
|
|
116
|
+
| **快照** | `snapshot` | 完整 DOM 树 |
|
|
117
|
+
| | `snapshot -i` | 只看可交互元素 |
|
|
118
|
+
| **交互** | `click <ref>` | 点击 |
|
|
119
|
+
| | `fill <ref> <text>` | 清空后填入 |
|
|
120
|
+
| | `type <ref> <text>` | 追加输入 |
|
|
121
|
+
| | `hover <ref>` | 悬停 |
|
|
122
|
+
| | `press <key>` | 按键(Enter, Tab, Control+a)|
|
|
123
|
+
| | `scroll <dir> [px]` | 滚动 |
|
|
124
|
+
| | `check` / `uncheck <ref>` | 复选框 |
|
|
125
|
+
| | `select <ref> <val>` | 下拉框 |
|
|
126
|
+
| **数据** | `get text <ref>` | 元素文本 |
|
|
127
|
+
| | `get url` / `get title` | 页面信息 |
|
|
128
|
+
| | `screenshot [path]` | 截图 |
|
|
129
|
+
| | `eval "<js>"` | 执行 JavaScript |
|
|
130
|
+
| **Fetch** | `fetch <url> [--json]` | 带登录态的 HTTP 请求 |
|
|
131
|
+
| **Site** | `site list` | 列出 adapter |
|
|
132
|
+
| | `site <name> [args]` | 运行 adapter |
|
|
133
|
+
| | `site update` | 更新社区 adapter |
|
|
134
|
+
| **网络** | `network requests [filter]` | 查看请求 |
|
|
135
|
+
| | `network requests --with-body` | 包含请求头和响应体 |
|
|
136
|
+
| | `network route "<url>" --abort` | 拦截请求 |
|
|
137
|
+
| | `network clear` | 清空记录 |
|
|
138
|
+
| **Tab** | `tab` | 列出标签页 |
|
|
139
|
+
| | `tab new [url]` | 新标签页 |
|
|
140
|
+
| | `tab <n>` | 切换标签页 |
|
|
141
|
+
| **调试** | `console` / `errors` | 控制台/JS 错误 |
|
|
142
|
+
| | `trace start` / `trace stop` | 录制用户操作 |
|
|
143
|
+
| **Daemon** | `daemon` / `stop` / `status` | 管理 daemon |
|
|
144
|
+
|
|
145
|
+
所有命令支持 `--json` 结构化输出和 `--tab <id>` 多标签页操作。
|
|
146
|
+
|
|
147
|
+
## 架构
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
bb-browser/
|
|
151
|
+
├── packages/
|
|
152
|
+
│ ├── cli/ # CLI(TypeScript,参数解析,HTTP 客户端)
|
|
153
|
+
│ ├── daemon/ # HTTP Daemon(SSE 桥接,请求响应匹配)
|
|
154
|
+
│ ├── extension/ # Chrome 扩展(Manifest V3,chrome.debugger CDP)
|
|
155
|
+
│ └── shared/ # 共享类型和协议定义
|
|
156
|
+
├── dist/ # 构建产物(npm 发布)
|
|
157
|
+
└── extension/ # 构建好的扩展(npm 发布)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
| 层 | 技术栈 |
|
|
161
|
+
|----|--------|
|
|
162
|
+
| CLI | TypeScript,零依赖 |
|
|
163
|
+
| Daemon | Node.js HTTP + SSE |
|
|
164
|
+
| Extension | Chrome MV3 + `chrome.debugger` API |
|
|
165
|
+
| 构建 | pnpm monorepo + Turborepo + tsup + Vite |
|
|
166
|
+
|
|
167
|
+
## 许可证
|
|
168
|
+
|
|
169
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
9
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
10
|
+
}) : x)(function(x) {
|
|
11
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
12
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
13
|
+
});
|
|
14
|
+
var __commonJS = (cb, mod) => function __require2() {
|
|
15
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
16
|
+
};
|
|
17
|
+
var __export = (target, all) => {
|
|
18
|
+
for (var name in all)
|
|
19
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
20
|
+
};
|
|
21
|
+
var __copyProps = (to, from, except, desc) => {
|
|
22
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
23
|
+
for (let key of __getOwnPropNames(from))
|
|
24
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
25
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
26
|
+
}
|
|
27
|
+
return to;
|
|
28
|
+
};
|
|
29
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
30
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
31
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
32
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
33
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
34
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
35
|
+
mod
|
|
36
|
+
));
|
|
37
|
+
|
|
38
|
+
// packages/shared/dist/index.js
|
|
39
|
+
function generateId() {
|
|
40
|
+
return crypto.randomUUID();
|
|
41
|
+
}
|
|
42
|
+
var DAEMON_PORT = 19824;
|
|
43
|
+
var DAEMON_HOST = "localhost";
|
|
44
|
+
var DAEMON_BASE_URL = `http://${DAEMON_HOST}:${DAEMON_PORT}`;
|
|
45
|
+
var SSE_HEARTBEAT_INTERVAL = 15e3;
|
|
46
|
+
var COMMAND_TIMEOUT = 3e4;
|
|
47
|
+
|
|
48
|
+
export {
|
|
49
|
+
__require,
|
|
50
|
+
__commonJS,
|
|
51
|
+
__export,
|
|
52
|
+
__toESM,
|
|
53
|
+
generateId,
|
|
54
|
+
DAEMON_PORT,
|
|
55
|
+
DAEMON_HOST,
|
|
56
|
+
DAEMON_BASE_URL,
|
|
57
|
+
SSE_HEARTBEAT_INTERVAL,
|
|
58
|
+
COMMAND_TIMEOUT
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=chunk-CWLDHQGR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../packages/shared/src/protocol.ts","../packages/shared/src/constants.ts"],"sourcesContent":["/**\n * CLI 与 Chrome Extension 之间的通信协议类型定义\n */\n\n/** 支持的操作类型 */\nexport type ActionType =\n | \"open\"\n | \"snapshot\"\n | \"click\"\n | \"hover\"\n | \"fill\"\n | \"type\"\n | \"check\"\n | \"uncheck\"\n | \"select\"\n | \"get\"\n | \"screenshot\"\n | \"close\"\n | \"wait\"\n | \"press\"\n | \"scroll\"\n | \"back\"\n | \"forward\"\n | \"refresh\"\n | \"eval\"\n | \"tab_list\"\n | \"tab_new\"\n | \"tab_select\"\n | \"tab_close\"\n | \"frame\"\n | \"frame_main\"\n | \"dialog\"\n | \"network\"\n | \"console\"\n | \"errors\"\n | \"trace\";\n\n/** 请求类型 */\nexport interface Request {\n /** 请求唯一标识 */\n id: string;\n /** 操作类型 */\n action: ActionType;\n /** 目标 URL(open 操作时必填) */\n url?: string;\n /** 元素引用(click, fill, get 操作时使用) */\n ref?: string;\n /** 输入文本(fill 操作时使用) */\n text?: string;\n /** 获取属性类型(get 操作时使用) */\n attribute?: string;\n /** 截图保存路径(screenshot 操作时使用) */\n path?: string;\n /** 是否只输出可交互元素(snapshot 命令使用) */\n interactive?: boolean;\n /** 移除空结构节点(snapshot 命令使用) */\n compact?: boolean;\n /** 限制树深度(snapshot 命令使用) */\n maxDepth?: number;\n /** JavaScript 代码(eval 命令使用) */\n script?: string;\n /** 选项值(select 命令使用) */\n value?: string;\n /** 标签页索引(tab_select, tab_close 命令使用) */\n index?: number;\n /** 标签页 ID(tab_select, tab_close 命令使用,优先于 index) */\n tabId?: number | string;\n /** CSS 选择器(frame 命令使用,定位 iframe) */\n selector?: string;\n /** dialog 响应类型(dialog 命令使用) */\n dialogResponse?: \"accept\" | \"dismiss\";\n /** prompt 对话框的输入文本(dialog accept 时可选) */\n promptText?: string;\n /** network 子命令:requests, route, unroute, clear */\n networkCommand?: \"requests\" | \"route\" | \"unroute\" | \"clear\";\n /** network route 选项 */\n routeOptions?: {\n abort?: boolean;\n body?: string;\n status?: number;\n headers?: Record<string, string>;\n };\n /** 过滤字符串(network requests, console 使用) */\n filter?: string;\n /** network requests 是否包含 body/headers */\n withBody?: boolean;\n /** console 子命令:get, clear */\n consoleCommand?: \"get\" | \"clear\";\n /** errors 子命令:get, clear */\n errorsCommand?: \"get\" | \"clear\";\n /** trace 子命令:start, stop, status */\n traceCommand?: \"start\" | \"stop\" | \"status\";\n /** 按键名(press 命令使用) */\n key?: string;\n /** 修饰键列表(press 命令使用) */\n modifiers?: string[];\n /** 滚动方向(scroll 命令使用) */\n direction?: string;\n /** 滚动距离(scroll 命令使用) */\n pixels?: number;\n /** 等待类型(wait 命令使用) */\n waitType?: string;\n /** 等待毫秒数(wait 命令使用) */\n ms?: number;\n}\n\n/** 元素引用信息 */\nexport interface RefInfo {\n /** CDP backendDOMNodeId(主定位方式) */\n backendDOMNodeId?: number;\n /** 元素的 XPath(向后兼容) */\n xpath?: string;\n /** 可访问性角色 */\n role: string;\n /** 可访问名称 */\n name?: string;\n /** 标签名 */\n tagName?: string;\n}\n\n/** 标签页信息 */\nexport interface TabInfo {\n /** 标签页在窗口中的索引(0-based) */\n index: number;\n /** 标签页 URL */\n url: string;\n /** 标签页标题 */\n title: string;\n /** 是否是当前活动标签页 */\n active: boolean;\n /** 标签页 ID */\n tabId: number;\n}\n\n/** Snapshot 命令返回的数据 */\nexport interface SnapshotData {\n /** 文本格式的可访问性树 */\n snapshot: string;\n /** 元素引用映射,key 为 ref ID */\n refs: Record<string, RefInfo>;\n}\n\n/** 网络请求信息 */\nexport interface NetworkRequestInfo {\n requestId: string;\n url: string;\n method: string;\n type: string;\n timestamp: number;\n status?: number;\n statusText?: string;\n failed?: boolean;\n failureReason?: string;\n requestHeaders?: Record<string, string>;\n requestBody?: string;\n requestBodyTruncated?: boolean;\n responseHeaders?: Record<string, string>;\n responseBody?: string;\n responseBodyBase64?: boolean;\n responseBodyTruncated?: boolean;\n mimeType?: string;\n bodyError?: string;\n}\n\n/** 控制台消息 */\nexport interface ConsoleMessageInfo {\n type: 'log' | 'info' | 'warn' | 'error' | 'debug';\n text: string;\n timestamp: number;\n url?: string;\n lineNumber?: number;\n}\n\n/** JS 错误信息 */\nexport interface JSErrorInfo {\n message: string;\n url?: string;\n lineNumber?: number;\n columnNumber?: number;\n stackTrace?: string;\n timestamp: number;\n}\n\n/** Trace 事件类型 - 录制用户操作 */\nexport interface TraceEvent {\n /** 事件类型 */\n type: 'click' | 'fill' | 'select' | 'check' | 'press' | 'scroll' | 'navigation';\n /** 时间戳 */\n timestamp: number;\n /** 事件发生时的页面 URL */\n url: string;\n \n /** 元素引用 - highlightIndex,可直接用于 @ref */\n ref?: number;\n /** 备用定位 - XPath */\n xpath?: string;\n /** CSS 选择器 */\n cssSelector?: string;\n \n /** 操作参数 - fill/select 的值 */\n value?: string;\n /** 操作参数 - press 的按键 */\n key?: string;\n /** 操作参数 - scroll 方向 */\n direction?: 'up' | 'down' | 'left' | 'right';\n /** 操作参数 - scroll 距离 */\n pixels?: number;\n /** 操作参数 - check/uncheck 状态 */\n checked?: boolean;\n \n /** 语义信息 - 元素角色 */\n elementRole?: string;\n /** 语义信息 - 元素名称 */\n elementName?: string;\n /** 语义信息 - 元素标签 */\n elementTag?: string;\n}\n\n/** Trace 录制状态 */\nexport interface TraceStatus {\n /** 是否正在录制 */\n recording: boolean;\n /** 已录制事件数量 */\n eventCount: number;\n /** 录制的标签页 ID */\n tabId?: number;\n}\n\n/** 响应数据 */\nexport interface ResponseData {\n /** 页面标题 */\n title?: string;\n /** 当前 URL */\n url?: string;\n /** Tab ID */\n tabId?: number;\n /** Snapshot 数据(snapshot 操作返回) */\n snapshotData?: SnapshotData;\n /** 获取的文本或属性值(get 操作返回) */\n value?: string;\n /** 截图路径(screenshot 操作返回) */\n screenshotPath?: string;\n /** 截图 data URL(screenshot 操作返回) */\n dataUrl?: string;\n /** eval 执行结果 */\n result?: unknown;\n /** 标签页列表(tab_list 命令返回) */\n tabs?: TabInfo[];\n /** 当前活动标签页索引(tab_list 命令返回) */\n activeIndex?: number;\n /** Frame 信息(frame 命令返回) */\n frameInfo?: {\n /** iframe 的 CSS 选择器 */\n selector?: string;\n /** iframe 的 name 属性 */\n name?: string;\n /** iframe 的 URL */\n url?: string;\n /** frame ID */\n frameId?: number;\n };\n /** dialog 信息(dialog 命令返回) */\n dialogInfo?: {\n /** 对话框类型:alert, confirm, prompt, beforeunload */\n type: string;\n /** 对话框消息 */\n message: string;\n /** 是否成功处理 */\n handled: boolean;\n };\n /** 网络请求列表(network requests 命令返回) */\n networkRequests?: NetworkRequestInfo[];\n /** 网络路由规则数量(network route/unroute 命令返回) */\n routeCount?: number;\n /** 控制台消息列表(console 命令返回) */\n consoleMessages?: ConsoleMessageInfo[];\n /** JS 错误列表(errors 命令返回) */\n jsErrors?: JSErrorInfo[];\n /** Trace 事件列表(trace stop 命令返回) */\n traceEvents?: TraceEvent[];\n /** Trace 录制状态(trace status 命令返回) */\n traceStatus?: TraceStatus;\n}\n\n/** 响应类型 */\nexport interface Response {\n /** 对应请求的 ID */\n id: string;\n /** 操作是否成功 */\n success: boolean;\n /** 成功时返回的数据 */\n data?: ResponseData;\n /** 失败时的错误信息 */\n error?: string;\n}\n\n/** SSE 事件类型 */\nexport type SSEEventType = \"connected\" | \"heartbeat\" | \"command\";\n\n/** SSE 事件数据 */\nexport interface SSEEvent {\n type: SSEEventType;\n data: unknown;\n}\n\n/** Daemon 状态 */\nexport interface DaemonStatus {\n running: boolean;\n extensionConnected: boolean;\n pendingRequests: number;\n uptime: number;\n}\n\n/**\n * 生成唯一请求 ID\n * @returns UUID v4 格式的字符串\n */\nexport function generateId(): string {\n return crypto.randomUUID();\n}\n","/**\n * bb-browser 共享常量\n */\n\n/** Daemon HTTP 服务端口 */\nexport const DAEMON_PORT = 19824;\n\n/** Daemon 主机地址 */\nexport const DAEMON_HOST = \"localhost\";\n\n/** Daemon 基础 URL */\nexport const DAEMON_BASE_URL = `http://${DAEMON_HOST}:${DAEMON_PORT}`;\n\n/** SSE 心跳间隔(毫秒) - 15秒确保 MV3 Service Worker 不休眠 */\nexport const SSE_HEARTBEAT_INTERVAL = 15000; // 15 秒\n\n/** 命令执行超时时间(毫秒) */\nexport const COMMAND_TIMEOUT = 30000; // 30 秒\n\n/** SSE 重连延迟(毫秒) */\nexport const SSE_RECONNECT_DELAY = 3000; // 3 秒\n\n/** SSE 最大重连尝试次数 */\nexport const SSE_MAX_RECONNECT_ATTEMPTS = 5;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6TO,SAAS,aAAqB;AACnC,SAAO,OAAO,WAAW;AAC3B;AC1TO,IAAM,cAAc;AAGpB,IAAM,cAAc;AAGpB,IAAM,kBAAkB,UAAU,WAAW,IAAI,WAAW;AAG5D,IAAM,yBAAyB;AAG/B,IAAM,kBAAkB;","names":[]}
|