dsh-browser-plus 0.0.0-stage → 0.5.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.
- package/CHANGELOG.md +153 -0
- package/LICENSE +22 -0
- package/NOTICE.md +7 -0
- package/README.en.md +119 -0
- package/README.md +118 -2
- package/assets/dsh-browser-plus-256.png +0 -0
- package/assets/dsh-browser-plus-512.png +0 -0
- package/assets/dsh-browser-plus-small.svg +9 -0
- package/assets/dsh-browser-plus.ico +0 -0
- package/assets/dsh-browser-plus.svg +11 -0
- package/assets/readme-workspace.png +0 -0
- package/client/index.js +185 -0
- package/cordis.patch.yml +41 -0
- package/docs/MIGRATION.md +48 -0
- package/docs/README.md +22 -0
- package/docs/SOAK-CHECKLIST.md +98 -0
- package/docs/architecture.md +88 -0
- package/docs/tool-reference.md +126 -0
- package/docs/user-guide.md +137 -0
- package/docs/why-browser.md +45 -0
- package/lib/browser/runtime.d.ts +238 -0
- package/lib/browser/runtime.js +330 -0
- package/lib/browser/types.d.ts +758 -0
- package/lib/browser/types.js +18 -0
- package/lib/browser-electron/auth-cookies.d.ts +54 -0
- package/lib/browser-electron/auth-cookies.js +83 -0
- package/lib/browser-electron/chrome-state.d.ts +211 -0
- package/lib/browser-electron/chrome-state.js +12 -0
- package/lib/browser-electron/entry.d.ts +73 -0
- package/lib/browser-electron/entry.js +65 -0
- package/lib/browser-electron/fingerprint.d.ts +29 -0
- package/lib/browser-electron/fingerprint.js +42 -0
- package/lib/browser-electron/host-main.d.ts +19 -0
- package/lib/browser-electron/host-main.js +2691 -0
- package/lib/browser-electron/icon.d.ts +11 -0
- package/lib/browser-electron/icon.js +23 -0
- package/lib/browser-electron/page-chrome.d.ts +21 -0
- package/lib/browser-electron/page-chrome.js +2269 -0
- package/lib/browser-electron/provider.d.ts +767 -0
- package/lib/browser-electron/provider.js +2825 -0
- package/lib/browser-electron/remote-host.d.ts +145 -0
- package/lib/browser-electron/remote-host.js +993 -0
- package/lib/browser-electron/task-summary.d.ts +2 -0
- package/lib/browser-electron/task-summary.js +12 -0
- package/lib/browser-electron/task-thumbnail.d.ts +11 -0
- package/lib/browser-electron/task-thumbnail.js +9 -0
- package/lib/browser-electron/write-guard.d.ts +41 -0
- package/lib/browser-electron/write-guard.js +123 -0
- package/lib/client.js +185 -0
- package/lib/command-browser/index.d.ts +20 -0
- package/lib/command-browser/index.js +35 -0
- package/lib/http-browser/index.d.ts +28 -0
- package/lib/http-browser/index.js +110 -0
- package/lib/index.d.ts +27 -0
- package/lib/index.js +25 -0
- package/lib/task-todos/index.d.ts +25 -0
- package/lib/task-todos/index.js +100 -0
- package/lib/tool-browser/index.d.ts +31 -0
- package/lib/tool-browser/index.js +2026 -0
- package/package.json +120 -4
- package/screenshots.json +3 -0
- package/scripts/build-client.mjs +20 -0
- package/scripts/build-icons.mjs +80 -0
- package/scripts/capture-window.ps1 +79 -0
- package/scripts/crop-image.ps1 +20 -0
- package/scripts/smoke-browser-tools.mjs +2051 -0
- package/scripts/smoke-chrome-world.mjs +65 -0
- package/scripts/smoke-electron-host.mjs +50 -0
- package/scripts/test-orb-drag.mjs +83 -0
- package/src/browser/runtime.ts +506 -0
- package/src/browser/types.ts +741 -0
- package/src/browser-electron/auth-cookies.ts +125 -0
- package/src/browser-electron/chrome-state.ts +192 -0
- package/src/browser-electron/entry.ts +125 -0
- package/src/browser-electron/fingerprint.ts +45 -0
- package/src/browser-electron/host-main.ts +2526 -0
- package/src/browser-electron/icon.ts +26 -0
- package/src/browser-electron/page-chrome.ts +2281 -0
- package/src/browser-electron/provider.ts +3366 -0
- package/src/browser-electron/remote-host.ts +1051 -0
- package/src/browser-electron/task-summary.ts +10 -0
- package/src/browser-electron/task-thumbnail.ts +17 -0
- package/src/browser-electron/write-guard.ts +134 -0
- package/src/command-browser/index.ts +61 -0
- package/src/http-browser/index.ts +139 -0
- package/src/index.ts +65 -0
- package/src/task-todos/index.ts +114 -0
- package/src/tool-browser/index.ts +2071 -0
- package/src/types/electron-shim.d.ts +143 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## v0.5.1 (2026-10-04)
|
|
4
|
+
### 新功能
|
|
5
|
+
- **网页右下角的悬浮球:Agent 在浏览器里干什么,一眼看得见** —— 半透明、可拖动(位置存在宿主),干活时转圈、角标是 todo 进度,悬停弹出清单与「现在执行」的动作。
|
|
6
|
+
- **人和 Agent 都能开窗了** —— `/browser` 斜杠命令(不产生模型消息)+ 右侧栏「DSH-Browser-Plus」面板,不再只能等 Agent 第一次调用工具。
|
|
7
|
+
- **`browser_snapshot` 能看进 iframe** —— 同源框架递归遍历,元素带 `frame` 序号且坐标已加偏移(ref 照样能点);跨源明确标 `readable: false`。
|
|
8
|
+
- **新增 `browser_highlight`** —— 用 DevTools 那套高亮框标出元素(走 CDP `Overlay`,完全不碰页面 DOM)。
|
|
9
|
+
- **新增 `browser_pdf`** —— 打印当前标签页;Electron 的 debugger 没有 CDP `Page.printToPDF`,改走宿主 `webContents.printToPDF`。
|
|
10
|
+
- **`browser_wait_for` 能等文字、也能等东西消失** —— 新增 `text` 与 `state`(`attached` / `hidden` / `detached`)。
|
|
11
|
+
### 优化
|
|
12
|
+
- **等不了的情况直接报错** —— 既没选择器也没文字、或要等消失却没给选择器 → `BROWSER_WAIT_INVALID`,不空等到超时。
|
|
13
|
+
### 修复
|
|
14
|
+
- **页面脚本能读到 Agent 的计划** —— 注入的 chrome 改跑**隔离世界**(`chromeWorld: 'isolated'`),页面对 `__dsh*` 全局一律 `undefined`;DOM、事件与补丁通道不变,显式配 `main` 可回到旧行为。
|
|
15
|
+
- **面板的两个 HTTP 路由能被别的网站调用** —— 要求 `Origin` 与 `Host` 一致;同源面板与 curl 不受影响。
|
|
16
|
+
- **任务面板里点另一条任务没反应** —— 点击读的 `dataset.dshTaskKey` 全文件没有任何地方写过(列表用 `dshKey` 建行),三处统一。
|
|
17
|
+
- **任务面板里只有当前任务有缩略图** —— 图像只发给可见表面;现在面板打开与切任务时把手里已有的图重放一次。
|
|
18
|
+
- **书签栏会压住网页内容** —— 改成和顶栏一样占视图高度(帧 84 → 118px),页面不再靠 `padding-top` 让位。
|
|
19
|
+
> 每条改动的背景、真机证据与踩过的坑,见对应提交信息。
|
|
20
|
+
|
|
21
|
+
## v0.5.0 (2026-10-03)
|
|
22
|
+
### 新功能
|
|
23
|
+
- **`browser_dialog`** —— 查看/引导 `alert`/`confirm`/`prompt`。
|
|
24
|
+
- **`browser_console` / `browser_network`** —— 读控制台报错、未捕获异常与网络请求(每个视图各 200 条环形缓冲)。
|
|
25
|
+
- **`browser_emulate`** —— 视口(可带移动端行为与 DPR)、自定义 UA、`prefers-color-scheme`。
|
|
26
|
+
- **`browser_execute` 现在也收语句体**(自动判别:先试表达式,再试脚本体,语句体用 `return` 返回值)。
|
|
27
|
+
- **`browser_snapshot` 新增 `query` 与 `limit`** —— 按 kind+label 过滤,且**过滤发生在计上限之前**(否则默认上限 60 之外的元素永远搜不到)。
|
|
28
|
+
### 优化
|
|
29
|
+
- **坐标点击落在视口外时明确报错**,并报出那个点上实际是什么元素(坐标点击**不会自动滚动**,以前是静默丢弃)。
|
|
30
|
+
### 修复
|
|
31
|
+
- **页面缩放 ≠ 100% 时,二级菜单弹层不贴按钮** —— 实测 160% 下偏 330px(`left` 311 → 502)。
|
|
32
|
+
- **`browser_dialog` 的 `inspect` 看不到刚触发的对话框** —— 它没有自己排空宿主里的对话框。
|
|
33
|
+
> 每条改动的背景、真机证据与踩过的坑,见对应提交信息。
|
|
34
|
+
|
|
35
|
+
## v0.4.3 (2026-09-30)
|
|
36
|
+
### 新功能
|
|
37
|
+
- **标签栏显示 favicon**(Chrome 的标签几乎由 favicon 主导,这是「像不像」最显眼的一块)。
|
|
38
|
+
- **注入式 chrome 新增 Chrome 风格标签栏**(渲染层已完成并真机验证)。
|
|
39
|
+
- **新增 `browser_drag`(工具数 36 → 37)**:`from` 按下 → 中间移动 → `to` 释放。
|
|
40
|
+
- **指针工具支持右键与修饰键**:`browser_click`/`browser_double_click` 新增 `button`(left/right/middle)与 `modifiers`(alt/ctrl/meta/shif…。
|
|
41
|
+
- **`DSH_BROWSER_PLUS_USER_DATA` 可覆盖宿主 profile**:Chromium 对 profile 加单例锁,此前无法并存两个宿主(验证脚本会与运行中的 DSH 冲突)。
|
|
42
|
+
- **指针工具支持选择器/文字寻址**:`browser_click`/`browser_double_click`/`browser_hover` 此前**只能给坐标**,想点一个按钮必须先 `browser_snapshot` 拿 `…。
|
|
43
|
+
- **`browser_scrape` 支持并发**:新增 `concurrency`(默认 1,上限 8),每个 worker 占一个自己的标签页,从共享队列取 URL。
|
|
44
|
+
- **新增 `browser_scrape`:批量抓取,结果直接落盘**:后台批量访问 URL,每页把一行 JSON 追加到文件,**结果完全不经过模型**——一千条与一条的 token 成本相同。
|
|
45
|
+
- **`browser_auth` 支持从文件导入登录状态**:新增 `file` 参数(`action=restore`),从 JSON 文件读取 cookie 列表 —— 真实导出动辄几百条,内联经模型传递不现实。
|
|
46
|
+
- **新增深色空状态页,并修复空白视图上所有操作超时**:新建的 `WebContentsView` 在首次导航前**没有提交任何文档** —— 既按默认白底渲染(和整套深色 UI 格格不入),又让 CDP **没有 frame 可 ev…。
|
|
47
|
+
- **可选:把注入 chrome 移进隔离世界**(`browser-electron.chromeWorld: isolated`,**默认仍是 main**)。
|
|
48
|
+
- **`browser_press_key` 支持标点**:此前只认字母数字与功能键,`Ctrl+-`、`Ctrl+/`、`,`、`.`、`[`、`]` 等一律抛 `BROWSER_KEY_UNKNOWN`,而工具描述却写「single …。
|
|
49
|
+
- **写入路径白名单**:`browser_screenshot` 与 `browser_download` 只能写入 `browser-electron.writeRoots`(默认工作目录 + 系统临时目录)之内的路径。
|
|
50
|
+
### 优化
|
|
51
|
+
- **取消抽屉设计 + 页面不再被顶栏遮挡**(用户要求「取消抽屉的设计,同时为了不遮挡,像谷歌浏览器那样处理」)。
|
|
52
|
+
- **chrome 改成 Chrome 那样的「窗框」,而不是浮动小部件**。
|
|
53
|
+
- **注入式 chrome 改成 Chrome 式常驻顶栏**。
|
|
54
|
+
- **用 DSH 自己的校验器验证全部 37 个工具的 schema**。
|
|
55
|
+
- **补上 JS 侧指纹的断言(冒烟共 33 项),并确认现有指纹是自洽的**。
|
|
56
|
+
- **交互效果断言补全到 10 项(冒烟共 31 项)**:新增 **`click_ref`**(文档里的主要交互方式,此前只验证过「调用返回了」,从未验证过「页面收到了」)、双击、滚动、`fill` 选 select 四条**效果断言*…。
|
|
57
|
+
- **集成冒烟扩到 21 项,覆盖工具层与并行**:新增 ① **真实工具层跑在真实 provider 上**(`browser_open`/`browser_content`/`browser_click`/`browser_snaps…。
|
|
58
|
+
- **新增真实集成冒烟 `npm run smoke:browser-tools`**:用**真实 Electron 宿主 + 真实 Chromium** 驱动**真实 provider**,覆盖 12 项(含 click 三种寻址、sc…。
|
|
59
|
+
- **`browser_scrape` 改用独立标签页**:此前批次调用的是作用于「会话当前激活标签页」的 `navigate`/`execute`,于是 ① 批次运行期间任何工具调用都会和它**抢同一个标签页**,抽取可能拿到错误的页面…。
|
|
60
|
+
- **后台批次跳过 250ms 绘制等待**:`waitForDocumentReady` 在 `document.readyState === complete` 后会**固定再等 250ms**,目的是让截图/快照不抓到空白渲染——但…。
|
|
61
|
+
- **对齐请求指纹,减少被判定为机器人**:实测服务端收到的请求里有三处明显破绽 —— ① `User-Agent` 里带着 `Electron/42.9.3`。
|
|
62
|
+
- **下载改由子进程直接落盘**:此前子进程把整包 base64 塞进一行 JSON 回传,父进程再解码写盘——64MiB 的下载在 host→parent→disk 路径上要复制约 8 份(含 RPC 行缓冲)。
|
|
63
|
+
- **测试 seam 移出声明的 API 面**:`tsconfig` 打开 `stripInternal`,`internals` 与 `DeferredRemoteView` 不再出现在 `lib/*.d.ts` 里(运行时导出保留,…。
|
|
64
|
+
- **chrome 重装改由宿主执行**:provider 在导航后注入的是**无 token** 的 `PAGE_CHROME_SCRIPT`,而只有宿主持有每视图 token——一旦宿主自身的注入失败,退化的那份会让工具栏按钮静默失效…。
|
|
65
|
+
- **历史记录不再全量深拷贝**:`browser_history` 此前对每条 entry 做 `JSON.parse(JSON.stringify(params))`,把完整脚本与输入文本逐条复制一遍。
|
|
66
|
+
- **单条历史有存储上限**:`execute` 的脚本与 `type` 的文本超过 32KiB 时会被截断并打标。
|
|
67
|
+
- **补上两处零覆盖**:① `entry.ts` 的组合入口(外部 viewHost 优先 / 缺省自托管 / 销毁时只 dispose 自托管 host / 配置透传)此前没有任何测试。
|
|
68
|
+
- **新增 CI**:`.github/workflows/ci.yml` 在 push/PR 上跑 `npm ci --omit=optional` + `npm test`,并额外用 `git diff --exit-code -- …。
|
|
69
|
+
- **新增 ESLint 最小集**:只启用类型感知的 `no-floating-promises` / `no-misused-promises` 与两条一致性规则,不引入格式化以免搅动现有风格。
|
|
70
|
+
- **减少跨进程 IPC**:`syncVisibleTaskVisibility` 此前对**每个** view(含其它任务的隐藏页与后台标签)各发一次 `executeJavaScript`。
|
|
71
|
+
- **`browser_screenshot` 仅在写盘时受白名单约束**:不带 `savePath` 的截图仍是只读,保持「只读工具永不拦截」的承诺。
|
|
72
|
+
- **超时错误带稳定 code**:`withTimeout` 现在抛 `BROWSER_OPERATION_TIMEOUT`(保留 `TimeoutError` 名称),此前只有 `execute`/`waitForElement` 两…。
|
|
73
|
+
- **主机自愈改用稳定错误码**:新增 `BROWSER_HOST_DEAD` 与 `isBrowserHostDead()`。
|
|
74
|
+
- **`available()` 实检**:`ElectronBrowserViewHost` 新增可选 `isAvailable?()`。
|
|
75
|
+
- **下载内存**:子进程下载上限 256MiB → 64MiB,父进程 RPC 缓冲 512MiB → 128MiB(按 base64 推导保留 1.5× 余量)。
|
|
76
|
+
- **`internals`**:标注 `@internal`。
|
|
77
|
+
- **测试可信度**:`npm test` 现在先执行 `tsc`(`pretest`),不再对可能过期的构建产物 `lib/` 做假绿测试。
|
|
78
|
+
### 修复
|
|
79
|
+
- **修复:窗口从最小化恢复后,视图不会被重新布局(一直是 0×0)**。
|
|
80
|
+
- **修复 `showView` 与 `createView` 的竞态 —— 新标签的视图永远不会被显示**。
|
|
81
|
+
- **修复:浏览器直接导出的 cookie 文件会被整份拒绝**。
|
|
82
|
+
- **键盘输入此前也在空转(由第 9 轮的修复一并治好,本轮补上断言)**:实测运行中的旧代码,`browser_press_key` 派发后页面收到的 `keydown` 列表**为空** —— Enter/Tab/Escape/方…。
|
|
83
|
+
- **修复:点击在真实网站上完全不生效**。
|
|
84
|
+
- **修 `text` 寻址在「逐字符 span」页面上匹配失败(真实集成测试抓到的真 bug)**:文字匹配此前枚举候选标签(`a, button, input, span, div, li, td…`),**漏了 `p` 等大量承载正…。
|
|
85
|
+
- **修复写盘白名单默认值从未生效**:`entry.ts` 的 `writeRoots`/`readRoots` 声明为 `z.array(z.string())` 而没有默认值,而 schemastery 会把**缺省键物化成 `[]…。
|
|
86
|
+
- **每次调用的 `timeoutMs` 被夹在工具预算之下**:`browser_wait_for`/`browser_content` 此前把调用方给的值原样下传,所以 `timeoutMs: 90000` 实际会在 60s 被运行时…。
|
|
87
|
+
- **自愈不再在空白页上重放输入**:主机崩溃后重建的视图是 `about:blank`,而 `Input.*` 在空白文档上会「什么都不做但正常 resolve」,于是 `browser_click`/`browser_type` 会在…。
|
|
88
|
+
- **快照 `truncated` 语义修正**:此前用 `out.length >= cap` 判断,页面恰好有 cap 个可见候选时会误报截断。
|
|
89
|
+
- **`browser_scroll` 描述与实现对齐**:实际是「约一屏(视口高度的 80%,最少 480px)」,描述原写「one viewport」。
|
|
90
|
+
- **`CHANGELOG.md` 现在会进 npm tarball**(此前 `files` 未列)。
|
|
91
|
+
- **缩略图捕获加超时**:`capturePage()` 在合成器卡住时可能永不 settle,而 `finally` 不会执行 → 单飞标志永远为 true,此后缩略图静默停更。
|
|
92
|
+
- **`installPageChrome` 的 active 判定改用 viewId**:此前只比 taskKey,导致可见任务的**后台标签页**导航时被当成「正在显示」,会启动其页面定时器并顶掉真正可见视图的 chrome epoc…。
|
|
93
|
+
- **`restoreAuth` 逐条隔离**:此前任一条 cookie 非法即整批 reject、已写入不可回滚、调用方也拿不到计数。
|
|
94
|
+
- **会话丢失会自动重开**:工具层按任务缓存 session id。
|
|
95
|
+
- **`browser_close_tab` 如实返回**:此前无条件 `{closed:true}`,render 里「Tab not found.」是死代码。
|
|
96
|
+
- **`browser_handoff` 纳入白名单**:它不是只读工具(会改任务控制状态),此前不受 `browser_restrict` 约束。
|
|
97
|
+
- **`browser_reset_session` 纳入每任务 FIFO**:此前直接 close,可能把并发排队操作正在使用的会话/视图拆掉。
|
|
98
|
+
- **`browser_restrict` 校验名字是否存在**:此前只校验 `browser_` 前缀,拼错(如 `browser_snapsho`)会被接受并静默拒绝该任务所有受守卫动作。
|
|
99
|
+
- **输入派发补上超时兜底**:`click`/`clickRef`/`doubleClick`/`hover`/`type`/`pressKey` 的 8 处 `Input.*` 派发此前是裸 `await`,页面主线程被同步 JS 阻…。
|
|
100
|
+
- **快照重试有总预算且尊重取消**:空清单重试此前最多 5 次、每次可等满求值超时(理论上约 182s,远超 60s 工具预算),且 `.catch(() => undefined)` 会吞掉 abort 继续重试。
|
|
101
|
+
- **`browser_fill` 不再静默假成功**:checkbox/radio 点击后回读 `checked`,未变更(disabled 或被处理器取消)报 `ok:false`。
|
|
102
|
+
- **`browser_content format=json` 不再恒返回 `{}`**:DOM 元素没有自有可枚举属性,`JSON.stringify(document.body)` 永远是 `{}`。
|
|
103
|
+
- **`browser_wait_for` 非法选择器快速失败**:此前会每 250ms 重试直到超时(默认 15s)再报一个误导性的 `BROWSER_WAIT_TIMEOUT`,现在立即抛 `BROWSER_SELECTOR_INVA…。
|
|
104
|
+
- **工具栏不再吞掉代理点击**:注入 chrome 的顶部中央 280×56 感应区在捕获阶段 `preventDefault` + `stopImmediatePropagation`,且从不检查 Agent 输入抑制窗口,导致落在该…。
|
|
105
|
+
- **缩略图失败不再 5Hz 重试**:抓取失败(空图/编码失败/抛错)时 dirty 标记未清除,`finally` 每 200ms 重排一次,任务面板打开期间会以 5 次/秒无限抓屏。
|
|
106
|
+
- **下载上限改为流式判定**:此前先 `arrayBuffer()` 读完整包再比 64MiB,超大响应会先撑爆渲染进程,上限形同虚设。
|
|
107
|
+
- **`browser_upload_file` 加读白名单**:此前只有写有白名单,上传可把任意本地文件交给页面(绕过 DSH 文件策略)。
|
|
108
|
+
- **任务摘要不再下发缩略图**:`window.__dshTasks` 走页面主世界,此前携带可见任务的 288px JPEG,任意页面可据此读走其他任务的屏幕内容。
|
|
109
|
+
- **`browser_restrict` 改为按任务隔离**:此前白名单是模块级全局状态,一个任务设置后会把**所有**并行任务的浏览器工具一起限制。
|
|
110
|
+
- **页面可见轨迹脱敏**:注入页面的 `window.__dshChromeBootstrap.trail` 只保留展示所需字段——`type` 折叠为字符数、`execute` 丢弃脚本、URL 折叠为 origin、路径折叠为 ba…。
|
|
111
|
+
- **页面→宿主控制通道加每视图 token**:`__dshBrowserTaskAction` 的 payload 必须携带 `createView` 生成的随机 token。
|
|
112
|
+
- **读操作纳入每任务 FIFO**:`snapshot`/`content`/`screenshot`/`list_tabs`/`history`/`session`/`space(list)` 现在会等待在飞写操作,修复并发 `bro…。
|
|
113
|
+
- **markdown 抓取修复**:`browser_content format=markdown` 的 walker 现在递归块级容器,标题/链接/列表在常见 `div` 嵌套下不再退化成纯文本。
|
|
114
|
+
- **`browser_upload_file`**:补 30s 超时与 Agent 输入抑制标记,与其它输入工具一致。
|
|
115
|
+
- **下载共用导航准入**:`browser_download` 与 `browser_navigate` 走同一套 URL 准入(仅 HTTP(S),拒绝 URL 内嵌凭据),不再绕过 `httpOnly`。
|
|
116
|
+
|
|
117
|
+
## v0.4.2 (2026-09-17)
|
|
118
|
+
### 新功能
|
|
119
|
+
- **按站点清理 Cookie**:`browser_auth action="clear"` 支持按 `domain`(含子域)与/或 `name` 精确删除 Cookie。
|
|
120
|
+
|
|
121
|
+
## v0.4.1 (2026-08-26)
|
|
122
|
+
### 新功能
|
|
123
|
+
- **多标签会话恢复**:keyed browser sessions are recovered when the tool-layer session cache is lost, so the first direct switc…。
|
|
124
|
+
|
|
125
|
+
## v0.4.0 (2026-08-26)
|
|
126
|
+
### 新功能
|
|
127
|
+
- **显式人机交接**:任务卡显示运行、等待用户、用户接管、失败和空闲状态。
|
|
128
|
+
- **语义浏览控制**:新增后退、前进、刷新、停止、滚动,以及由 `snapshotId` 和元素 ref 驱动的精确点击/滚动到元素工具。
|
|
129
|
+
- **低干扰工具栏**:工具栏默认隐入页面上方,顶部中间悬停出现圆形下箭头。
|
|
130
|
+
### 优化
|
|
131
|
+
- **轻量工作区同步**:Host 改为 bootstrap + versioned patch。
|
|
132
|
+
- **资源预算**:任务缩略图仅在任务面板打开时按需单飞捕获,带 2 秒节流和 32 项缓存。
|
|
133
|
+
|
|
134
|
+
## v0.3.1 (2026-08-23)
|
|
135
|
+
### 新功能
|
|
136
|
+
- **单窗口任务管理器**:所有 DSH 任务共享一个可见浏览器窗口,同时保留隔离的任务视图、标签和历史。
|
|
137
|
+
- **任务标签**:`browser_space` 命名或列出浏览器任务,不再表示原生窗口。
|
|
138
|
+
- **可视工作区**:任务与操作轨迹可同时打开,切换任务同步轨迹,并显示可见页面的实时缩略图。
|
|
139
|
+
- **Browser Flow 图标**:新增 SVG 主源、PNG/ICO 衍生资源及 Electron 窗口图标接入。
|
|
140
|
+
|
|
141
|
+
## v0.3.0 (2026-08-21)
|
|
142
|
+
### 新功能
|
|
143
|
+
- **JS 对话框**:宿主自动 accept(页面永不卡死),草案以 `drainDialog` 读回并写入 `browser_history`(`dialog` 记录)。
|
|
144
|
+
- **输入工具**:`browser_press_key`(CDP keyDown/keyUp,修饰键位掩码)、`browser_double_click`(clickCount 2)、`browser_hover`(mouseMoved…。
|
|
145
|
+
- **等待与定位**:`browser_wait_for`(250ms 有界轮询,`BROWSER_WAIT_TIMEOUT`)。
|
|
146
|
+
- **每任务窗口**:每个 DSH 任务一个独立 `BrowserWindow`(createView key)。
|
|
147
|
+
### 优化
|
|
148
|
+
- **稳定性**:Electron 锁定 42.9.3(43.4.1 组合器故障)。
|
|
149
|
+
- **质量**:32/32 测试(FakeHost 行为测试 12 条 + 源码断言/页面 chrome 断言)。
|
|
150
|
+
|
|
151
|
+
## v0.2.0 (2026-08-21)
|
|
152
|
+
### 新功能
|
|
153
|
+
- 首版 `dsh-browser-plus`:共享可见浏览器、ego 风格页面内工具栏、操作轨迹(trail)面板、用户控制检测、稳定单视图合成。
|
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ParticleLight
|
|
4
|
+
Copyright (c) 2026 dsh-browser contributors
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
package/NOTICE.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Notice
|
|
2
|
+
|
|
3
|
+
This repository contains independently maintained work for **dsh-browser-plus**.
|
|
4
|
+
|
|
5
|
+
Some components were originally derived from the MIT-licensed `dsh-browser` codebase. The upstream MIT copyright notice remains in [LICENSE](LICENSE), as required by that license.
|
|
6
|
+
|
|
7
|
+
All subsequent product design, branding, runtime recovery behavior, documentation, tests, and maintenance in this repository are maintained by ParticleLight.
|
package/README.en.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# dsh-browser-plus
|
|
2
|
+
|
|
3
|
+
> A visible browser runtime for DeepSeek Harness. Humans and agents operate the same real page, not a headless replay or screenshot proxy.
|
|
4
|
+
|
|
5
|
+
dsh-browser-plus is developed on top of the MIT-licensed `dsh-browser` codebase and independently maintained by ParticleLight.
|
|
6
|
+
|
|
7
|
+
[](https://github.com/deepseek-ai/deepseek-harness)
|
|
8
|
+
[](https://awesome-dsh-plugin.com)
|
|
9
|
+
[](https://www.npmjs.com/package/dsh-browser-plus)
|
|
10
|
+
[](https://www.npmjs.com/package/dsh-browser-plus)
|
|
11
|
+
[](https://github.com/ParticleLight/dsh-browser-plus/stargazers)
|
|
12
|
+
[](LICENSE)
|
|
13
|
+
[](https://github.com/ParticleLight/dsh-browser-plus/actions/workflows/ci.yml)
|
|
14
|
+
[](#install)
|
|
15
|
+
[](https://github.com/ParticleLight/dsh-browser-plus/releases)
|
|
16
|
+
|
|
17
|
+
## Why it exists
|
|
18
|
+
|
|
19
|
+
Browser automation should not disappear into a process the user cannot inspect. dsh-browser-plus keeps the browser window visible while giving agents reliable CDP control.
|
|
20
|
+
|
|
21
|
+
- **Visible by default**: a real Electron `WebContentsView`, not a headless relay.
|
|
22
|
+
- **Task isolation**: all DSH sessions share one visible window while keeping isolated task views, tabs, and history; the page task manager switches the visible view, and `browser_space` names browser tasks.
|
|
23
|
+
- **Human handoff**: page chrome, bookmarks, the task workspace, operation trail, and user activity detection live on the real page; a user can take control of the active task and explicitly return it to the agent.
|
|
24
|
+
- **Task workspace**: task and operation trail are independent opaque panels (Chrome menu surface, `#292a2d`) that can stay open together. Each task exposes running, waiting-user, human-control, failed, or idle state. Thumbnails refresh on demand only while the task panel is open; background tasks retain their last image.
|
|
25
|
+
|
|
26
|
+

|
|
27
|
+
|
|
28
|
+
- **Physical input**: keyboard, mouse, hover, double-click, and file selection use CDP instead of synthetic `element.click()` events.
|
|
29
|
+
- **Recovery-aware**: a recycled child re-materializes the same session view; the first recovered capture waits for compositor readiness.
|
|
30
|
+
- **Stable baseline**: Electron 42.9.3 is pinned; the resolver rejects Electron 43.4.1 because of compositor failures.
|
|
31
|
+
|
|
32
|
+
## Install
|
|
33
|
+
|
|
34
|
+
From npm (recommended):
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
dsh plugin --profile web add dsh-browser-plus
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Or straight from the repository:
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
dsh plugin --profile web add github:ParticleLight/dsh-browser-plus
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
If another browser bundle is already installed, read the [migration guide](docs/MIGRATION.md), then restart DSH Web.
|
|
47
|
+
|
|
48
|
+
## Main capabilities
|
|
49
|
+
|
|
50
|
+
| Scenario | Tools |
|
|
51
|
+
| --- | --- |
|
|
52
|
+
| Open and inspect | `browser_open`, `browser_snapshot`, `browser_content`, `browser_screenshot` |
|
|
53
|
+
| Print and highlight | `browser_pdf`, `browser_highlight` |
|
|
54
|
+
| Native navigation | `browser_back`, `browser_forward`, `browser_reload`, `browser_stop`, `browser_scroll` |
|
|
55
|
+
| Snapshot references | `browser_click_ref`, `browser_scroll_into_view` |
|
|
56
|
+
| Page interaction | `browser_click`, `browser_press_key`, `browser_double_click`, `browser_hover`, `browser_type` |
|
|
57
|
+
| Forms and files | `browser_fill`, `browser_upload_file`, `browser_wait_for` |
|
|
58
|
+
| Tasks and handoff | `browser_tasks`, `browser_handoff`, `browser_list_tabs`, `browser_switch_tab`, `browser_close_tab`, `browser_space` |
|
|
59
|
+
| Auth and recovery | `browser_auth`, `browser_reset_session`, `browser_history` |
|
|
60
|
+
| Dialogs | `browser_dialog` |
|
|
61
|
+
| Diagnostics | `browser_console`, `browser_network` |
|
|
62
|
+
| Device emulation | `browser_emulate` |
|
|
63
|
+
| Dragging | `browser_drag` |
|
|
64
|
+
| Page scripts | `browser_execute` |
|
|
65
|
+
| Bulk scraping | `browser_scrape` |
|
|
66
|
+
| Downloads | `browser_download` |
|
|
67
|
+
| Replay | `browser_replay` |
|
|
68
|
+
| Bot checks | `browser_challenge` |
|
|
69
|
+
| Action allow-list | `browser_restrict` |
|
|
70
|
+
| Session | `browser_session`, `browser_reset` |
|
|
71
|
+
|
|
72
|
+
Snapshots expose a short-lived `snapshotId` plus element references. Prefer reference tools and take a fresh snapshot after the page changes; page-level scripts automatically ignore the browser's own chrome.
|
|
73
|
+
|
|
74
|
+
## Opening the browser window
|
|
75
|
+
|
|
76
|
+
The window normally appears the first time the agent calls a browser tool. A human can open it too, two ways:
|
|
77
|
+
|
|
78
|
+
- **The `/browser` command** — type `/` in the composer (or click `+`) and pick it; the window opens or is raised, and **no model message is produced**.
|
|
79
|
+
- **The DSH-Browser-Plus tab in the right sidebar** (its own name and icon, so it never collides with the product's own browser tab) — pick it from the rightbar's add list: the window comes up as the panel opens, and the panel keeps a button for raising it again plus the current task count.
|
|
80
|
+
|
|
81
|
+
> The product's own browser tab is a different thing: DSH's sandboxed iframe browser, unrelated to this self-hosted window.
|
|
82
|
+
|
|
83
|
+
## How it works
|
|
84
|
+
|
|
85
|
+
```text
|
|
86
|
+
browser_* tools
|
|
87
|
+
-> BrowserRuntime (ctx.browser seam)
|
|
88
|
+
-> ElectronBrowserProvider (CDP)
|
|
89
|
+
-> RemoteElectronViewHost (loopback JSON-RPC)
|
|
90
|
+
-> host-main.js (BrowserWindow + WebContentsView)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The chrome and task manager are injected through a closed Shadow DOM rather than a second Electron view. Versioned incremental workspace updates keep task and trail rendering light while background task updates stay isolated and do not steal the user's visible page.
|
|
94
|
+
|
|
95
|
+
`alert`, `confirm`, and `prompt` are accepted immediately **by default** so pages do not block, and the detail is recorded as a `dialog` item in `browser_history`. To drive a page that confirms a destructive action, set how the NEXT dialog is answered with `browser_dialog` (`accept` / `dismiss`, with `promptText` for `prompt()`) and then trigger it; `inspect` reports the last one.
|
|
96
|
+
|
|
97
|
+
## Reliability rules
|
|
98
|
+
|
|
99
|
+
1. Never reparent a visible `WebContentsView`.
|
|
100
|
+
2. The CDP capture fallback only touches siblings in the same window and restores them.
|
|
101
|
+
3. Native and full-page capture wait once for compositor readiness after child recovery.
|
|
102
|
+
4. Dialogs, captures, dynamic waits, and child recovery have regression tests and live SOAK coverage.
|
|
103
|
+
|
|
104
|
+
See [SOAK-CHECKLIST](docs/SOAK-CHECKLIST.md) for the complete runtime verification list.
|
|
105
|
+
|
|
106
|
+
## Development
|
|
107
|
+
|
|
108
|
+
```sh
|
|
109
|
+
npm install
|
|
110
|
+
npm run build
|
|
111
|
+
npm test
|
|
112
|
+
npm run smoke:electron-host # requires a local DSH Web instance; validates real Electron Host navigation and page handoff
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for contribution rules, [docs](docs/README.md) for the full documentation set, and [CHANGELOG](CHANGELOG.md) for version history.
|
|
116
|
+
|
|
117
|
+
## License
|
|
118
|
+
|
|
119
|
+
MIT. See [LICENSE](LICENSE) and [NOTICE](NOTICE.md).
|
package/README.md
CHANGED
|
@@ -1,3 +1,119 @@
|
|
|
1
|
-
#
|
|
1
|
+
# dsh-browser-plus
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
专为 DeepSeek Harness(DSH)打造的 EGO 风格可视化 Agent 浏览器。基于 `dsh-browser` 构建,支持人机协同操作:用户可以在真实页面中操作,Agent 也能同步执行、接管和恢复任务。浏览器支持多任务流并行管理与切换,并完整记录 Agent 的操作轨迹;任务流和操作轨迹均配备独立的可视化菜单面板,让任务状态、页面缩略图与操作过程一目了然。
|
|
4
|
+
|
|
5
|
+
基于 MIT 许可的 `dsh-browser` 代码基础持续开发,并由 ParticleLight 独立维护。
|
|
6
|
+
|
|
7
|
+
[](https://github.com/deepseek-ai/deepseek-harness)
|
|
8
|
+
[](https://awesome-dsh-plugin.com)
|
|
9
|
+
[](https://www.npmjs.com/package/dsh-browser-plus)
|
|
10
|
+
[](https://www.npmjs.com/package/dsh-browser-plus)
|
|
11
|
+
[](https://github.com/ParticleLight/dsh-browser-plus/stargazers)
|
|
12
|
+
[](LICENSE)
|
|
13
|
+
[](https://github.com/ParticleLight/dsh-browser-plus/actions/workflows/ci.yml)
|
|
14
|
+
[](#安装)
|
|
15
|
+
[](https://github.com/ParticleLight/dsh-browser-plus/releases)
|
|
16
|
+
|
|
17
|
+
## 为何使用它
|
|
18
|
+
|
|
19
|
+
浏览器自动化不应躲在用户看不见的进程里。dsh-browser-plus 把浏览器窗口留在用户眼前,同时让 agent 获得可靠的 CDP 操作能力。
|
|
20
|
+
|
|
21
|
+
- **真实可见**:Electron `WebContentsView`,不是 headless relay。
|
|
22
|
+
- **任务隔离**:所有 DSH session 共享一个可见窗口,但各自保留隔离的任务视图、标签与历史;页面任务管理器切换可见视图,`browser_space` 命名浏览器任务。
|
|
23
|
+
- **人机协作**:工具栏是**常驻顶栏**(画在独立视图里,不随页面缩放);书签、任务工作区与操作轨迹都在真实页面上运行,用户可在工具栏最右侧接管或显式交还给 Agent。
|
|
24
|
+
- **任务工作区**:任务与操作轨迹是彼此独立的不透明面板(Chrome 菜单表面 `#292a2d`),可同时打开;每项任务显示执行中、等待用户、用户接管、失败或空闲状态。缩略图仅在任务面板打开时为当前可见任务按需刷新,后台任务保留最后图像。
|
|
25
|
+
|
|
26
|
+

|
|
27
|
+
|
|
28
|
+
- **真实输入**:键盘、鼠标、hover、双击和文件选择都走 CDP,而不是 `element.click()` 伪事件。
|
|
29
|
+
- **恢复能力**:child 回收后会重新物化相同会话的视图;恢复后的首张截图等待 compositor 稳定。
|
|
30
|
+
- **稳定基线**:固定 Electron 42.9.3;43.4.1 的 compositor 故障会被 resolver 拒绝。
|
|
31
|
+
|
|
32
|
+
## 安装
|
|
33
|
+
|
|
34
|
+
从 npm 安装(推荐):
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
dsh plugin --profile web add dsh-browser-plus
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
或直接从仓库安装:
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
dsh plugin --profile web add github:ParticleLight/dsh-browser-plus
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
已有浏览器 bundle 时,先阅读[迁移指南](docs/MIGRATION.md),然后重启 DSH Web。
|
|
47
|
+
|
|
48
|
+
## 主要能力
|
|
49
|
+
|
|
50
|
+
| 场景 | 工具 |
|
|
51
|
+
| --- | --- |
|
|
52
|
+
| 打开与读取 | `browser_open`、`browser_snapshot`、`browser_content`、`browser_screenshot` |
|
|
53
|
+
| 打印与高亮 | `browser_pdf`、`browser_highlight` |
|
|
54
|
+
| 语义导航 | `browser_back`、`browser_forward`、`browser_reload`、`browser_stop`、`browser_scroll` |
|
|
55
|
+
| 快照引用 | `browser_click_ref`、`browser_scroll_into_view` |
|
|
56
|
+
| 页面交互 | `browser_click`、`browser_press_key`、`browser_double_click`、`browser_hover`、`browser_type` |
|
|
57
|
+
| 表单与文件 | `browser_fill`、`browser_upload_file`、`browser_wait_for` |
|
|
58
|
+
| 任务与交接 | `browser_tasks`、`browser_handoff`、`browser_list_tabs`、`browser_switch_tab`、`browser_close_tab`、`browser_space` |
|
|
59
|
+
| 登录与恢复 | `browser_auth`、`browser_reset_session`、`browser_history` |
|
|
60
|
+
| 对话框 | `browser_dialog` |
|
|
61
|
+
| 诊断 | `browser_console`、`browser_network` |
|
|
62
|
+
| 设备模拟 | `browser_emulate` |
|
|
63
|
+
| 拖拽 | `browser_drag` |
|
|
64
|
+
| 页面脚本 | `browser_execute` |
|
|
65
|
+
| 批量抓取 | `browser_scrape` |
|
|
66
|
+
| 下载 | `browser_download` |
|
|
67
|
+
| 回放 | `browser_replay` |
|
|
68
|
+
| 人机验证 | `browser_challenge` |
|
|
69
|
+
| 动作白名单 | `browser_restrict` |
|
|
70
|
+
| 会话 | `browser_session`、`browser_reset` |
|
|
71
|
+
|
|
72
|
+
快照返回短生命周期的 `snapshotId` 与元素引用;优先用 `browser_click_ref` 或 `browser_scroll_into_view` 操作,页面变化后重新快照。页面级脚本会自动过滤浏览器自身 chrome。
|
|
73
|
+
|
|
74
|
+
## 打开浏览器窗口
|
|
75
|
+
|
|
76
|
+
窗口默认只在 Agent 第一次调用浏览器工具时出现。人也可以自己打开它,有两个入口:
|
|
77
|
+
|
|
78
|
+
- **`/browser` 命令** —— 在输入框敲 `/`(或点 `+`)选「浏览器」,回车即打开或前置窗口。它**不产生模型消息**,只是把窗口带到眼前。
|
|
79
|
+
- **右侧栏「DSH-Browser-Plus」** —— 在右侧栏的「添加」列表里选它(名字和图标都是这个插件自己的,避免和 DSH 自带的「浏览器」撞名),面板打开的同时窗口就被带出来了;面板里还有一个按钮可以随时再前置一次,并显示当前有几个浏览器任务。
|
|
80
|
+
|
|
81
|
+
> 右侧栏里 DSH 自带的「浏览器」是另一个东西:那是 DSH 自己的沙箱 iframe 浏览器,与这个自托管窗口无关。
|
|
82
|
+
|
|
83
|
+
## 工作方式
|
|
84
|
+
|
|
85
|
+
```text
|
|
86
|
+
browser_* tools
|
|
87
|
+
-> BrowserRuntime (ctx.browser seam)
|
|
88
|
+
-> ElectronBrowserProvider (CDP)
|
|
89
|
+
-> RemoteElectronViewHost (loopback JSON-RPC)
|
|
90
|
+
-> host-main.js (BrowserWindow + WebContentsView)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
页面 chrome 和任务管理器通过 closed Shadow DOM 注入,而不是第二个 Electron view;任务状态与轨迹以版本化增量消息同步,后台任务更新自己的隔离视图,不会抢走用户当前可见页面。
|
|
94
|
+
|
|
95
|
+
`alert`、`confirm`、`prompt` **默认**会被立刻接受,避免页面卡死,详情记到 `browser_history` 的 `dialog` 条目。要驱动「确认删除」这类页面,先用 `browser_dialog` 设好**下一个**对话框怎么答(`accept` / `dismiss`,`prompt()` 可配 `promptText`)再触发它;`inspect` 报告上一次。
|
|
96
|
+
|
|
97
|
+
## 可靠性规则
|
|
98
|
+
|
|
99
|
+
1. 不 reparent 可见 `WebContentsView`。
|
|
100
|
+
2. CDP capture 回退只临时处理同一窗口的 sibling,并保证恢复。
|
|
101
|
+
3. child 恢复后,native 和 full-page capture 都只等待一次 compositor settle。
|
|
102
|
+
4. 对话框、截图、动态等待和 child recovery 均有回归测试与真实 SOAK 覆盖。
|
|
103
|
+
|
|
104
|
+
完整运行时检查见 [SOAK-CHECKLIST](docs/SOAK-CHECKLIST.md)。
|
|
105
|
+
|
|
106
|
+
## 开发
|
|
107
|
+
|
|
108
|
+
```sh
|
|
109
|
+
npm install
|
|
110
|
+
npm run build
|
|
111
|
+
npm test
|
|
112
|
+
npm run smoke:electron-host # 需要本地 DSH Web 已启动;验证真实 Electron Host 导航与页面交接
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
贡献方式见 [CONTRIBUTING.md](CONTRIBUTING.md)。更完整的使用说明在 [docs](docs/README.md),版本变更见 [CHANGELOG](CHANGELOG.md)。
|
|
116
|
+
|
|
117
|
+
## License
|
|
118
|
+
|
|
119
|
+
MIT。详见 [LICENSE](LICENSE) 与 [NOTICE](NOTICE.md)。
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" role="img" aria-label="dsh-browser-plus">
|
|
2
|
+
<!-- The 16/32px derivative: the two title-bar dots are sub-pixel at that size, so
|
|
3
|
+
they are dropped and the outline is drawn a little heavier instead. -->
|
|
4
|
+
<rect x="10" y="10" width="236" height="236" rx="54" fill="#202124"/>
|
|
5
|
+
<g transform="translate(20 20) scale(9)" fill="none" stroke="#ffffff" stroke-width="2.1" stroke-linecap="round" stroke-linejoin="round">
|
|
6
|
+
<rect x="3.25" y="4.75" width="17.5" height="14.5" rx="3.25"/>
|
|
7
|
+
<path d="M3.25 9.4h17.5"/>
|
|
8
|
+
</g>
|
|
9
|
+
</svg>
|
|
Binary file
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" role="img" aria-label="dsh-browser-plus">
|
|
2
|
+
<!-- Minimal white line art on the browser's own surface colour. The plate is what
|
|
3
|
+
keeps a white outline legible on a light taskbar; on a dark one it disappears. -->
|
|
4
|
+
<rect x="10" y="10" width="236" height="236" rx="54" fill="#202124"/>
|
|
5
|
+
<g transform="translate(20 20) scale(9)" fill="none" stroke="#ffffff" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
|
|
6
|
+
<rect x="3.25" y="4.75" width="17.5" height="14.5" rx="3.25"/>
|
|
7
|
+
<path d="M3.25 9.4h17.5"/>
|
|
8
|
+
<circle cx="6.15" cy="7.05" r=".9" fill="#ffffff" stroke="none"/>
|
|
9
|
+
<circle cx="8.75" cy="7.05" r=".9" fill="#ffffff" stroke="none"/>
|
|
10
|
+
</g>
|
|
11
|
+
</svg>
|
|
Binary file
|