DeepSeek Harness 桌面版
31.5/100
综合分
2
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/20 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
自动兼容检查未通过:仓库 package.json 标记 private,未发布到 npm,需从源码安装。以下命令仍可尝试,但可能失败。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add EasyTZ/dsh-desktop该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:已验证
是什么
dsh 原生插件 · market
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 15 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查需源码安装仓库 package.json 标记 private,未发布到 npm,需从源码安装
展开查看检查明细 ↓
以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。
✓npm 包deepseek-desktop @ 0.1.0-rc.9
✓Node 引擎未声明 engines.node
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明
源码安装时若 pnpm 拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑。
验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/12 06:03:03
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 110 处,展示前 85 条)
- 写入本地文件src/main/index.js:142
fs.renameSync(USER_KERNEL_DIR, trash); - 删除本地文件src/main/index.js:147
try { fs.rmSync(USER_KERNEL_DIR, { recursive: true, force: true }); } catch (e2) { - 执行外部命令固定命令src/main/index.js:198
cmdline = execFileSync('ps', ['-p', String(record.pid), '-o', 'command='], - 读取本地文件src/main/index.js:248
if (fs.existsSync(lnk)) return; - 执行外部命令来自配置/变量src/main/dsh-service.js:221
this.child = spawn(nodeExe, args, { - 发起网络请求src/main/dsh-service.js:392
const req = http.get(probeUrl(url), (res) => { - 执行外部命令固定命令src/main/dsh-service.js:455
execFile('taskkill', ['/pid', String(child.pid), '/T', '/F'], () => { - 读取本地文件src/main/window.js:13
if (fs.existsSync(c)) return c; - 读取本地文件src/main/window.js:29
if (fs.existsSync(c)) return c; - 读取本地文件src/main/kernel-updater.js:72
if (this.configPath && fs.existsSync(this.configPath)) { - 读取本地文件src/main/kernel-updater.js:73
return JSON.parse(fs.readFileSync(this.configPath, 'utf8')); - 写入本地文件src/main/kernel-updater.js:84
fs.mkdirSync(path.dirname(this.configPath), { recursive: true }); - 写入本地文件src/main/kernel-updater.js:85
fs.writeFileSync(this.configPath, JSON.stringify(this._config, null, 2) + '\n'); - 发起网络请求src/main/kernel-updater.js:150
const res = await fetch(this._packageUrl(), { - 写入本地文件src/main/kernel-updater.js:221
fs.mkdirSync(path.join(staging, 'runtime'), { recursive: true }); - 写入本地文件src/main/kernel-updater.js:224
fs.copyFileSync(this.builtinNodeExe, path.join(staging, NODE_BIN)); - 删除本地文件src/main/kernel-updater.js:260
return this._fsRetry(() => fs.rmSync(target, { recursive: true, force: true }), `remove ${target}`, opts); - 读取本地文件src/main/kernel-updater.js:291
names = fs.readdirSync(parent); - 读取本地文件src/main/kernel-updater.js:317
while (fs.existsSync(backup)) { - 读取本地文件src/main/kernel-updater.js:321
if (fs.existsSync(this.userKernelDir)) { - 写入本地文件src/main/kernel-updater.js:323
await this._fsRetry(() => fs.renameSync(this.userKernelDir, backup), `rename ${this.userKernelDir}`); - 写入本地文件src/main/kernel-updater.js:327
fs.renameSync(staging, this.userKernelDir); - 读取本地文件src/main/kernel-updater.js:330
if (fs.existsSync(backup)) fs.renameSync(backup, this.userKernelDir); - 执行外部命令来自配置/变量src/main/kernel-updater.js:404
const child = spawn(cmd, args, { - 执行外部命令来自配置/变量src/main/kernel-updater.js:523
const child = spawn(nodeExe, args, { - 执行外部命令固定命令src/main/kernel-updater.js:552
execFile('taskkill', ['/pid', String(child.pid), '/T', '/F'], () => {}); - 读取本地文件src/main/app-updater.js:71
if (this.configPath && fs.existsSync(this.configPath)) { - 读取本地文件src/main/app-updater.js:72
return JSON.parse(fs.readFileSync(this.configPath, 'utf8')); - 写入本地文件src/main/app-updater.js:83
fs.mkdirSync(path.dirname(this.configPath), { recursive: true }); - 写入本地文件src/main/app-updater.js:84
fs.writeFileSync(this.configPath, JSON.stringify(this._config, null, 2) + '\n'); - 发起网络请求src/main/app-updater.js:113
const res = await fetch(RELEASES_LATEST_URL, { - 发起网络请求src/main/app-updater.js:136
const res = await fetch(GITEE_TAGS_URL, { signal: AbortSignal.timeout(8000) }); - 读取本地文件src/shared/kernel-unpack.js:45
if (fs.existsSync(systemTar)) return systemTar; - 读取本地文件src/shared/kernel-unpack.js:56
return fs.existsSync(archivePathOf(kernelDir)) && !isKernelComplete(kernelDir); - 写入本地文件src/shared/kernel-unpack.js:63
fs.mkdirSync(dir, { recursive: true }); - 写入本地文件src/shared/kernel-unpack.js:64
fs.writeFileSync(probe, ''); - 删除本地文件src/shared/kernel-unpack.js:65
fs.rmSync(probe, { force: true }); - 读取本地文件src/shared/kernel-unpack.js:85
if (!fs.existsSync(archive)) throw new Error(`找不到内核归档:${archive}`); - 删除本地文件src/shared/kernel-unpack.js:118
fs.rmSync(archive, { force: true }); - 删除本地文件src/shared/kernel-unpack.js:119
fs.rmSync(path.join(kernelDir, MANIFEST_NAME), { force: true }); - 读取本地文件src/shared/kernel-unpack.js:134
if (!fs.existsSync(manifestPath)) return; - 读取本地文件src/shared/kernel-unpack.js:135
const expected = JSON.parse(fs.readFileSync(manifestPath, 'utf8'))?.files; - 读取本地文件src/shared/kernel-unpack.js:139
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { - 执行外部命令来自配置/变量src/shared/kernel-unpack.js:156
const child = spawn(resolveTarCommand(), ['-xf', archive, '-C', target], { - 写入本地文件src/shared/kernel-unpack.js:223
await fsp.chmod(open.path, open.mode & 0o7777); - 写入本地文件src/shared/kernel-unpack.js:271
await fsp.mkdir(dest, { recursive: true }); - 写入本地文件src/shared/kernel-unpack.js:285
await fsp.mkdir(path.dirname(dest), { recursive: true }); - 读取本地文件src/shared/profile-plugins-installer.js:68
if (!nodeExe || !pnpmCliPath || !fs.existsSync(pnpmCliPath)) return null; - 写入本地文件src/shared/profile-plugins-installer.js:70
fs.mkdirSync(shimDir, { recursive: true }); - 写入本地文件src/shared/profile-plugins-installer.js:73
fs.writeFileSync( - 写入本地文件src/shared/profile-plugins-installer.js:80
fs.writeFileSync(shim, `#!/bin/sh\nexec "${nodeExe}" "${pnpmCliPath}" "$@"\n`, 'utf8'); - 写入本地文件src/shared/profile-plugins-installer.js:81
fs.chmodSync(shim, 0o755); - 执行外部命令来自配置/变量src/shared/profile-plugins-installer.js:117
execFile(nodeExe, [binJs, 'plugin', '--profile', PROFILE_NAME, 'remove', ...names], { - 执行外部命令来自配置/变量src/shared/profile-plugins-installer.js:131
execFile(nodeExe, [binJs, 'plugin', '--profile', PROFILE_NAME, 'add', ...specs], { - 写入本地文件src/shared/profile-plugins-installer.js:190
fs.mkdirSync(dir, { recursive: true }); - 读取本地文件src/shared/profile-plugins-installer.js:193
const existed = fs.existsSync(dest); - 写入本地文件src/shared/profile-plugins-installer.js:201
fs.copyFileSync(path.join(profileDistDir, 'index.json'), path.join(dir, 'index.json')); - 读取本地文件src/shared/profile-plugins-installer.js:236
srcStat = fs.statSync(src); - 读取本地文件src/shared/profile-plugins-installer.js:239
if (fs.existsSync(dest)) return false; - 读取本地文件src/shared/profile-plugins-installer.js:256
return fs.statSync(target); - 读取本地文件src/shared/profile-plugins-installer.js:281
for (const name of fs.readdirSync(dir)) { - 删除本地文件src/shared/profile-plugins-installer.js:283
fs.rmSync(path.join(dir, name), { force: true }); - 写入本地文件src/shared/orphan-kernel.js:40
fs.writeFileSync(filePath, JSON.stringify(record)); - 删除本地文件src/shared/orphan-kernel.js:52
fs.rmSync(filePath, { force: true }); - 读取本地文件src/shared/file-logger.js:24
if (fs.existsSync(logPath)) fs.renameSync(logPath, `${logPath}.old`); - 发起网络请求src/shared/kernel-boot.js:84
const req = http.get(url, (res) => { - 执行外部命令来自配置/变量src/shared/dsh-locate.js:42
const out = execFileSync(cmd, args, { encoding: 'utf8', windowsHide: true }).trim(); - 执行外部命令来自配置/变量src/shared/dsh-locate.js:53
execFile(cmd, args, { windowsHide: true }, (err, stdout) => { - 读取本地文件src/shared/dsh-locate.js:67
if (c && fs.existsSync(c)) return c; - 读取本地文件src/shared/dsh-locate.js:77
if (process.env.DSH_INSTALL_DIR && fs.existsSync(process.env.DSH_INSTALL_DIR)) { - 读取本地文件src/shared/dsh-locate.js:87
if (process.env.DSH_INSTALL_DIR && fs.existsSync(process.env.DSH_INSTALL_DIR)) { - 读取本地文件src/shared/dsh-locate.js:97
if (process.env.DSH_BIN_JS && fs.existsSync(process.env.DSH_BIN_JS)) { - 读取本地文件src/shared/dsh-locate.js:108
if (process.env.DSH_PNPM_DIR && fs.existsSync(process.env.DSH_PNPM_DIR)) { - 读取本地文件src/shared/dsh-locate.js:114
if (fs.existsSync(path.join(dir, 'bin', 'pnpm.cjs'))) return dir; - 读取本地文件src/shared/activation-patch.js:36
parsed = JSON.parse(fs.readFileSync(statePath, 'utf8')); - 写入本地文件src/shared/activation-patch.js:82
fs.mkdirSync(path.dirname(patchPath), { recursive: true }); - 写入本地文件src/shared/activation-patch.js:83
fs.writeFileSync(patchPath, renderActivationPatch(disableIds), 'utf8'); - 读取本地文件src/shared/profile-plugins.js:33
if (!fs.existsSync(manifestPath)) return []; - 读取本地文件src/shared/profile-plugins.js:34
const plugins = JSON.parse(fs.readFileSync(manifestPath, 'utf8')); - 读取本地文件src/shared/profile-plugins.js:64
if (!fs.existsSync(indexPath)) return []; - 读取本地文件src/shared/profile-plugins.js:65
const entries = JSON.parse(fs.readFileSync(indexPath, 'utf8')); - 读取本地文件src/shared/profile-plugins.js:163
const parsed = JSON.parse(fs.readFileSync(file, 'utf8')); - 写入本地文件src/shared/profile-plugins.js:182
fs.mkdirSync(path.dirname(file), { recursive: true }); - 写入本地文件src/shared/profile-plugins.js:183
fs.writeFileSync(file, `${JSON.stringify(state, null, 2)}\n`, 'utf8'); - 读取本地文件src/shared/profile-plugins.js:193
const manifest = JSON.parse(fs.readFileSync(
扫描于 2026/11/4(0 天前) · 范围 入口闭包 + 全包扫描 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 双击即用
- 跨平台运行
- 免装环境
README
由 DeepSeek 最新模型翻译生成DeepSeek Harness 桌面版
以 DeepSeek Harness(下称 dsh)为内核的桌面版 AI 编程助手,支持 Windows · Linux · macOS。
双击即用 —— 不需要装 Node.js,不需要懂命令行。
查看浅色主题
📥 下载与安装
到 Releases 页面下载对应你系统的那个:
| 平台 | 文件 | 怎么用 |
| Windows | ...-Setup-x.x.x.exe | 安装包:一路「下一步」,装完有桌面图标 —— 新手选这个 |
| Windows | ...-Portable-x.x.x.zip | 绿色版:解压即用,免安装,适合放 U 盘 |
| Linux x64 | ...-x.x.x.AppImage | chmod +x 之后双击或命令行运行,不用安装 |
| macOS Apple Silicon | ...-x.x.x.dmg | 打开后按图示拖进「应用程序」;首次启动按 DMG 内的安全放行步骤操作 |
🇨🇳 国内打不开 GitHub?
展开完整文档(README 剩余 1 节)
DeepSeek Harness 桌面版 以 DeepSeek Harness(下称 dsh)为内核的桌面版 AI 编程助手,支持 Windows · Linux · macOS。 双击即用 —— 不需要装 Node.js,不需要懂命令行。 查看浅色主题 📥 下载与安装 到 Releases 页面下载对应你系统的那个: | 平台 | 文件 | 怎么用 | | Windows | ...-Setup-x.x.x.exe | 安装包:一路「下一步」,装完有桌面图标 —— 新手选这个 | | Windows | ...-Portable-x.x.x.zip | 绿色版:解压即用,免安装,适合放 U 盘 | | Linux x64 | ...-x.x.x.AppImage | chmod +x 之后双击或命令行运行,不用安装 | | macOS Apple Silicon | ...-x.x.x.dmg | 打开后按图示拖进「应用程序」;首次启动按 DMG 内的安全放行步骤操作 | 🇨🇳 国内打不开 GitHub? 源码在两个平台各有一份,Gitee 那份是自动同步的镜像,你 push 到 GitHub 之后它自己跟上: | 平台 | 地址 | 有什么 | | GitHub | github.com/EasyTZ/dsh-desktop | 源码 + 安装包(Releases) | | Gitee | gitee.com/huo_sydney/dsh-desktop | 源码(只读镜像),问题与 PR 请到 GitHub 提 | 安装包只有 GitHub 一份:每份 160MB 以上,超了 Gitee 免费仓库单个附件 100MB 的上限,搬不过去。 所以每个 Release 的说明正文里都附了一组代理下载链接,往下翻到「🇨🇳 国内下载加速」那一节,文件跟 Assets 里的完全相同。 连 Release 页面本身都打不开的话,把代理前缀拼在完整原始地址前面就是下载地址,版本号换成最新的即可: https://gh-proxy.com/https://github.com/EasyTZ/dsh-desktop/releases/download/v1.9.3/DeepSeek-Harness-Desktop-Setup-1.9.3.exe 代理由第三方运营,会挂也会限速;换个前缀(如 https://ghfast.top/)拼在同样的原始地址前通常也能下。 各平台的首次启动提示(点开看) Windows:本程序没有购买代码签名证书,系统可能提示「未知发布者」,或被杀毒软件拦一下 —— 选择「仍要运行 / 允许」即可。 macOS:当前使用免费的 ad-hoc 签名,没有 Developer ID 与 Apple 公证,首次打开时 Gatekeeper 会拦截。先尝试双击一次,然后进入系统设置 → 隐私与安全 → 安全性 → 仍要打开,验证密码并确认「打开」。DMG 安装窗口里也会直接显示这三步。 只提供 Apple Silicon(M 系列)版本,Intel Mac 暂不支持。 Linux:AppImage 自挂载需要 FUSE 2(libfuse.so.2)。如果双击 / 执行没反应,先试 ./xxx.AppImage --appimage-extract-and-run —— 能跑就说明是 FUSE 的事,装一下发行版的 fuse 包即可。另外需要 GTK3 / NSS / ALSA 这些常见图形库,装了桌面环境的发行版基本都有;真缺的话报错会写明缺哪个 .so,按名字装。 部分桌面环境不带 libappindicator,那样不会有托盘图标 —— 应用照常运行,用 Ctrl + Alt + Space 唤出窗口即可。 ✨ 它能做什么 开箱即用,不折腾环境 包里自带完整运行环境(node + dsh 内核),装好就能聊。拷到另一台没装过任何东西的电脑上,照样跑。 内核可以单独升级,不用等我们发版 「内核」是真正干活的 dsh 本体,它和桌面版分成两条线升级。上游发了新版,你在客户端里点一下就升级了。 更新前会真实启动一次新内核做自检,失败自动回滚 —— 不会把能用的装成不能用的。 常驻后台,随叫随到 关窗口自动缩进托盘,Ctrl + Alt + Space(macOS 是 Cmd + Alt + Space)随时唤出。任务跑完或需要你确认时,窗口在后台会弹系统通知并闪任务栏,不用守着屏幕。 应用本身有新版也会提醒 系统通知 + 托盘菜单,点开直达发布页。装还是不装,仍由你决定。 🧩 四个内置面板,一处完成开发工作 每个面板都沿用 dsh 的主题、圆角与交互,不再把四张比例不同的截图硬塞进四宫格。 🛒 插件市场 · 安装、更新与管理 搜索 npm 上的 dsh 插件,查看详情和截图,一键安装、更新、停用或卸载。随桌面版分发的插件即使卸载,也能从本地副本离线装回。 🌿 Git 面板 · 日常操作不用离开会话 查看改动、逐文件暂存、提交、推送与切换分支;最近提交明确区分已推送和未推送状态,点开即可检查完整改动。 💻 终端面板 · 命令与输出留在工作区 在当前工作区运行命令并查看实时输出,支持多标签、命令历史、路径补全和 Ctrl+C 中断;后台任务结束后会用状态灯提醒。 💰 余额与花费 · 用量随时可见 侧边栏直接显示账户余额和本次花费;详情面板按模型汇总 token、日/周/月用量与当前单价,不必切换到账单网页。 这些插件都装在你自己的 dsh 配置目录里,和你从市场装的第三方插件是同一套机制 —— 换内核不影响它们,你也可以随时卸掉。 🚀 开始使用 第一次启动:双击图标后会先出现启动窗口(logo + 加载动画),几秒后自动进入主界面 —— 这是程序在后台铺开内核并拉起本地服务,只会慢这一次。 填 API Key(必做):点左下角齿轮 →「模型」→ 填入 DeepSeek API Key(形如 sk-xxxx,在 platform.deepseek.com 申请)→ 保存。不填也能打开界面,但一发消息就会失败。 | 关窗口不等于退出 | 点 ✕ 只是缩进托盘,右键托盘图标才是「退出」 | | 随时唤出 | Ctrl + Alt + Space(macOS 是 Cmd + Alt + Space) | | 反馈问题 | 右键托盘图标 →「反馈问题」,直达 GitHub Issues | | 关于 | 右键托盘图标 →「关于」,查看应用版本、内核版本、作者与项目地址 | | 安全模式 | 右键托盘图标 →「进入安全模式」,只加载插件市场、跳过其余插件,方便把出问题的插件停掉;同一位置变成「退出安全模式」,点它重启回正常模式 | 🔄 内核更新 - 自动检查:每天后台查一次,有新版会弹更新窗口;也可右键托盘 →「检查内核更新」手动查。 - 更新流程:点「立即更新」→ 等进度走完 → 点「立即重启」生效(选「稍后」也行,下次启动自动用新版)。 - 下载源:默认国内镜像 registry.npmmirror.com,更新窗口底部可切到官方源。 - 不会更新坏:新内核先通过真实启动自检才会启用,异常时自动回退到自带内核。 ❓ 常见问题 | 现象 | 原因 / 处理 | | 窗口关了找不到了 | 在托盘里,点一下图标即可 | | 余额显示「查询失败」 | 没填 API Key,去「设置 → 模型」补上 | | 双击没反应 / 被拦截 | 没做代码签名。Windows 选「仍要运行」;macOS 右键 →「打开」;杀软误报可加白名单 | | 从旧版升级后首次启动偏慢 | 正在切换到新版内核,等几秒,只会发生一次 | | 启动失败并弹出错误框 | 错误框里有原因摘要;多为内核损坏,可在更新窗口点更新重装内核 | | 装了插件但没反应 | 插件要重启内核才生效,右键托盘 → 退出后重新打开 | | 装了某个插件后界面卡死 / 白屏 | 右键托盘 →「进入安全模式」,到插件市场把它停用或卸载,再「退出安全模式」 | | 装了某个插件后启动就崩 | 崩溃提示框上点「安全模式启动」,进去把它停用或卸载,再正常重启 | | Linux 上没有托盘图标 | 桌面环境不带 libappindicator。应用照常运行,用快捷键唤出窗口 | 💬 反馈与交流 用着有问题、有想要的功能,欢迎随时提 —— 这个项目就是靠反馈改进的。 - 报 bug / 提需求:提交 Issue,客户端托盘菜单里的「反馈问题」可直接跳转。 - QQ 群:群号 263261649 更新日志:见 CHANGELOG.md 或 Releases 页面。 🧑💻 开发者文档 普通用户看到这里就够了,下面是给想改代码、想自己打包的人看的。 架构设计、插件契约与踩坑记录详见 AGENTS.md 与 docs/decisions/。 环境准备只要 Node.js ≥ 22。 不需要全局装 dsh 或 pnpm —— 内核由 prepare-kernel 按 kernel-src/ 里声明的精确版本联网 npm ci 装出来,跟打包机上碰巧装了什么无关(理由见 packaging.md)。 国内网络下载 Electron 与打包工具很慢,建议先设镜像: $env:ELECTRON_MIRROR="https://npmmirror.com/mirrors/electron/" $env:ELECTRON_BUILDER_BINARIES_MIRROR="https://npmmirror.com/mirrors/electron-builder-binaries/" 注意 electron 44 起包里没有 postinstall,npm install 并不会下载 Electron 二进制;真正下载它的是 npm run dist(dist.mjs 会在调 electron-builder 之前自己补上,幂等)。 克隆后建议启用仓库自带的 git 钩子(git config 不随仓库走,每份克隆各做一次): git config core.hooksPath .githooks 只有一个钩子:commit-msg 会剥掉提交消息末尾的机器署名 trailer(Co-Authored-By: ...@anthropic.com、🤖 Generated with ...)。本仓库的提交消息只描述改动、不带署名,而写消息的工具各有各的默认行为,靠约定管不住 —— 放在钩子里才是无论谁怎么写都生效。人类协作者的 Co-Authored-By 不受影响。 常用命令 npm install # 装依赖(不含 Electron 二进制,见上) npm start # 开发态运行(外壳 spawn 本机全局 dsh) npm test # 单元测试(node:test,零第三方依赖) npm run typecheck # tsc --checkJs 静态检查(无编译产物) npm run dist # 打包 → 产物收进 release/(目标平台按当前系统猜) npm run dist -- --linux # 显式指定目标平台(--win / --linux / --mac) npm run dist:dir # 只出 unpacked 目录,快速验证打包态 npm run link-plugins # 联调插件:改同级插件仓库的代码即刻生效(可常开) npm run plugins-status # 看插件当前是「钉 tag」还是「联调」 npm run dist 依次执行 校验插件 pin → 装内核 → 打插件 tgz → 内核自检 → 打包 → 收产物。中间那步自检会真的把内核启动一次等它就绪,这是唯一能挡住「裁剪把运行时真要用的文件删掉了」这类错误的手段。 发版走 CI 1. 改 package.json 的 version 2. 在 CHANGELOG.md 顶部加一节 git tag v1.2.3 git push origin v1.2.3 推 tag 触发 release.yml:Windows / Linux / macOS 三个 job 并行打包,各自跑完整条流水线(含内核自检),产物汇合后由 publish job 一次性发布到 Releases,发布说明自动取 CHANGELOG 里对应版本那一节。 发布成功后 publish job 会删掉旧的 Release,只留最新这一个;tag 一律保留 —— tag 是构建凭据,留着才能从任意历史版本重新出包,而每版三平台产物近 1GB,攒着只会让人下错版本。 日常 git push 不会发版,只会跑 ci.yml(测试 + 类型检查)。本地 npm run dist 保留,作为打 tag 前的快速验证。 为什么打包非要上 CI:内核自检只能在目标平台上做,而多端意味着要在三个平台上各做一次。跨平台交叉打包做不到这件事。详见 multiplatform.md。 插件开发 五个插件都是独立仓库,以 @easytz/* 发布到 npm,本仓库按钉住的 tag 作为 git 依赖引用,只为打成 tgz 放进安装包。 它们装在用户的 dsh profile 里(~/.dsh/profiles/web/),和用户从插件市场装的第三方插件是同一套机制、同一个目录 —— 换内核不影响它们,用户也能自己卸载(市场本身除外,它是管理入口)。 想改插件代码:把对应仓库克隆到本仓库的同级目录,跑 npm run link-plugins,之后改完直接生效(改界面代码内核会自动热重载,改服务端代码重启内核),不必每次 push + 打 tag。联调可以常开 —— npm run dist 会自动临时解除、打完恢复,并在你有未提交的插件改动时中止(否则打出的包用的是钉住的旧版本,不含你的改动)。 只更新插件不用发 app:插件仓库打 tag + npm publish 之后,已装用户的侧边栏就会出现更新角标。随包的那份 tgz 只影响新装用户,可以攒到下次发 app 时一起带上。 架构 Electron 外壳 + 自包含 dsh 内核。外壳不渲染任何业务 UI —— spawn 内核后轮询 HTTP 就绪,再让 BrowserWindow 加载本地回环地址;所有会话 / 文件 / 终端能力都来自 dsh 自身的 web 应用,外壳只负责窗口、标题栏、托盘、快捷键、通知与内核更新。 src/main/ Electron 主进程 src/preload/ 预加载脚本(注入标题栏 / 暴露 updater 接口) src/shared/ 纯 Node 模块,主进程与构建脚本共用,也是单测落点 scripts/ 构建期 CLI(ESM) kernel-src/ 内核的安装规格(版本声明 + lockfile),不是内核本身 plugins/ profile-plugins.json(随包分发哪几个插件的清单) 本项目没有编译步骤,src/ 直接打进 asar —— 这是打包设计的承重墙。 许可证 MIT
预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
EasyTZ/dsh-desktop
DeepSeek Harness 桌面版
相关插件 · 市场 / 管理
插件精选列表awesome-dsh-plugin/awesome-dsh-plugin
DeepSeek Harness(dsh)插件精选列表
★ 22,225未汉化DSH
73.6
新词雷达zhuyansen/new-term-radar
new-term-radar新词雷达
★ 2,049已汉化MCP
72.8
插件生态导航0xsline/awesome-deepseek-harness
安装 贡献指南 DeepSeek Docs 公开插件目录 Issues
★ 1,188已汉化DSH
72.6
技能注册中心iflytek/skillhub
企业级开源智能体技能注册中心——发布、发现并管理组织内可复用的技能包。
★ 5,370已汉化DSH
71.9
插件市场目录imsai-sh/awesome-deepseek-harness-plugins
面向 DeepSeek Harnessdsh生态的社区插件目录,共收录 13941 个插件含 PR 收录与…
★ 355已汉化DSH
71.8
插件精选清单Anil-matcha/awesome-dsh-plugin
DeepSeek Harnessdsh精选指南——DeepSeek…
★ 1,013已汉化DSH
71.7
这是你的仓库?认领条目