diff --git a/content/posts/dsh-launcher-intro/img/cover.svg b/content/posts/dsh-launcher-intro/img/cover.svg new file mode 100644 index 0000000..489a999 --- /dev/null +++ b/content/posts/dsh-launcher-intro/img/cover.svg @@ -0,0 +1 @@ +DSH LauncherDeepSeek Harness 桌面启动器 · Windows / macOS / Linux按目录 + 版本启动 \ No newline at end of file diff --git a/content/posts/dsh-launcher-intro/img/home.jpg b/content/posts/dsh-launcher-intro/img/home.jpg new file mode 100644 index 0000000..6ab4c91 Binary files /dev/null and b/content/posts/dsh-launcher-intro/img/home.jpg differ diff --git a/content/posts/dsh-launcher-intro/img/market.jpg b/content/posts/dsh-launcher-intro/img/market.jpg new file mode 100644 index 0000000..7ad0f17 Binary files /dev/null and b/content/posts/dsh-launcher-intro/img/market.jpg differ diff --git a/content/posts/dsh-launcher-intro/index.md b/content/posts/dsh-launcher-intro/index.md new file mode 100644 index 0000000..75a8f5d --- /dev/null +++ b/content/posts/dsh-launcher-intro/index.md @@ -0,0 +1,110 @@ +--- +title: DSH Launcher — 一个把 DeepSeek Harness 装进桌面 GUI 的启动器 +published: 2026-08-28 +updated: 2026-08-28 +description: 介绍 DSH Launcher,一个用 Wails v2 + Go + React 编写的跨平台桌面启动器(Windows / macOS / Linux),按「目录 + 版本」一键启动 DeepSeek Harness:实例管理、npm 版本查询、实时日志、插件市场,推 tag 自动构建发布三端安装包。 +image: /posts/dsh-launcher-intro/img/cover.svg +tags: ['DSH', 'DeepSeek', 'Wails', 'Go', 'React', '桌面应用', 'CI/CD'] +difficulty: 入门 +--- + +## DSH Launcher 是什么 + +[DSH Launcher](https://github.com/wishesl/dsh-launcher) 是一个**跨平台桌面 GUI 启动器**(Windows / macOS / Linux),用来以「指定目录 + 指定版本」的方式启动 [DeepSeek Harness(DSH)](https://github.com/deepseek-ai/DeepSeek-Harness),并可视化地查询版本、管理实例、查看实时日志、安装插件。 + +DSH 的启动方式本质是一条 `npx -y @deepseek-ai/dsh@<版本> web` 命令(在某个工作目录里运行)。启动器把「选目录 + 选版本 + 启动/停止 + 看版本」封装成了开箱即用的图形界面。 + +![DSH Launcher 主页](/posts/dsh-launcher-intro/img/home.jpg) + +![插件市场](/posts/dsh-launcher-intro/img/market.jpg) + +## 为什么做这个 + +写这个启动器主要为了解决两个真实的痛点: + +1. **npx 会优先命中启动目录里的本地 `node_modules` 副本**——哪怕 npm 上已经发了新版,只要目录里有旧版,`npx @deepseek-ai/dsh web` 就永远跑旧版。想升级得先搞清楚"我到底在跑哪一份",非常容易记混。 +2. **版本查询 / 升级要敲一堆命令行**:`npm view @deepseek-ai/dsh versions`、`npx -y @deepseek-ai/dsh@latest web`……记不住,还容易敲错。 + +启动器的价值就一句话:**一个实例 = 一个目录 + 一个版本**,多个实例互不干扰,版本对照一目了然,再也不用手敲 npx 命令。 + +## 核心功能 + +| 功能 | 说明 | +|------|------| +| **实例管理** | 每个实例绑定一个目录和一个版本;卡片式列表,状态指示灯区分 启动中 / 运行中 / 已停止 / 异常退出,支持一键 启动 / 停止 / 删除 / 打开网页 | +| **版本查询** | 展示 npm `latest` / `next` dist-tag、全部版本历史与发布时间;本地实际版本通过读取目录 `node_modules/@deepseek-ai/dsh/package.json` 探测;官方 registry 优先,npmmirror 兜底 | +| **实时日志** | 启动日志流式回显到右侧常驻面板,自动识别 Web 地址、区分崩溃与正常退出、清理孤儿进程 | +| **插件市场** | 内置插件市场:发现 / 收藏 / 安装 / 卸载 DSH 插件,进度实时展示 | +| **系统托盘** | 点 ✕ 默认最小化到托盘而非退出,DSH 继续后台运行;托盘菜单可启动/停止各实例 | +| **单实例** | 重复启动 exe 只会把已运行实例的窗口唤回前台,不会开第二个窗口 | +| **自动发布** | 推 `v*` 标签即触发 GitHub Actions 构建三端产物并发布 Release | + +## 两个有意思的设计 + +### 1. 服务态与进程态分离 + +最初版本里,「顶部显示 DSH 已就绪 / 打开按钮」完全依赖启动器自己管理的进程状态:进程输出里正则抓 URL → TCP 探测 → 标记 ready。这套逻辑有个隐患——一旦进程管理状态和真实情况脱节(比如快速停止/重启时的竞态、冷启动时持久化状态泄漏),顶部就永远显示"运行中"却没有打开按钮。 + +后来把它拆成了**两套互不影响的独立状态**: + +| 状态 | 判定依据 | 驱动什么 | +|------|----------|----------| +| **服务态**(dsh 已启动) | 配置端口能正常访问 DSH 服务(后端 HTTP 探测,2s 兜底轮询 + 启停/保存/删除即时重查) | 顶部「已就绪」+ 打开按钮 | +| **进程态**(启动器在管理) | 启动器自己 spawn / kill 的进程生命周期 | 实例卡片的 启动 / 停止 按钮 | + +好处:只要端口真的在服务,顶部就能打开——哪怕进程是被外部方式拉起来的;进程管理状态怎么折腾都不影响"能不能打开"。 + +### 2. 跨平台的进程管理抽象层 + +Wails v2 框架本身支持三端,但项目真正跨平台需要处理**进程树管理**这个平台差异最大的部分。抽象成了 `procattr_windows.go` / `procattr_unix.go` 两个文件: + +| 能力 | Windows | macOS / Linux | +|------|---------|----------------| +| 启动 shell | `cmd /c`(解析 `.cmd` shim) | `sh -c` | +| 子进程属性 | `HideWindow`(不闪控制台) | `Setsid`(独立会话/进程组) | +| 进程树终止 | Job Object + `taskkill /T /F` | `kill(-pgid)` 组杀树 | + +`dsh_process.go`、`install.go`、`market_ops.go`、`env.go` 全部改走统一的 `shellCommand()` / `killProcessTree()`,不再有散落的平台代码。 + +## 技术栈 + +| 层 | 技术 | +|----|------| +| 桌面壳 / 后端 | **Wails v2.15.0** + **Go 1.25**(Windows / macOS / Linux 三端) | +| 前端 | **React 18** + **TypeScript** + **Vite 3** | +| 系统托盘 | `fyne.io/systray`(独立 goroutine 跑消息循环,三端通用) | +| 单实例 | Wails `options.SingleInstanceLock` | +| CI / 发布 | GitHub Actions:三平台矩阵自动构建 + Releases | + +## 多平台发布踩过的坑 + +自动化发布([workflow](https://github.com/wishesl/dsh-launcher/blob/master/.github/workflows/release.yml))流程是:**推 `v*` 标签 → 三平台并行构建 → 统一发 Release**。过程中踩了几个典型坑: + +1. **Ubuntu 24.04 移除了 webkit2gtk-4.0**:Wails v2.10.2 默认仍要 4.0,24.04 只有 4.1。解法是升级 Wails 到 **v2.15.0**,构建时加 `-tags webkit2_41`,并补装 `libsoup-3.0-dev`。 +2. **`macos-13`(Intel runner)已被 GitHub 下线**:macOS x64 产物改为在 arm64 runner 上用 `GOARCH=amd64` 交叉编译(Xcode 通用工具链原生支持)。 +3. **Go 版本水涨船高**:Wails v2.15 要求 Go 1.25,CI 的 `setup-go` 也要跟着升。 + +## 快速上手 + +```bash +# 下载对应平台安装包(Releases 页)或自行构建 +git clone https://github.com/wishesl/dsh-launcher.git +cd dsh-launcher +wails build # Windows / macOS +wails build -tags webkit2_41 # Linux(需 webkit2gtk-4.1 系统依赖) +``` + +打开应用后: + +1. 左侧「实例」→「+ 添加实例」→ 选择 DSH 启动目录 → 选版本 → 启动方式选**本地副本**(官方推荐)→ 保存; +2. 卡片点「启动」,右侧日志面板自动弹出并实时滚动; +3. 顶部出现「DSH 已就绪 · 名称 · 地址」后点它即可在浏览器打开 DSH web; +4. 提示「本地副本未安装」时先点「安装到目录」,把该版本真实装进目录的 `node_modules`。 + +## 开源信息 + +- GitHub:[wishesl/dsh-launcher](https://github.com/wishesl/dsh-launcher) +- Releases(三平台安装包): +- 技术选型参考:DSH 本质是 `npx @deepseek-ai/dsh@<版本> web` 跑在选定目录里,多实例互不干扰;一个目录对应一个版本,别混着用。 + +欢迎 Star、提 Issue,或者直接来提功能需求 🙂