DeepSeek Harness(dsh)浏览器插件
34.9/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/19 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
自动兼容检查有告警:未发布到 npm registry,仅可从源码安装;安装清单取自 packages/browser-unified-plugin/package.json。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add Short-Arm-Ape/dsh-browser-unified该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:已验证
是什么
dsh 原生插件 · browser
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 16 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查⚠ 装前注意未发布到 npm registry,仅可从源码安装;安装清单取自 packages/browser-unified-plugin/package.json
展开查看检查明细 ↓
以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。
✗npm 包dsh-browser-unified(未发布到 npm,仅可源码安装)
✓Node 引擎要求 ^22.19.0 || >=24.0.0 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明
验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/11/3 19:28:53
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 95 处,展示前 83 条)
- 发起网络请求extension/background.js:184
const res = await fetch(`http://127.0.0.1:${port}/api/status`, { - 读取本地文件packages/browser-unified-mit/lib/tools.js:42
const parsed = JSON.parse(await readFile(file, 'utf8')); - 执行外部命令固定命令packages/browser-unified-mit/lib/tools.js:49
execFile('git', args, { timeout: 25_000, maxBuffer: 1 << 20, windowsHide: true }, (error, stdout, stderr) => { - 发起网络请求packages/browser-unified-mit/lib/tools.js:259
const outcome = await approval.request({ agent: { id: agent.id }, toolName: 'browser_design_edit', reason, signal: exec.signal }); - 读取本地文件packages/browser-unified-mit/lib/tools.js:263
const before = await readFile(registryFile, 'utf8'); - 写入本地文件packages/browser-unified-mit/lib/tools.js:264
await copyFile(registryFile, registryFile + '.bak'); - 写入本地文件packages/browser-unified-mit/lib/tools.js:266
await writeFile(registryFile, JSON.stringify(reg, null, 2) + '\n', 'utf8'); - 读取本地文件packages/browser-unified-mit/src/tools.ts:47
const parsed: unknown = JSON.parse(await readFile(file, 'utf8')) - 执行外部命令固定命令packages/browser-unified-mit/src/tools.ts:55
execFile('git', args as string[], { timeout: 25_000, maxBuffer: 1 << 20, windowsHide: true }, (error, stdout, stderr) => { - 发起网络请求packages/browser-unified-mit/src/tools.ts:261
const outcome = await approval.request({ agent: { id: agent.id }, toolName: 'browser_design_edit', reason, signal: (exec as { signal?: AbortSignal }). - 读取本地文件packages/browser-unified-mit/src/tools.ts:266
const before = await readFile(registryFile, 'utf8') - 写入本地文件packages/browser-unified-mit/src/tools.ts:267
await copyFile(registryFile, registryFile + '.bak') - 写入本地文件packages/browser-unified-mit/src/tools.ts:269
await writeFile(registryFile, JSON.stringify(reg, null, 2) + '\n', 'utf8') - 读取本地文件packages/browser-unified-plugin/lib/browser-profiles.js:170
if (existsSync(local)) - 读取本地文件packages/browser-unified-plugin/lib/browser-profiles.js:176
if (existsSync(appPath)) - 读取本地文件packages/browser-unified-plugin/lib/browser-profiles.js:183
if (existsSync(candidate)) - 读取本地文件packages/browser-unified-plugin/lib/browser-profiles.js:239
return readFileSync('/proc/version', 'utf8').toLowerCase().includes('microsoft'); - 执行外部命令固定命令packages/browser-unified-plugin/lib/browser-profiles.js:280
const out = execFileSync('cmd.exe', ['/c', `echo %${name}%`], { - 读取本地文件packages/browser-unified-plugin/lib/browser-profiles.js:432
if (extensionId === '' || !existsSync(userDataDirLocal)) - 读取本地文件packages/browser-unified-plugin/lib/browser-profiles.js:435
if (!existsSync(profilePath)) - 发起网络请求packages/browser-unified-plugin/lib/buddy.js:338
const res = await fetch(`http://127.0.0.1:${port}/api/status`, { - 读取本地文件packages/browser-unified-plugin/lib/buddy.js:462
const raw = await readFile(marksFile(), 'utf8'); - 写入本地文件packages/browser-unified-plugin/lib/buddy.js:481
await mkdir(path.dirname(marksFile()), { recursive: true }); - 写入本地文件packages/browser-unified-plugin/lib/buddy.js:482
await writeFile(marksFile(), JSON.stringify({ version: 1, sessions: state.marks.sessions }, null, 2) + '\n', 'utf8'); - 发起网络请求packages/browser-unified-plugin/lib/client.js:560
fetch(UPDATE_API, { headers: { accept: 'application/vnd.github+json' } }) - 发起网络请求packages/browser-unified-plugin/lib/client.js:827
return fetch('http://127.0.0.1:' + port + '/api/status', { - 读取本地文件packages/browser-unified-plugin/lib/index.js:338
const raw = JSON.parse(readFileSync(this.pairingFile(), 'utf8')); - 写入本地文件packages/browser-unified-plugin/lib/index.js:351
mkdirSync(path.dirname(this.pairingFile()), { recursive: true }); - 写入本地文件packages/browser-unified-plugin/lib/index.js:352
writeFileSync(this.pairingFile(), `${JSON.stringify(record, undefined, '\t')}\n`, 'utf8'); - 读取本地文件packages/browser-unified-plugin/lib/index.js:441
if (existsSync(local)) { - 读取本地文件packages/browser-unified-plugin/lib/index.js:724
if (looksLikePath && !existsSync(exe)) { - 执行外部命令来自配置/变量packages/browser-unified-plugin/lib/index.js:729
const child = spawn(exe, args, { detached: true, stdio: 'ignore' }); - 发起网络请求packages/browser-unified-plugin/lib/index.js:1093
const outcome = await approval.request({ - 写入本地文件packages/browser-unified-plugin/lib/index.js:1216
await mkdir(dir, { recursive: true }); - 写入本地文件packages/browser-unified-plugin/lib/index.js:1221
await writeFile(file, buffer); - 写入本地文件packages/browser-unified-plugin/lib/index.js:1239
await mkdir(path.dirname(file), { recursive: true }); - 写入本地文件packages/browser-unified-plugin/lib/index.js:1242
await mkdir(dir, { recursive: true }); - 读取本地文件packages/browser-unified-plugin/lib/index.js:2830
const pkg = JSON.parse(readFileSync(path.join(here, '..', 'package.json'), 'utf8')); - 读取本地文件packages/browser-unified-plugin/lib/index.js:2845
const doc = JSON.parse(readFileSync(file, 'utf8')); - 读取本地文件packages/browser-unified-plugin/lib/permissions.js:98
stat = statSync(file); - 读取本地文件packages/browser-unified-plugin/lib/permissions.js:109
parsed = JSON.parse(readFileSync(file, 'utf8')); - 读取本地文件packages/browser-unified-plugin/lib/unified-tools.js:97
const parsed = JSON.parse(await readFile(file, 'utf8')); - 执行外部命令固定命令packages/browser-unified-plugin/lib/unified-tools.js:104
execFile('git', args, { timeout: 25_000, maxBuffer: 1 << 20, windowsHide: true }, (error, stdout, stderr) => { - 发起网络请求packages/browser-unified-plugin/lib/unified-tools.js:207
outcome = await approval.request({ agent, toolName, reason, signal: exec.signal }); - 读取本地文件packages/browser-unified-plugin/lib/unified-tools.js:411
const before = await readFile(registryFile, 'utf8'); - 写入本地文件packages/browser-unified-plugin/lib/unified-tools.js:412
await copyFile(registryFile, registryFile + '.bak'); - 写入本地文件packages/browser-unified-plugin/lib/unified-tools.js:414
await writeFile(registryFile, JSON.stringify(reg, null, 2) + '\n', 'utf8'); - 写入本地文件packages/browser-unified-plugin/lib/unified-tools.js:553
await copyFile(file, file + '.bak'); - 写入本地文件packages/browser-unified-plugin/lib/unified-tools.js:554
await writeFile(file, JSON.stringify(reg, null, 2) + '\n', 'utf8'); - 读取本地文件packages/browser-unified-plugin/src/browser-profiles.ts:206
if (existsSync(local)) out.push(local) - 读取本地文件packages/browser-unified-plugin/src/browser-profiles.ts:210
if (existsSync(appPath)) out.push(appPath) - 读取本地文件packages/browser-unified-plugin/src/browser-profiles.ts:215
if (existsSync(candidate)) out.push(candidate) - 读取本地文件packages/browser-unified-plugin/src/browser-profiles.ts:262
return readFileSync('/proc/version', 'utf8').toLowerCase().includes('microsoft') - 执行外部命令固定命令packages/browser-unified-plugin/src/browser-profiles.ts:301
const out = execFileSync('cmd.exe', ['/c', `echo %${name}%`], { - 读取本地文件packages/browser-unified-plugin/src/browser-profiles.ts:469
if (extensionId === '' || !existsSync(userDataDirLocal)) return undefined - 读取本地文件packages/browser-unified-plugin/src/browser-profiles.ts:471
if (!existsSync(profilePath)) return undefined - 发起网络请求packages/browser-unified-plugin/src/buddy.ts:347
const res = await fetch(`http://127.0.0.1:${port}/api/status`, { - 读取本地文件packages/browser-unified-plugin/src/buddy.ts:469
const raw = await readFile(marksFile(), 'utf8'); - 写入本地文件packages/browser-unified-plugin/src/buddy.ts:487
await mkdir(path.dirname(marksFile()), { recursive: true }); - 写入本地文件packages/browser-unified-plugin/src/buddy.ts:488
await writeFile(marksFile(), JSON.stringify({ version: 1, sessions: state.marks.sessions }, null, 2) + '\n', 'utf8'); - 读取本地文件packages/browser-unified-plugin/src/index.ts:549
const raw = JSON.parse(readFileSync(this.pairingFile(), 'utf8')) as PairingRecord - 写入本地文件packages/browser-unified-plugin/src/index.ts:562
mkdirSync(path.dirname(this.pairingFile()), { recursive: true }) - 写入本地文件packages/browser-unified-plugin/src/index.ts:563
writeFileSync(this.pairingFile(), `${JSON.stringify(record, undefined, '\t')}\n`, 'utf8') - 读取本地文件packages/browser-unified-plugin/src/index.ts:652
if (existsSync(local)) { - 读取本地文件packages/browser-unified-plugin/src/index.ts:927
if (looksLikePath && !existsSync(exe)) { - 执行外部命令来自配置/变量packages/browser-unified-plugin/src/index.ts:932
const child = spawn(exe, args, { detached: true, stdio: 'ignore' }) - 发起网络请求packages/browser-unified-plugin/src/index.ts:1318
const outcome = await approval.request({ - 写入本地文件packages/browser-unified-plugin/src/index.ts:1471
await mkdir(dir, { recursive: true }) - 写入本地文件packages/browser-unified-plugin/src/index.ts:1476
await writeFile(file, buffer) - 写入本地文件packages/browser-unified-plugin/src/index.ts:1498
await mkdir(path.dirname(file), { recursive: true }) - 写入本地文件packages/browser-unified-plugin/src/index.ts:1500
await mkdir(dir, { recursive: true }) - 读取本地文件packages/browser-unified-plugin/src/index.ts:3088
const pkg = JSON.parse(readFileSync(path.join(here, '..', 'package.json'), 'utf8')) as { version?: unknown } - 读取本地文件packages/browser-unified-plugin/src/index.ts:3100
const doc = JSON.parse(readFileSync(file, 'utf8')) as { record?: { rows?: { title?: { val?: unknown } } } } - 读取本地文件packages/browser-unified-plugin/src/permissions.ts:133
stat = statSync(file) - 读取本地文件packages/browser-unified-plugin/src/permissions.ts:143
parsed = JSON.parse(readFileSync(file, 'utf8')) - 读取本地文件packages/browser-unified-plugin/src/unified-tools.ts:103
const parsed: unknown = JSON.parse(await readFile(file, 'utf8')) - 执行外部命令固定命令packages/browser-unified-plugin/src/unified-tools.ts:111
execFile('git', args as string[], { timeout: 25_000, maxBuffer: 1 << 20, windowsHide: true }, (error, stdout, stderr) => { - 发起网络请求packages/browser-unified-plugin/src/unified-tools.ts:229
outcome = await approval.request({ agent, toolName, reason, signal: (exec as { signal?: AbortSignal }).signal }) - 读取本地文件packages/browser-unified-plugin/src/unified-tools.ts:416
const before = await readFile(registryFile, 'utf8') - 写入本地文件packages/browser-unified-plugin/src/unified-tools.ts:417
await copyFile(registryFile, registryFile + '.bak') - 写入本地文件packages/browser-unified-plugin/src/unified-tools.ts:419
await writeFile(registryFile, JSON.stringify(reg, null, 2) + '\n', 'utf8') - 写入本地文件packages/browser-unified-plugin/src/unified-tools.ts:547
await copyFile(file, file + '.bak') - 写入本地文件packages/browser-unified-plugin/src/unified-tools.ts:548
await writeFile(file, JSON.stringify(reg, null, 2) + '\n', 'utf8')
扫描于 2026/11/2(1 天前) · 范围 全包扫描 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
README
由 DeepSeek 最新模型翻译生成dsh-browser-unified
English · 中文
四条 DeepSeek Harness(dsh)浏览器插件路线合一的可安装插件:用你自己的真实浏览器 (DSH Browser Control 扩展 + 本地桥)给模型提供 27 个 browser_ 工具,前面统一加一层可配置的 URL 策略守卫,另附「上游自检 / 设计注册表」工具三件套与 GUI 设置分区。
仓库 = packages/(合并产物)+ upstream/(只留许可正文:四个第三方上游与前身项目各自的 LICENSE,源码基线由 upstream-baseline.json 的 commit SHA 钉住,可按 SHA 重新获取)。
合并核心与插件壳整包以 AGPL-3.0-only 发布(含 caob23/dsh-browser-control 桥收编代码,归属矩阵见 NOTICE.md)。
安装
一条命令产出全部 Release 资产(含自检闸门):node scripts/build-release.mjs → 产物在 dist-release/(三个包的 tgz + 扩展 zip + 兼容旧名的干净 zip + .sha256 + INSTALL.md)。
展开完整文档(README 剩余 1 节)
dsh-browser-unified English · 中文 四条 DeepSeek Harness(dsh)浏览器插件路线合一的可安装插件:用你自己的真实浏览器 (DSH Browser Control 扩展 + 本地桥)给模型提供 27 个 browser_ 工具,前面统一加一层可配置的 URL 策略守卫,另附「上游自检 / 设计注册表」工具三件套与 GUI 设置分区。 仓库 = packages/(合并产物)+ upstream/(只留许可正文:四个第三方上游与前身项目各自的 LICENSE,源码基线由 upstream-baseline.json 的 commit SHA 钉住,可按 SHA 重新获取)。 合并核心与插件壳整包以 AGPL-3.0-only 发布(含 caob23/dsh-browser-control 桥收编代码,归属矩阵见 NOTICE.md)。 安装 一条命令产出全部 Release 资产(含自检闸门):node scripts/build-release.mjs → 产物在 dist-release/(三个包的 tgz + 扩展 zip + 兼容旧名的干净 zip + .sha256 + INSTALL.md)。 1. 浏览器扩展(必须用本仓库这版,不能用上游 caob23/dsh-browser-control 版): 从本仓库 Releases 下载 DSH-Browser-Control-v1.0.37.zip → 解压到任意目录 → edge://extensions(Chrome 为 chrome://extensions)开「开发者模式」→「加载解压缩的扩展」。 扩展源码就在本仓库 extension/,与插件同协议但多了 frames / 自建窗口 / 端口自动发现 / 导航完成判定 / div 化 SPA 元素识别等改动 —— 换回上游扩展这些能力会失效。 2. 插件(两个包一起装):从 Releases 下载 browser-unified-core-<ver>.tgz 与 dsh-browser-unified-<ver>.tgz,然后: dsh plugin add github:Short-Arm-Ape/dsh-browser-unified 不能用。 实测(pnpm 12.5.1)会装出一个 @short-arm-ape/dsh-browser-unified@0.0.0 的占位包:仓库根目录不是包(真正的包在 packages/ 下),装出来的东西没有 lib/ 也没有 dsh.bundle.patch,dsh 不会挂载它。GitHub 上装的路径只适合"仓库根就是插件包"的仓库。这里请用下面的 Release 资产(file:),或者把仓库 clone 下来用 file: 指到 packages/ 里的目录。 推荐:由 CLI 落到 profile 的 vendor/ 并改好 package.json dsh plugin --profile <profile> add file:<path>/browser-unified-core-<ver>.tgz \ file:<path>/dsh-browser-unified-<ver>.tgz 等价的手工写法: pnpm add <path>/browser-unified-core-<ver>.tgz <path>/dsh-browser-unified-<ver>.tgz package.json: dependencies: "browser-unified-core": "file:<...>/browser-unified-core-<ver>.tgz" "dsh-browser-unified": "file:<...>/dsh-browser-unified-<ver>.tgz" dsh.profile.bundles: 加入 "dsh-browser-unified" 重启 dsh web 后生效(宿主新代码与 GUI client 半区都需要重启加载)。 包内 patch 已默认 enabled: true(装上即监听 9777);要关就在 profile 层按 id 覆盖 config。 想要 MIT 许可、不含 caob23/dsh-browser-control 派生代码的版本,用同仓库的 MIT 版 dsh-browser-unified-mit (不带浏览器桥与 browser_ 工具,仅 URL 策略 / 审批 / 自更新等模块)。 建议(专用配置文件):把 DSH Browser Control 扩展装在专用的浏览器配置文件里,与日常浏览隔离;需要访问本机服务(如 127.0.0.1)时把 urlMode 设为 intranet。跨 profile 自动拉起与 “无痕式临时干净配置”属拟议能力(design de-013),尚未实现。 配置与设置界面 GUI:设置 →「浏览器」(0.3.0+) 插件以 settings.section 在 DSH 设置对话框注册了独立的 「浏览器」 分区(形如 better-sidebar 的「侧边卡片」),逐项即时生效(改 URL 策略 / 云元数据列表只重建策略、不重启监听): | 项 | 说明 | | 启用浏览器桥 | 关闭则工具仍挂载,调用时报如何开启 | | URL 策略档位 | public(默认,拦私网/回环/云元数据)/intranet(放行本地/LAN,仍拦云元数据) | | 端口 / 令牌 / 截图目录 / registry 目录 | 监听与路径(改动重启本地桥) | | 云元数据端点拦截 | 主开关 + 拦截主机名列表 + 拦截 IP 列表(整体替换内置默认;GUI 可「恢复内置默认」或「清空全部」) | profile YAML(等价高级项,cordis.patch.yml) - id: browser-bridge config: enabled: true urlMode: public # public | intranet blockMetadata: true # 云元数据拦截总开关 metadataHostnames: [metadata, metadata.google.internal, instance-data, instance-data.ec2.internal, metadata.azure.internal, metadata.tencentyun.com] metadataIps: [169.254.169.254, 100.100.100.200, fd00:ec2::254] registryDir: '<repo-dir>' # 指向本仓库根(含 design/registry.json + upstream-baseline.json);留空读包内 registry/ port: 9777, token: dsh-local, shotsDir: dsh-browser-shots(默认即可) 云元数据端点语义:内置默认(AWS/GCP/Azure 169.254.169.254、阿里 100.100.100.200、腾讯/阿里 metadata hostname 等)只是初始值;两条列表一旦给出即整体替换([] = 该族不拦),用于非三大云 / 自建 VPC 等场景的按需维护。public 档还有一条固定的默认主机黑名单(localhost / metadata 等)作为安全网,不受上述列表影响。 模型可用能力 | 工具 | 说明 | | browser_navigate / read / snapshot / click / type / press / scroll / tabs / evaluate | 驱动真实浏览器(含登录态) | | browser_screenshot / pdf / emulate | 截图(落盘 shotsDir)、导出 PDF、设备视口模拟 | | browser_cleanup | 清理截图与 __ 前缀临时产物 | | browser_console_log / network_log / network_clear | 页内 console / 网络请求观测 | | browser_check_update | 只读:上游相对开发基线是否有新提交(DRIFT / UP-TO-DATE / UNREACHABLE) | | browser_design_show / browser_design_edit | 读 / 受控改 design/registry.json(写必经审批,自动 .bak) | 导航类命令(nav / tabs.open)在发给扩展之前先过统一 UrlPolicy;被拦目标根本到不了浏览器。 安全模型 - URL 策略(src/url-policy.ts,MIT 上游语义蒸馏):public 档拦私网/回环/云元数据并做 resolve-then-validate DNS 复核;intranet 档有意放行本地/LAN,只保留元数据端点黑名单与用户黑名单。 - 鉴权:写入类操作(browser_design_edit、基线推进、源码变更)一律用户审批,fail-closed;外部内容(上游 commit / README / 网页文本)只作数据、绝不充当指令或工具参数。 - 已知边界(未实现里程碑):策略只拦“工具发起的导航”;页面自身 XHR / 重定向 / iframe / WebSocket / DNS-rebinding 需扩展端逐请求拦截(design de-005);browser_evaluate 尚无 allowEval 门控(de-006);无 GUI 实时画面(de-007)。设计注册表见 design/registry.json。 目录结构 dsh-browser-unified/ ├── README.md 本文件 ├── NOTICE.md 上游来源/版本/许可证归属矩阵 ├── upstream-baseline.json 开发基线:五上游归档日 commit SHA ├── design/ 设计意图唯一书面出处 │ ├── README.md 工具契约 / 威胁模型与鉴权 / 条目状态机 │ └── registry.json impactRules(单一事实源)/ tooling / authz / designEntries ├── scripts/check-upstream.ps1 上游自检(只读) ├── .github/workflows/ci.yml CI:三包构建 + tests/ 全部套件(宿主侧,不碰真浏览器) ├── tests/ 回归套件 10 套(325 项断言)+ run-all.mjs 汇总入口 ├── upstream/ 只留各上游的 LICENSE(+ 上游自带的第三方声明);源码按 SHA 取 └── packages/ ├── browser-unified-core/ 合并核心(AGPL):url-policy / approval / bridge(收编) / guarded-bridge / self-update ├── browser-unified-plugin/ dsh 插件壳(AGPL):27 个 browser_* 工具 + 自更新三件套 + GUI「浏览器」设置分区 └── browser-unified-mit/ MIT 精简版(无桥、无驱动工具) 自动验证 两条线,别混在一起: | 层 | 跑什么 | 什么时候 | | CI(GitHub Actions,ubuntu + node 22) | 三个包 npm ci + 构建(走仓库自己的 build-pack)+ tests/ 全部 10 套(325 项断言)+ lib/client.js 与 client/client.js 字节一致 | 每次 push 到 main、每个 PR、手动触发 | | 本地手动验证(真浏览器) | 只有它验得了的那层:浮层、硬锁、导航完成判定、div 化 SPA 元素识别 | 改扩展或改闸门时手跑(做法见 design/) | 本地一条命令:node tests/run-all.mjs(可带过滤词,例如 node tests/run-all.mjs tool)。 每个套件都是独立进程、自己数断言、自己用退出码交代结果,所以 CI 里不需要额外的断言解析。 CI 不做的事(免得看到绿就以为能上线): - 不跑真浏览器:runner 上没有你的浏览器和已加载的扩展,「扩展装上去之后到底能不能点」它验不了; - 不打 Release:node scripts/build-release.mjs 是本机发布流程(要真扩展 zip、要上传资产)。 CI 里有两处不那么直觉、但必须这样的地方(YAML 里也写了注释): 1. packages/browser-unified-plugin 用裸包名 import 'browser-unified-core',而 core 不是它的 package.json 依赖(本地也是手工装的)。npm 不管这条链接,CI 里用一条 ln -s 复原同一布局; 2. 构建走 node scripts/build-pack.mjs --no-pack 而不是裸 tsc:客户端那一半(client/client.js → lib/client.js)只有前者会复制,单跑 tsc 会让设置页测试读到旧文件。 上游与许可 | 归档 | 路线 | 浏览器 | 安全模型 | 并入 | | dsh-browser-xylt369 | 类型化 seam + Playwright | 插件另起 Edge | 四层 URL 守卫 | ✅ url-policy(public)/approval | | dsh-intranet-browser-short-arm-ape(本项目前身,非外部上游) | 上者内网分支 | 独立实例+profile | 元数据黑名单+逐次审批 | ✅ url-policy(intranet)/approval | | dsh-browser-control-kyo615 | @playwright/mcp 子进程 | 另起 Chrome | 无 URL 校验 | ➖ 仅归档(live-view 候选) | | dsh-browser-control-caob23 | 扩展+本地 WS 桥(CDP) | 用户真实浏览器 | 无 URL 校验(本插件已补) | ✅ bridge + GuardedBridge | | dsh-agent-webops(参考上游) | headless Edge(CDP) 独立实例 | 一次性临时 profile | 无 URL 校验(参考) | ➖ 归档参考(de-019;de-013/17 相关) | - 构建 / 验证:packages/browser-unified-core、browser-unified-plugin、browser-unified-mit 各自 npm run typecheck / npm run build;插件用 node scripts/build-pack.mjs(tsc→lib, client/client.js→lib/client.js,npm pack 到包根)。产物 dsh-browser-unified-0.7.3.tgz。 - 上游自检:pwsh scripts/check-upstream.ps1 [-UpstreamId <id>] [-UpdateBaseline]。 只查 role=merge 的条目(目前只有 caob23)—— reference 档只在决定接线某功能时翻归档取用,不做定时自检(2026-10-13 起)。检出 DRIFT 后必须先向你报告“上游改了什么、影响哪些合并模块”,你确认后 agent 才 re-vendor + 合并 + typecheck;-UpdateBaseline 只推进 merge 档的基线 SHA。改动会写 design/registry.json 条目。 - 安全红线:本机 git 缺 CA 时脚本内置 -c http.sslBackend=openssl -c http.sslVerify=false (只读参数);外部文本不得当指令执行。 与上游功能差距 (0.3.0 之后与四并入/候选上游逐项对比的差距清单:页面级请求拦截、allowEval 门控、GUI 实时画面、 stealth / web-permission 授权 UI 等未实现项,见 docs/gap-analysis.md,条目状态在 design/registry.json;dsh-agent-webops 为参考归档(非合并源),见 de-019。)详见对话产出的差距报告。 相关项目 - caob23/dsh-browser-control —— 本插件收编并扩展的上游:本地 WS 桥 + MV3 扩展,AGPL-3.0。 - dsh-intranet-browser —— 本插件的前身(已归档),URL 策略与审批层来自它。 - @deepseek-ai/dsh —— 宿主(DeepSeek Harness)。 - dsh-plugin.org —— 插件市场;它的安装失败报告里有本文档用到的诊断信息。 许可 - 合并核心与插件壳:AGPL-3.0-only(MIT 逻辑并入 AGPL 在法理上允许;caob23 源码行保留头部版权与来源,NOTICE.md 为完整归属矩阵)。分发 / 提供网络服务须遵守 AGPL-3.0 第 13 条。 - MIT 版:packages/browser-unified-mit。
预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
Short-Arm-Ape/dsh-browser-unified
DeepSeek Harness(dsh)浏览器插件
相关插件 · 浏览器
智能体插件框架deepseek-ai/deepseek-harness
DeepSeek Harnessdsh是由 DeepSeek AI 开发的开源 agent harness智能体框架。
★ 270,422已汉化DSH
71.9
多设备 Agent 看板YaoApp/yao
✨ 所有 Agent 和工作区集中管理,覆盖你的每一台设备。任务看板追踪进度,桌面端、移动端、浏览器、API…
★ 8,147已汉化DSH
71.2
可扩展侧边栏工作台omdsh-dev/DSH-better-sidebar
DSH 的双工作台:原生右侧栏 + 自绘底部面板,并把 ctx.betterSidebar 服务开放给所有插件
★ 4,761已汉化DSH
71.1
浏览器自动化桥Tencent/BrowserSkill
你的 Agent。你的浏览器。连接,就能协作。
★ 9,928已汉化DSH
71
AI 小说创作工作台EthanYoQ/AI-Novel-Writer
AI 小说作家 / AI Novel Writer
★ 1,591已汉化DSH
70.7
智能体浏览器引擎platonai/Browser4
DeepSeek Harness 集成
★ 1,175已汉化DSH
70.4