概览
@linsibin/dsh-task-board
README / ZH
插件文档
dsh-task-board —— DeepSeek Harness 任务看板插件
在 DSH Desktop Web GUI 的顶部页签条(与「对话」「轨迹」并列)新增一个 「任务」 页签, 提供可视化的任务管理看板:
- 三栏看板:创建任务(待办)/ 执行任务(进行中)/ 完成任务(完成)
- 任务组:每栏内按「任务组」字段分组,点击组名可折叠/展开该组全部卡片
- 任务卡片:id(UUID)、标题、任务组、描述(Markdown)、工作目录、关联文件、状态
- 新建 / 编辑 / 删除:右上角「新建任务」弹窗录入全部字段;卡片上提供编辑与删除
- 拖拽执行:把卡片拖进「执行任务」栏 → 插件自动为它创建一个绑定
workDir的 独立 DSH 会话,把卡片描述作为 Prompt 以 queue 模式发送给 Agent 真实执行; 执行中卡片实时显示输出;出现回合结束且会话空闲后自动流转到「完成任务」栏 - 重跑:把「完成任务」栏里的卡片再次拖进「执行任务」栏即可重新执行
- 失败处理:prompt 被拒 / Agent 报错 / 超时(8 小时)→ 回到「创建任务」栏并在卡上 显示错误信息,可再次拖入执行
- 本地持久化:任务数据存于浏览器 localStorage(key
dsh-task-board:v1),刷新不丢 - 与主题一致:颜色全部使用 DSH 主题 CSS 变量(
--dsw-*),自动适配浅色/暗色
代码注释为中文。
目录结构
dsh-task-board/
├─ package.json # 包清单:dsh.client(web)+ dsh.bundle(patch)双声明
├─ cordis.patch.yml # bundle patch:把本插件作为一行插入 Loader 组合树
├─ tsconfig.json # 仅供编辑器/类型阅读;构建不依赖它
├─ lib/
│ ├─ index.js # host 半边(Loader 在 Node 侧装载的空插件)
│ └─ client.js # 浏览器半边(构建产物,禁止手改;改 src/client.tsx 后重跑 build)
├─ src/
│ └─ client.tsx # 浏览器半边源码(全部看板逻辑,中文注释)
└─ scripts/
└─ build.mjs # 构建脚本:TSX → CJS + ModuleLoader 注册壳 → lib/client.js
双面体说明
本插件是一个标准的 DSH「客户端插件」npm 包,同一包包含两个半边:
| 半边 | 文件 | 作用 |
|---|---|---|
| host 半边 | lib/index.js |
Loader 在 Node 侧装载的 Cordis 插件;纯 UI 插件为空 apply |
| 浏览器半边 | lib/client.js |
注册进 Web GUI 的客户端插件:{ inject, apply } |
package.json 的两处关键声明(机制证据见 DSH 官方 @deepseek-ai/dsh-client-* 包):
"dsh": {
"client": { // 浏览器半边声明(platform 必须是 "web")
"platform": "web",
"inject": [ /* 图中依赖的其它客户端包 */ ]
},
"bundle": { // 作为 profile bundle 的声明(提供 Loader patch)
"patch": "./cordis.patch.yml"
}
}
浏览器半边必须整体是一个注册包:
window.__ModuleLoader__.load({
id: "dsh-task-board",
factory: (require) => {
var module = { exports: {} };
var exports = module.exports;
// ...本插件代码...
return module.exports; // { inject: [...], apply(ctx) }
}
});
apply(ctx) 里通过 ctx.slots.inject("conversation.view", …) 注册页签,
这是「对话」/「轨迹」页签的同一官方机制(conversation.view 是 list 槽)。
环境与构建
- 需要 Node.js(本机验证于 v22.19)。
- 离线可用:构建脚本使用 DSH profile 里自带的 TypeScript(
~/.dsh/profiles/node_modules/typescript) 做纯转译,不联网、不安装任何依赖。也可用DSH_TS_LIB环境变量指定 typescript.js 路径。
# 重新生成 lib/client.js(改过 src/client.tsx 后执行)
node scripts/build.mjs
# 可选:监听 src/client.tsx 变化自动重建(配合客户端 HMR 调试)
node scripts/build.mjs --watch
注:
lib/client.js是提交产物;不改源码就不需要跑构建。
安装到 DSH Desktop(激活 profile)
本插件的激活目标是桌面 profile(当前 GUI 即由它驱动)。三选一:
方式 A:DSH 终端 CLI(推荐)
在 DSH Desktop 内启动的 DSH 终端中执行:
dsh plugin --profile desktop add <本目录绝对路径>
说明:
- 本包声明了
dsh.bundle,因此 CLI 会自动把它加入~/.dsh/profiles/desktop/package.json的dsh.profile.bundles, 并作为直接依赖安装进 profile。 - 因为插件 manifest(bundles 清单)发生变化,必须重启 DSH Desktop 才能生效。 重启后顶部页签条会出现「任务」(需先打开/新建一个会话——页签条属于会话头部, 与「对话」「轨迹」同机制)。
方式 B:手工安装(不依赖 CLI)
编辑
~/.dsh/profiles/desktop/package.json:dependencies增加本包(file: 指向绝对路径);dsh.profile.bundles增加"@linsibin/dsh-task-board"。
在 profile 目录执行
pnpm install(若本机 pnpm 不可用可改用dsh plugin --profile desktop install)。重启 DSH Desktop。
方式 C:npm 安装
npm install @linsibin/dsh-task-board
然后在 desktop profile 的 dsh.profile.bundles 中加入 "@linsibin/dsh-task-board" 并重启 DSH Desktop。
方式 C:内置插件市场(如可用)
若桌面设置 → Plugins 中能看到市场,可按市场安装流程添加本地目录或已发布包; 未发布时优先用方式 A / B。
不要手工编辑
cordis.yml——它在每次启动时会被重写。用户层改动请走cordis.patch.yml或上述安装流程。
验证清单(验收标准对照)
| 验收项 | 如何验证 |
|---|---|
| 顶部出现「任务」页签 | 打开任意会话 → 会话头部页签条出现「任务」(在「对话」「轨迹」之后) |
| 新建包含任务组与文件的卡片 | 点「新建任务」→ 填标题/组/描述/工作目录/文件(每行一个)→ 保存 → 卡片出现在「创建任务」栏并按组显示 |
| 拖拽触发执行 / AI 开始回复 | 把卡片拖到「执行任务」栏 → 卡片出现运行指示、实时输出;浏览器控制台打印 [dsh-task-board] 日志;侧栏会话列表出现由插件创建的新会话 |
| 完成后自动流转 | Agent 回合结束且会话空闲 → 卡片自动进入「完成任务」栏并带结果摘要 |
| 完成后可拖回重跑 | 把「完成任务」栏卡片再拖进「执行任务」栏 → 重新执行 |
| 任务组折叠/展开 | 点击组名折叠或展开该组全部卡片 |
| 状态持久化 | 刷新页面后任务仍存在 |
失败路径:prompt 被拒、Agent 报错或超时会回到「创建任务」栏并显示 ⚠ 错误,
可再次拖入重试。
实现原理(执行链路)
卡片拖入「执行任务」栏后,浏览器半边执行:
ctx.sessions.create({ cwd: workDir })—— 为该卡创建独立会话(host 接受任意 绝对 cwd,不经 workspace 注册表)。空 workDir 则不传,使用默认工作目录。ctx.sessions.binding(sessionId)→binding.session.open()—— 拿到会话对象并打开事件窗口。session.prompt([{ type: 'text', text: 任务描述 }], 'queue')—— 发送任务。- 订阅
binding.eventSource:实时收集assistant/message、assistant/chunk文本回填卡片。 - 轮询会话快照:出现
turn/end且running === false且队列清空 → 判定完成, 自动置为completed;promptError/lastAgentError→ 失败回待办;超过 8 小时强制回待办。 - 停止:调用
session.cancel()(降级remote.session.cancel)并回待办。
每次执行都会新建一个会话并保留在 GUI 会话列表里(卡片记录
sessionId), 便于事后打开该会话复查执行全过程。
常见坑与备注
- 页签只在有会话时出现:
conversation.view槽挂在会话头部,必须先打开/新建一个 会话才能看到页签条(「对话/轨迹/任务」)。这是官方机制,非本插件限制。 - 重启边界:首次加入 bundle 后必须重启 DSH Desktop;之后仅改
src/client.tsx并 重新构建lib/client.js,可利用 DSH 常驻的客户端 HMR 原地热替换该插件(无需整页刷新, 但插件内 React 状态会丢失;不改 manifest 就不必重启)。 - 不要修改
cordis.yml、安装目录(Program Files 下 asar 内容)。 - 任意目录执行:
session.create接受任意绝对 cwd,但主机 fs/sandbox 策略是否放行 未登记目录取决于主机配置;若被拦,请先通过 GUI 把该目录登记为工作区,或改填已有工作区。 - 浏览器半边纯度门:
lib/client.js运行时只能require平台 seed 与图内包, 因此本插件未引入任何第三方运行时依赖;源码注释中的类型仅为阅读用。
开发备忘
- 改源码:编辑
src/client.tsx→node scripts/build.mjs→ 观察 HMR 或刷新页面。 - 改页签文案:编辑文件末尾
zh/en字典。 - 加字段:
Task接口 + 新建/编辑弹窗 + 卡片渲染三处同步修改。 - 构建脚本定位 TypeScript 失败时:设置环境变量
DSH_TS_LIB指向typescript.js。
