Skip to content

Releases: lyp88997/dsh-browser-service

0.8.1:界面美化、分辨率/胶囊坐标、窗口外观自定义、随包全局技能

Choose a tag to compare

@lyp88997 lyp88997 released this 30 Sep 15:39

[0.8.1] — 2026-09-30

主题:收口界面与外观,并让「装完就有全局技能」。 这是 0.8.0 之后的三批修补(P6/P7/P8)加一个新的交付形态(随包全局技能,S)的合并发布;约束从头到尾没有变:33 个 browser_* 工具面是内置接缝的,零新增工具——这一版改的全是面板自己与「技能怎么随包落地」。

起因(三条真实反馈 + 一个新需求)

  1. 「完整分析并美化界面,美化菜单切换和窗口布局渲染效果,胶囊放置左侧上方」;随后又提「网络里共 10812 条,增加手动清理按钮,设置页增加自动清理项」「胶囊位置可自定义」「浏览器输入网址点击跳转无响应」「美化左侧按钮」。
  2. 「1,增加分辨率可调设置,2,胶囊设置增加坐标可自定义,例如水平偏移 15,垂直偏移 48,面板间距 10,层级基准 40。3,自动清理似乎未生效,检查优化」,以及「画面还是很模糊」。
  3. 「1 增加设置页可自定义调交互窗口边框主题色,透明度,玻璃效果(毛玻璃,液态玻璃)」「2 给设置页增加保存按钮,生效提示,例如已保存刷新页面生效,其他错误提示」「3 疑问,浏览器后端是否有多个标签页?标签页加载的是哪个?」;随后又反馈「主题生效的只是边缘看到线条颜色,侧边栏和底栏顶栏没有生效」。
  4. 新增需求:把「怎么用浏览器工具」做成随包发布的全局技能(DSH 的技能发现只认磁盘目录,package.json 的 dsh 清单里没有技能位)。

P6 界面美化与体验修补

# 项 影响 处理
P6-1 面板配色写死深色,亮色主题下像贴了块黑卡片 与宿主界面割裂 客户端整套改用宿主设计令牌 var(--dsw-alias-*, 回退值)(卡片/文字/边框/悬停/危险色/滚动条),暗亮主题自动跟随;等宽字体只留在日志与 URL 上
P6-2 胶囊钉在右下角、压着状态栏,也没法挪 挡视线 默认移到左上角,设置里可换四个角:纯函数 pillAnchor(pos) 只给命中角写偏移、其余 auto,与窗口几何一起存 localStorage
P6-3 入口图标是 ▣ ✓ ⌨ ⇄ ⚙ 字形(字重不一,部分平台渲染成彩色 emoji);菜单切换没有键盘可达性 观感与可访问性都差 换成 5 个 16×16 线描 SVG(描边 currentColor);入口改真 role="tablist"/"tab"/"tabpanel" + roving tabindex + aria-selected/aria-controls/aria-labelledby + 方向键/Home/End 环绕;开合/切换/悬停加 120–160 ms 过渡,prefers-reduced-motion 下全关;拖动与缩放改 rAF 节流直改 DOM、松手才落状态
P6-4 网络日志上万条,只能等文件自己轮转,清不掉 想重来一次得手工删文件 宿主新增 POST /browser-service/logs({action:'clear'|'trim', kind, keep} → clearEntries(),走同一套回环/同源/方法闸);客户端每个日志入口右上角加「清理」(点两次确认,3 秒不动手自动取消);设置里加「自动清理」上限(关闭/1000/5000/20000),某类超上限时保留最近一半,只在面板打开时检查
P6-5 地址栏输入网址点「跳转」没有任何反应 以为功能根本没做 真因:一个浏览器会话都没有时宿主回 409,而客户端把失败原因藏了起来。改成宿主按地址栏意图 provider.open('面板地址栏') 再 openUrl()(跳转顺便把页面开起来),客户端补 https://(与服务端 normalizeUrl 同规则)、把宿主给的原因显示在地址栏正下方
P6-6 失败原因设完就消失(真缺陷) 看起来像「点了没反应」 取帧 pump 每次成功都 setError(null),会把刚设置的动作错误瞬间抹掉 ⇒ 拆成 frameErr/actionErr 两条通道,取帧成功不再动动作错误
P6-7 窗口每拖一次缩放手柄就悄悄长 2 px;实时画面点击坐标偏约 1 px(真缺陷) 窗口越拖越大、点击略偏 前者缺 box-sizing:border-box(样式写 620px 实渲 622px),后者是舞台 1px 边框让元素框比图片内容框大 2px(改成 inset box-shadow 画边框,使两者相等)

P7 分辨率与胶囊坐标可调、清理可见化、画面清晰度

# 项 影响 处理
P7-1 浏览器窗口分辨率只能改插件配置(viewportWidth/viewportHeight),改一次要重启 DSH 想按屏幕或页面调大小时没办法 设置里新增「浏览器窗口分辨率」(1280×720 / 1440×900 / 1600×900 / 1920×1080)。宿主新增 POST /browser-service/viewport → provider.setViewport({width,height}):夹到 640×360 ~ 3840×2160,对已打开的每个页面 page.setViewportSize 并回 applied 计数(单页失败只记警告),之后新建的会话沿用该尺寸;非法值抛 BROWSER_VIEWPORT_INVALID;panel.json.service.viewport 回读当前生效值。设置页会显示 ✓ 已生效 1920×1080(已应用到 1 个页面)
P7-2 胶囊只能选四个角、离角距离写死;窗口与胶囊的 z-index 也写死 想挪几个像素躲开宿主左侧栏也做不到;和宿主浮层抢叠压顺序没法调 设置里新增「水平偏移」「垂直偏移」(0–400 px,默认 15/48,按选中的角生效)、「面板间距」(0–64 px,默认 10——既是窗口贴边留白,也是自动收回可见范围时用的边距)、「层级基准」(1–2000,默认 40)。胶囊与窗口改用内联 z-index(胶囊 = zBase,窗口 = zBase + 1),CSS 里写死的 40 删掉
P7-3 「自动清理」设了上限却毫无反应(真缺陷,用户报「似乎未生效」) 以为功能坏了,只能手工删日志文件 真因两条:① 运行中的 DSH 里宿主半边还是旧版——实测 POST /browser-service/logs 返回 405、GET 同路径 404,新路由根本没挂,必须重启 DSH(客户端半边改完只刷新页面不够);② 客户端 postLogs 只回布尔、判断 if (results.some(Boolean)) retry(),把失败静默吞掉。改成 postJson() 返回 {ok,status,body,error},手动清理与自动清理的成败都在窗口顶部出条提示——成功 已自动清理:网络 12000 → 500,失败 清理网络日志不可用:宿主没有这条路由(HTTP 404)——宿主半边是旧版,重启 DSH 后生效(404/405 专门给人话指引)
P7-4 实时画面糊:分辨率调大了也不见清楚(真缺陷,用户报「画面还是很模糊」) 画面像蒙了一层,页面上的字看不清,调设置也没用 真因:客户端取帧只发 ?quality=&max=,没发 maxh;宿主 clampInt(null, 240, 1200, …) 里 Number(null) === 0 被当成「给了值」,于是高度上限算成了下限 240 ——而 CDP 的 Page.startScreencast 是「等比缩到 max × maxh 的框里」,1920×1080 的页面被压成 384×240,再由界面放大 ⇒ 糊。处理:① clampInt 把 null/空串一律当没给(回落当前值/默认),宿主与客户端同一份语义;② 客户端取帧带上 maxh=最大边,让「最大边」真正只是长边上限;③ 默认取帧质量 70 → 85、默认高度上限 800 → 1200,设置页加一句人话说明

P8 窗口外观可自定义、设置显式保存

# 项 影响 处理
P8-1 窗口的边框与底色只能跟宿主主题走,想调成自己喜欢的颜色/透明度做不到;「玻璃」只是固定的一层模糊 想把窗口调得更透、更亮或更暗,或让它不要那么抢眼,都没有入口 设置页新增第一段「窗口外观」:边框颜色(跟随主题 / 无边框 / 蓝紫绿琥珀红青六个预设色 / 取色器自定任意色,只放行预设值或 #rrggbb 形状,别的一律回落主题色——这些值会写进 CSS 变量,所以先卡一道)、背景不透明度(40/60/80/95/100%,用 color-mix(in srgb, 主题底色 N%, transparent),所以底色仍随暗/亮主题走,只改实心程度)、玻璃效果(关 / 毛玻璃=backdrop-filter: blur(10px) saturate(1.15) / 液态玻璃=blur(18px) saturate(1.65) 再加一道斜向高光与内圈描边光;都是 CSS 近似,不做真折射)。窗口与收起后的胶囊共用同一份外观;纯函数 appearanceStyle(settings, kind) 算出四组 CSS 变量,borderOf 负责颜色规整
P8-2 设置一改就落盘,没有「保存」这个动作,也没有任何回执;万一写不进本地存储,用户完全看不出来 改错了没法整体放弃,也不知道自己改的到底存住了没有 设置改成草稿 + 显式保存:任何改动立刻按新值渲染(预览),但只有点顶部吸顶栏的「保存」才写进 localStorage;未保存时栏里是琥珀色 ● 有未保存的改动(窗口外观已先按新值显示),左侧「设置」入口与收起后的胶囊上出现小圆点。保存成功绿字 ✓ 已保存:窗口外观立即生效,刷新页面也保留。;写本地存储失败(无痕模式/站点策略)红字 保存失败:这个浏览器不让写本地存储(无痕模式或站点策略),改动只在本次打开有效。,草稿保留。「恢复默认」把外观恢复默认值(同样要先保存才落盘)。几何自动保存改用「上次保存的设置」,草稿不会被顺手落盘
P8-3 同一拍里连点两个设置按钮时,后点的会把先点的覆盖掉(写 P8 时在预览工装里实测到) 手快的人会看到「点了却没变」,以为按钮坏了 设置的写入通道从「传整份设置」改成传补丁:SettingsPane 只 onPatch({…}),父组件用 setSettings((prev) => normalizeSettings({...prev, ...patch})) 的函数式更新,两个改动都保留。这不是新引入的缺陷,而是 P8 新增外观三件套时暴露出来的旧写法问题
P8-4 调了边框色/透明度后只有最外圈那条线在变:标题栏、左侧入口竖排、底栏、列表吸顶条各自带着自己的不透明主题色块,把窗口的透明度挡住(用户反馈:「主题生效的只是边缘看到线条颜色,侧边栏和底栏顶栏没有生效」) 外观设置看起来只改了描边,玻璃效果也几乎看不出来,像是没生效 内部分区改用与外壳同一份透明度的分层底色:appearanceStyle 除原有四组变量外再产出 --bsp-card(=外壳底色,列表吸顶条/分组标题/保存栏用)、--bsp-surface(=抬升一层的底色,标题栏/左侧入口/底栏/展开行/JSON 块/结果条用)、--bsp-divider(选了自定义边框色时分隔线用同色调 45% 的浅色;跟随主题/无边框时保持宿主细线——无边框 只去掉最外圈那条);样式表里对应的 background/border-* 全部改成 var(--bsp-*, 旧值) 兜底,所以没挂上变量时观感与以前完全一致

S 随包全局技能(新的交付形态)

# 项 影响 处理
S-1 两份技能只存在于开发机的 $DSH_HOME/skills 里,别人装完包什么也没有;而 DSH 的技能发现只认磁盘目录,package.json 的 dsh 清单也没有技能位 「怎么用浏览器工具」和「坏了怎么修」只对作者可用 包内新增 skills/browser/SKILL.md 与 skills/browser-runtime/SKILL.md(后者还带 scripts/browse.mjs、chromium-wrapper.sh、fonts.conf、setup-libs.sh、verify-cjk.mjs,共 7 个文件),新增 src/skills.mjs 做同步
S-2 无脑覆盖会踩掉用户自己改过的技能 装个插件把人家写的东西冲掉,是不可接受的行为 同步带归属台账(目标目录里的 .dsh-browser-service.skills.json):目标不存在→装;与源逐字节相同→记为我们的、不动;与台账旧哈希相同→是本包旧版、覆盖升级;用户改过的/同名但不在台账里的→跳过并记日志,要覆盖必须 --force。幂等,重复跑不写盘
S-3 装完还得手动敲命令才落盘 多一步就有人不做 插件启动时自动同步:plugin/lib/index.js 的 apply() 顶部(早于 provider 注册)执行,失败只记一行 warn,绝不影响 provider;新增配置 skillsDir(默认空=$DSH_HOME/skills)与 syncSkills(默认 true)
S-4 落盘的东西需要能查状态 出了「同名文件被跳过」得知道为什么 CLI 新增 browsersvc skills(列每个文件:缺失/已最新/可升级/你改过/非本包,并给待处理数与冲突数)与 browsersvc skills --install [--force] [--dir=…] [--json],与插件共用同一份实现
  • 目标目录 $DSH_HOME/skills 是 DSH 的用户级技能根(rank 400,仅次于宿主自带 bundled),所以装完就是全局可用。
  • 验收:scripts/verify-bundle.mjs 新增第 6 段 8 项(空目录报缺失且退出码 0、--install 真落盘且 7 个文件全在、台账写入版本与哈希、重复跑幂等、改过的文件不覆盖、--force 才覆盖且内容回到随包版本、skills --json 可被脚本消费、配置项 skillsDir/syncSkills 在 schema 里),并在 tarball 形状断言里加 1 项(含两份 SKILL.md 与 browser-runtime/scripts/)。

验收与影响面

  • scripts/verify-daemon.mjs 35/35(不变);scripts/verify-provider.mjs 116 通过 0 失败(不变,含 P7 的 setViewport 段);scripts/verify-data.mjs 86 通过 0 失败(不变,含 P6 日志清理路由、P7 分辨率写路由与「缺 maxh 不塌到下限」的回归断言);scripts/verify-bundle.mjs 52 → 61 通过 0 失败(P6:46 → 50;P7:50;P8:50 → 52 的 5c 段 17 → 19 项;本轮新增第 6 段随包技能 8 项 + tarball 技能文件断言 1 项);scripts/verify-matrix.mjs 4 个宿主版本 × 12 项全过。
  • 半边归属:P6 的「日志清理路由」与 P7 的「分辨率路由 + 服务信息块」在宿主半边(plugin/lib/panel.js、plugin/lib/provider.js、src/opslog.mjs)⇒ 升级后必须重启 DSH;P6 的界面、P8 的全部,以及 P7 的设置控件与提示条在客户端半边(plugin/client.js)⇒ 刷新页面(Ctrl+F5)即可。S 的技能同步发生在插件启动时,重启 DSH 最稳(也可以随时 browsersvc skills --install)。
  • P7-3 那条「自动清理没反应」正是这个半边差异造成的真实误报:路由没挂时客户端把失败静默吞了;现在失败会明说「宿主半边是旧版,重启 DSH 后生效」。
  • 预览工装(/tmp/panel-preview,只用于开发)里在真浏览器中逐项复核过:分辨率 200 成功小字 / 403 跨站失败文案、清理 404 红条、?big=1 下自动清理成功横幅(真发了 {action:'trim',kind:'ops'|'network',keep:500})、胶囊按 30/60 落位且内联 z-index = 120(窗口 121)、P8 三项同拍生效且草稿不落盘、保存写入并刷新保留、Storage.prototype.setItem 抛错时红字、取色器 #ff00aa、「无边框 + 40% + 关」时四块内部分区底色降到 ... / 0.4 且分隔线回落宿主细线。
  • 未自动化覆盖的部分:上述 DOM 行为(保存栏文案、色块选中、草稿不落盘、失败红字、内部分区实际渲染色)不进 verify-*,只在预览工装人工跑过;自动化覆盖的是纯函数、路由契约与 CLI 状态。
  • 文档:根 README.md 按本轮结构重写(新增「随包全局技能」一节、面板路由表、目录结构),配置表补 skillsDir/syncSkills,验收计数统一为 35/116/61/86/4×12;docs/architecture.md、docs/verification.md、plugin/README.md、CONTRIBUTING.md 同步。

0.8.0 —— 窗口与入口重做(可拖动/可缩放 + 左侧入口 + 设置区)

Choose a tag to compare

@lyp88997 lyp88997 released this 29 Sep 15:35

与 0.7.0 相同的约束:33 个 browser_* 工具仍由内置接缝提供,零新增工具。

用户可见

  • 窗口可拖动、可自由缩放:按住标题栏拖动,右下角手柄缩放(最小 320×240),双击标题栏或 ⤢ 最大化/还原,收起 回到右下角胶囊;位置与大小记在浏览器本地(设置里可关),浏览器窗口缩放时自动收回可见范围。
  • 入口改成左侧一竖排:网页 / 操作 / 控制台 / 网络 / 设置(日志入口带条数)。
  • 新增设置区:画面质量(40/55/70/85/95)、最大边(480/800/1280/1600/1920)、打开即取帧、面板刷新间隔、日志条数、默认入口、记住窗口位置;底部是只读服务信息(版本/会话/CDP 地址/保存目录名/标签上限/空闲回收/录制开关/生效取帧参数)。
  • 画质与最大边改完不用重启:随取帧请求下发(?quality=&max=&maxh=),服务端夹到安全范围后按新参数重开流,响应头回 x-frame-quality / x-frame-max。

修复

  • clampRect 把「没记过位置」(x/y 为 null,本意贴右下角)当成 0 的缺陷:Number(null) === 0 会让窗口跑到左上角;改为显式判空再夹取(客户端探针当场暴露)。

验收

  • verify-daemon 35/35、verify-provider 110 通过 0 失败、verify-bundle 44/44、verify-data 66 通过 0 失败、verify-matrix 4 个宿主版本 × 12/12。

安装

dsh plugin --profile web add dsh-browser-service@0.8.0

装后重启 DSH(宿主半边 panel.js/liveview.mjs 在 boot 时加载)。只改客户端半边时刷新页面即可。

v0.7.0 — 实时交互网页窗口(P4)

Choose a tag to compare

@lyp88997 lyp88997 released this 29 Sep 00:26

v0.7.0 —— 实时交互网页窗口(P4)

这一版把网页面板从「只能看日志」变成能看到并直接操作:面板多了第一个标签「网页」,里面是真实浏览器的实时画面——点一下、滚一下、敲字、在地址栏跳转,都直接作用在真页面上(像 dsh-univer-office 的浮动实时窗口,只是内容换成网页)。

约束不变:33 个 browser_* 工具不属于本包(来自依赖 dsh-builtin-browser),所以这一版一个工具都不新增——实时窗口是面板里的展示与输入层。

新增

# 能力 说明
P4-1 帧流 plugin/lib/liveview.mjs 用 Page.startScreencast(JPEG,质量 70,最长边 1280)经回环代理订阅帧。只在画面变化时下发(静止零流量,实测帧约 6.8 KB、滚动动画期约 13.8 fps),逐帧 ack。CDP 会话懒建:不开流也能先转操作
P4-2 操作注入 Input.dispatchMouseEvent / insertText / dispatchKeyEvent / mouseWheel 把点击、滚动、打字、按键打回真页面;地址栏回车走 provider.openUrl(复用 http(s) 校验与操作记账)
P4-3 三条同源路由 GET /browser-service/live.jpg?since=N(长轮询,最多等 1500ms,只回比 since 新的帧,没有新帧回 204)、GET /browser-service/live.json(地址栏/标题/推流状态,每秒同步)、`POST
P4-4 三道闸 只认回环地址(非本机 403)、方法白名单(405)、POST/DELETE 要求 origin/referer 与 Host 同源(跨站 403)
P4-5 自动停流 宿主半边 30 秒没取到帧就停流(unref,不阻塞退出);客户端在收起/暂停/卸载时发 DELETE;会话关闭、reset、切标签、掉线复活都会把流停掉

客户端半边 plugin/client.js 加了 LivePane:长轮询取帧 → URL.createObjectURL → <img>(换帧时 revoke 旧 URL),鼠标/滚轮/键盘按「屏幕矩形 → 帧宽高」线性换算坐标后转发(不猜坐标),地址栏回车跳转,标签页默认打开「网页」。

验收

  • node scripts/verify-daemon.mjs → 35/35
  • node scripts/verify-provider.mjs → 110 通过,0 失败
  • node scripts/verify-bundle.mjs → 41/41(40 → 41:客户端引用的三条实时路由与服务端一字不差)
  • node scripts/verify-data.mjs → 61 通过,0 失败(45 → 61:新增 P4 四条路由与三道闸 16 项)
  • node scripts/verify-matrix.mjs --dsh <bin> … --smoke → 4 个宿主版本 × 12 项

已知限制

  • 实时窗口只对本机回环请求开放。如果你是从别的机器直连 DSH Web(不是 127.0.0.1),面板的日志标签照常,但实时窗口会 403——这是刻意保留的闸门,宁可拦住也不把浏览器交出去。
  • 跨站网页仍然只能帧流(不能 iframe 嵌),与 dsh-univer-office 同路子。

升级

dsh plugin --profile web add dsh-browser-service@0.7.0   # 注意:@latest 在依赖范围已满足时不会升级
# 或固定地址(永不过期):
dsh plugin --profile web add https://github.com/lyp88997/dsh-browser-service/releases/latest/download/dsh-browser-service.tgz

升级后需重启 DSH:面板(含实时窗口条目)要重启才出现。之后改 plugin/client.js 不必重启(客户端半边支持热替换,刷新页面即可);改宿主半边要重启。

v0.6.0 — 可观测性与网页面板(P3)

Choose a tag to compare

@lyp88997 lyp88997 released this 28 Sep 18:11

v0.6.0 —— 可观测性与网页面板(P3)

约束先摆在前面:33 个 browser_* 工具不属于本包(它们来自依赖 dsh-builtin-browser 的 tool-browser),所以这一版一个工具都不新增——观测与导出全部走 CLI + 状态文件,网页面板是纯只读展示层。

新增

# 能力 用法
P3-1 操作日志:每次浏览器操作记 {时间, 动作, 耗时 ms, 成败, 错误原因, 会话/标签} browsersvc ops [--lines=20] [--json] → <root>/ops.jsonl
P3-2 控制台与控制台错误 browsersvc console [--lines=40] [--json] → <root>/console.jsonl(文本截 500 字)
P3-3 网络请求(两阶段:request / response,带状态码与耗时;不记头与体) browsersvc network [--lines=40] [--json] → <root>/network.jsonl
P3-4 HAR:每个会话自动录一份(playwright-core 的 recordHar) browsersvc har [--session=s1] [--out=file] → <root>/har/<时间戳>-<会话>.har,留最近 10 份
P3-5 cookie / localStorage 导出与注入(走浏览器级 CDP 会话,不依赖 DSH 会话) `browsersvc cookies [--url=…] [--json
P3-6 右下角只读浮动看板:操作/控制台/网络三页签、异常红点、暂停与收起 宿主半边挂 GET /browser-service/panel.json,客户端半边 plugin/client.js(手写、零构建、只 require('react'))

实现要点:观测落盘层 src/opslog.mjs 环形覆盖(1/1/2 MiB)、任何 IO 异常都吞掉(观测绝不能把浏览器调用搞挂)、文件 0600;provider 侧用 traced() 通用追踪 + #addTab 唯一漏斗挂监听器,因此以后新增的方法自动进日志;面板路由只在宿主提供 webServer 时挂载,没有 inject 的 ctx 会跳过而不是报错(provider 不受影响)。

刻意没做的:本版不注册任何 tool.call.toolview 内联行(要拿 ToolCallBlock 形状且不能弄坏出厂通用行),留作后续小版本。

验收

  • node scripts/verify-daemon.mjs → 35/35
  • node scripts/verify-provider.mjs → 110 通过,0 失败
  • node scripts/verify-bundle.mjs → 40/40(33 → 40,新增客户端半边 5c 段 7 项)
  • node scripts/verify-data.mjs → 45 通过,0 失败(新脚本:五个观测面 + 面板路由 + 容错)
  • node scripts/verify-matrix.mjs --dsh <bin> … --smoke → 4 个宿主版本 × 12 项

升级

dsh plugin --profile web add dsh-browser-service@0.6.0   # 注意:@latest 在依赖范围已满足时不会升级
# 或固定地址(永不过期):
dsh plugin --profile web add https://github.com/lyp88997/dsh-browser-service/releases/latest/download/dsh-browser-service.tgz

升级后需重启 DSH:网页面板的宿主半边(那条只读路由)要重启才出现。之后改 plugin/client.js 不必重启(客户端半边支持热替换,刷新页面即可)。

v0.5.1 — DSH 版本适配:启动期能力探测 + 多版本实测矩阵(P2)

Choose a tag to compare

@lyp88997 lyp88997 released this 28 Sep 08:27

v0.5.1 —— DSH 版本适配:启动期能力探测 + 多版本实测矩阵(P2)

目标:DSH 升级或接缝(dsh-builtin-browser)变化时,失败要看得懂,且把「到底适配哪些宿主版本」变成实测证据而不是猜。

适配

# 项 处理
P2-1 宿主/接缝不匹配时只抛上游模块错 新增 plugin/lib/compat.js:boot 时校验接缝导出面(browser 必须有函数默认导出、tool-browser 必须有 name/apply/inject 且 inject 含 tools+browser)并读宿主与接缝版本;不符只打印一句人话(含两侧版本)并安静退出,不再安装期报模块错
P2-2 宿主没有 ctx.browser.registerBrowserProvider 时行为不明 apply 显式检查并给同类错误信息
P2-3 配置 schema 依赖 @deepseek-ai/schemastery 被当作本包独享依赖 按官方 peer 规则移到 peerDependencies + devDependencies(与宿主共享同一实例),dependencies 只剩 dsh-builtin-browser 与 playwright-core
P2-4 工具面(33 个)没有断言 verify-bundle.mjs 静态数接缝工具面:33 个且含 browser_a11y
P2-5 兼容性只有「本机实测」一句话 新增 scripts/verify-matrix.mjs(+scripts/lib/matrix-probe.mjs):同一个 tarball 装进多个宿主版本,每版本 12 项,含 --smoke 真开 example.com 读回正文
P2-6 隔离环境里 profiles/node_modules/@deepseek-ai 不存在,peer 解析路径没测过 抽出 scripts/lib/host-peers.mjs:按 boot 时同样的形态补目录(实体目录 + 软链宿主 240 项 + 补 dsh 自身,后者不在宿主 peer 目录里),并在安装测试里断言入口可加载

刻意不做:不写 dsh.engines(宿主 DshManifest 里没有该字段,宿主不读也不校验);不写 @deepseek-ai/dsh 的 semver peer 范围——semver 的预发布规则下 >=0.1.5-rc.1 <0.2.0 只解锁 0.1.5 的预发布,同范围的 0.1.7-rc.2 会被判为不符,写了反而给出错误的兼容信号。

实测矩阵(--smoke)

宿主 DSH 结果
0.1.5-rc.3(本机宿主,全局装) 12/12 ✅
0.1.7-rc.1 12/12 ✅
0.1.7-rc.2(npm latest/next) 12/12 ✅
0.1.6-alpha.2(alpha 通道) 12/12 ✅

接缝 dsh-builtin-browser 实测面:0.1.22。

验收

  • node scripts/verify-daemon.mjs → 35/35
  • node scripts/verify-provider.mjs → 110 通过,0 失败
  • node scripts/verify-bundle.mjs → 33/33(23 → 33,新增 10 项)
  • node scripts/verify-matrix.mjs --dsh dsh … --smoke → 4 个宿主版本全通过

升级

dsh plugin --profile web add dsh-browser-service@0.5.1   # 注意:@latest 在依赖范围已满足时不会升级
# 或固定地址(永不过期):
dsh plugin --profile web add https://github.com/lyp88997/dsh-browser-service/releases/latest/download/dsh-browser-service.tgz

升级后需重启 DSH(插件代码在 boot 时 import)。启动期探测不通过时,日志里会出现一行 插件未启用 —— 浏览器接缝与预期不符(接缝 X,宿主 Y):…,浏览器工具会缺席——这就是适配信号。

v0.5.0 — 资源收口:标签页上限 + 空闲释放(P1)

Choose a tag to compare

@lyp88997 lyp88997 released this 27 Sep 17:32

v0.5.0 —— 资源收口:标签页上限 + 空闲释放(P1)

完整测试量出两条资源事实:

  1. 一个标签页约 623 MB 常驻,每多开一个标签 +92.8 MB(6 个标签全关后回落,不泄漏,但没有上限);
  2. 插件从第一次用浏览器起就挂着 CDP 连接,守护进程的 idleMs 空闲回收永远不会触发——约 600 MB 的浏览器会常驻到 DSH 进程结束。

修复

# 项 处理
P1-1 标签页无上限 新增配置 maxTabs(默认 5,夹 1..50);#newTab 先准入再 newPage,超限报 BROWSER_TAB_LIMIT,文案列出上限与当前标签,并提示 browser_close_tab / browser_reset;拒绝时不留半开的页
P1-2 插件的 CDP 连接常驻 ⇒ idleMs 失效 最后一个会话关闭后插件主动断开连接(#releaseIfIdle,只在没有任何会话时执行);此后守护进程按 idleMs 空闲退出,下一次调用按 F25 自愈拉起
P1-3 idleMs 只能手改 autoStartCommand 新增配置 idleMs(默认 300000 = 5 分钟,夹 1000..86400000),由 defaultAutoStartCommand(config) 拼进自启命令;不配则不带该参数(向后兼容),越界夹住而不是让自启直接失败

另外:.browser 残留清理 504 MB → 389 MB(删掉未被任何配置/脚本引用的 moli/pw/profile/daemon-profile)。

验收

  • node scripts/verify-daemon.mjs → 35/35
  • node scripts/verify-provider.mjs → 110 通过,0 失败(95 → 110,新增 15 项覆盖上面三条)
  • node scripts/verify-bundle.mjs → 23/23

升级

dsh plugin --profile web add dsh-browser-service@0.5.0   # 注意:@latest 在依赖范围已满足时不会升级
# 或固定地址(永不过期):
dsh plugin --profile web add https://github.com/lyp88997/dsh-browser-service/releases/latest/download/dsh-browser-service.tgz

升级后需重启 DSH(插件代码在 boot 时 import)。

v0.4.4 — 修掉代理 keep-alive 免检(F27)

Choose a tag to compare

@lyp88997 lyp88997 released this 27 Sep 17:04

v0.4.4 —— 修掉代理 keep-alive 免检(F27)

完整测试时,用复用连接的 HTTP 客户端(Node http.request 默认 keep-alive)发现:同一条 TCP 连接上的第二个请求可以绕过凭据门与白名单。

代理每条连接只在 onData 里解析一次请求头,解析完即 client.pipe(up); up.pipe(client) 变成裸管道。于是先带真 token 请求一次 GET /json/version(200),再在同一条连接上 PUT /json/new(无凭据)也拿到 200(应 403),错 token 同样不被拦。

危害有限(要先持有合法 token,而持有 token 本就能走 /devtools/*),但「挡掉 /json/new|close|activate」的安全承诺不成立。

修复

  • 非 WebSocket(Upgrade)请求一律按 connection: close 转发;元数据分支回完即 client.end()。
  • 普通 HTTP 分支改为单向转发(不再把客户端接回上游),上游空闲 2s 收尾,连接不留悬挂。
  • CDP WebSocket 长连接仍双向 pipe(F20 的「长连接空闲 11s 不被 408 拆掉」行为不变)。

验收

  • node scripts/verify-daemon.mjs → 35/35(32 → 35:原「/json/protocol 长连接空闲 11s 仍存活」的 F20 断言换成「真实 CDP WebSocket 空闲 11s 仍可用」,并新增「同一连接上的第二个请求拿不到 200」「代理在响应后主动收掉非升级连接」)
  • node scripts/verify-provider.mjs → 95 通过,0 失败
  • node scripts/verify-bundle.mjs → 23/23

升级

dsh plugin --profile web add dsh-browser-service@latest
# 或固定地址(永不过期):
dsh plugin --profile web add https://github.com/lyp88997/dsh-browser-service/releases/latest/download/dsh-browser-service.tgz

v0.4.3 — 默认保存目录对齐内置 provider(D1)

Choose a tag to compare

@lyp88997 lyp88997 released this 27 Sep 15:46

v0.4.3 —— 默认保存目录对齐内置 provider(D1)

接缝工具 schema(来自依赖 dsh-builtin-browser,对所有 provider 生效)对 browser_screenshot / browser_download 的 savePath 写的是「必须落在 configured downloadDir 内(默认=系统 Downloads 目录)」。本 provider 此前在 downloadDir 未配置时不做任何目录限制:模型按说明以为写进了 Downloads,实际可以写任意绝对路径——描述与行为不一致,提示注入也能借此让浏览器工具写任意路径。

v0.4.3 起默认就有限制:downloadDir 未配置时取系统 Downloads 目录。

dsh plugin --profile web add dsh-browser-service@latest
# 或固定地址(永不过期):
dsh plugin --profile web add https://github.com/lyp88997/dsh-browser-service/releases/latest/download/dsh-browser-service.tgz

本版改动

  • 新增 defaultDownloadDir()(与内置 ElectronBrowserProvider 完全同语义):存在的 XDG_DOWNLOAD_DIR 优先 → 家目录下存在的 Downloads/下载/下載 → 回落 ~/Downloads(目录在首次写入时由 mkdir(recursive) 建出来)。
  • downloadDir 现在恒有值,#admitSavePath 去掉「未配置就不限目录」的分支:准入从「配了才限范围」变成「始终限范围」。
  • 文档同步:README 配置表 / 安全模型 / 已知限制 11 / FAQ、docs/architecture.md、docs/verification.md、CHANGELOG.md。

⚠️ 升级必读(行为变化)

savePath 默认只能写进系统 Downloads 目录,savePath: /tmp/x.png 这类写法现在会被拒(BROWSER_SCREENSHOT_BLOCKED / BROWSER_DOWNLOAD_BLOCKED)。要写进工作区或别处,就在 profile patch 的 browser-cdp 行 config 里显式配 downloadDir(patch 整行替换 config,覆盖时该行其它键要重述)。

验收

  • node scripts/verify-daemon.mjs → 32/32
  • node scripts/verify-provider.mjs → 95 通过,0 失败(88 → 95:默认目录四条解析规则、默认目录之外被拒两条、默认目录内可写入且目录被建出来)
  • node scripts/verify-bundle.mjs → 23/23(一次性隔离 DSH_HOME 里真跑官方 dsh plugin add/remove)

v0.4.2 — 纯文档版(对齐生态 README)

Choose a tag to compare

@lyp88997 lyp88997 released this 27 Sep 11:37

v0.4.2 —— 纯文档版(代码与 v0.4.1 完全相同)

只为让 npm 页面与仓库首页用上对齐生态后的 README:npm 只渲染已发布 tarball 里的 README,所以文档改善必须走一个新版本号。

dsh plugin --profile web add dsh-browser-service@latest
# 或固定地址(永不过期):
dsh plugin --profile web add https://github.com/lyp88997/dsh-browser-service/releases/latest/download/dsh-browser-service.tgz

本版改动(全在文档)

  • README 按同类热门插件(Tencent/BrowserSkill、dsh-web、dsh-browser 等 15 个抽样)的共性重写:徽章 + 英文 TL;DR + 语义化章节(这是什么 / 快速开始 / 环境要求与兼容性 / 工具参考 / 配置 / 架构 / 已知限制 / FAQ / 升级与卸载 / 进度 / 更新记录 / 文档 / 贡献 / 许可),编号章节退场。
  • 新增 33 个 browser_* 工具参考表与 13 个配置键的完整表;修正 plugin/README.md 里两处与代码不符的默认值(connectTimeoutMs 30000→10000、actionTimeoutMs 15000→30000),配置表归属收敛到根 README。
  • 版本变更史抽成 CHANGELOG.md;32 条验收 PASS 原文与 seam-probe 端到端日志移到新增的 docs/verification.md。
  • docs 去内部代号并改名:provider-m2.md → architecture.md、feasibility.md → design-notes.md、profile-patch.browser-cdp.yml → profile-patch.browser-service.yml。
  • 新增 CONTRIBUTING.md;README 里的包内文件链接改为绝对 GitHub URL。

验收(与 0.4.1 同一套,代码未变)

  • node scripts/verify-daemon.mjs → 32/32
  • node scripts/verify-provider.mjs → 88 通过,0 失败
  • node scripts/verify-bundle.mjs → 23/23(一次性隔离 DSH_HOME 里真跑官方 dsh plugin add/remove)

v0.4.1 — npm 发布 + README 修正

Choose a tag to compare

@lyp88997 lyp88997 released this 27 Sep 10:19

v0.4.1 —— npm 发布 + README 修正

v0.4.0 起本仓库只有一个交付物:dsh-browser-service 一个包既是 DSH 组合包(bundle),也是守护进程 CLI 与 provider。

# A) npm(0.4.0 起已发布)
dsh plugin --profile web add dsh-browser-service@latest
# B) GitHub Release 资产(同一个包)
dsh plugin --profile web add https://github.com/lyp88997/dsh-browser-service/releases/latest/download/dsh-browser-service.tgz

安装后重启 DSH,用 dsh --profile <name> --dump-config | grep -E 'browserProvider|patched by|not found' 校验(应出现 browserProvider: cdp-daemon 与 # == dsh-browser-service 层)。

  • 不要再单独装 dsh-builtin-browser 组合包;装过就先 dsh plugin --profile <name> remove dsh-builtin-browser
  • 不要用旧名 dsh-browser-cdp(npm 上是别人的同名包)
  • 不再需要配 autoStartCommand:默认用包内 bin/browsersvc.mjs start,首次用浏览器时自动拉起守护进程

本版变更

项 说明
npm 2026-09-27 发布 dsh-browser-service@0.4.0,同日重发 @0.4.1——0.4.0 的 tarball 里带的是发布前的 README(写着「没有走 npm」),代码与 0.4.0 完全相同
文档 README §3.3 起提供 npm / Release 两条等价安装命令;scripts/verify-bundle.mjs 的默认 tarball 版本改读根 package.json(原来写死,会随发版腐烂)

验收(零外网依赖)

  • node scripts/verify-daemon.mjs → 32/32
  • node scripts/verify-provider.mjs → 88 通过,0 失败
  • node scripts/verify-bundle.mjs → 23/23(一次性隔离 DSH_HOME 里真跑官方 dsh plugin add/remove)
  • npm 短命令在一次性隔离 DSH_HOME 里实测:add dsh-browser-service@latest → bundles 追加本包、--dump-config 出本包层与 browserProvider: cdp-daemon