关掉终端,DeepSeek Harness 继续运行:我做了一个轻量后台启动器

1 阅读5分钟

deepseek-launcher 是一个社区开源项目,不是 DeepSeek 官方产品。项目地址:github.com/wyf-777/dee…

最近在使用 DeepSeek Harness 时,我遇到一个很实际的问题:官方启动方式需要让终端一直开着。

npx @deepseek-ai/dsh web

这条命令本身没有问题,但作为一个需要频繁使用的本地 Web 工具,它还不太像日常桌面应用:关闭终端后服务会结束;重新使用时要再次输入命令;想确认状态、查看日志或停止进程,也需要回到命令行处理。

于是我写了一个轻量启动器 deepseek-launcher,把 Harness 变成可以长期驻留、随时打开的后台服务。

最终效果

安装后只需要运行:

deepseek

启动器会依次完成:

  1. 检查 Harness 是否已经运行;
  2. 在隐藏窗口中启动服务;
  3. Windows 下启动系统托盘;
  4. 等待服务端口就绪;
  5. 在默认浏览器中打开 Web 界面。

终端可以直接关闭,Harness 服务不会随之退出。

它不是简单的命令别名,还提供了一组日常管理命令:

命令作用
deepseek后台启动服务、托盘并打开界面
deepseek status查看运行状态,退出码可用于脚本判断
deepseek stop停止服务并退出托盘
deepseek restart重启服务
deepseek logs 50查看最近 50 行服务日志
deepseek update拉取最新 Harness 并重启
deepseek autostart onWindows 下开启登录自启动

默认地址为 http://127.0.0.1:3080。如果需要调整端口,可以设置 DSH_PORT;状态目录也可以通过 DSH_HOME 覆盖。

使用前后对比

一条命令背后的启动链路

项目主体是一个 CommonJS 编写的 Node.js CLI,Windows 后台进程和托盘由 PowerShell 辅助脚本负责。

启动链路

入口文件 deepseek.js 负责命令分发、端口探测、PID 管理和跨平台行为。Windows 下,它不会直接用 Node.js 启动完整的 Harness 进程树,而是调用 start-server.ps1

$cmd = "/c npx --yes $Spec web >> $q$LogFile$q 2>&1"
$p = Start-Process `
  -FilePath 'cmd.exe' `
  -ArgumentList $cmd `
  -WindowStyle Hidden `
  -PassThru

$p.Id | Out-File -FilePath $PidFile -Encoding ascii

日志被追加写入 ~/.dsh/server.log,根进程 PID 则写入 ~/.dsh/launcher-server.pid

macOS 和 Linux 没有使用这些 PowerShell 脚本,而是通过 Node.js 的 detached 子进程运行,因此核心的后台启动、状态、日志和浏览器打开能力仍然可用,只是目前没有系统托盘。

为什么不只使用 windowsHide

最开始我也尝试过 Node.js 中常见的组合:

spawn(command, args, {
  detached: true,
  windowsHide: true,
  stdio: 'ignore'
})

问题在于实际进程链并不是单个进程,而是:

启动器 -> cmd -> npx -> node -> Harness

windowsHide 可以隐藏直接创建的窗口,但在多层子进程链中,后续控制台程序仍可能产生可见窗口。对于需要长期驻留的桌面体验,这种偶发终端窗口很影响使用。

最终项目在 Windows 上改用 Start-Process -WindowStyle Hidden 启动外层进程,并让隐藏状态沿启动链路保持。这样关闭最初运行 deepseek 的终端后,后台服务仍然独立运行,也不会留下一个长期占用任务栏的命令行窗口。

不用 Electron,也能拥有系统托盘

托盘部分使用 PowerShell 调用系统自带的 WinForms:

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

$icon = New-Object System.Windows.Forms.NotifyIcon
$icon.Visible = $true

这样做的原因很直接:这个项目的主体仍然是一个 CLI 启动器,没有必要为了几个托盘操作再引入一个完整桌面框架。

托盘目前提供四个操作:

  • 打开 DeepSeek Harness;
  • 查看经过颜色码清理的服务日志;
  • 开启或关闭登录自启动;
  • 停止服务并退出托盘。

双击图标可以直接打开 Web 界面。托盘还会每 3 秒探测一次本地端口,蓝色鲸鱼表示运行中,灰色鲸鱼表示服务已经停止。

Windows 托盘菜单

状态、停止和日志如何管理

启动器会同时参考端口和 PID:

  • 端口探测用于判断服务是否已经就绪;
  • PID 文件用于定位由启动器创建的进程树;
  • Windows 下 PID 不可用时,会通过 netstat -ano 查找对应监听进程;
  • 停止时使用 taskkill /T 结束完整进程树,避免只结束外层 cmd 后留下 Harness 子进程。

deepseek status 的退出码也有明确含义:运行中为 0,未运行为 1。因此它不仅能给人查看,也可以被脚本调用。

日志命令则会移除常见 ANSI 颜色控制码,避免直接查看日志时出现难以阅读的转义字符。托盘中的“查看日志”还会生成一份最多 200 行、包含当前状态说明的文本,再交给记事本打开。

开机自启动没有依赖用户 PATH

Windows 的登录自启动通过当前用户注册表完成:

HKCU\Software\Microsoft\Windows\CurrentVersion\Run

注册表中记录的是 PowerShell 启动命令和当前 Node.js 可执行文件的绝对路径。这样即使登录时用户 PATH 尚未完全初始化,也能找到正确的 Node.js。

自启动使用内部的 silent 模式,只启动服务和托盘,不会在每次登录后自动弹出浏览器。

安装方式

需要 Node.js 18 或更高版本。推荐先克隆项目并查看脚本内容:

git clone https://github.com/wyf-777/deepseek-launcher.git
cd deepseek-launcher
powershell -ExecutionPolicy Bypass -File .\install.ps1

安装脚本会把运行文件复制到 %USERPROFILE%\bin,并将该目录加入当前用户 PATH。如果没有检测到 Node.js,它会尝试通过 winget 安装 Node.js LTS。

项目也提供一行式远程安装:

irm https://raw.githubusercontent.com/wyf-777/deepseek-launcher/master/install-remote.ps1 | iex

远程执行脚本前应该先确认来源可信,或者打开脚本检查后再运行。对于更在意供应链安全的环境,建议使用前面的克隆安装方式。

这个项目保持了哪些边界

deepseek-launcher 只负责启动和管理 Harness,不接管 Harness 自己的模型配置。

模型、Provider 和配额仍然配置在 ~/.dsh/settings.yaml,API Key 可以放在 ~/.dsh/.credentials.yaml 或系统环境变量中。启动器不会要求把密钥写进项目目录,也不会把密钥打包进安装文件。

启动器自身没有第三方 npm 运行依赖。Windows 托盘使用系统已有的 PowerShell、WinForms 和 System.Drawing,项目的主要运行文件也只有一个 JavaScript 入口、几个 PowerShell 脚本和两枚状态图标。

当前限制和下一步

目前这个项目更偏向 Windows 使用体验,macOS 和 Linux 已支持后台启动,但还没有原生托盘。服务状态当前通过 TCP 端口判断,还不是完整的 HTTP 健康检查。

后续我计划继续完善:

  • 更严格的 Node.js 版本检测;
  • 更清晰的安装和升级反馈;
  • 自动化测试与发布流程;
  • macOS、Linux 的托盘方案;
  • 独立安装包。

如果你也在使用 DeepSeek Harness,并且不想一直保留一个终端窗口,可以试试这个项目:

GitHub:github.com/wyf-777/dee…

项目采用 MIT License。欢迎提交 Issue、改进建议或 Pull Request。