modelbus/deepseek-harness-pro
deepseek-harness-pro 是基于 deepseek-harness 的 Web+Electron 客户端,兼容已有的deepseek-harness环境,并支持一键部署最新版deepseek-harness。相比原web功能做出增强:新增实时任务看板、电脑管家(清理/调优/进程管理)、独立插件中心等功能。界面友好,跨平台,开源免费,让 deepseek-harness 更强大易用。
项目介绍Project Overview
deepseek-harness-pro 是 DSH 宿主插件仓库,将 upstream deepseek-harness 作为 git submodule 引入,并以 app/web 独立前端覆盖 upstream 的 apps/web,使 pnpm dsh web 自动加载宿主 dist。核心能力包括 pnpm run build 重新打包 upstream 并用宿主 dist 覆盖、pnpm dsh-pro web 启动定制入口,以及 app/* 下的 Cordis 插件通过 symlink 自动注入 profile。适用场景:在 DSH 上做宿主级 Web 定制或开发 Cordis 插件并发布为 npm 包。警示:克隆时若未加 --recurse-submodules 需运行 pnpm run setup 补全子模块;子模块内禁止直接修改,依赖更新由 upstream Dependabot 负责。
deepseek-harness-pro is a DSH host repository that tracks upstream deepseek-harness as a git submodule and replaces its apps/web with a self-contained app/web frontend, so pnpm dsh web automatically loads the host-built dist. Core capabilities include pnpm run build to rebuild upstream and overwrite its dist with the host frontend, pnpm dsh-pro web to launch the customized entry, and symlink-based auto-injection of app/* Cordis plugins into the dsh profile. Use it for host-level web customization or developing and publishing Cordis plugins. Caveat: clone with --recurse-submodules or run pnpm run setup; do not edit inside deepseek-harness/, since dependency updates are managed by upstream Dependabot.
请帮我了解并安装插件:【deepseek-harness-pro】【https://github.com/modelbus/deepseek-harness-pro】
把上面这条消息直接发给当前会话里的 DSH,让它帮你了解并安装。安装命令不一定准确,发给 DSH 更稳。Send this message to DSH in your current session. CLI install commands may not be accurate across systems — DSH will figure it out for you.
或使用命令行安装(适合开发者)Or use CLI install (for developers)
命令行安装CLI Install
dsh plugin --profile web add github:modelbus/deepseek-harness-pro
把 modelbus/deepseek-harness-pro 加入你的 DSH 配置(web profile)即可启用。
READMEREADME
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,自动加载所有 app/* 插件
pnpm run dsh-pro:web # = dsh:web(语义别名:宿主定制的 dsh 入口)
pnpm run dsh-pro # = upstream `pnpm dsh`(不指定 profile,默认 headless)
pnpm run demo:bundle # 打包 app/demo-cordis 示例插件
pnpm run demo:typecheck # app/demo-cordis 类型检查
pnpm run demo:pack # bundle + 出 tarball(准备发布)
pnpm run ui-tweak:bundle # 打包 app/ui-tweak 插件
pnpm run apps:link # 手动触发 symlink(preinstall 默认跑)
pnpm run profile:sync # 手动把 app/* bundles 写进 dsh profile dsh.profile.bundles
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:web # 自动加载所有 app/* 插件:监听 webserver、注入 __DSH_BOOT__、serve 我们的 dist
示例插件 (app/demo-cordis/)
app/demo-cordis/ 是一个宿主侧 Cordis 客户端插件示例,向 dsh web 注入三个 slot 注册:
| Slot | 类型 | 行为 |
|---|---|---|
sidebar.footer.action |
list (id) |
"演示/Demo" 按钮 → 显示当前 session 数量的 Modal |
conversation.hero.workspace |
single (id) |
占位 hero(conversation 空状态时渲染) |
tool.call.toolview |
keyed(generator 双 yield) | demo-approve / demo-decline 两个原子注册 |
启动(开发循环)
pnpm install # 注册 workspace + symlink 插件 + 注入 cordis.patch.yml
pnpm run build # 一次性:upstream dsh build + 宿主 web 覆盖(首次必需)
# 然后开两个终端:
# 终端 1
pnpm demo:watch # tsdown watch 模式,src/ 变了自动重建 lib/
# 终端 2
pnpm dsh:web # 零参数启动,自动加载所有 app/* 插件
浏览器打开 http://127.0.0.1:4567(默认 web 端口),侧边栏底部出现 "演示/Demo" 按钮。
后续迭代插件:编辑 app/demo-cordis/src/client/* → tsdown 自动重建 → 浏览器刷新即可。
加一个新的 host-side 插件
mkdir app/<my-plugin> && cd app/<my-plugin>—— 复制app/demo-cordis/的结构。包名 scope 用@dhs-pro/(deepseek-ai 是官方 scope,不要占用),例如@dhs-pro/my-plugin- 编辑
package.json:name→@dhs-pro/my-plugindependencies用npm:^0.1.1-rc.1(已发布的@deepseek-ai/dsh-client-*),不用link:peerDependencies含@deepseek-ai/cordis: "*"(dsh 安装自带)dsh.client.platform: "web"与dsh.bundle.patch: "./cordis.patch.yml"(已默认)
- 编辑
cordis.patch.yml(不是cordis.yml)——- id: my-plugin/name: '@dhs-pro/my-plugin' - 在根
pnpm-workspace.yaml的packages加app/<my-plugin> pnpm install—— preinstall 自动 symlink 到~/.dsh/profiles/web/node_modules/@dhs-pro/my-plugin,并把包名 append 到dsh.profile.bundlespnpm --filter @dhs-pro/my-plugin run bundle产出lib/pnpm dsh:web—— 零参数启动,新插件自动加载(dsh 自己的loadProfile读dsh.bundle.patch把 patch 应用到 layer stack)
新插件加完 cordis.patch.yml 后零配置:下次 pnpm install + pnpm dsh:web 自动加载。
发布到 npm 的版本:去掉 private: true,加 "publishConfig": { "access": "public" },跑 pnpm <my-plugin>:pack 出 tarball,pnpm publish --filter @dhs-pro/my-plugin。用户只需 dsh plugin --profile web add @dhs-pro/my-plugin 就装上——dsh 自己的 reconcile 把 bundle + client 两侧都加载。详见 docs/plugin-guide.md §12。
关于 symlink 与 patch 注入(自动化)
scripts/setup.sh 在 preinstall 钩子里依次调用:
scripts/link-app-workspaces.sh— 把所有app/*/package.json#namesymlink 到~/.dsh/profiles/web/node_modules/<name>。跳过app/web(它走 dist 覆盖路径,不需要 Loader 解析)。Scope 从 package.json 推断,@dhs-pro/<pkg>→node_modules/@dhs-pro/<pkg>。scripts/sync-profile-bundles.sh— 扫描app/*/package.json,收集所有声明了dsh.bundle.patch的包名,追加到~/.dsh/profiles/web/package.json#dsh.profile.bundles(不动 upstream 自带的@deepseek-ai/dsh-base等)。这与 dsh 自己dsh plugin add的 reconcile 流程对齐——host repo 借用同一条官方加载路径。
profile 目录还不存在(首次运行)时 link + inject 是 no-op:先 pnpm dsh:web Ctrl-C 让 dsh 自动初始化 profile,再 pnpm install 即可。
UI 主题 / 特效插件 (app/ui-tweak/)
app/ui-tweak/ 是一个宿主侧 UI 定制示例:把 CSS 风格改写和 JS 特效作为 Cordis 插件加载,覆盖整个 shell 的视觉与交互。可作为二次开发 web UI 的起点。
它做了什么
主题 token 改写 — 启动时(默认
midnight)调用document.documentElement.style.setProperty('--dsw-*', ...),把当前主题 调色板写入 root。upstream shell 与所有 plugin 读同一套--dsw-alias-*token,整页立即重绘。Cmd+./Ctrl+.循环切换default/midnight/sepia/candy四套调色板。全局 stylesheet 注入 — 在
<head>末尾追加一个<style id="dsh-tweak-sheet">,对 shell 结构类([class*='card']、[class*='panel']等)做高优先级覆盖:圆角、阴影、scroll-driven parallax 视差(--dsw-tweak-scroll-y)、Konami 彩蛋动画。JS 特效 —
Cmd+./Ctrl+.全局切换主题- 滚动时写
--dsw-tweak-scroll-y给:root,触发 CSS 视差 - Konami code (
↑↑↓↓←→←→BA) 触发 1.5s hue-rotate 闪光
Sidebar 按钮 — 在
sidebar.footer.action注册一个ThemeButton,显示当前主题名 + 主题色点,点击循环切换。
启动
pnpm install # preinstall 自动 link + 注入 cordis.patch.yml
pnpm --filter @dhs-pro/ui-tweak run bundle # 一次性
pnpm dsh:web # 零参数启动,加载所有 app/* 插件
不需要为某个具体插件再写一条 dsh:web:<name> 命令 —— 所有 app/*/cordis.yml 都由 scripts/sync-profile-bundles.sh 自动注册到 dsh profile 的 dsh.profile.bundles,dsh web 启动时自己通过官方 loadProfile 路径加载。
迭代开发:pnpm ui-tweak:watch 在终端 1 自动重建,pnpm dsh:web 在终端 2 运行;改 themes.ts / styleSheet.ts / effects.ts 任一即生效。
编辑主题/特效
| 想改什么 | 文件 |
|---|---|
| 调色板(颜色、键名) | app/ui-tweak/src/client/themes.ts |
| 全局 CSS 覆盖(圆角、阴影、视差、动画) | app/ui-tweak/src/client/styleSheet.ts |
| 键盘 / 滚动 / 彩蛋监听 | app/ui-tweak/src/client/effects.ts |
| Sidebar 按钮 UI | app/ui-tweak/src/client/ThemeButton.tsx + ThemeButton.module.css |
| Slot 注册与生命周期 | app/ui-tweak/src/client/index.ts |
局限(明确知道)
Cordis slot 系统是声明式且叠加的:插件可以新增 slot entry,但不能替换已注册部件。这意味着:
- ✓ 可以加新按钮、新动画、新事件、新主题
- ✓ 可以在自己注册的 component 内自由使用 CSS Module 改风格
- ✓ 可以通过 CSS 变量 + 全局 stylesheet 改绝大多数 shell 视觉(因为 shell 读
--dsw-*token) - ✗ 不能直接覆盖 upstream shell 已注册的 component(如果某个菜单必须换样式,需要先在
effects.ts里给对应节点injectStyle或setAttribute,或者开新 slot)
如需更深改造,下一步可:写一个 app/ui-shell-override/,里面把 ui-shell 已声明 slot 的整个 children 列出来作为 hook 点,逐个替换。
同步 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 # preinstall: init submodule + link 插件 + 注入 cordis.patch.yml
│ ├── detect-pkg-manager.sh
│ ├── link-app-workspaces.sh # symlink app/* Cordis 插件到 dsh profile
│ ├── sync-profile-bundles.sh # sync dsh.profile.bundles with all dsh.bundle.patch-declaring apps
│ └── run.sh # 包管理器无关的入口包装
├── docs/
│ ├── plugin-guide.md # 1500+ 行 host-repo 插件开发手册
│ ├── plugin-development.md # Cordis 内核 + dsh-base/web-app 内部细节
│ └── web-api.md # pnpm dsh web 的浏览器↔Node HTTP 协议
├── package.json
├── pnpm-workspace.yaml
├── pnpm-lock.yaml
└── README.md
进一步阅读
- 本仓
docs/plugin-guide.md— host-repo 插件开发手册(app/<pkg>/工作流、symlink、dsh.profile.bundles同步、tsdown bundle、npm 发布) docs/plugin-development.md— Cordis 内核机制 + dsh-base/web-app 内部细节- 上游
cordis-tutorial/— 7 章从零跑教程(first plugin → into the harness),最贴近"我刚接触 Cordis"的入口
nexu-io/open-design
ruvnet/ruflo
amruthpillai/reactive-resume
esengine/DeepSeek-Reasonix
volcengine/OpenViking
Molunerfinn/PicGo
titanwings/colleague-skill
nocobase/nocobase