🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

桌面客户端 hx876298682-tech/deepseek-harness-desktop

DeepSeek Harness
hx876298682-tech74 天前有提交已提供中文文档扫描:含敏感能力

把 Web 界面打包成开箱即用的桌面应用

25.9/100
综合分
1
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/11 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add hx876298682-tech/deepseek-harness-desktop
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:待复验
是什么
dsh 原生插件 · ui
装得上吗
曾在 dsh 0.2.0-rc.2 下真实安装成功,但当前 dsh 已更新至 0.2.1-rc.5,本站尚未在新版下复验
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 74 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 117 处,展示前 100 条)
  • 写入本地文件
    main.js:48
    try { appendFileSync(logPath, line + String.fromCharCode(10)); } catch { }
  • 发起网络请求
    main.js:53
    const response = await fetch(DSH_PLUGIN_TOPIC_API, { headers: { Accept: "application/vnd.github+json", "User-Agent": "deepseek-harness-desktop" } });
  • 写入本地文件
    main.js:83
    try { appendFileSync(logPath, "--- launch ---" + String.fromCharCode(10)); } catch { }
  • 读取本地文件
    main.js:118
    if (existsSync(managedBin)) process.env.DSH_BIN = managedBin;
  • 发起网络请求
    main.js:145
    const response = await fetch("http://127.0.0.1:" + DSH_WEB_DEFAULT_PORT + "/", {
  • 读取本地文件
    main.js:185
    if (npmPath && existsSync(npmPath)) return { nodePath: systemNode, npmPath, managed: false, version: systemVersion };
  • 读取本地文件
    main.js:191
    if (!npmPath || !existsSync(npmPath)) throw new Error("托管 Node.js 的 npm 不可用");
  • 读取本地文件
    main.js:195
    if (!existsSync(managedBin)) throw new Error("dsh 安装完成但找不到 CLI 入口");
  • 执行外部命令来自配置/变量
    main.js:264
    child = spawn(cmd, args, { detached: true, cwd: process.env.DSH_DESKTOP_SERVER_CWD || homedir(), env: process.env, stdio: ["ignore", "pipe", "pipe"] }
  • 读取本地文件
    main.js:298
    if (process.env.DSH_DESKTOP_NPM && existsSync(process.env.DSH_DESKTOP_NPM)) return process.env.DSH_DESKTOP_NPM;
  • 读取本地文件
    main.js:299
    if (info && info.npmPath && existsSync(info.npmPath)) return info.npmPath;
  • 执行外部命令来自配置/变量
    main.js:313
    const commandChild = spawn(command, args, {
  • 发起网络请求
    main.js:344
    const response = await fetch(url, {
  • 请求外部主机github.com
    main.js:360
    const response = await fetch("https://github.com/" + DESKTOP_REPOSITORY + "/releases/latest", {
  • 发起网络请求
    main.js:360
    const response = await fetch("https://github.com/" + DESKTOP_REPOSITORY + "/releases/latest", {
  • 发起网络请求
    main.js:434
    const response = await fetch(asset.browser_download_url, {
  • 写入本地文件
    main.js:439
    await mkdir(updateDir, { recursive: true });
  • 写入本地文件
    main.js:449
    await pipeline(nodeStream, createWriteStream(assetPath));
  • 执行外部命令来自配置/变量
    main.js:454
    const helperChild = spawn(helper.command, helper.args, { detached: true, stdio: "ignore", windowsHide: true });
  • 执行外部命令固定命令
    main.js:557
    const taskkill = spawn("taskkill", ["/pid", String(pid), "/T", "/F"], { stdio: "ignore", windowsHide: true });
  • 读取本地文件
    resolve-dsh.js:39
    for (const v of readdirSync(join(nvmRoot, "versions", "node"))) dirs.add(join(nvmRoot, "versions", "node", v, "bin"));
  • 读取本地文件
    resolve-dsh.js:43
    for (const v of readdirSync("/usr/local/n/versions/node")) dirs.add(join("/usr/local/n/versions/node", v, "bin"));
  • 读取本地文件
    resolve-dsh.js:54
    try { const st = statSync(p); if (st.isFile() || st.isSymbolicLink()) return p; } catch { }
  • 读取本地文件
    resolve-dsh.js:70
    for (const dir of readdirSync(root)) {
  • 读取本地文件
    resolve-dsh.js:73
    const st = statSync(p);
  • 读取本地文件
    resolve-dsh.js:86
    if (!existsSync(npm)) return null;
  • 执行外部命令来自配置/变量
    resolve-dsh.js:87
    const r = spawnSync(npm, ["root", "-g"], { encoding: "utf8", timeout: 15000 });
  • 执行外部命令来自配置/变量
    resolve-dsh.js:108
    const r = spawnSync(nodePath, [binJs, "--version"], { encoding: "utf8", timeout: 15000 });
  • 执行外部命令来自配置/变量
    runtime.js:54
    const child = spawn(command, args, { stdio: ["ignore", "pipe", "pipe"], shell: process.platform === "win32" });
  • 执行外部命令来自配置/变量
    runtime.js:83
    const result = spawnSync(nodePath, ["--version"], { encoding: "utf8", timeout: 15000 });
  • 请求外部主机nodejs.org
    runtime.js:89
    const response = await fetch(`https://nodejs.org/dist/index.json`, {
  • 发起网络请求
    runtime.js:89
    const response = await fetch(`https://nodejs.org/dist/index.json`, {
  • 发起网络请求
    runtime.js:106
    const response = await fetch(url, {
  • 写入本地文件
    runtime.js:119
    await pipeline(stream, createWriteStream(destination));
  • 发起网络请求
    runtime.js:124
    const response = await fetch(url, { headers: { Accept: "text/plain", "User-Agent": "deepseek-harness-desktop" } });
  • 读取本地文件
    runtime.js:135
    const stream = createReadStream(path);
  • 写入本地文件
    runtime.js:143
    await mkdir(destination, { recursive: true });
  • 读取本地文件
    runtime.js:157
    const entries = readdirSync(directory);
  • 读取本地文件
    runtime.js:159
    try { return statSync(entry).isDirectory() && existsSync(runtimeNodePath(entry)); } catch { return false; }
  • 读取本地文件
    runtime.js:159
    try { return statSync(entry).isDirectory() && existsSync(runtimeNodePath(entry)); } catch { return false; }
  • 写入本地文件
    runtime.js:167
    await mkdir(runtimeBase, { recursive: true });
  • 读取本地文件
    runtime.js:170
    if (existsSync(existingNode)) return { nodePath: existingNode, npmPath: runtimeNpmPath(marker), managed: true };
  • 删除本地文件递归
    runtime.js:187
    await rm(marker, { recursive: true, force: true });
  • 写入本地文件
    runtime.js:188
    await rename(root, marker);
  • 删除本地文件递归
    runtime.js:190
    await rm(work, { recursive: true, force: true });
  • 读取本地文件
    runtime.js:192
    if (!existsSync(existingNode)) throw new Error("Node.js 安装完成但找不到 node 可执行文件");
  • 读取本地文件
    image-input-defaults.js:69
    if (!existsSync(path)) return { path, changed: false, providers: [] };
  • 读取本地文件
    image-input-defaults.js:70
    const source = readFileSync(path, "utf8");
  • 写入本地文件
    image-input-defaults.js:73
    writeFileSync(path, result.source, "utf8");
  • 写入本地文件
    image-input-defaults.js:84
    mkdirSync(home, { recursive: true });
  • 读取本地文件
    usage-stats-plugin.js:35
    const pkg = JSON.parse(await readFile(join(bundledPluginRoot(), "package.json"), "utf8"));
  • 读取本地文件
    usage-stats-plugin.js:44
    return await readFile(path, "utf8");
  • 读取本地文件
    usage-stats-plugin.js:103
    const pkg = JSON.parse(await readFile(join(target, "package.json"), "utf8"));
  • 读取本地文件
    usage-stats-plugin.js:109
    const patch = await readFile(patchPath, "utf8");
  • 读取本地文件
    usage-stats-plugin.js:123
    const sourcePackage = JSON.parse(await readFile(join(sourceRoot, "package.json"), "utf8"));
  • 写入本地文件
    usage-stats-plugin.js:128
    await mkdir(target, { recursive: true });
  • 写入本地文件
    usage-stats-plugin.js:132
    await mkdir(join(target, "scripts"), { recursive: true });
  • 写入本地文件
    usage-stats-plugin.js:135
    await mkdir(dirname(patchPath), { recursive: true });
  • 写入本地文件
    usage-stats-plugin.js:140
    await writeFile(patchPath, enabledPatch, "utf8");
  • 写入本地文件
    _extracted/main.js:39
    try { appendFileSync(logPath, line + String.fromCharCode(10)); } catch { }
  • 读取本地文件
    _extracted/main.js:60
    if (existsSync(managedBin)) process.env.DSH_BIN = managedBin;
  • 写入本地文件
    _extracted/main.js:62
    try { appendFileSync(logPath, "--- launch ---" + String.fromCharCode(10)); } catch { }
  • 执行外部命令来自配置/变量
    _extracted/main.js:127
    child = spawn(cmd, args, { detached: true, cwd: process.env.DSH_DESKTOP_SERVER_CWD || homedir(), env: process.env, stdio: ["ignore", "pipe", "pipe"] }
  • 读取本地文件
    _extracted/main.js:157
    if (process.env.DSH_DESKTOP_NPM && existsSync(process.env.DSH_DESKTOP_NPM)) return process.env.DSH_DESKTOP_NPM;
  • 读取本地文件
    _extracted/main.js:158
    if (info && info.npmPath && existsSync(info.npmPath)) return info.npmPath;
  • 读取本地文件
    _extracted/main.js:161
    if (existsSync(sibling)) return sibling;
  • 读取本地文件
    _extracted/main.js:165
    if (existsSync(candidate)) return candidate;
  • 执行外部命令来自配置/变量
    _extracted/main.js:172
    const commandChild = spawn(command, args, {
  • 发起网络请求
    _extracted/main.js:202
    const response = await fetch(url, {
  • 发起网络请求
    _extracted/main.js:262
    const response = await fetch(asset.browser_download_url, {
  • 写入本地文件
    _extracted/main.js:267
    await mkdir(updateDir, { recursive: true });
  • 写入本地文件
    _extracted/main.js:277
    await pipeline(nodeStream, createWriteStream(assetPath));
  • 读取本地文件
    _extracted/main.js:298
    if (!existsSync(managedBin)) throw new Error("安装完成后找不到新的 dsh CLI");
  • 读取本地文件
    _extracted/resolve-dsh.js:36
    for (const v of readdirSync(join(nvmRoot, "versions", "node"))) dirs.add(join(nvmRoot, "versions", "node", v, "bin"));
  • 读取本地文件
    _extracted/resolve-dsh.js:40
    for (const v of readdirSync("/usr/local/n/versions/node")) dirs.add(join("/usr/local/n/versions/node", v, "bin"));
  • 读取本地文件
    _extracted/resolve-dsh.js:48
    try { const st = statSync(p); if (st.isFile() || st.isSymbolicLink()) return p; } catch { }
  • 读取本地文件
    _extracted/resolve-dsh.js:63
    for (const dir of readdirSync(root)) {
  • 读取本地文件
    _extracted/resolve-dsh.js:66
    const st = statSync(p);
  • 读取本地文件
    _extracted/resolve-dsh.js:79
    if (!existsSync(npm)) return null;
  • 执行外部命令来自配置/变量
    _extracted/resolve-dsh.js:80
    const r = spawnSync(npm, ["root", "-g"], { encoding: "utf8", timeout: 15000 });
  • 执行外部命令来自配置/变量
    _extracted/resolve-dsh.js:101
    const r = spawnSync(nodePath, [binJs, "--version"], { encoding: "utf8", timeout: 15000 });
  • 读取本地文件
    plugins/dsh-usage-stats/lib/index.js:211
    const raw = await readFile(cachePath(), "utf8");
  • 写入本地文件
    plugins/dsh-usage-stats/lib/index.js:233
    await mkdir(dirname(path), { recursive: true });
  • 写入本地文件
    plugins/dsh-usage-stats/lib/index.js:237
    await writeFile(tmp, JSON.stringify(serialized), "utf8");
  • 写入本地文件
    plugins/dsh-usage-stats/lib/index.js:238
    await rename(tmp, path);
  • 写入本地文件
    usage-stats-plugin.test.js:18
    await mkdir(join(root, "lib"), { recursive: true });
  • 写入本地文件
    usage-stats-plugin.test.js:19
    await mkdir(join(root, "scripts"), { recursive: true });
  • 写入本地文件
    usage-stats-plugin.test.js:20
    await writeFile(join(root, "package.json"), JSON.stringify(FAKE_PACKAGE));
  • 写入本地文件
    usage-stats-plugin.test.js:21
    await writeFile(join(root, "lib", "index.js"), "export default 1;\n");
  • 写入本地文件
    usage-stats-plugin.test.js:22
    await writeFile(join(root, "scripts", "install.mjs"), "// installer\n");
  • 写入本地文件
    usage-stats-plugin.test.js:23
    await writeFile(join(root, "cordis.patch.yml"), "- insert:\n - id: usage-stats\n name: dsh-usage-stats\n");
  • 读取本地文件
    usage-stats-plugin.test.js:43
    const installed = JSON.parse(await readFile(join(home, "profiles", "node_modules", "dsh-usage-stats", "package.json"), "utf8"));
  • 读取本地文件
    usage-stats-plugin.test.js:46
    const patch = await readFile(join(home, "profiles", "web", "cordis.patch.yml"), "utf8");
  • 删除本地文件递归
    usage-stats-plugin.test.js:55
    await rm(source, { recursive: true, force: true });
  • 删除本地文件递归
    usage-stats-plugin.test.js:56
    await rm(home, { recursive: true, force: true });
  • 读取本地文件
    usage-stats-plugin.test.js:65
    const first = await readFile(join(home, "profiles", "web", "cordis.patch.yml"), "utf8");
  • 读取本地文件
    usage-stats-plugin.test.js:67
    const second = await readFile(join(home, "profiles", "web", "cordis.patch.yml"), "utf8");
  • 删除本地文件递归
    usage-stats-plugin.test.js:72
    await rm(source, { recursive: true, force: true });
  • 删除本地文件递归
    usage-stats-plugin.test.js:73
    await rm(home, { recursive: true, force: true });
  • 删除本地文件递归
    usage-stats-plugin.test.js:101
    await rm(home, { recursive: true, force: true });
扫描于 2026/11/3(1 天前) · 范围 入口闭包 + 全包扫描 · 来源 GitHub 仓库
涉及外部主机:github.com、nodejs.org

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 打包Web界面为桌面应用
  • Electron桌面外壳

README

由 DeepSeek 最新模型翻译生成
DeepSeek Harness Desktop 把 DeepSeek Harness 变成一个更方便使用的桌面应用。 当前版本:v0.1.8 支持 macOS、Windows 和 Linux。 实际界面 主界面 DeepSeek Harness Desktop 主界面 设置与更新 DeepSeek Harness Desktop 设置与更新页面 它能做什么? - 像普通桌面软件一样打开 DeepSeek Harness - 第一次打开时,自动准备 Node.js 和 DeepSeek Harness - 不需要用户提前安装 DeepSeek Harness - 支持在设置里更新 Harness 和桌面应用 - 在设置 → 插件中增加“论坛插件”,可以浏览 GitHub 上的 DSH 插件 - 支持复制、粘贴和常用快捷键 - 支持发送图片 - DeepSeek 模型保持官方的纯文本限制 - 其他模型默认尝试发送图片,如果模型不支持,会显示服务商返回的错误 - 支持发送文本和代码文件 - 点击输入框左下角的回形针按钮选择文件 - 也可以把文件直接拖到输入框 - 支持 TXT、Markdown、JSON、CSV 和常见代码文件 - 单个文件最大 1 MB,一次最多 5 个文件 - PDF、Word、Excel 等文件暂时不支持
展开完整文档(README 剩余 1 节)
DeepSeek Harness Desktop

把 DeepSeek Harness 变成一个更方便使用的桌面应用。

当前版本:v0.1.8

支持 macOS、Windows 和 Linux。

实际界面

主界面

DeepSeek Harness Desktop 主界面

设置与更新

DeepSeek Harness Desktop 设置与更新页面

它能做什么?

- 像普通桌面软件一样打开 DeepSeek Harness
- 第一次打开时,自动准备 Node.js 和 DeepSeek Harness
- 不需要用户提前安装 DeepSeek Harness
- 支持在设置里更新 Harness 和桌面应用
- 在设置 → 插件中增加“论坛插件”,可以浏览 GitHub 上的 DSH 插件
- 支持复制、粘贴和常用快捷键
- 支持发送图片
- DeepSeek 模型保持官方的纯文本限制
- 其他模型默认尝试发送图片,如果模型不支持,会显示服务商返回的错误
- 支持发送文本和代码文件
- 点击输入框左下角的回形针按钮选择文件
- 也可以把文件直接拖到输入框
- 支持 TXT、Markdown、JSON、CSV 和常见代码文件
- 单个文件最大 1 MB,一次最多 5 个文件
- PDF、Word、Excel 等文件暂时不支持
- 支持 macOS、Windows 和 Linux

内置插件:用量统计(dsh-usage-stats)

应用自带 dsh-usage-stats 插件(多供应商余额、订阅额度与 Token 用量分析)。每次启动应用时,它会自动把插件安装/同步到当前 dsh 环境(DSH_HOME 或 ~/.dsh)的 profiles/web,并幂等启用:

- 设置 → 插件 → “用量统计”标签页可查看安装状态,手动点击“安装 / 更新”可重新同步。
- 安装后重启 dsh web 并在浏览器硬刷新,侧边栏底部会出现“用量/余额”(Usage/Balance)入口。
- 插件源码位于 plugins/dsh-usage-stats,安装逻辑见 usage-stats-plugin.js。

安装使用

普通用户

从 Releases 下载对应系统的安装包:

- macOS Apple Silicon:下载 arm64.dmg
- macOS Intel:下载 x64.dmg
- Windows:下载 .exe
- Linux:下载 .AppImage

安装后直接打开即可。

第一次打开时需要联网,软件会自动下载运行所需的文件。以后打开不需要重复下载。

macOS 提示

目前安装包没有 Apple 官方签名。如果系统提示无法打开:

1. 右键点击应用
2. 选择“打开”
3. 再点击“打开”确认

更新软件

打开应用左下角的“设置”,进入“更新”:

- DeepSeek Harness CLI:更新官方 Harness
- DeepSeek Harness Desktop:更新桌面应用

桌面应用更新会下载新版本,自动退出、替换旧版本并重新打开应用。若应用正从 DMG 挂载盘运行,请先将它拖入 Applications 文件夹;没有写入权限时会提示你手动安装。

从源码运行

需要安装 Node.js 和 npm:

npm ci
npm start

运行测试:

npm run test:update-utils

构建安装包:

macOS Apple Silicon
npm run dist:mac-arm64

macOS Intel
npm run dist:mac-x64

Linux
npm run dist:linux

Windows
npm run dist:win

常见问题

需要提前安装 DeepSeek Harness 吗?

不需要。桌面应用第一次启动时会自动准备 Node.js,并自动安装官方 Harness。

第一次打开失败怎么办?

请确认网络正常,然后重新打开应用。如果仍然失败,可以查看应用日志:

dsh-desktop.log

关闭桌面应用时,dsh web 会一起关闭吗?

会。桌面应用启动的 dsh web 是它的子进程,关闭应用时会先给它发 SIGTERM 等待优雅退出(最长约 5 秒),超时再强制结束,不会留下后台孤儿进程。

只有一种情况例外:如果 dsh web 是在打开桌面应用之前就已经由其他方式(例如终端)启动的,桌面应用只是复用它,关闭时不会动它。

如何发送文件?

点击输入框左下角的回形针按钮,选择文本或代码文件。也可以直接把文件拖到输入框里。

目前支持 TXT、Markdown、JSON、CSV 和常见代码文件。文件内容会以文字的形式放进消息,并带上文件名。

单个文件不能超过 1 MB,一次最多选择 5 个文件。PDF、Word、Excel 等文件暂时不支持。

为什么有些模型不能发图片?

不同模型的能力不一样。桌面端会先尝试发送图片,如果模型或服务商不支持,接口会返回错误。DeepSeek 官方模型仍按官方规则只支持文本。

说明

本项目是官方 DeepSeek Harness 的桌面外壳,不是官方 Harness 核心代码的复制版。官方项目仍在持续开发中,后续可能会有功能变化。

官方仓库:deepseek-ai/deepseek-harness

DSH 插件论坛:github.com/topics/dsh-plugin

本项目仓库:deepseek-harness-desktop

许可证

MIT License
预览分享卡片长什么样 ↓hx876298682-tech/deepseek-harness-desktop
分享 · DeepSeek Harness Hub
hx876298682-tech/deepseek-harness-desktop

把 Web 界面打包成开箱即用的桌面应用

这是你的仓库?认领条目

回到顶部