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

Linux 桌面移植补丁 lql341/deepseek-harness-linux-desktop

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

为桌面应用补齐 Linux 打包与 macOS 一致行为

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

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

自动兼容检查未通过:仓库根目录及浅层子目录均无 dsh 插件清单,无法用 dsh 插件安装命令安装。以下命令仍可尝试,但可能失败。
无法用 dsh 插件命令安装(仓库内无 dsh 插件清单)
git clone https://github.com/lql341/deepseek-harness-linux-desktop.git
按该仓库 README 的原生方式安装;若作者另行发布了 DSH 插件包,请以其文档为准

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:需留意
是什么
dsh 原生插件 · vision
装得上吗
实装验证未通过(unknown),装前请到仓库确认最近更新与 issue
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 34 天前
档位由哪些信号合成

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

验证判据与等级说明 →
⚠︎ 实装验证未通过(unknown · 2026/10/1) ——可能是验证环境差异,装前建议到 GitHub 仓库确认最近更新与 issue。
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查需源码安装

仓库根目录及浅层子目录均无 dsh 插件清单,无法用 dsh 插件安装命令安装

展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✗npm 包deepseek-harness-linux-desktop(未发布到 npm,仅可源码安装)
✓Node 引擎未声明 engines.node
✓dsh CLI 依赖未声明 dsh 版本约束
✗入口文件缺少入口声明

源码安装时若 pnpm 拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑。

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/11 22:26:57

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

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

可执行外部命令读写/删除本地文件读取剪贴板或密钥环境变量
查看扫描证据(共 90 处,展示前 67 条)
  • 读取本地文件
    ci/check-docs.mjs:5
    const read = path => readFileSync(path, 'utf8')
  • 读取本地文件
    ci/check-docs.mjs:26
    if (!existsSync(resolve(root, path))) fail(`missing translation: ${path}`)
  • 读取本地文件
    ci/check-docs.mjs:31
    for (const entry of readdirSync(directory, { withFileTypes: true })) {
  • 读取本地文件
    ci/check-docs.mjs:44
    if (!existsSync(enPath) || !existsSync(zhPath)) continue
  • 读取本地文件
    ci/check-docs.mjs:62
    if (targetPath.startsWith('../') || !existsSync(absolute)) { fail(`broken local link: ${path}: ${target}`); continue }
  • 读取本地文件
    ci/check-docs.mjs:65
    if (anchor && extname(absolute) === '.md' && statSync(absolute).isFile()) {
  • 删除本地文件递归
    ci/check-docs.test.mjs:13
    t.after(() => rmSync(root, { recursive: true, force: true }))
  • 读取本地文件
    ci/check-docs.test.mjs:18
    const content = readFileSync(file, 'utf8')
  • 写入本地文件
    ci/check-docs.test.mjs:20
    writeFileSync(file, content.replace(before, after))
  • 删除本地文件
    ci/check-docs.test.mjs:27
    ['missing translation', root => unlinkSync(join(root, 'docs/DOCUMENTATION.zh-CN.md')), /missing translation/],
  • 写入本地文件
    ci/check-docs.test.mjs:28
    ['unpaired page', root => writeFileSync(join(root, 'unpaired.md'), '# Unpaired\n'), /unpaired Markdown/],
  • 写入本地文件
    ci/check-docs.test.mjs:37
    ['invalid pinned base', root => writeFileSync(join(root, 'ci/upstream-base-tag'), 'not-a-tag\n'), /invalid pinned base/],
  • 写入本地文件
    ci/check-docs.test.mjs:46
    writeFileSync(join(root, 'ci/upstream-base-tag'), 'dsh-v9.9.9-rc.1\n')
  • 写入本地文件
    ci/desktop-operation-audit.mjs:28
    mkdirSync(packageDir, { recursive: true })
  • 写入本地文件
    ci/desktop-operation-audit.mjs:29
    writeFileSync(join(packageDir, 'package.json'), JSON.stringify({ name, version: '1.0.0', dsh: { bundle: { patch: './cordis.patch.yml' } } }))
  • 写入本地文件
    ci/desktop-operation-audit.mjs:30
    writeFileSync(join(packageDir, 'cordis.patch.yml'), JSON.stringify([{ insert: name === 'core'
  • 写入本地文件
    ci/desktop-operation-audit.mjs:32
    writeFileSync(join(packageDir, 'plugin.mjs'), 'export function apply(ctx) { ctx.provide("operationAuditProbe", true) }\n')
  • 写入本地文件
    ci/desktop-operation-audit.mjs:36
    writeFileSync(join(profileDir, 'package.json'), JSON.stringify(manifest))
  • 写入本地文件
    ci/desktop-operation-audit.mjs:38
    writeFileSync(config, '[]\n')
  • 读取本地文件
    ci/desktop-operation-audit.mjs:67
    assert.ok(existsSync(entry), 'The isolated Worker must be a physical packaged file')
  • 读取本地文件
    ci/desktop-operation-audit.mjs:85
    const report = readFileSync(reportPath, 'utf8')
  • 删除本地文件递归
    ci/desktop-operation-audit.mjs:99
    rmSync(directory, { recursive: true, force: true })
  • 写入本地文件
    ci/release-signature.test.mjs:17
    writeFileSync(join(directory, 'key.pem'), privateKey.export({ type: 'pkcs8', format: 'pem' }))
  • 写入本地文件
    ci/release-signature.test.mjs:18
    writeFileSync(join(directory, 'key.pub.pem'), publicKey.export({ type: 'spki', format: 'pem' }))
  • 写入本地文件
    ci/release-signature.test.mjs:20
    writeFileSync(artifact, 'release bytes')
  • 写入本地文件
    ci/release-signature.test.mjs:21
    writeFileSync(join(directory, 'SHA256SUMS'),
  • 删除本地文件递归
    ci/release-signature.test.mjs:28
    t.after(() => rmSync(directory, { recursive: true, force: true }))
  • 执行外部命令来自配置/变量
    ci/release-signature.test.mjs:29
    execFileSync(process.execPath, [sign, '--manifest', join(directory, 'SHA256SUMS'),
  • 执行外部命令来自配置/变量
    ci/release-signature.test.mjs:31
    execFileSync(process.execPath, [verify, '--manifest', join(directory, 'SHA256SUMS'),
  • 写入本地文件
    ci/release-signature.test.mjs:34
    writeFileSync(join(directory, 'package.deb'), 'tampered bytes')
  • 执行外部命令来自配置/变量
    ci/release-signature.test.mjs:35
    assert.throws(() => execFileSync(process.execPath, [verify, '--manifest', join(directory, 'SHA256SUMS'),
  • 删除本地文件递归
    ci/release-signature.test.mjs:41
    t.after(() => rmSync(directory, { recursive: true, force: true }))
  • 执行外部命令来自配置/变量
    ci/release-signature.test.mjs:42
    execFileSync(process.execPath, [sign, '--manifest', join(directory, 'SHA256SUMS'),
  • 删除本地文件递归
    ci/release-signature.test.mjs:45
    t.after(() => rmSync(other, { recursive: true, force: true }))
  • 写入本地文件
    ci/release-signature.test.mjs:47
    writeFileSync(join(other, 'other.pub.pem'), publicKey.export({ type: 'spki', format: 'pem' }))
  • 执行外部命令来自配置/变量
    ci/release-signature.test.mjs:48
    assert.throws(() => execFileSync(process.execPath, [verify, '--manifest', join(directory, 'SHA256SUMS'),
  • 删除本地文件递归
    ci/release-signature.test.mjs:54
    t.after(() => rmSync(directory, { recursive: true, force: true }))
  • 执行外部命令来自配置/变量
    ci/release-signature.test.mjs:57
    assert.throws(() => execFileSync(process.execPath, [sign, '--manifest', join(directory, 'SHA256SUMS'),
  • 读取本地文件
    ci/scnet-release-audit.mjs:60
    return JSON.parse(readFileSync(path, 'utf8'))
  • 读取本地文件
    ci/scnet-release-audit.mjs:67
    return createHash('sha256').update(readFileSync(path)).digest('hex')
  • 读取本地文件
    ci/scnet-release-audit.mjs:71
    return lstatSync(path).isDirectory() ? sha256(join(path, 'dsh', 'desktop-runtime.json')) : sha256(path)
  • 读取本地文件
    ci/scnet-release-audit.mjs:75
    return `sha512-${createHash('sha512').update(readFileSync(path)).digest('base64')}`
  • 读取本地文件
    ci/scnet-release-audit.mjs:85
    for (const entry of readdirSync(directory, { withFileTypes: true })) {
  • 读取本地文件
    ci/scnet-release-audit.mjs:102
    const root = statSync(path).isDirectory() ? path : dirname(path)
  • 执行外部命令固定命令
    ci/scnet-release-audit.mjs:248
    const help = spawnSync('python3', [script, '--help'], {
  • 执行外部命令来自配置/变量
    ci/scnet-release-audit.mjs:310
    const result = spawnSync(runtime, args, {
  • 写入本地文件
    ci/scnet-release-audit.mjs:335
    if (options.output) writeFileSync(options.output, `${JSON.stringify(evidence, undefined, 2)}\n`)
  • 执行外部命令固定命令
    ci/scnet-release-audit.mjs:365
    const unpack = spawnSync('dpkg-deb', ['-x', deb, extracted], { stdio: 'inherit' })
  • 删除本地文件递归
    ci/scnet-release-audit.mjs:370
    rmSync(extracted, { recursive: true, force: true })
  • 删除本地文件递归
    ci/scnet-setup-audit.test.mjs:11
    t.after(() => rmSync(root, { recursive: true, force: true }))
  • 写入本地文件
    ci/scnet-setup-audit.test.mjs:24
    mkdirSync(join(bundle, path, '..'), { recursive: true }); writeFileSync(join(bundle, path), content)
  • 写入本地文件
    ci/scnet-setup-audit.test.mjs:24
    mkdirSync(join(bundle, path, '..'), { recursive: true }); writeFileSync(join(bundle, path), content)
  • 写入本地文件
    ci/scnet-setup-audit.test.mjs:26
    writeFileSync(join(runtime, 'package.json'), JSON.stringify({ dependencies: { 'dsh-scnet': '0.6.13' } }))
  • 写入本地文件
    ci/scnet-setup-audit.test.mjs:27
    writeFileSync(join(runtime, 'desktop-runtime.json'), JSON.stringify({ schemaVersion: 1,
  • 执行外部命令来自配置/变量
    ci/scnet-setup-audit.test.mjs:34
    const run = (required = true) => spawnSync(process.execPath, [new URL('./scnet-release-audit.mjs', import.meta.url).pathname,
  • 删除本地文件
    ci/scnet-setup-audit.test.mjs:45
    const f = fixture(t); unlinkSync(join(f.unpacked, 'skills/scnet-hpc/scripts/scnet.py'))
  • 写入本地文件
    ci/scnet-setup-audit.test.mjs:49
    const f = fixture(t); writeFileSync(join(f.unpacked, 'connector/callback.mjs'), 'changed')
  • 删除本地文件递归
    ci/scnet-setup-audit.test.mjs:57
    const f = fixture(t); rmSync(f.unpacked, { recursive: true })
  • 读取本地文件
    ci/sign-release.mjs:31
    const keyPem = keyPath === undefined ? process.env.DSH_RELEASE_SIGNING_KEY : readFileSync(keyPath, 'utf8')
  • 读取密钥环境变量
    ci/sign-release.mjs:31
    const keyPem = keyPath === undefined ? process.env.DSH_RELEASE_SIGNING_KEY : readFileSync(keyPath, 'utf8')
  • 读取本地文件
    ci/sign-release.mjs:39
    const manifest = readFileSync(manifestPath)
  • 写入本地文件
    ci/sign-release.mjs:42
    writeFileSync(outputPath, `${detached}\n`, { mode: 0o644 })
  • 读取本地文件
    ci/sign-release.mjs:46
    const expected = readFileSync(publicKeyHint, 'utf8').trim()
  • 读取本地文件
    ci/verify-release-signature.mjs:28
    const manifest = readFileSync(manifestPath)
  • 读取本地文件
    ci/verify-release-signature.mjs:29
    const detached = Buffer.from(readFileSync(signaturePath, 'utf8').trim(), 'base64')
  • 读取本地文件
    ci/verify-release-signature.mjs:30
    if (!verify(null, manifest, createPublicKey(readFileSync(publicKeyPath, 'utf8')), detached)) {
  • 读取本地文件
    ci/verify-release-signature.mjs:45
    const actual = createHash('sha256').update(readFileSync(join(directory, name))).digest('hex')
扫描于 2026/11/4(0 天前) · 范围 全包扫描 · 来源 GitHub 仓库

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

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

功能亮点

  • Linuxx64打包补丁
  • 对齐macOS使用体验

DeepSeek Harness 桌面应用的非官方 Linux x64(AppImage/deb)移植补丁集,力求接近 macOS 的使用体验

README

由 DeepSeek 最新模型翻译生成
deepseek-harness-linux-desktop 非官方补丁集,为 DeepSeek Harness 桌面应用 提供 Linux x64 发布目标(AppImage + deb),并使其行为与 macOS 构建保持一致。 上游仅发布 macOS 和 Windows —— 其自身的 apps/desktop/README.md 中声明 “Linux 不是受支持的桌面发布目标”,并且打包测试断言必须拒绝 linux-x64 目标。本仓库就是打开这条路径的差异补丁集。 状态:仅补丁,未在 Linux 上验证。 这些补丁是针对上游标签编写的,并在 macOS 上进行了检查(语法层面,外加树哈希验证其可干净应用)。它们从未在 Linux 上编译、打包或运行过。首次构建时请预留一些小的修复工作 ——故障排查表列出了预期会遇到的问题。 基线:上游标签 dsh-v0.2.0-rc.2(提交 639ed0153972),5 个补丁,33 个文件, +798 / −119。
展开完整文档(README 剩余 1 节)
deepseek-harness-linux-desktop

非官方补丁集,为 DeepSeek Harness 桌面应用 提供 Linux x64 发布目标(AppImage + deb),并使其行为与 macOS 构建保持一致。

上游仅发布 macOS 和 Windows —— 其自身的 apps/desktop/README.md 中声明 “Linux 不是受支持的桌面发布目标”,并且打包测试断言必须拒绝 linux-x64 目标。本仓库就是打开这条路径的差异补丁集。

状态:仅补丁,未在 Linux 上验证。
这些补丁是针对上游标签编写的,并在 macOS 上进行了检查(语法层面,外加树哈希验证其可干净应用)。它们从未在 Linux 上编译、打包或运行过。首次构建时请预留一些小的修复工作 ——故障排查表列出了预期会遇到的问题。

基线:上游标签 dsh-v0.2.0-rc.2(提交 639ed0153972),5 个补丁,33 个文件, +798 / −119。

目录

- 1. 你将获得什么
- 2. 要求与固定路径
- 3. 构建 —— 一键脚本
- 4. 构建 —— 分步进行(含成功条件)
- 5. 验收清单(7 项行为)
- 6. 产物及其落盘位置
- 7. 故障排查
- 8. 已验证 / 未验证
- 9. 已知限制
- 10. 布局、许可证、署名

1. 你将获得什么

| # | macOS 行为 | 补丁集如何在 Linux 上实现 |
| 1 | 应用启动 | 桌面策略门禁在 Linux 上不再抛出 desktop policy: unsupported platform |
| 2 | 窗口边框 | titleBarStyle: 'hidden' + titleBarOverlay(与 Windows 使用的相同机制),因此页面拥有标题栏区域;DSH_DESKTOP_LINUX_NATIVE_FRAME=1 可恢复桌面边框 |
| 3 | 关闭最后一个窗口后任务继续运行 | window-all-closed 现在仅在 Windows 上退出;应用程序及其 Host 保持存活,并提供 Show Window 菜单项以恢复窗口 |
| 4 | PATH 上的 dsh 命令 | 新增 POSIX 启动器以及命令安装器的 Linux 分支(~/.local/bin/dsh);已存在的外部命令会被报告并备份,绝不会被静默覆盖 |
| 5 | dsh:// 深链接 | 桌面条目带有 MimeType=x-scheme-handler/dsh;shell 已注册该 scheme |
| 6 | 捆绑运行时 | 运行时准备按目标平台选择 Linux 载荷(Node/pnpm/Python、Electron 二进制、原生包),而不是假定 macOS 或 Windows |
| 7 | 更新 | Linux 包不带 feed;设置 DSH_DESKTOP_LINUX_UPDATE_ORIGIN 可选择加入自托管的通用(AppImage)feed |

Office 文档转换开箱即用:Linux 使用捆绑的 WASM LibreOffice 引擎(@deepseek-ai/libreoffice-kit-wasm),而非系统 LibreOffice。

2. 要求与固定路径

构建主机必须是 Linux x86_64。 该补丁保留了上游的规则,即 linux-x64 拒绝在其他任何地方构建,因此无法从 macOS 交叉构建。linux-arm64 不属于本系列。

| 要求 | 值 | 检查 |
| 主机 | Linux x86_64 | uname -sm → Linux x86_64 |
| Node | ^22.19.0 \|\| >=24.0.0 | node -v |
| pnpm | 11.7.0 | corepack enable && pnpm -v |
| git | 任意较新版本 | git --version |
| 可用磁盘 | ≥ 15 GB(检出约 200 MB,依赖 + Electron + 运行时负载数 GB) | df -h "$HOME" |
| 网络 | registry.npmjs.org、nodejs.org、Python 独立构建、github.com(Electron)、electron-builder 自身的下载 | 取决于代理;参见故障排查 |
| 冒烟运行所需的显示 | X11/Wayland,或 xvfb-run | echo "$DISPLAY$WAYLAND_DISPLAY" |

本文档通篇使用的路径——请先设置它们:

export PATCH_REPO="$HOME/src/deepseek-harness-linux-desktop" # 本仓库
export SRC="$HOME/src/deepseek-harness" # 上游检出(在下方创建)
export TARGET_DIR="$SRC/apps/desktop/.desktop-build/targets/linux-x64"
export ARTIFACTS="$TARGET_DIR/artifacts"

3. 构建——一次性脚本

代理可以按原样执行此代码块(它会在第一个失败的断言处中止):

set -euo pipefail

--- 预检 -------------------------------------------------------------
[ "$(uname -s)" = "Linux" ] || { echo "FAIL: host is not Linux"; exit 1; }
[ "$(uname -m)" = "x86_64" ] || { echo "FAIL: host is not x86_64"; exit 1; }
command -v git >/dev/null || { echo "FAIL: git missing"; exit 1; }
command -v node >/dev/null || { echo "FAIL: node missing"; exit 1; }
corepack enable >/dev/null 2>&1 || true
[ "$(pnpm -v)" = "11.7.0" ] || echo "WARN: pnpm is $(pnpm -v), expected 11.7.0"

export PATCH_REPO="${PATCH_REPO:-$HOME/src/deepseek-harness-linux-desktop}"
export SRC="${SRC:-$HOME/src/deepseek-harness}"

--- 获取补丁集并应用它 --------------------------------------
[ -d "$PATCH_REPO/.git" ] || git clone https://github.com/lql341/deepseek-harness-linux-desktop.git "$PATCH_REPO"
sh "$PATCH_REPO/apply.sh" "$SRC"

--- 证明补丁已落地 ---------------------------------------------
[ "$(git -C "$SRC" rev-parse HEAD^{tree})" = "0c006d75f9a36f3e428f51364b59bf3e63770484" ] \
|| { echo "FAIL: patched tree hash mismatch"; exit 1; }
[ -f "$SRC/apps/desktop/.env.linux" ] || { echo "FAIL: .env.linux missing"; exit 1; }

--- 依赖 ----------------------------------------------------------
cd "$SRC"
pnpm install --frozen-lockfile

--- 低成本预检:验证 .env.linux 和构建工具链 ---------
pnpm --dir apps/desktop run check:package # 预期:"would publish 0.2.0-rc.2 ... valid"

--- 先做目录构建:它到底能不能启动? ----------------------------
pnpm --dir apps/desktop run package:linux:x64:dir

--- 真实产物 --------------------------------------------------------
pnpm --dir apps/desktop run package:linux:x64
ls -l "$SRC/apps/desktop/.desktop-build/targets/linux-x64/artifacts"

4. 构建 — 分步进行(含成功条件)

步骤 0 — 主机预检

uname -sm # 预期:Linux x86_64
node -v # 预期:v22.19+ 或 v24+
corepack enable && pnpm -v # 预期:11.7.0
df -h "$HOME" # 预期:可用空间 >= 15G

如果 uname -m 是 aarch64,或者 uname -s 是 Darwin,请停止:本补丁集不涵盖该组合。在 macOS 上你仍然可以应用这些补丁(步骤 1 在任何系统上都可用),但 package:linux:x64 会拒绝运行。

步骤 1 — 克隆本仓库并应用补丁系列

git clone https://github.com/lql341/deepseek-harness-linux-desktop.git "$PATCH_REPO"
sh "$PATCH_REPO/apply.sh" "$SRC"

apply.sh 会在标签 dsh-v0.2.0-rc.2 处克隆上游,创建分支 linux-desktop,对所有 5 个补丁运行 git am,并将 .env.linux.example 复制为 .env.linux(打包代码需要该文件,缺少它会中止)。

成功条件 — 以下四项必须全部成立:

git -C "$SRC" log --oneline | head -1
预期:"docs(desktop): describe the Linux build and its known limits"
git -C "$SRC" rev-parse HEAD^{tree}
预期:0c006d75f9a36f3e428f51364b59bf3e63770484
git -C "$SRC" status --porcelain # 预期:为空
test -f "$SRC/apps/desktop/.env.linux" && echo env-ok

若要审查而非直接信任:git -C "$SRC" log --stat 会显示这 5 个主题提交。

步骤 2 — 安装依赖

cd "$SRC"
pnpm install --frozen-lockfile

预期退出码为 0。如果默认 registry 较慢,可以使用镜像 — 要么在 apps/desktop/.env.linux 中设置 DSH_DESKTOP_NPM_REGISTRY(供捆绑运行时安装使用),要么为 Electron 下载设置 ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/。

步骤 3 — 低成本预检(不构建,仅需数秒)

pnpm --dir apps/desktop run check:package

这会校验 .env.linux、发布设置和主机工具链,然后打印类似 desktop package: linux-x64 would publish 0.2.0-rc.2; local configuration and toolchain valid 的内容。在花费时间进行真实构建之前,先修复它报告的任何问题 — 这是发现 pnpm 版本错误、缺少 .env.linux 或其中条目有误的最廉价方式。

步骤 4 — 目录构建(第一次真实构建)

pnpm --dir apps/desktop run package:linux:x64:dir

每个打包命令都会自行构建整个仓库、准备 Electron 发行版、从 registry 安装生产运行时闭包,并写入解包后的应用程序。预期需要数分钟并产生大量输出;退出码为 0 即通过条件。

成功条件:

ls -d "$ARTIFACTS"/linux-unpacked # 解包后的应用程序markdown
ls -l "$ARTIFACTS/linux-unpacked/DeepSeek Harness" # Electron 二进制文件,可执行

步骤 5 — AppImage + deb sh
pnpm --dir apps/desktop run package:linux:x64
ls -l "$ARTIFACTS"/.AppImage "$ARTIFACTS"/.deb

预期恰好有两个产物,名称来自产品版本(参见 §6)。
Linux 不运行签名或公证,因此这里不需要其他操作。

如果你想使用自己的编号,请传入 --build-version,例如
pnpm --dir apps/desktop run package:linux:x64 -- --build-version 0.2.0-rc.2.linux.1;
如果不传,产物将携带上游产品版本。

步骤 6 — 冒烟运行 sh 目录构建,无头主机: xvfb-run -a "$ARTIFACTS/linux-unpacked/DeepSeek Harness"

或者安装 deb(这也是让 dsh 命令可用的方式,参见 §9):
sudo apt install ./"$ARTIFACTS"/deepseek-harness--linux-x64.deb
dpkg -L deepseek-harness | grep -E '/(bin|opt)/' # 找到已安装的可执行文件然后从桌面菜单启动它,或运行上面打印的路径(要加引号:它包含一个空格)

前 30 秒内需要观察的事项:

- 它必须到达工作区/欢迎界面,并且不能打印 desktop policy: unsupported platform;
- 窗口不应有系统标题栏,并且原生控件位于右上角(如果桌面环境绘制了奇怪的东西,请使用
DSH_DESKTOP_LINUX_NATIVE_FRAME=1 重试);
- 在没有用户命名空间的容器中,Chromium 的沙箱可能拒绝启动——优先使用 deb,或者仅作为最后手段添加 --no-sandbox(这会降低安全性)。

5. 验收清单(7 项行为)

按顺序运行这些检查;每一项都对应 patches/ 中的一个补丁。

| # | 检查 | 命令 / 观察 | 预期 |
| 1 | 启动 | 按步骤 6 启动 | 工作区打开,没有 unsupported platform 错误 |
| 2 | 窗口镶边 | 查看窗口;切换 DSH_DESKTOP_LINUX_NATIVE_FRAME=1 | 叠加式标题栏 + 原生控件;环境变量可恢复边框 |
| 3 | 保持存活 | 关闭最后一个窗口,然后运行 pgrep -af "DeepSeek Harness" | 进程仍在运行;Show Window* 菜单项会重新显示窗口;显式 Quit 会真正退出 |
| 4 | dsh 在 PATH 中 | 从应用 UI 安装命令,然后在一个新 shell 中运行:command -v dsh && dsh --version | ~/.local/bin/dsh,运行捆绑的 CLI(确保 ~/.local/bin 在 PATH 中) |
| 5 | 深度链接 | xdg-mime query default x-scheme-handler/dsh 然后 xdg-open 'dsh://open' | 已注册 desktop 文件,并且窗口获得焦点 |
| 6 | 运行时 + Office | 在会话中运行 shell 工具;请求 DOCX→PDF 转换 | bash 工具可用(Landlock,内核 ≥ 5.13);通过捆绑的 WASM 引擎转换成功 |
| 7 | 更新 | 在没有 DSH_DESKTOP_LINUX_UPDATE_ORIGIN 的情况下启动 | 不检查更新;设置自托管的通用 feed origin 后,应用会读取 latest-linux.yml |

6. 产物及其落盘位置

所有内容都写入 apps/desktop/.desktop-build/targets/linux-x64/ 下:

| 路径 | 内容 |
| artifacts/linux-unpacked/ | 解包后的应用程序(来自 :dir);可执行文件 DeepSeek Harness |
| artifacts/deepseek-harness--linux-x64.AppImage | AppImage |
| artifacts/deepseek-harness--linux-x64.deb | Debian 包 |
| runtime/ | 为此目标准备的 Electron + pnpm + 启动器 |
| dsh/ | 捆绑的 dsh 运行时树,将成为 app.asar/dsh |
| package-set/、downloads/ | 中间包集合和已下载的归档 |
| packaging-runs/ | 每次运行的日志和发布记录 |

使用默认版本时,这些是 deepseek-harness-0.2.0-rc.2-linux-x64.AppImage 和 …-linux-x64.deb。

7. 故障排查

| 症状 | 原因 | 操作 |
| desktop package: unsupported target "linux-x64" | 补丁未应用 | 重新运行步骤 1;验证树哈希 |
| desktop package: cannot read …/.env.linux; copy … | 缺少必需的环境文件 | cp apps/desktop/.env.linux.example apps/desktop/.env.linux |
| desktop package: linux-x64 requires a Linux x64 build host | 在 macOS/arm64 上构建 | 在 Linux x86_64 上构建 |
| desktop package: unsupported setting X in …/.env.linux | 键不在 Linux 模板中 | 仅使用 DSH_DESKTOP_APP_ID、DSH_DESKTOP_NPM_REGISTRY、DSH_DESKTOP_LINUX_UPDATE_ORIGIN、策略来源 |
| ERR_PNPM_UNSUPPORTED_ENGINE / 奇怪的依赖错误 | Node 或 pnpm 错误 | Node ^22.19 \|\| >=24,pnpm 11.7.0 |
| Electron 下载超时 / 404 | 代理或镜像 | ELECTRON_MIRROR,或导出 HTTPS_PROXY |
| missing required LibreOffice engine wasm | 运行时树中缺少 WASM 套件 | 确认已安装 @deepseek-ai/libreoffice-kit-wasm(它是 @deepseek-ai/libreoffice-kit 的可选依赖) |
| main.ts 中来自 tsc 的类型错误 | 第一次真正的类型检查 | 报告它们;策略分支收窄是最可能的位置 |
| AppImage 拒绝启动(沙箱 / 用户命名空间) | Ubuntu 23.10+ AppArmor 限制 | 安装 deb,或添加 AppArmor 配置文件;--no-sandbox 仅作为最后手段 |
| dsh 安装被拒绝,提示 "transient AppImage mount" | AppImage 资源位于临时挂载中 | 安装 deb,或解压 AppImage 并设置 DSH_DESKTOP_RESOURCES |
| 深度链接无任何作用 | 桌面文件未注册 | 确认 xdg-mime query default x-scheme-handler/dsh;重新安装 deb |

8. 已验证 / 未验证

已验证:

- 该系列补丁在 dsh-v0.2.0-rc.2 上干净应用;git am 后生成的树哈希为 0c006d75f9a36f3e428f51364b59bf3e63770484,没有遗留更改。
- apply.sh 在 C locale 且未配置 git 身份的情况下端到端运行:全新浅克隆 → 5 个补丁 → 创建 .env.linux → 退出码 0。
- 每个更改的文件都通过语法检查;所有原生依赖均已针对
npm registry 解析(存在 Linux 变体,node-pty 提供 linux-x64/arm64 预构建)。

未验证(需要 Linux 主机):

- pnpm install、check:package、编译和类型检查。
- Electron 的 titleBarOverlay 在各桌面环境下的外观;两种主题下的窗口拖拽/调整大小和标题栏尺寸。
- landlock-run 解包和 bash 沙箱、deb 元数据、XDG 深度链接关联。
- 桌面测试套件,上游从未在 Linux 上运行过,且可能存在预先存在的失败。在未打补丁的标签上运行一次以获取基线,然后再进行比较。

9. 已知限制

- 无法 1:1 实现:macOS 红绿灯按钮、侧边栏 vibrancy、Dock 弹跳。该补丁集以原生覆盖窗口控件、扁平侧边栏和通知作为替代。
- dsh 命令需要 deb:AppImage 的资源位于临时挂载中,因此从中安装命令会被拒绝,并给出可操作的提示信息(DSH_DESKTOP_RESOURCES 是用于已解包目录树的逃生通道)。
- 平台标识:Linux 构建会向 DeepSeek Platform 报告 macOS 桌面标识,因为共享账户包只为 x-client-platform 定义了 darwin/win32(省略它会降级为 web)。
- 强制更新策略在 Linux 上无效(没有官方 Linux 更新源)。
- 仅支持 linux-x64;linux-arm64 不属于本系列。
- 欢迎窗口的标题栏颜色仅在创建时跟随系统调色板。
- deb 维护者字段是占位符(DeepSeek Harness)。

10. 布局、许可证、署名

patches/0001..0005*.patch git format-patch 系列,按文件名顺序应用 apply.sh 在基础标签处克隆上游,应用该系列,创建 .env.linux LINUX-DESKTOP.md 长篇指南:逐文件说明、已验证事实、待办事项 LICENSE MIT(上游 DeepSeek + 本补丁集)

每个补丁对应一个主题:(1) 接受目标,(2) 安装 dsh 命令,
(3) 准备 Linux 运行时负载,(4) 类 macOS 外壳行为,(5) 文档。

本补丁集在 MIT 许可证下分发(见 LICENSE)。这些补丁是针对 deepseek-ai/deepseek-harness 的差异补丁,该项目采用 MIT 许可证,版权所有 (c) 2026 DeepSeek;该声明在此保留。

与 DeepSeek 无关联、未获其认可或支持。上游处于开发者预览阶段且迭代迅速,因此在变基到更新的标签时预计会出现冲突。
预览分享卡片长什么样 ↓lql341/deepseek-harness-linux-desktop
分享 · DeepSeek Harness Hub
lql341/deepseek-harness-linux-desktop

为桌面应用补齐 Linux 打包与 macOS 一致行为

这是你的仓库?认领条目

回到顶部