chen7712369
dsh-web-launcher
基于浏览器的Deepseek Harness快速启动器。免去每次使用都要打开命令行手动敲命令行的麻烦。
- Stars
- 0
- Language
- JavaScript
- Created
- Aug 16, 2026
- Updated
- Aug 16, 2026
Introduction
🪝🐋 dsh-web-launcher · DeepSeek Harness 网页启动器
浏览器一键安装 / 启动 / 关闭 / 监控 DeepSeek Harness,从此不用再打开终端敲命令。
跨设备 · 跨平台:无写死机器路径,支持 macOS / Windows / Linux。
浏览器打开 http://127.0.0.1:3910/
✨ 功能特性
| 功能 | 说明 |
|---|---|
| ▶ 一键启动 | 后台拉起 DSH 进程(detached 独立进程),启动后自动打开 Harness 页面(新窗口先显示等待页,就绪后自动跳转;被浏览器拦截时点"打开 DSH 网页"兜底) |
| ⏹ 一键关闭 | 温和关闭(POSIX SIGTERM / Windows taskkill),12 秒未退出升级强杀;进程组/进程树一并清理 |
| 🔍 智能发现 | 自动发现 DSH:state.json → 插件自报 PID → 端口探测(lsof / ss / netstat 多级回退),终端手动启动的 DSH 也能接管关闭 |
| 🖥️ 系统检测 | 启动即检测操作系统:仅支持 macOS / Windows / Linux,其他系统显示"不受支持"并禁用操作 |
| 📦 自动安装 | 未安装 DSH 时点击启动 → 弹窗询问 → 确认后执行官方命令 npx -y @deepseek-ai/dsh,进度条 + 实时日志,安装完成自动启动 |
| 🗑 清除日志 | 一键清空 DSH / 安装 / 启动器日志(二次确认) |
| 📊 连接监控 | 实时显示 Harness 页面活动 TCP 连接数,标签页堆积时预警(防止连接风暴拖垮 DSH) |
| 🛡️ 进程保护 | PID 复用防御、并发启动互斥、敏感文件权限收紧(0600)、未处理拒绝防护 |
页面实时显示:DSH 的 PID、运行时长、命令来源、操作系统、安装状态、最近事件、活动 TCP 连接数,以及 logs/dsh.log 尾部日志(可切换 DSH / 安装 / 启动器三个日志源)。
环境要求
- Node.js ≥ 18(仅需 Node,零 npm 依赖)
- DeepSeek Harness 可选项:不装也可以,启动器会引导你自动安装
快速开始
# 1. 下载 / 克隆本项目(或直接拷贝 server.mjs + config.json)
# 2. 运行(任选其一)
node server.mjs # 前台运行(Ctrl+C 停止)
node server.mjs --daemon # 自我守护:fork 后台副本后立即退出,副本脱离会话常驻
# 3. 打开启动器
# 浏览器访问 http://127.0.0.1:3910/
使用说明
页面按钮
| 按钮 | 作用 |
|---|---|
| ▶ 启动 DSH | 拉起 DSH 并自动打开 Harness 页面(未安装则弹窗询问安装) |
| ⏹ 关闭 DSH | 关闭 DSH(含子进程树) |
| 🌐 打开 DSH 网页 | 手动打开 Harness 界面(默认 http://127.0.0.1:3080),复用已有标签页 |
首次使用流程(三连问)
- 操作系统检测:启动器启动后立即检测系统,不受支持时页面顶部显示红色警告并禁用全部操作
- 安装检测:点"启动 DSH"时若设备上无 DeepSeek Harness(npx 缓存 / 全局安装 / PATH 均无),弹窗询问是否安装
- 自动安装:确认后执行官方命令
npx -y @deepseek-ai/dsh(需联网,首次下载约几百 MB),页面显示动画进度条 + 已耗时,自动切到"安装日志"标签;安装校验成功后自动启动 DSH
架构原理
┌─────────────────────────────────────────────┐
│ 浏览器(启动器页面 :3910 / Harness 页面 :3080)│
└──────────────┬──────────────────────────────┘
│ HTTP / 轮询
┌──────────────▼──────────────────────────────┐
│ server.mjs(零依赖 Node HTTP 服务,独立常驻)│
│ · 状态 / 启动 / 关闭 / 安装 / 日志 / 自检 API │
│ · DSH 命令自动探测 + 进程发现(多级回退) │
└──────────────┬──────────────────────────────┘
│ detached spawn(setsid / 新进程组)
┌──────────────▼──────────────────────────────┐
│ DeepSeek Harness(dsh web,:3080) │
│ 输出经 pipe 泵入 logs/dsh.log │
└─────────────────────────────────────────────┘
- 零依赖:仅用 Node 内置模块(http / child_process / fs / os / path)
- 独立常驻:DSH 关闭/崩溃不影响启动器;DSH 也独立于启动器存活
- 跨平台细节:
which/where、lsof/ss/netstat、SIGTERM/taskkill 全部按平台分支处理;Windows 下 cmd 包装命令原样传参(路径含空格安全)
零配置自动探测
config.json 只保留端口等少量选项,DSH 启动命令完全自动探测:
- node 可执行文件 = 启动器自身的
process.execPath(永远正确) - dsh CLI 查找顺序:
- npx 缓存(
~/.npm/_npx/*/…/ Windows%LOCALAPPDATA%\npm-cache\_npx\*) - pnpm 全局(
~/.local/share/pnpm/global/*/~/Library/pnpm/global/*,版本目录自动遍历) - 常见全局安装位置(
~/.npm-global、%APPDATA%\npm、Homebrew/usr/local与/opt/homebrew、/usr/lib) - PATH 中的
dsh命令(Windows 自动过滤.ps1包装) - 找不到时视为未安装:启动按钮触发安装确认弹窗
- npx 缓存(
- 工作目录默认用户主目录;子进程环境剥离所有
DSH_*与npm_*变量(防止启动器自身运行在 DSH 会话中时污染新实例)
手动覆盖(可选)
{
"launcherPort": 3910, // 启动器页面端口
"webPort": 3080, // DSH 监听端口(进程发现用)
"webUrl": "http://127.0.0.1:3080", // 可选,默认按 webPort 生成
"command": ["node", "/path/to/dsh/lib/bin.js", "web"], // 可选,显式指定(裸 "node" 自动替换为 process.execPath)
"cwd": "/path", // 可选
"env": { "KEY": "value" } // 可选,额外注入子进程环境
}
页面状态栏会显示命令来源(
detected: …/override: …/not-installed),方便排查。
安装为自启服务(彻底告别终端)
| 平台 | 命令 | 说明 |
|---|---|---|
| macOS | ./install.sh | 注册 launchd LaunchAgent,登录自启 + KeepAlive |
| Linux | ./install.sh | 注册 systemd 用户服务,开机自启 + 崩溃重启 |
| Windows | install.bat | 注册登录计划任务 |
卸载:macOS/Linux 用 ./install.sh uninstall;Windows 用 install.bat uninstall。
API
| 接口 | 说明 |
|---|---|
GET /api/health | 启动器存活检查(含 os 信息) |
GET /api/status | 完整状态:os(系统检测)、installed/installing/lastInstall(安装状态)、installCommand、DSH 运行状态、webConnections(活动 TCP 连接数) |
POST /api/start | 启动 DSH(未安装返回 needInstall:true,已在运行返回 already) |
POST /api/install | 异步执行官方安装命令,完成后自动启动 DSH |
POST /api/stop | 关闭 DSH |
POST /api/claim | 外部进程自报 PID(DSH 插件用它报告自身 PID) |
GET /api/log | 日志尾部,?file=dsh|install|launcher 切换来源 |
POST /api/log-clear | 清空日志(?file= 同上,固定白名单映射,无路径穿越风险) |
POST /api/probe | 自检(验证启动器不受沙箱限制) |
健壮性设计
- 无资源泄漏:日志 fd 跨启动复用、进程退出即关闭;日志轮询只读尾部 512KB,日志再大也不整文件载入内存
- 并发互斥:并发启动请求只拉起一个 DSH 实例(防多标签页双开)
- PID 复用防御:state/claim 记录的 PID 只有「监听 webPort」或「30 秒内本启动器拉起」才被信任,防止 DSH 退出后 PID 被系统复用导致误杀无辜进程
- 进程组关闭:本启动器拉起的 DSH 用进程组信号关闭(子进程一起退);外部启动的只发单进程信号(不误伤进程组)
- 未处理拒绝防护:所有异步路径都有 catch,安装后自动启动异常不会导致进程崩溃
- 敏感文件权限:启动时自动将
config.json/state.json收紧为 0600 - 页面资源节省:标签页隐藏时暂停轮询,恢复可见立即刷新
- 标签页防堆积:打开 DSH 页面复用本页面已打开的窗口引用(JS 引用复用,跨浏览器可靠),并实时显示活动 TCP 连接数,连接 ≥12 时预警
已知问题排查
| 现象 | 处理 |
|---|---|
| Harness 页面卡在 "HARNESS Loading plugins…" | 浏览器里开了多个 Harness 标签页,连接/重连风暴拖垮了 DSH 插件加载。关闭所有多余标签页(保留 1 个),页面几秒内自动恢复,无需重启 DSH |
| 启动器显示"⚠ 约 N 个页面在连接" | 同上,关闭多余的 Harness 标签页;1 个页面常驻约 3 个活动 TCP 连接(2 WebSocket + 1 HTTP) |
| 端口 3080 被占用(EADDRINUSE) | 已有 DSH 实例在运行:直接在启动器点"启动"即可接管,或先"关闭"再启动 |
| 启动后自动打开的窗口显示"无法连接" | DSH 尚未就绪,等待页会自动刷新;若超时请点击"打开 DSH 网页" |
目录结构
dsh-web-launcher/
├── server.mjs # 主程序(零依赖 Node HTTP 服务,含内置网页)
├── config.json # 配置(端口等,可选覆盖)
├── install.sh # macOS / Linux 自启安装脚本
├── install.bat # Windows 自启安装脚本
├── README.md
├── logs/ # 运行日志(自动生成)
│ ├── dsh.log # DSH 进程输出
│ ├── install.log # 安装过程输出
│ └── launcher.log # 启动器自身输出
└── state.json # 运行时状态(PID 等,自动生成,不入库)
安全说明
- 仅监听
127.0.0.1,供本机个人使用;任何本机进程都能调用 API,请勿暴露到公网 config.json/state.json自动收紧为 0600 权限- 日志接口固定白名单映射,无路径穿越风险;页面输出全部经过转义,无 XSS 注入点
日志
| 文件 | 内容 |
|---|---|
logs/dsh.log | DSH 进程输出(页面"DSH 日志"标签可看尾部) |
logs/install.log | 安装过程输出(页面"安装日志"标签可看尾部) |
logs/launcher.log | 启动器自身输出(守护/自启模式) |
logs/launchd.log | 服务管理器输出(launchd/systemd) |
相关链接
- DeepSeek Harness(官方) — 官方推荐运行方式:
npx -y @deepseek-ai/dsh web - DeepSeek Harness 官方文档:README