全部插件

DSH / BUNDLE / CLIENT-UI

@linsibin/dsh-task-board

v0.1.0linsibin / dsh-task-boardbbd45b6947

可安装组合包UI 与客户端插件社区 · Topic 自动分析Web UI

概览

@linsibin/dsh-task-board

DSH task-board plugin: adds a kanban tab (Chat/Trajectory/Tasks) to the DSH web GUI with drag-to-execute real agent runs.

README / ZH

插件文档

dsh-task-board —— DeepSeek Harness 任务看板插件

English · 中文

在 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.jsondsh.profile.bundles, 并作为直接依赖安装进 profile。
  • 因为插件 manifest(bundles 清单)发生变化,必须重启 DSH Desktop 才能生效。 重启后顶部页签条会出现「任务」(需先打开/新建一个会话——页签条属于会话头部, 与「对话」「轨迹」同机制)。

方式 B:手工安装(不依赖 CLI)

  1. 编辑 ~/.dsh/profiles/desktop/package.json

    • dependencies 增加本包(file: 指向绝对路径);
    • dsh.profile.bundles 增加 "@linsibin/dsh-task-board"
  2. 在 profile 目录执行 pnpm install(若本机 pnpm 不可用可改用 dsh plugin --profile desktop install)。

  3. 重启 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 报错或超时会回到「创建任务」栏并显示 错误, 可再次拖入重试。


实现原理(执行链路)

卡片拖入「执行任务」栏后,浏览器半边执行:

  1. ctx.sessions.create({ cwd: workDir }) —— 为该卡创建独立会话(host 接受任意 绝对 cwd,不经 workspace 注册表)。空 workDir 则不传,使用默认工作目录。
  2. ctx.sessions.binding(sessionId)binding.session.open() —— 拿到会话对象并打开事件窗口。
  3. session.prompt([{ type: 'text', text: 任务描述 }], 'queue') —— 发送任务。
  4. 订阅 binding.eventSource:实时收集 assistant/messageassistant/chunk 文本回填卡片。
  5. 轮询会话快照:出现 turn/endrunning === false 且队列清空 → 判定完成, 自动置为 completedpromptError / lastAgentError → 失败回待办;超过 8 小时强制回待办。
  6. 停止:调用 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.tsxnode scripts/build.mjs → 观察 HMR 或刷新页面。
  • 改页签文案:编辑文件末尾 zh / en 字典。
  • 加字段:Task 接口 + 新建/编辑弹窗 + 卡片渲染三处同步修改。
  • 构建脚本定位 TypeScript 失败时:设置环境变量 DSH_TS_LIB 指向 typescript.js