dsh-web-search-ddg
aooyoo
Zero-token DuckDuckGo search provider for the DeepSeek Harness (DSH) web seam — local headless browser, no API key, no m…
PROJECT TOPICS
PROJECT README
面向
@deepseek-ai/dsh的开源桌面客户端 —— 把 dsh 的 Web UI 装进一个原生窗口里,省去手动在浏览器里打开本地服务的麻烦。
DSH Desktop 是一个 Electron 桌面应用,封装了 DeepSeek 官方的 dsh(DeepSeek Harness)CLI 调用。
dsh 本身是一个 Node.js 命令行工具,启动后会在本地 127.0.0.1:3080 监听一个 Web UI(浏览器界面)。DSH Desktop 做的工作就是:
spawn 一个 Electron 子进程,以 ELECTRON_RUN_AS_NODE=1 让它当作 Node 运行时,跑起 @deepseek-ai/dsh 的 web 子命令。dsh web: http://127.0.0.1:xxxx/ 地址,把它塞进一个 BrowserWindow 里的 <iframe>。hiddenInset、Windows 的 hiddenInset overlay)、主题色同步、启动 Splash 动画等桌面化体验。iframe 加载完成后优雅地淡出 Splash,关窗时一并清理子进程。适合不想每次都打开终端、敲 dsh web 然后手动复制链接到浏览器的用户。
EADDRINUSE 自动换端口重试window.open 自动用系统默认浏览器打开prefers-color-scheme,并尊重 dsh 自家的 settings.yaml 用户偏好这是本项目最重要的设计点之一 —— 最终用户拿到的安装包是一个完全自包含的二进制。
打包用的是 Electron 43.x,而 Electron 二进制本身已经把 Node.js 嵌进去了。electron-builder 打包时:
electron-builder.json5 里 files: ["dist", "dist-electron"] 把渲染层与主进程 build 产物打进去;npmRebuild: false —— 跳过原生模块的本地编译步骤;asarUnpack: ["node_modules/**"] —— 把 @deepseek-ai/dsh 的依赖解包到 app.asar.unpacked(这部分运行时需要从磁盘真实读取,不能压缩进 asar);electron/main.ts 里通过 process.execPath 启动 Electron 子进程,并设置 ELECTRON_RUN_AS_NODE=1 让它当作 Node 跑 dsh web;参见 release/0.0.0/ 目录(一次完整打包的输出):
| 平台 | 产物 | 体积 |
|---|---|---|
| macOS | DSH Desktop-Mac-0.0.0-Installer.zip |
~163 MB |
| Windows | DSH Desktop-Windows-0.0.0-Setup.exe |
~144 MB |
| Linux | DSH Desktop-Linux-0.0.0.AppImage |
~163 MB |
体积主要是 Electron 运行时 + Node.js 嵌入 + Chromium,属于 Electron 应用的普遍水平。看到这个体积不要慌——这正是下面「未来计划」想用 Tauri 解决的问题。
只有 从源码构建 时才需要:
dpkg / fakeroot 等 AppImage 工具链)也就是说: 开发需要 Node/Bun,运行不需要。
前往 Releases 页面下载对应平台的安装包。
DSH Desktop-Mac-{version}-Installer.dmg(或 .zip)。.dmg,把 DSH Desktop.app 拖进 /Applications。系统设置 → 隐私与安全性 点「仍要打开」。DSH Desktop-Windows-{version}-Setup.exe。C:\Users\<you>\AppData\Local\Programs\DSH Desktop)。DSH Desktop-Linux-{version}.AppImage。chmod +x DSH\ Desktop-Linux-*.AppImage。./DSH\ Desktop-Linux-*.AppImage 启动。fuse:sudo apt install fuse libfuse2(Ubuntu 22.04+ 需要 libfuse2)。app.getPath('userData') 下的 dsh/ 子目录:~/Library/Application Support/DSH Desktop/dsh/%APPDATA%\DSH Desktop\dsh\~/.config/DSH Desktop/dsh/git clone https://github.com/MonshinYu/dsh-desktop.git
cd dsh-desktop
# 推荐使用 Bun(已含 bun.lock)
bun install
# 或使用 Node
npm install
bun run dev # 等价于 npx vite,Electron 主进程 HMR + 渲染层 HMR
这条命令会同时:
vite-plugin-electron)electron/*.ts 与 src/*.ts 的变更自动热重载bun run build # tsc 类型检查 + vite 打包 + electron-builder 打包
# 或只跑前端打包:
bun run build -- --mode production # 注意:脚本里 -mwl 会触发跨平台构建
如需调试打包后的运行时,可以只跑 vite build 然后手启 Electron:
npx vite build
npx electron dist-electron/main.js
bun run build
脚本内部是 tsc && vite build && electron-builder -mwl,-mwl 表示 macOS / Windows / Linux 三平台都构建(实际只能产出当前机器支持的平台,其它平台产物是无效占位)。
# 仅 macOS
bunx electron-builder --mac
# 仅 Windows
bunx electron-builder --win
# 仅 Linux
bunx electron-builder --linux
所有产物统一输出到 release/${version}/:
release/0.0.0/
├── DSH Desktop-Mac-0.0.0-Installer.dmg
├── DSH Desktop-Mac-0.0.0-Installer.zip
├── DSH Desktop-Windows-0.0.0-Setup.exe
├── DSH Desktop-Linux-0.0.0.AppImage
├── mac/ # macOS 未打包的 .app(直接可运行)
├── win-unpacked/ # Windows 未打包的目录(直接可运行)
└── linux-unpacked/ # Linux 未打包的目录
主配置在 electron-builder.json5:
appId: com.deepseek.dsh-desktop(沿用了 dsh 的命名空间,二次开发请改成你自己的)productName: DSH Desktopasar + asarUnpack: 必要配置,必须解包 node_modules 才能跑 dsh 子进程nsis.oneClick: false / allowToChangeInstallationDirectory: true: Windows 给用户选安装路径的自由dsh-desktop/
├── electron/ # Electron 主进程 + Preload
│ ├── main.ts # 应用入口:单实例锁 / 窗口创建 / 生命周期
│ ├── preload.ts # contextBridge:暴露 window.api 给渲染层
│ ├── dsh-server.ts # ★ 核心:管理 dsh 子进程(启停 / 状态 / 端口)
│ ├── titlebar.ts # 原生标题栏定制 + 主题同步注入
│ └── splash-theme.ts # 解析 Splash 用色(dark / light 主题)
│
├── src/ # 渲染层(Vite + 原生 TS + CSS)
│ ├── main.ts # 渲染层入口:监听 dsh 状态 → 设置 iframe.src
│ └── style.css # 样式
│
├── index.html # 渲染层 HTML 骨架(含 Splash SVG、iframe)
├── vite.config.ts # Vite 配置 + vite-plugin-electron
├── electron-builder.json5 # 打包配置
├── package.json # 脚本入口
├── tsconfig.json # TypeScript 配置
└── bun.lock # 锁文件(Bun 优先)
用户双击图标
│
▼
Electron 主进程启动 (electron/main.ts)
│
├─► 创建 BrowserWindow(隐藏),显示 Splash
│
├─► dshServer.start() ──► spawn Node 子进程
│ │
│ ▼
│ @deepseek-ai/dsh web --port <free>
│ │
│ ▼
│ stdout 解析 "dsh web: http://127.0.0.1:xxxx/"
│ │
│ ▼
│ IPC → 渲染层收到 { state: 'ready', url }
│
▼
渲染层拿到 url → 写入 <iframe>.src
│
▼
iframe load 事件 → 淡出 Splash → 显示主窗口
本项目是开源二创,下面列出所有引用的上游项目,致敬原作者。
| 包 | 版本 | 许可证 | 用途 | 出处 |
|---|---|---|---|---|
@deepseek-ai/dsh |
^0.1.0-rc.6 |
MIT | 核心 CLI:本项目内置它的 web 子命令,所有 UI 逻辑都来自它 |
deepseek-ai/deepseek-harness (apps/cli 子目录) |
@deepseek-ai/dsh 本身又是基于 Cordis 插件框架构建的,由 deepseek-ai 组织维护。
| 包 | 版本 | 用途 | 出处 |
|---|---|---|---|
electron |
^43.4.0 |
桌面运行时(自带 Chromium + Node.js) | electron/electron |
electron-builder |
^24.13.3 |
跨平台打包为安装包 | electron-userland/electron-builder |
vite |
8.0.16 |
渲染层构建工具 | vitejs/vite |
vite-plugin-electron |
^0.28.6 |
Vite 与 Electron 主进程的集成 | electron-vite/vite-plugin-electron |
vite-plugin-electron-renderer |
^0.14.5 |
渲染层直接使用 Node API | 同上 |
typescript |
^5.2.2 |
类型检查 | microsoft/TypeScript |
dsh 把这些都装在内置的 node_modules 里,应用启动时直接复用:
cordis (DeepSeek 维护的 IoC 插件框架)@deepseek-ai/cordis-plugin-* (HMR / 加载器 / 计时器插件)@deepseek-ai/dsh-* (cli / boot / base / web-app / headless / 工具集 / 终端 / Python / 人设 / 计划模式 / 子代理 / ... 30+ 子包)commander (CLI 参数解析)js-yaml (配置解析)所有上游组件均以 MIT 协议开源。
本项目 不是 DeepSeek 官方出品,也不是 @deepseek-ai/dsh 的官方桌面客户端。
@deepseek-ai/dsh 的开源代码二次封装而成,遵守上游 MIT 协议。dsh 的 web UI 自带内容,本项目没有修改或冒充 DeepSeek 官方。com.deepseek.dsh-desktop 这个 appId 是临时沿用 dsh 的命名空间,正式发布前请改成你自己的反向域名(例如 com.yourname.dsh-desktop),以避免与未来的潜在官方桌面端冲突。如上游 dsh 项目对命名空间、二次开发有进一步约定,请以最新上游协议为准。
开发者正在研究通过 Tauri 二次开发这个项目。
当前 Electron 方案的代价是肉眼可见的 —— 安装包 150+ MB、内存占用 300+ MB、冷启动慢。开发者正在评估基于 Tauri 的全新实现,核心优势:
| 维度 | 当前 Electron | 计划中的 Tauri |
|---|---|---|
| 运行时 | Chromium + Node.js 嵌入 | 系统原生 WebView (WKWebView / WebView2 / WebKitGTK) |
| 安装包体积 | ~150 MB | 预计 < 10 MB |
| 内存占用 | 300+ MB | 预计 < 100 MB |
| 冷启动时间 | 2–4 秒 | 预计 < 1 秒 |
| 后端语言 | TypeScript | Rust (更安全、更快) |
| 运行时自带 | Node.js(嵌入) | Bun(内置) |
Tauri 内置 Bun 当作 JS/TS 运行时(无需用户安装 Node),比 Node.js 启动更快、文件 IO 更猛,而且天生的 TS / ESM 友好 —— 跟 Electron 时代把 Node 塞进二进制的思路完全一致,但体积与速度都更优。
一个 Rust 后端 + Bun 跑前端 + 系统 WebView 渲染 = 体积更小、速度更快、内存更少。
@deepseek-ai/dsh 在 Bun 下的兼容性、Cordis 插件体系在 Bun 下的运行表现Command 启动 Bun 子进程跑 dsh web,再用 tauri::WebviewWindow 加载本地服务dsh-desktop-tauri 命名发起A: 第一次启动时 dsh 需要初始化 $DSH_HOME/profiles/web(约 1–3 秒),再下载/编译少量依赖。如果卡在 Splash 超过 30 秒,查看日志:
~/Library/Logs/DSH Desktop/dsh-server.log%APPDATA%\DSH Desktop\logs\dsh-server.log~/.config/DSH Desktop/logs/dsh-server.logA: dsh-server 默认从 3080 开始扫描,遇到占用自动递增直到 3129。绝大多数情况够用。如果都不空闲,切到 dsh:retry 通道(Electron DevTools 里调用 window.api.retry())。
A: 因为 dsh 本身需要连接大模型 API,离线时不工作;但 DSH Desktop 本身没有任何必须联网的部分。
dsh web 命令的关系?A: 完全等价。DSH Desktop 内部跑的就是 dsh web --port <port>,你可以同时在终端跑 dsh web,两者用的 profile 目录相同。
A: 重新下载安装包覆盖安装即可。$DSH_HOME/dsh/ 下的会话数据保留。
A: 本项目以 MIT 协议开源(沿用上游 dsh 的协议)。详见 LICENSE。
@deepseek-ai/dsh)如果你也在封装一个 AI CLI 的桌面客户端,欢迎交流 forked 经验。
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。