DshShell · 适用于 Windows 10 1809 及以上

双击,就是全部。

把 dsh web 包装成一个可双击的桌面程序。 开屏页先做环境自检,后台拉起引擎,就绪后自动进入界面。

  • 单个自包含 exe
  • 约 53 MB
  • 免安装
  • 无需 .NET 运行时
  • MIT 许可

界面为示意,细节以实际程序为准

为什么需要一个壳

一条命令,和一次双击。

dsh web 本身已经很好用。但作为一个每天都要打开的日常工具,它还差一层外壳。

npx dsh web原始
DshShell本壳
要开终端,一个黑窗口一直挂着
双击即用,没有控制台窗口
引擎端口和地址要从输出里自己找
自动分配空闲端口,自动导航
Node 没装时报错难懂
开屏页直接显示环境自检,指出缺什么
引擎装坏了要自己去清目录
界面里直接提供「重新安装引擎」
首次安装 223 MB,全程没有反馈
按包计数的下载进度条
关窗之后 Node 进程可能残留
关闭时回收整个进程树

要开终端,一个黑窗口一直挂着

双击即用,没有控制台窗口

引擎端口和地址要自己找

自动分配空闲端口,自动导航

Node 没装时报错难懂

开屏页显示环境自检,指出缺什么

引擎装坏了要手动清目录

界面里直接提供「重新安装引擎」

首次安装 223 MB 全程无反馈

按包计数的下载进度条

关窗之后 Node 进程可能残留

关闭时回收整个进程树

功能

三件事,做到底。

启动与生命周期

关掉窗口,什么也不留下。

单实例运行:再次双击只会唤起已经打开的窗口。端口交给系统分配,不和你已有的实例抢。关闭时回收整个引擎进程树。

单实例Local\DshShell(每 Windows 会话)
端口--port 0 → 53421(系统分配)
退出回收整个进程树,无孤儿进程
崩溃回到开屏页并给出「重试」

引擎管理

三级解析,只动自己的东西。

先找专用目录,再找 PATH 上的 dsh,最后找 npm npx 缓存。都没有,才用 npm 装到本地。

1本地引擎目录%LOCALAPPDATA%\DshShell\engine
2PATH 上的 dshwhere dsh
3npm npx 缓存_npx\…

开屏页状态面板

它先说清楚缺什么。

Node、引擎、WebView2 的版本一目了然,缺失项直接标红。失败时给「重试」和「打开日志」。

Node22.14.0
引擎未安装
WebView2131.0.2903.86
操作重试 · 打开日志 · 重新安装引擎

启动流程

双击之后,四步之内。

整个过程没有控制台窗口,也没有需要你回答的问题。

01 —— 双击

它直接起来,不弹黑窗口。

程序以无控制台模式启动,先抢一把单实例锁;已经有实例在跑,就把那个窗口唤到前面,而不是再开一个。

锁在 Local\ 命名空间,粒度是每 Windows 会话——多用户同时登录,各自可以开一个。

02 —— 自检

并行检查三件东西。

Node 版本、已装引擎版本、WebView2 版本。缺哪一项,就在屏幕底部把哪一项标红,而不是等到推进到一半才报错。

检测结果与后续的安装进度共用同一条底部状态栏,不会互相覆盖。

03 —— 拉起引擎

解析、更新,然后用空闲端口启动。

先在三个位置解析引擎;只对自己安装的那一份做静默更新,再把 dsh web --port 0 --no-open 交给后台。

更新前取一把跨进程互斥锁,避免两个会话同时往同一个目录里写。更新节流:每 24 小时最多一次。

04 —— 就绪

校验通过,才导航过去。

引擎打印的地址必须同时是回环主机、http 协议、带合法 token,才被接受为导航目标。任何一条不满足,就不跳转。

引擎中途崩溃或界面加载失败,会退回开屏页并给出「重试」,而不是把你留在一个死页面上。

安装与更新

223 MB 的下载,
不该是一片空白。

首次运行要装约 584 个包。而 npm install 在默认日志级别下直到结束才输出任何内容,所以进度只能自己算。

584个包

首次运行要抓取的 tgz 包数,也是进度条的分母。

2.5秒

持续这么久没有新包,就切换为不确定态「正在更新引擎…」。

223MB

首次安装的下载量,全程都有反馈。

两点如实说明

  1. 分母是估算值(来自实际安装的 lockfile 条目数),进度条可能停在 100% 之前就完成。对 223 MB 的下载来说,「数字在动」比「精确」更有价值。
  2. npm 把 http 日志写到 stderr 而不是 stdout,所以两个流都会解析。只计 .tgz、失败请求不计、同一 URL 去重。

安全边界

只认回环地址。

引擎会打印一个带 token 的本地地址。壳只接受同时满足全部条件的那一个,其余一律拒绝。

必须同时满足

  • 主机是 127.0.0.1、localhost 或 ::1
  • 协议是 http,端口在 1–65535 之间
  • 带有合法的 token 参数
  • 不含控制字符

一律拒绝

  • 远程主机
  • 局域网地址
  • 0.0.0.0
  • 伪装成回环的域名
  • https
  • file:
  • javascript:
  • ftp:
  • 缺少 token
  • 控制字符
  • 越界端口

日志脱敏

写进日志之前先打码:token=、JSON 形式的 "token":"…"、Authorization 头,以及 api_key、password 这类键名。

14:22:11GET /?token=••••••••••
14:22:11{"token":"••••••••••"}
14:22:11Authorization: ••••••••••
14:22:11api_key=•••••••••• password=••••••••••

日志在 %TEMP%\dsh-shell.log,超过 2 MB 轮转为 .old。它是跨会话累积的——要判断「本次启动是否正常」,请从最后一次 DshShell starting 开始看。

DshShellv0.2.0· MIT

现在就可以双击它。

单个自包含 exe,约 53 MB。免安装,也无需 .NET 运行时。仅 Windows。

SHA-256 029E6D7EB8ABD875B05C984DD2046C2AB275982B18288EFD8014E0C3B2782E47

v0.2.0(构建自 eab618d)的校验值。下载后可自行核对:Get-FileHash .\DshShell.exe -Algorithm SHA256

操作系统

Windows 10 1809(17763)或更高,x64。WebView2 Runtime 一般已预装;缺失时程序会给出官方下载链接。

Node.js

引擎本身是 Node 程序,所以必需,建议 LTS。首次运行需联网,自动安装 @deepseek-ai/dsh。

不需要

不需要安装程序,不需要管理员权限,不需要 .NET 运行时(已内嵌),也不需要 Electron——用的是系统自带的 WebView2。

尚未做代码签名。首次运行可能触发 SmartScreen 提示,选择「更多信息 → 仍要运行」即可。

排障时,东西在哪

项位置
日志%TEMP%\dsh-shell.log(超 2 MB 轮转为 .old;凭据已打码)
引擎%LOCALAPPDATA%\DshShell\engine(删掉即强制重装)
WebView2 数据%LOCALAPPDATA%\DshShell\WebView2
更新节流标记%LOCALAPPDATA%\DshShell\last-update-check
整体重置删除 %LOCALAPPDATA%\DshShell 即可

从源码构建

需要 .NET SDK 10。

产物是单个自包含 exe,分发时只需要这一个文件。

构建
# 构建 + 发布到 .\publish\DshShell.exe
pwsh .\build.ps1

# 顺带从 SVG 重新生成 app.ico
# (需要 tools\ 下的 sharp)
pwsh .\build.ps1 -RebuildIcon
测试
# 单元测试,约 2 秒
dotnet test .\tests\DshShell.Tests\DshShell.Tests.csproj

# 端到端冒烟测试,约 10 秒
pwsh .\test.ps1

两层测试互补,都不需要联网,也不改动 PATH。单元测试通过注入的接缝驱动启动失败路径,每一种故障都是确定的。

场景断言
Node.js 不存在报「需要安装 Node.js」,且不启动任何进程
npm 不存在 / 安装失败报出原因,不继续去启动引擎
引擎始终不打印 URL报启动超时
引擎就绪前退出报退出码,且不当成崩溃
引擎就绪后崩溃触发崩溃事件,且不报成启动失败
就绪 URL 策略6 个接受用例 + 12 个拒绝用例(远程主机、LAN 地址、0.0.0.0、回环伪装域名、非 http 协议、无 token、控制字符、越界端口)
下载进度解析只计 .tgz、失败请求不计、同 URL 去重、节流、卡住判定
重新安装引擎删除所属引擎目录;且只在引擎类故障时才提供该按钮

环境变量(可选,仅供自动化 / 测试)

正常使用不需要设置;不设置时行为与上文完全一致。

变量作用
DSHSHELL_LOG覆盖日志路径
DSHSHELL_INSTANCE使用独立的单实例互斥体 / 事件名
DSHSHELL_WEBVIEW2_DIR独立的浏览器用户数据目录
DSH_HOME独立的 harness 主目录(引擎识别的变量)

test.ps1 用它们启动一个与你的实例互不干扰的隔离实例。

已知限制

不打算藏起来的部分。

  • 依赖目标机已安装 Node.js。.NET 运行时已经内嵌,Node 没有。
  • 单实例是每 Windows 会话粒度(Local\)。多用户会话可以各开一个。
  • 每个 harness 主目录同一时刻只允许一个引擎。引擎插件层持单属主锁,因此同一用户下无法并行运行两个引擎。
  • 引擎更新到 @latest,未固定版本。更新是静默的,每个 24 小时最多检查一次。
  • 未做代码签名。首次运行可能看到 SmartScreen 提示。
  • 仅 Windows。用的是 WinForms + WebView2,没有跨平台版本。