dsh-inner-browser-use 0.11.44 → 0.18.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 +112 -75
- package/README.zh.md +90 -45
- package/client.js +473 -3276
- package/docs/ARCHITECTURE.md +196 -150
- package/docs/BENCH.md +234 -0
- package/docs/COMPATIBILITY.md +72 -102
- package/docs/ROADMAP.md +176 -0
- package/docs/VERIFY.md +131 -415
- package/index.js +230 -1117
- package/locale/en.json +11 -22
- package/locale/zh.json +11 -22
- package/package.json +12 -5
- package/read.js +718 -0
- package/scripts/doctor.mjs +89 -0
- package/sidecar.js +1364 -0
- package/tools.js +1652 -0
- package/docs/upstream/cookie-persistence.md +0 -52
package/README.md
CHANGED
|
@@ -1,119 +1,156 @@
|
|
|
1
1
|
# dsh-inner-browser-use
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A Chrome that the agent owns, mirrored into the right column of DeepSeek Harness.
|
|
4
4
|
|
|
5
|
-
The agent
|
|
5
|
+
The agent opens pages, reads them, clicks, types and scrolls. The browser is a separate
|
|
6
|
+
Chrome with its own profile on disk, not the tab the product ships: the column shows a
|
|
7
|
+
live picture of that browser, and your own cursor keeps working on the picture.
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
## What you get
|
|
9
|
+
## Tools
|
|
10
10
|
|
|
11
11
|
| Tool | What it does |
|
|
12
12
|
| --- | --- |
|
|
13
|
-
| `
|
|
14
|
-
| `
|
|
15
|
-
| `
|
|
16
|
-
| `
|
|
17
|
-
| `
|
|
18
|
-
| `
|
|
19
|
-
| `
|
|
20
|
-
| `
|
|
21
|
-
| `
|
|
22
|
-
|
|
13
|
+
| `sidecar_open` | Starts the browser (or reuses the running one) and opens an address. `headless: false` shows a real window on the desktop instead. |
|
|
14
|
+
| `sidecar_view` | Returns the address, the title, every control as `1 … 120`, and the visible text. |
|
|
15
|
+
| `sidecar_extract` | Returns the items a CSS selector matches, one compact line each with its link, instead of the whole page. |
|
|
16
|
+
| `sidecar_click` | Clicks a numbered control, or an `x`/`y` point. `double: true` double-clicks. A cookie banner or modal over the control is cleared first, then the click happens. |
|
|
17
|
+
| `sidecar_type` | Types text into the focused field, or clicks a numbered control first. Chinese goes in as one string. `submit: true` presses Enter. |
|
|
18
|
+
| `sidecar_key` | Presses one key: Enter, Tab, Escape, Backspace, Delete, ArrowUp/Down, Home, End, PageUp, PageDown. |
|
|
19
|
+
| `sidecar_scroll` | Scrolls the wheel at the centre of the page, or at `x`/`y`. `dy: 600` is about a screen down. |
|
|
20
|
+
| `sidecar_shot` | Saves a full-size PNG into `~/.dsh-inner-browser-use/screenshots` and returns the path. |
|
|
21
|
+
| `sidecar_state` | Reports whether the browser runs, which profile it uses, its address and title, and how many columns are showing it. |
|
|
22
|
+
|
|
23
|
+
`sidecar_view` answers with one page of text:
|
|
23
24
|
|
|
24
|
-
|
|
25
|
+
```
|
|
26
|
+
https://example.com
|
|
27
|
+
Example Domain
|
|
25
28
|
|
|
26
|
-
|
|
29
|
+
1 [a] More information
|
|
30
|
+
7 [input] Search
|
|
31
|
+
```
|
|
27
32
|
|
|
28
|
-
|
|
33
|
+
Numbers stay valid until the next read. Anything that changes the page returns a fresh read.
|
|
29
34
|
|
|
30
|
-
The
|
|
31
|
-
folder of that working directory:
|
|
35
|
+
## The column
|
|
32
36
|
|
|
33
|
-
|
|
34
|
-
.
|
|
35
|
-
.gitignore keeps the folder out of your project's own version control
|
|
36
|
-
screenshots/ PNGs from browser_screenshot
|
|
37
|
-
downloads/ files the page offered to browser_download
|
|
38
|
-
```
|
|
37
|
+
The pane is a picture of the browser, sent as JPEG over the session's own stream: 1440×900,
|
|
38
|
+
quality 72, every frame, about 82 KB and 25 per second on a page at rest.
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
Two pointers live on that picture:
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
- **The black arrow** is the agent. It marks where its last click landed, and it moves the
|
|
43
|
+
moment a new one is dispatched, without waiting for the page to repaint.
|
|
44
|
+
- **Your cursor** is the real one. Hovering, clicking, the wheel and keystrokes are sent to
|
|
45
|
+
the browser as real mouse and keyboard input, so a site that rejects scripted clicks still
|
|
46
|
+
works. Moving your mouse never moves the black arrow.
|
|
47
|
+
|
|
48
|
+
The address row above the picture is an address bar: type an address and press Enter, or use
|
|
49
|
+
back, forward and reload. The field follows the page except while you are editing it.
|
|
50
|
+
|
|
51
|
+
Typing arrives two ways: composed text (Chinese, emoji, anything the input method produces)
|
|
52
|
+
lands as one insertion, and keys arrive as themselves, so Backspace deletes one character on
|
|
53
|
+
the page.
|
|
54
|
+
|
|
55
|
+
The pane opens only in the session that asked for it. A tool call in another session drives
|
|
56
|
+
the same browser without taking the column that someone else is reading.
|
|
57
|
+
|
|
58
|
+
## Logins
|
|
59
|
+
|
|
60
|
+
The profile is a directory of its own: `~/.dsh/inner-browser-use/chrome/default`. It sits
|
|
61
|
+
outside the product's browser storage, which is created per process and gone on restart, so a
|
|
62
|
+
sign-in here is still there the next day.
|
|
45
63
|
|
|
46
|
-
|
|
64
|
+
- **Plugin reload.** A reload adopts the Chrome that is still running, with the page it was on.
|
|
65
|
+
- **Harness restart.** The same directory is opened again, so cookies, `localStorage` and
|
|
66
|
+
passwords that Chrome saved all survive.
|
|
67
|
+
- **Shutdown.** The browser is asked to close rather than killed, which is when Chrome writes
|
|
68
|
+
the last of its cookies; an idle browser is closed after 15 minutes, and the clock stops
|
|
69
|
+
while a column is watching.
|
|
70
|
+
|
|
71
|
+
Screenshots are the only thing written outside the profile:
|
|
72
|
+
`~/.dsh-inner-browser-use/screenshots/`.
|
|
73
|
+
|
|
74
|
+
## Measured
|
|
75
|
+
|
|
76
|
+
| | |
|
|
77
|
+
| --- | --- |
|
|
78
|
+
| Navigate to first frame | ~850 ms, network included |
|
|
79
|
+
| Frame | 1440×900 JPEG, ~82 KB |
|
|
80
|
+
| Stream | ~25 frames per second |
|
|
81
|
+
| Pointer move to arrow | 0.8–7 ms |
|
|
82
|
+
| Read, dense page | 444 tokens (1510 chars, 90 controls) |
|
|
83
|
+
| Read round trip | 1–4 ms |
|
|
84
|
+
| Click round trip | 2 ms |
|
|
85
|
+
| Screenshot | 77 ms, 113 KB |
|
|
86
|
+
|
|
87
|
+
## Install
|
|
47
88
|
|
|
48
89
|
```bash
|
|
90
|
+
git clone https://github.com/regrevia/dsh-inner-browser-use
|
|
49
91
|
dsh plugin install /path/to/dsh-inner-browser-use
|
|
50
92
|
```
|
|
51
93
|
|
|
52
|
-
|
|
94
|
+
In the app: **Plugins → Install from folder**, and pick the clone. To install the packed
|
|
95
|
+
tarball instead, build it from that directory and install the file:
|
|
53
96
|
|
|
54
97
|
```bash
|
|
55
|
-
|
|
98
|
+
npm pack # writes dsh-inner-browser-use-0.16.0.tgz
|
|
99
|
+
dsh plugin install ./dsh-inner-browser-use-0.16.0.tgz
|
|
56
100
|
```
|
|
57
101
|
|
|
58
|
-
The plugin appears under **Plugins** as
|
|
102
|
+
The plugin appears under **Plugins** as *Background browser*. It needs Google Chrome or
|
|
103
|
+
Chromium on the machine; see [docs/COMPATIBILITY.md](docs/COMPATIBILITY.md).
|
|
59
104
|
|
|
60
105
|
## Use
|
|
61
106
|
|
|
62
107
|
1. Open the chat you want the agent to browse for.
|
|
63
|
-
2. Ask
|
|
64
|
-
|
|
65
|
-
The
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
- **
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
- **
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
panel; a call for any other chat gets a page out of sight instead, so the panel stays as you arranged it.
|
|
89
|
-
At most three such pages are kept, and the oldest goes first.
|
|
90
|
-
- **A capture of a chat you are not looking at.** Reading, clicking and typing work on a tab that chat already
|
|
91
|
-
had, because they drive the page itself; a tab is opened only for the chat on screen. Pixels come from a surface the app is drawing, and a view
|
|
92
|
-
behind another tab of the same pane is not drawn: the capture tries to bring this chat's tab forward, and if the
|
|
93
|
-
page still has no surface it says so in a couple of seconds instead of waiting. Read what you need from the page
|
|
94
|
-
instead — `browser_script` returns the same content.
|
|
108
|
+
2. Ask for something on a page: *"open example.com and tell me the title"*.
|
|
109
|
+
|
|
110
|
+
The first call starts the browser and puts its mirror in this chat's right column. Nothing
|
|
111
|
+
opens before a call: a chat that never asked for a page keeps its column as it was.
|
|
112
|
+
|
|
113
|
+
## Frames, downloads, network
|
|
114
|
+
|
|
115
|
+
- **Frames are read, including cross-site ones.** Controls inside an iframe are numbered like
|
|
116
|
+
the page's own, whether Chrome shares the page's process or runs the frame apart; a click in
|
|
117
|
+
either lands where the frame actually sits.
|
|
118
|
+
- **A download lands on disk.** A click that saves a file writes it into the browser's own
|
|
119
|
+
profile folder, and `sidecar_downloads` names it, its size and when it arrived.
|
|
120
|
+
- **The network is visible.** `sidecar_network` lists what the page asked for, newest first,
|
|
121
|
+
so a page that fills itself in from an address can be understood without a screenshot.
|
|
122
|
+
- **An overlay does not eat the action.** A cookie banner over the button is cleared the way a
|
|
123
|
+
person would clear it, then the click lands — in the same call, and in every step of a
|
|
124
|
+
`sidecar_do` batch. Anything offering to delete, pay or sign out is reported instead.
|
|
125
|
+
|
|
126
|
+
## What it does not do
|
|
127
|
+
|
|
128
|
+
- **It does not touch your Chrome.** The browser runs from a separate profile with no
|
|
129
|
+
connection to the window you are using.
|
|
130
|
+
- **The viewport is fixed.** 1440×900, desktop layout, no resizing and no mobile emulation.
|
|
131
|
+
- **One page at a time.** A link that opens a tab is followed — the mirror lands on the new
|
|
132
|
+
page and the popup closes — so there is never a second page to choose between.
|
|
95
133
|
|
|
96
134
|
## Compatibility
|
|
97
135
|
|
|
98
136
|
| | |
|
|
99
137
|
| --- | --- |
|
|
100
|
-
| Harness |
|
|
101
|
-
|
|
|
102
|
-
|
|
|
138
|
+
| Harness | 0.2.0 or newer |
|
|
139
|
+
| Chrome | Google Chrome, Chromium or Canary, 112 or newer |
|
|
140
|
+
| Runtime | Node 20 or newer |
|
|
103
141
|
| License | MIT |
|
|
104
142
|
|
|
105
|
-
|
|
143
|
+
Details in [docs/COMPATIBILITY.md](docs/COMPATIBILITY.md); how the halves connect in
|
|
144
|
+
[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).
|
|
106
145
|
|
|
107
|
-
##
|
|
146
|
+
## Development
|
|
108
147
|
|
|
109
148
|
```bash
|
|
110
149
|
node --test test/*.test.mjs
|
|
111
150
|
```
|
|
112
151
|
|
|
113
|
-
The
|
|
114
|
-
|
|
115
|
-
- **The page comes back on its own.** The pane is rebuilt from time to time; when that leaves the view blank, the
|
|
116
|
-
next tool call reopens the page that chat was last told to open, so a run is not interrupted by it.
|
|
152
|
+
The server half is zero-dependency ESM, the page half is a client module loaded at runtime.
|
|
153
|
+
Neither has a build step.
|
|
117
154
|
|
|
118
155
|
## License
|
|
119
156
|
|
package/README.zh.md
CHANGED
|
@@ -1,82 +1,127 @@
|
|
|
1
1
|
# dsh-inner-browser-use
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
一个由 agent 自己养的 Chrome,实时投到 DeepSeek Harness 的右栏里。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
agent 打开网页、读页面、点、输入、滚动。这个浏览器是独立的 Chrome 进程,用自己的磁盘
|
|
6
|
+
profile,不是产品自带的那个浏览页签:右栏放的是它的画面,而画面上的鼠标仍然是你自己的。
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
## 提供的工具
|
|
8
|
+
## 工具
|
|
10
9
|
|
|
11
10
|
| 工具 | 作用 |
|
|
12
11
|
| --- | --- |
|
|
13
|
-
| `
|
|
14
|
-
| `
|
|
15
|
-
| `
|
|
16
|
-
| `
|
|
17
|
-
| `
|
|
18
|
-
| `
|
|
19
|
-
| `
|
|
20
|
-
| `
|
|
21
|
-
| `
|
|
22
|
-
|
|
12
|
+
| `sidecar_open` | 启动浏览器(已在跑就复用)并打开一个地址。传 `headless: false` 会改为在桌面上开真实窗口。 |
|
|
13
|
+
| `sidecar_view` | 返回地址、标题、编号成 `1 … 120` 的控件,以及可见文字。 |
|
|
14
|
+
| `sidecar_extract` | 按 CSS 选择器把列表项读成一行一条、带链接,比整页读省得多。 |
|
|
15
|
+
| `sidecar_click` | 点编号控件,或点 `x`/`y` 坐标。`double: true` 双击。控件被横幅或弹层挡着时,先关掉它再点。 |
|
|
16
|
+
| `sidecar_type` | 往焦点输入框输入文字,也可以先点一个编号控件。中文整段送进去。`submit: true` 回车提交。 |
|
|
17
|
+
| `sidecar_key` | 按一个键:Enter、Tab、Escape、Backspace、Delete、上下左右、Home、End、PageUp、PageDown。 |
|
|
18
|
+
| `sidecar_scroll` | 在页面中心滚轮,也可以指定 `x`/`y`。`dy: 600` 约一屏。 |
|
|
19
|
+
| `sidecar_shot` | 存一张原尺寸 PNG 到 `~/.dsh-inner-browser-use/screenshots`,返回路径。 |
|
|
20
|
+
| `sidecar_state` | 报浏览器在不在跑、用的哪个 profile、地址、标题,以及有几个右栏在看它。 |
|
|
21
|
+
|
|
22
|
+
`sidecar_view` 一次给一页文本:
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
```
|
|
25
|
+
https://example.com
|
|
26
|
+
Example Domain
|
|
25
27
|
|
|
26
|
-
|
|
28
|
+
1 [a] More information
|
|
29
|
+
7 [input] Search
|
|
30
|
+
```
|
|
27
31
|
|
|
28
|
-
|
|
32
|
+
编号到下一次读之前都有效。任何改动页面的操作都会顺带返回一次新的读取。
|
|
29
33
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
34
|
+
## 右栏
|
|
35
|
+
|
|
36
|
+
那一栏显示的是浏览器的画面,按会话自己的流发 JPEG:1440×900,质量 72,每帧都发;静止
|
|
37
|
+
页面上约 82 KB 一帧、每秒 25 帧。
|
|
38
|
+
|
|
39
|
+
画面上有两个指针:
|
|
40
|
+
|
|
41
|
+
- **黑色箭头是 agent。** 它标在 agent 上一次点击的落点上,新的点击一发出箭头就动,不等
|
|
42
|
+
页面重绘。
|
|
43
|
+
- **鼠标是你自己的。** 悬停、点击、滚轮、按键都当作真实输入交给浏览器,所以对拦截脚本点击
|
|
44
|
+
的站也照常管用。移动鼠标不会带动黑色箭头。
|
|
45
|
+
|
|
46
|
+
画面上方那行地址就是地址栏:输入域名回车,页面换成它;旁边是后退、前进、刷新。你在编辑时
|
|
47
|
+
它不会跟着页面跳。
|
|
48
|
+
|
|
49
|
+
输入分两路进来:输入法合成的文字(中文、emoji 等)整段插入,按键则按原样送过去,所以
|
|
50
|
+
Backspace 在页面上删掉的是一个字。
|
|
33
51
|
|
|
34
|
-
|
|
52
|
+
右栏只在向它要过页面的那个会话里打开。别的会话调用工具时用的是同一个浏览器,但不会抢走
|
|
53
|
+
别人正在看的这一栏。
|
|
54
|
+
|
|
55
|
+
## 登录态
|
|
56
|
+
|
|
57
|
+
profile 是独立目录:`~/.dsh/inner-browser-use/chrome/default`。它在产品自己的浏览数据之外
|
|
58
|
+
——那份数据是每个进程临时建的,进程一退就没了,所以在这里登过的账号第二天还在。
|
|
59
|
+
|
|
60
|
+
- **插件重载。** 重载会接上仍在运行的那个 Chrome,页面也还在原处。
|
|
61
|
+
- **Harness 重启。** 重新打开同一个目录,cookie、`localStorage` 和 Chrome 存下的密码都留着。
|
|
62
|
+
- **退出。** 关浏览器是请它自己关(`Browser.close`),Chrome 在这一步才把 cookie 落盘;空闲
|
|
63
|
+
15 分钟会关掉,有右栏在看时不计这段空闲。
|
|
64
|
+
|
|
65
|
+
profile 之外只写一样东西:`~/.dsh-inner-browser-use/screenshots/` 里的截图。
|
|
66
|
+
|
|
67
|
+
## 实测
|
|
68
|
+
|
|
69
|
+
| | |
|
|
70
|
+
| --- | --- |
|
|
71
|
+
| 打开页面到第一帧 | 约 850 ms,含网络加载 |
|
|
72
|
+
| 单帧 | 1440×900 JPEG,约 82 KB |
|
|
73
|
+
| 画面 | 约 25 帧每秒 |
|
|
74
|
+
| 指针移动到箭头跟上 | 0.8–7 ms |
|
|
75
|
+
|
|
76
|
+
## 安装
|
|
35
77
|
|
|
36
78
|
```bash
|
|
79
|
+
git clone https://github.com/regrevia/dsh-inner-browser-use
|
|
37
80
|
dsh plugin install /path/to/dsh-inner-browser-use
|
|
38
81
|
```
|
|
39
82
|
|
|
40
|
-
|
|
83
|
+
在应用里走 **插件 → 从文件夹安装**,选这个仓库目录。要装打包好的 tgz,就在该目录里打一个再装:
|
|
41
84
|
|
|
42
85
|
```bash
|
|
43
|
-
|
|
86
|
+
npm pack # 得到 dsh-inner-browser-use-0.12.1.tgz
|
|
87
|
+
dsh plugin install ./dsh-inner-browser-use-0.12.1.tgz
|
|
44
88
|
```
|
|
45
89
|
|
|
46
|
-
|
|
90
|
+
装好后在 **插件** 里显示为 *后台浏览器*。机器上要有 Google Chrome 或 Chromium,细节见
|
|
91
|
+
[docs/COMPATIBILITY.md](docs/COMPATIBILITY.md)。
|
|
47
92
|
|
|
48
93
|
## 使用
|
|
49
94
|
|
|
50
|
-
1.
|
|
51
|
-
2.
|
|
95
|
+
1. 打开你想让 agent 代跑的会话。
|
|
96
|
+
2. 直接说要页面上的什么事:*「打开 example.com,告诉我标题」*。
|
|
52
97
|
|
|
53
|
-
|
|
98
|
+
第一次调用会启动浏览器,并把镜像放进这个会话的右栏。没有调用就不会有东西自己打开:没要过
|
|
99
|
+
页面的会话,右栏保持原样。
|
|
54
100
|
|
|
55
|
-
##
|
|
101
|
+
## 框架、下载、网络
|
|
56
102
|
|
|
57
|
-
-
|
|
58
|
-
-
|
|
59
|
-
-
|
|
103
|
+
- **iframe 能读,跨站也能。** 不管是和页面共用进程,还是 Chrome 单独给一个进程,里面的控件都和页面自己的控件一样有编号;点击按框架在页面上的实际位置落点。
|
|
104
|
+
- **下载会落到磁盘。** 点一下就下载的文件写在这个浏览器自己的 profile 目录里,`sidecar_downloads` 报出文件名、大小和到达时间。
|
|
105
|
+
- **能看到网络。** `sidecar_network` 倒序列出页面请求了什么,自己用接口填内容、屏幕上又看不出原因的页面,不用截图去猜。
|
|
106
|
+
- **遮罩不吞动作。** 盖在按钮上的 cookie 横幅会按人的做法先关掉再点下去,同一次调用里完成;`sidecar_do` 的每一步都一样。写着删除、支付、退出的遮罩只报告,不代按。
|
|
60
107
|
|
|
61
|
-
##
|
|
108
|
+
## 不做什么
|
|
62
109
|
|
|
63
|
-
-
|
|
64
|
-
-
|
|
65
|
-
-
|
|
66
|
-
- **一个工作区一个分区。** 同一工作区的两个会话共用浏览器存储,和内置浏览器开两个标签时一样。
|
|
67
|
-
- **没有新窗口、没有权限弹窗。** 想在新的窗口打开的链接留在当前页里。
|
|
68
|
-
- **没有标签时会替你开。** 会话里还没有内置浏览器时,第一次调用就在那里开一页;你自己开的那页同样会被接管。
|
|
110
|
+
- **不动你自己的 Chrome。** 浏览器跑在单独的 profile 上,和你正在用的窗口没有关系。
|
|
111
|
+
- **视口固定。** 1440×900、桌面布局,不缩放,也不模拟手机。
|
|
112
|
+
- **一次一页。** 点开新页签的链接会被跟过去:镜像落到新页面,弹窗随即关掉,不会留下第二个页面要选。
|
|
69
113
|
|
|
70
|
-
##
|
|
114
|
+
## 兼容性
|
|
71
115
|
|
|
72
116
|
| | |
|
|
73
117
|
| --- | --- |
|
|
74
|
-
| Harness |
|
|
75
|
-
|
|
|
76
|
-
|
|
|
118
|
+
| Harness | 0.2.0 及以上 |
|
|
119
|
+
| Chrome | Google Chrome、Chromium 或 Canary,112 及以上 |
|
|
120
|
+
| 运行时 | Node 20 及以上 |
|
|
77
121
|
| 许可 | MIT |
|
|
78
122
|
|
|
79
|
-
|
|
123
|
+
细节在 [docs/COMPATIBILITY.md](docs/COMPATIBILITY.md),两半怎么连起来在
|
|
124
|
+
[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)。
|
|
80
125
|
|
|
81
126
|
## 开发
|
|
82
127
|
|
|
@@ -84,7 +129,7 @@ dsh plugin install https://github.com/regrevia/dsh-inner-browser-use/releases/do
|
|
|
84
129
|
node --test test/*.test.mjs
|
|
85
130
|
```
|
|
86
131
|
|
|
87
|
-
|
|
132
|
+
服务端那一半是零依赖 ESM,页面那一半是运行时加载的客户端模块,都不需要构建。
|
|
88
133
|
|
|
89
134
|
## 许可
|
|
90
135
|
|