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 完成三件事:
- 跑
preinstall→scripts/setup.sh→ 必要时git submodule update --init --recursive+ 给 submodule 装依赖 - 安装根 dev-only 工具(暂无)
- 安装 workspace member
app/web的依赖(vite、react、...)
如果克隆时忘了 --recurse-submodules,scripts/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 web(pnpm 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 的精确语义:
pnpm --dir deepseek-harness run build—— upstream 完整发布构建:build 所有 host packages、tsdown 出apps/cli/lib/bin.js、build:web产出apps/web/dist/,并写client-build-record。pnpm --filter @deepseek-ai/dsh-web-frontend run build—— 宿主app/webvite build,输出app/web/dist/。rm -rf deepseek-harness/apps/web/dist && cp -R app/web/dist/. deepseek-harness/apps/web/dist/—— 用宿主 dist 覆盖 submodule 的 dist。- 此时
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 web 与 pnpm 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-web 在 app/web/vite.config.ts 中通过 resolve.alias 解析为 deepseek-harness/packages/client/web/src/index.ts。tsconfig.json 的 paths 把它指向本地 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.ts、styles/global.css、main.ts、env.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-harness 根 package.json 有 postinstall: 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/config 写 extensions.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