Back to home@modelbus

deepseek-harness-pro

deepseek-harness-pro 是基于 deepseek-harness 的 Web+Electron 客户端,兼容已有的deepseek-harness环境,并支持一键部署最新版deepseek-harness。相比原web功能做出增强:新增实时任务看板、电脑管家(清理/调优/进程管理)、独立插件中心等功能。界面友好,跨平台,开源免费,让 deepseek-harness 更强大易用。

Stars
2
Language
TypeScript
Created
Aug 21, 2026
Updated
Aug 23, 2026

Introduction

deepseek-harness-pro

宿主仓库,跟踪 deepseek-harness 作为 git submodule,并以独立 web 前端 (app/web) 替换 upstream 的 apps/web,使得 pnpm dsh web 自动加载本仓的 web 产物。

deepseek-harness/ 子目录的内容来自 upstream 仓库,不要在此目录内直接修改。本仓不复制 upstream 任何源码:宿主 web 仅含一个 main.ts 入口和一份 vite 配置;web shell 本身来自 upstream 的 @deepseek-ai/dsh-client-web(通过 vite alias 解析到 submodule 的 packages/client/web/src/index.ts,是该包 ./src/* exports 明确允许的用法)。

首次克隆

git clone --recurse-submodules https://github.com/<your-org>/deepseek-harness-pro.git
cd deepseek-harness-pro
pnpm install          # 或 npm install / yarn install

--recurse-submodules 拉取 deepseek-harness/ 子目录。pnpm install 完成三件事:

  1. preinstallscripts/setup.sh → 必要时 git submodule update --init --recursive + 给 submodule 装依赖
  2. 安装根 dev-only 工具(暂无)
  3. 安装 workspace member app/web 的依赖(vite、react、...)

如果克隆时忘了 --recurse-submodulesscripts/setup.sh 仍会检测到空子模块目录并主动 git submodule update --init --recursive deepseek-harness,所以两种克隆方式都能正常工作

pnpm-lock.yaml 在根目录生成。app/web/node_modules 是 pnpm 链接,不要单独 pnpm install 它。

包管理器

package.json 是 pnpm workspace 声明(pnpm-workspace.yaml),所以 pnpm 是首选且功能完整。yarn / npm 也能跑 pnpm install 的等价流程(scripts/setup.sh 会自动检测并调用),但 yarn/npm 不能跑 pnpm --dir deepseek-harness dsh webpnpm dsh 是 pnpm 的 workspace CLI shortcut)。

为了在三种包管理器下都能用,仓库额外提供一个 scripts/run.sh 包装:

./scripts/run.sh install   # 等价于 setup.sh + pkg_manager install
./scripts/run.sh web       # 等价于 pnpm run web
./scripts/run.sh build     # 等价于 pnpm run build(见下)
./scripts/run.sh dsh:web   # 等价于 pnpm run dsh:web(要求 pnpm)

检测顺序:pnpm > yarn > npm,由 scripts/detect-pkg-manager.sh 决定。

常用脚本

pnpm run web          # 启动 app/web 的 Vite dev server(默认 http://localhost:5173)
pnpm run web:build    # 一次性:app/web 生产构建到 app/web/dist/
pnpm run build        # 完整发布构建:upstream dsh + 宿主 web 覆盖
pnpm run build:web-only   # 仅重建宿主 web 并覆盖到 submodule 的 apps/web/dist
pnpm run dsh:web      # = `pnpm dsh web`:跑已 build 的 upstream dsh,加载宿主 web
pnpm run dsh-pro:web  # = dsh:web(语义别名:宿主定制的 dsh 入口)
pnpm run dsh-pro      # = upstream `pnpm dsh`(不指定 profile,默认 headless)
pnpm run setup        # 仅跑 scripts/setup.sh

pnpm run build 的精确语义:

  1. pnpm --dir deepseek-harness run build —— upstream 完整发布构建:build 所有 host packages、tsdown 出 apps/cli/lib/bin.jsbuild:web 产出 apps/web/dist/,并写 client-build-record
  2. pnpm --filter @deepseek-ai/dsh-web-frontend run build —— 宿主 app/web vite build,输出 app/web/dist/
  3. rm -rf deepseek-harness/apps/web/dist && cp -R app/web/dist/. deepseek-harness/apps/web/dist/ —— 用宿主 dist 覆盖 submodule 的 dist。
  4. 此时 require.resolve('@deepseek-ai/dsh-web-frontend/dist/index.html')(由 packages/bundle/web-app 触发)指向宿主 dist;pnpm dsh-pro web 自动加载宿主 web。

build:web-only 跳过步骤 1,仅做步骤 2-3。修改上游 client 代码后想要完整重打 dsh 产物,跑 pnpm run build

pnpm dsh-pro webpnpm dsh web 的区别仅在名字:都调用 deepseek-harness/apps/cli/lib/bin.js(由步骤 1 产出),并且因为步骤 3 的覆盖,web profile 注入的 __DSH_BOOT__ 服务的是宿主 dist。这是宿主定制的 dsh 入口;当未来 app/cli 真正承载 dsh 的二次开发时,再把脚本切到本地 app/cli/lib/bin.js

独立的 web 前端 (app/web/)

app/web/ 是本仓唯一的自有 web 前端。源文件树:

app/web/src/
├── main.ts               Vite entry: import global.css + runApp()
├── mount.ts              find #root, instantiate AppWebEntry
├── bootstrap.ts          host customization hooks (customSeams)
├── env.d.ts              Vite + CSS ambient types
├── node-module-stub.ts   browser stand-in for node:module
├── styles/global.css     host-level global stylesheet
└── types/dsh-client-web.d.ts   ambient module declaration for typecheck

mount.ts 是手写入口:

import { AppWebEntry } from '@deepseek-ai/dsh-client-web'
import { customSeams } from './bootstrap.ts'

export function runApp(): Promise<void> {
  const container = document.getElementById('root')
  if (container === null) throw new Error('app/web: missing #root element')
  const entry = new AppWebEntry(container, customSeams)
  return entry.run()
}

@deepseek-ai/dsh-client-webapp/web/vite.config.ts 中通过 resolve.alias 解析为 deepseek-harness/packages/client/web/src/index.tstsconfig.jsonpaths 把它指向本地 src/types/dsh-client-web.d.ts ambient stub,让 host 端 tsc 不必顺着 submodule 源码做整库类型检查。

包名 @deepseek-ai/dsh-web-frontend 与 upstream apps/web 同名,因此 dsh web 通过 require.resolve 加载到的就是宿主构建的 dist。app/web/README.md 详细说明在哪里做二次开发(bootstrap.tsstyles/global.cssmain.tsenv.d.ts)。

关于 standalone dev

upstream deepseek-harness/apps/web/vite.config.ts 故意拒绝 vite dev(必须有 host 注入 window.__DSH_BOOT__)。app/web/vite.config.ts 移除了这个守卫,因此 pnpm run web 可以在没有 host 的情况下启动 Vite dev server,仅渲染 boot page(<AppWebEntry> 启动后立即因缺少 window.__DSH_BOOT__ 而停下)。要让 plugin 真正加载,需要另一终端:

pnpm run dsh-pro:web   # 跑 upstream host:监听 webserver、注入 __DSH_BOOT__、serve 我们的 dist

同步 upstream

git submodule update --remote deepseek-harness

这会把 deepseek-harness/ 更新到 upstream 最新 commit,然后在父仓里产生一个新的 gitlink 变更,需要单独提交:

git add deepseek-harness
git commit -m "chore(deps): bump deepseek-harness submodule"

升级到指定 commit / tag / branch

cd deepseek-harness
git checkout dsh-v0.1.1-rc.1   # 或某个 branch / commit
cd ..
git add deepseek-harness
git commit -m "chore(deps): pin deepseek-harness to dsh-v0.1.1-rc.1"

CI

.github/workflows/submodule-freshness.yml 每天 00:30 UTC 跑一次,比较 deepseek-harness 子模块当前 pinned SHA 与 upstream master。若落后则 fail 并提示重启命令。可手动 Actions → Submodule freshness → Run workflow 触发。

如果不再需要这个提醒,删掉 .github/workflows/submodule-freshness.yml 即可。

Dependabot

本仓启用 Dependabot。.github/dependabot.yml 已删除,避免它跨 submodule 扫描 deepseek-harness/package.json 产生孤儿 PR。子模块内的依赖更新由 upstream /deepseek-harness/.github/dependabot.yml 自己负责。

代理

如果所在网络访问 GitHub 需要代理,请在执行上述命令前导出代理环境变量:

export https_proxy=http://127.0.0.1:7890
export http_proxy=http://127.0.0.1:7890
export all_proxy=socks5://127.0.0.1:7890

也可在 ~/.gitconfig 中全局配置:

[http]
    proxy = http://127.0.0.1:7890
[https]
    proxy = http://127.0.0.1:7890

已知问题

install-lefthook.mjs 在 submodule 模式下 postinstall 失败

deepseek-harnesspackage.jsonpostinstall: node scripts/install-lefthook.mjs。在 submodule 模式下:

[install-lefthook] cannot enable extensions.worktreeConfig while core.worktree
is in the common config; move it to the main worktree config first

install-lefthook.mjs 想给子模块 .git/configextensions.worktreeConfig = true,但 git 拒绝,因为 core.worktree 还在 common config 区。所有 workspace 包都已装好,只有 lefthook 钩子没装上。

scripts/setup.sh 默认就以 --ignore-scripts 跑 submodule install,绕开这条 postinstall。如果想要 lefthook 钩子,可在子模块里手动把 core.worktree 提到 worktree 区:

cd deepseek-harness
git config --local --unset core.worktree
git config core.worktree "$(pwd)"
git config extensions.worktreeConfig true

ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION on first install

pnpm >= 11 默认对未列入白名单的 dep 拒绝执行(minimumReleaseAge 默认 1 天)。vite 间接依赖 browserslist → electron-to-chromium,其版本更新频繁。本仓 pnpm-workspace.yaml 显式关闭了这两个 supply-chain check(verifyDepsBeforeInstall: false / minimumReleaseAge: 0),并附 README 说明如何临时重新启用。

目录结构

deepseek-harness-pro/
├── .gitmodules              # submodule 配置(HTTPS URL)
├── docs/                    # 本仓自有文档
├── app/
│   └── web/                 # 宿主 web 前端(@deepseek-ai/dsh-web-frontend)
│       ├── src/
│       │   ├── main.ts
│       │   ├── mount.ts
│       │   ├── bootstrap.ts
│       │   ├── env.d.ts
│       │   ├── node-module-stub.ts
│       │   ├── styles/global.css
│       │   └── types/dsh-client-web.d.ts
│       ├── README.md        # 二次开发指南
│       ├── vite.config.ts   # alias 全部 @deepseek-ai/* 到 submodule 源码
│       └── package.json
├── deepseek-harness/        # ← upstream 源码(git submodule)
├── scripts/
│   ├── setup.sh             # 初始化 submodule + 安装依赖
│   ├── detect-pkg-manager.sh
│   └── run.sh               # 包管理器无关的入口包装
├── package.json
├── pnpm-workspace.yaml
├── pnpm-lock.yaml
└── README.md