@linxin666/dsh-client-ui-task-board 0.1.11 → 0.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,6 @@
1
+ # Bilingual-pair consistency record (docs/i18n.md): the git blob hash of each
2
+ # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
+ # after editing either side, bring the other along and re-record with:
4
+ # node scripts/verify-docs.mjs --write <dir>
5
+ README.md: bbbadebabdee529b7a0ea831519cf909a4716844
6
+ README.zh.md: 64b6539d2a4505e3824657e62dcfb4dfab88704e
package/README.md CHANGED
@@ -1,97 +1,63 @@
1
- # dsh-task-board — DSH web GUI 任务看板插件
2
-
3
- 一个可热插拔的 DeepSeek Harness (DSH) 客户端 GUI 插件:在侧边栏「新会话」下方增加
4
- **任务看板**入口,点击后中间列整体切换为多列看板视图;任务以 DSH 自身的会话机制
5
- **真实执行**(`session.prompt`),执行状态实时回写卡片。
6
-
7
- - 不修改 DSH 源码:以 cordis 插件 + 浏览器 DOM 扩展挂载(外挂形态与
8
- `dsh-web-ui/packages/skins/skin-center` 一致)。
9
- - 卸载即恢复原状,其它 managed 段(dsh-skin / skin-center / 个人配置)互不干扰。
10
- - 任务数据本地持久化,刷新页面、重启 DSH 均不丢失。
11
-
12
- ## 功能
13
-
14
- - **侧边栏入口**:`[data-pane="sidebar"]` 列内、新会话按钮下方注入「任务看板」入口行
15
- (宽栏显示图标+文字,折叠 rail 显示纯图标,随 DSH 皮肤 token 自适应)。
16
- - **多列看板**:待规划 / 待办 / 进行中 / 已完成 / 已失败 五列;卡片显示标题、描述、
17
- 状态、更新时间、执行次数;顶部支持搜索过滤、新建任务、返回对话。
18
- - **任务详情**:点卡片打开详情(标题/描述/执行 Prompt/执行记录),**不会**一点就执行;
19
- 详情内提供「执行 / 重新执行」「删除(带确认)」「查看会话(跳转到执行 transcript)」
20
- 以及手动移到待规划/待办。
21
- - **真实执行**:点「执行」后,插件通过客户端 runtime 连接工作区会话
22
- (`workspaces.connectWorkspace`,空白会话复用或 host 新建),把任务标题设为会话名,
23
- 以任务 Prompt 调用 `session.prompt([{ type: 'text', text }], 'queue')` 驱动真实 agent;
24
- 随后订阅该会话快照,轮次真实结束后把卡片置为 已完成/已失败 并记录执行结果。
25
- 执行会话会出现在会话列表,可点进对话查看真实 transcript。
26
- - **状态回写**:卡片状态(进行中 → 完成/失败)由真实会话状态驱动;刷新页面/重启后,
27
- 遗留的 running 任务会按会话现状自动对账(reconcile)。
28
- - **定时任务**:详情面板可为任务配置定时执行——启用开关 + 5 段 cron 表达式
29
- (分 时 日 月 周,支持 `*` / `*/n` / `a-b` / 逗号列表)+ 常用预设(每天 09:00、
30
- 每小时、每 10 分钟、每周一 09:00);启用即计算并持久化「下次运行时间」,卡片显示
31
- 定时 标识;到点自动走真实执行链路(同手动执行),执行会话照常可跳转。
32
- - **系统提示词注入**:host 半边(`src/index.ts`)通过 `SystemPrompt.section` 注册
33
- `plugin:task-board` 段(order 200),向每个 agent 声明本插件存在、能力与限制——
34
- 插件在组合中(mount 后重启 DSH)即注入,移出组合(unmount 后重启)即消失,
35
- agent 无需任何外部文档就能知道如何与本看板协作。
36
-
37
- ## 目录结构
1
+ # dsh-task-board — DSH web GUI task board plugin
2
+
3
+ English | [中文](README.zh.md)
4
+
5
+ A hot-pluggable DeepSeek Harness (DSH) client GUI plugin: it adds a **task board** entry below "新会话" (New session) in the sidebar; clicking it switches the middle column entirely to a multi-column kanban view. Tasks execute for **real** through DSH's own session mechanism (`session.prompt`), and execution status is written back to the card in real time.
6
+
7
+ - No DSH source modification: mounted as a cordis plugin + browser DOM extension (add-on shape identical to `dsh-web-ui/packages/skins/skin-center`).
8
+ - Unmounting restores the original state; other managed segments (dsh-skin / skin-center / personal config) are unaffected.
9
+ - Task data persists locally; it survives a page refresh and a DSH restart.
10
+
11
+ ## Features
12
+
13
+ - **Sidebar entry**: injects a "任务看板" (task board) entry row inside the sidebar column (`[data-pane="sidebar"]` on older shells, `[class*="sidebarCol"]` on the DSH 0.1.0-rc.6 AppFrame layout) below the new-session button (wide rail shows icon + text, collapsed rail shows a bare icon, adapting to DSH skin tokens).
14
+ - **Multi-column board**: five columns — 待规划 (to plan) / 待办 (to do) / 进行中 (in progress) / 已完成 (done) / 已失败 (failed); cards show title, description, status, update time, and execution count; the top supports search filter, new task, and back to chat.
15
+ - **Task details**: click a card to open details (title/description/execution prompt/execution log) — it does **not** execute on a single click; the details offer "执行 / 重新执行" (Run / Re-run), "删除" (Delete, with confirm), "查看会话" (View session, jumps to the execution transcript), and a manual move to 待规划/待办.
16
+ - **Real execution**: on "执行" (Run), the plugin connects a workspace session through the client runtime (`workspaces.connectWorkspace`, reusing a blank session or letting the host create one), names the session after the task title, and drives a real agent via `session.prompt([{ type: 'text', text }], 'queue')`; it then subscribes to that session's snapshot and, once the round really finishes, sets the card to 已完成/已失败 and records the execution result. The execution session appears in the session list and can be opened to view the real transcript.
17
+ - **Status write-back**: card status (进行中 → 完成/失败) is driven by the real session state; after a page refresh/restart, leftover running tasks are auto-reconciled against the current session state (reconcile).
18
+ - **Scheduled tasks**: the details panel can schedule a task — an enable switch + a 5-field cron expression (分 时 日 月 周, supporting `*` / `*/n` / `a-b` / comma lists) + common presets (daily 09:00, every hour, every 10 minutes, Mondays 09:00); enabling computes and persists the "下次运行时间" (next run time), and the card shows a scheduled marker; at the due time it automatically takes the same real-execution path (as manual run), and the execution session remains linkable.
19
+ - **System-prompt injection**: the host half (`src/index.ts`) registers a `plugin:task-board` section (order 200) via `SystemPrompt.section`, declaring this plugin's existence, capabilities, and limits to every agent — it is injected when the plugin is in the composition (after mount + DSH restart) and disappears when removed (after unmount + restart), so an agent needs no external docs to know how to work with this board.
20
+
21
+ ## Directory structure
38
22
 
39
23
  ```
40
- package.json / tsconfig.json / tsdown.config.ts # 独立仓库构建
41
- build/tsdown.client.ts + build/web/src/platform.ts # 从 DSH checkout 复制的 client bundle 预设(与运行版本保持同步)
42
- src/index.ts / src/invariant.ts # host 半边:仅注入 SystemPrompt section(其余无行为)
43
- src/client/index.ts # apply(ctx):接线 runtime 服务 + 挂载 DOM
44
- src/client/sidebar-entry.ts # 侧边栏入口注入(自愈式 MutationObserver)
45
- src/client/board-mount.tsx # 中间列看板挂载 + 显隐切换
46
- src/client/board/*.tsx # React 看板视图(列/卡片/详情/新建/确认)
47
- src/client/board.module.css # 样式(--dsw-* token,随主题/皮肤自适应)
48
- src/core/tasks.ts # 任务模型 + 状态机(纯函数)
49
- src/core/schedule.ts # cron 解析 + 下次运行时刻(纯函数)
50
- src/core/scheduler.ts # 浏览器调度器(每分钟 tick 触发到期任务)
51
- src/core/store.ts # 持久化(TaskStore 接口 + localStorage 实现)
52
- src/core/execution.ts # 真实执行服务(会话连接/prompt/结算观察)
53
- src/core/controller.ts # 控制器(台账状态、视图状态、导航感知)
54
- tests/*.spec.ts # 存储/状态流转/执行触发/cron/调度 自动化测试
55
- scripts/dsh-task-board.js # 一键挂载/卸载/状态 CLI
24
+ package.json / tsconfig.json / tsdown.config.ts # standalone repo build
25
+ build/tsdown.client.ts + build/web/src/platform.ts # client bundle preset copied from the DSH checkout (kept in sync with the running version)
26
+ src/index.ts / src/invariant.ts # host half: only injects SystemPrompt section (no other behavior)
27
+ src/client/index.ts # apply(ctx): wires runtime services + mounts DOM
28
+ src/client/sidebar-entry.ts # sidebar entry injection (self-healing MutationObserver)
29
+ src/client/board-mount.tsx # middle-column board mount + show/hide toggle
30
+ src/client/board/*.tsx # React board views (columns/cards/details/new/confirm)
31
+ src/client/board.module.css # styles (--dsw-* tokens, adapting to theme/skin)
32
+ src/core/tasks.ts # task model + state machine (pure functions)
33
+ src/core/schedule.ts # cron parsing + next-run time (pure functions)
34
+ src/core/scheduler.ts # browser scheduler (ticks every minute to fire due tasks)
35
+ src/core/store.ts # persistence (TaskStore interface + localStorage impl)
36
+ src/core/execution.ts # real execution service (session connect/prompt/settlement watch)
37
+ src/core/controller.ts # controller (ledger state, view state, navigation awareness)
38
+ tests/*.spec.ts # automated tests: storage/state transitions/execution trigger/cron/scheduling
39
+ scripts/dsh-task-board.js # one-click mount/unmount/status CLI
56
40
  ```
57
41
 
58
- ## 为什么这样接(调研结论)
59
-
60
- - **侧边栏没有可用的外挂槽位**:侧边栏壳只声明 `sidebar.workspaces` /
61
- `sidebar.settings` 两个 single 槽位,且已被 ui-workspace / ui-settings 占用;
62
- 外部插件无法注册新槽位(声明即占有,重复声明抛错)。因此入口行走
63
- skin 先例的 **DOM 注入**,并用 MutationObserver 自愈(React 重渲染波及该节点时
64
- 同帧内重新插入,无闪烁)。
65
- - **中间列无法通过槽位替换**:`conversation` 槽位是 single 且已被 ui-conversation
66
- 占用。看板视图以 DOM 方式挂在 `[data-pane="conversation"]` 列内(React 不管的
67
- 尾部子节点),通过 `<html data-dsh-taskboard-active>` 属性切换显隐,底下的对话
68
- 子树保持挂载有状态。
69
- - **持久化用浏览器 localStorage**:客户端插件跑在浏览器里,DSH 没有浏览器可写的
70
- 文件通道(与 skin-center 对 `cordis.patch.yml` 的调研结论一致);localStorage 也是
71
- DSH 客户端自身快照存储(`createSnapshotStore` persist)的持久化方式。
72
- - **执行走客户端 runtime**:`ctx.sessions.list` 订阅会话状态(`running` /
73
- `byId`),`ctx.workspaces.connectWorkspace()` 创建/复用会话,
74
- `session.prompt()` 真实驱动 agent,`ctx.sessions.open()` 跳转 transcript。
75
- - **后台结算靠列表对账**:未打开的会话没有对话快照窗口(cold),所以执行结算以
76
- 会话列表为准——每次列表变化都对账 running 任务;结果判定依次取「列表缺失→已取消 /
77
- 仍在跑→等待 / 对话快照可见→按 lastAgentError / 原始历史尾部→turn-error 节点证明失败 /
78
- 否则按成功」,对账幂等。
79
- - **定时任务在浏览器端调度**:插件是纯客户端(无服务端通道),所以「到点执行」由
80
- 标签页内的调度器完成——每分钟 tick 一次,页面从后台恢复可见时立即补 tick;到点
81
- 触发前先把「下次运行」顺延到下一个 cron 匹配点再执行,同一 tick 不会重复触发;
82
- 页面加载早期(会话列表基线未就绪)不触发,避免误执行。限制:需要标签页保持打开
83
- (关闭期间错过的调度按「错过即跳过」处理,下次打开时只补跑已顺延的到期任务);
84
- 任务处于「进行中」时到点跳过本次,等下一个 cron 匹配点。
85
-
86
- ## 安装
87
-
88
- 推荐直接安装全家桶聚合包 `@linxin666/dsh-web-ui-all`(一个包装齐全部功能插件与皮肤),或单独安装本插件:
42
+ ## Why it is wired this way (research conclusions)
43
+
44
+ - **No usable add-on slot in the sidebar**: the sidebar shell only declares two single slots, `sidebar.workspaces` / `sidebar.settings`, both already taken by ui-workspace / ui-settings; an external plugin cannot register a new slot (declaring means claiming, and duplicating throws). So the entry goes through the skin-precedent **DOM injection**, self-healed with a MutationObserver (when a React re-render touches the node it re-inserts within the same frame, no flicker).
45
+ - **The middle column cannot be replaced through a slot**: the `conversation` slot is single and already taken by ui-conversation. The board view mounts on the center column (`[data-pane="conversation"]` on older shells, `[class*="centerCol"]` on the DSH 0.1.0-rc.6 AppFrame layout) as a tail child node (outside React's ownership), toggled via the `<html data-dsh-taskboard-active>` attribute, keeping the chat subtree below mounted and stateful.
46
+ - **Persistence uses browser localStorage**: client plugins run in the browser and DSH has no browser-writable file channel (matching skin-center's research on `cordis.patch.yml`); localStorage is also how DSH's own client snapshot store (`createSnapshotStore` persist) persists.
47
+ - **Execution rides the client runtime**: `ctx.sessions.list` subscribes to session state (`running` / `byId`), `ctx.workspaces.connectWorkspace()` creates/reuses a session, `session.prompt()` drives a real agent, and `ctx.sessions.open()` jumps to the transcript.
48
+ - **Background settlement relies on list reconciliation**: an unopened session has no chat-snapshot window (cold), so settlement keys off the session list — every list change reconciles running tasks; result judgment takes, in order, "missing from list → cancelled / still running → wait / chat snapshot visible → by lastAgentError / tail of raw history → a turn-error node proves failure / otherwise success", and reconciliation is idempotent.
49
+ - **Scheduled tasks run in the browser scheduler**: the plugin is pure-client (no server channel), so "run at the due time" is done by the in-tab scheduler — a tick every minute, with an immediate catch-up tick when the page returns from the background; before firing it first moves "next run" forward to the next cron match so the same tick never fires twice; it does not fire early in page load (before the session-list baseline is ready), avoiding mis-execution. Limitation: the tab must stay open (schedules missed while closed are "miss = skip", and only already-deferred due tasks are caught up on the next open); a task that is 进行中 (in progress) skips the current due time and waits for the next cron match.
50
+ - **Same-origin tabs share one ledger**: additions, edits, and deletions in any tab propagate to the others through storage events (`LocalStorageTaskStore.subscribeExternal`), so a task deleted in one tab can never keep firing from another tab's stale in-memory copy — nor be written back by that copy's later persistence (schedule roll-forward, execution settlement).
51
+
52
+ ## Install
53
+
54
+ Install the family aggregate package `@linxin666/dsh-web-ui-all` (all plugins and skins in one) or this plugin alone:
89
55
 
90
56
  ```sh
91
- # 推荐:直接从 npm 安装
57
+ ### 从 npm 安装(推荐)
92
58
  dsh plugin --profile web add @linxin666/dsh-client-ui-task-board
93
59
 
94
- # 或从仓库安装(开发调试)
60
+ ### 从仓库安装(开发调试)
95
61
  git clone https://github.com/zhu1090093659/dsh-web-ui.git
96
62
  cd dsh-web-ui
97
63
  pnpm install && pnpm -r build
@@ -99,40 +65,36 @@ dsh plugin --profile web add link:$(pwd)/packages/dsh-task-board
99
65
 
100
66
  ```
101
67
 
102
- 安装后**重启 `dsh web`**,侧边栏「新会话」下方出现「任务看板」入口即生效;页面刷新不够,需重启进程。
68
+ After installing, **restart `dsh web`** — a "任务看板" (task board) entry appears below "新会话" (New session) in the sidebar; a page refresh is not enough, the process must restart.
103
69
 
104
- ## 构建
70
+ ## Build
105
71
 
106
- 前置:Node ≥ 20,官方 NPM SDK 可访问(若仍使用私有 scope 认证则配置 `NPM_TOKEN` 环境变量 + 项目 `.npmrc`,见仓库
107
- `docs/plugins.md`)。类型与运行时 API 全部来自官方 NPM SDK(`@deepseek-ai/*`
108
- devDependencies),**无需任何 DSH 源码 checkout**。
72
+ Prerequisites: Node ≥ 20 with the official NPM SDK reachable (configure the `NPM_TOKEN` env var + project `.npmrc` if still using private-scope auth; see the repo `docs/plugins.md`). Types and runtime APIs all come from the official NPM SDK (`@deepseek-ai/*` devDependencies); **no DSH source checkout is required**.
109
73
 
110
74
  ```sh
111
75
  cd ~/code/dsh-web-ui/packages/dsh-task-board
112
- pnpm install # 首次(workspace 根执行 pnpm install)
113
- pnpm run build # 产出 lib/index.js + lib/client.js(tsdown + shared/tsdown.client.ts 预设)
114
- pnpm run typecheck # 类型检查(node_modules 的 SDK 包类型)
115
- pnpm test # vitest:存储读写 / 状态流转 / 执行触发
76
+ pnpm install # first time (run pnpm install at the workspace root)
77
+ pnpm run build # produces lib/index.js + lib/client.js (tsdown + shared/tsdown.client.ts preset)
78
+ pnpm run typecheck # type check (SDK package types from node_modules)
79
+ pnpm test # vitest: storage read/write / state transitions / execution trigger
116
80
  ```
117
81
 
118
- ## 挂载 / 卸载
82
+ ## Mount / Unmount
119
83
 
120
- 本插件采用官方 profile-bundle 形态(package.json 声明 `dsh.bundle.patch` +
121
- `dsh.client`,见 `cordis.patch.yml`)。挂载 = 在 web profile 清单
122
- (`~/.dsh/profiles/web/package.json`)注册依赖与 bundle 行并安装:
84
+ This plugin uses the official profile-bundle shape (package.json declares `dsh.bundle.patch` + `dsh.client`, see `cordis.patch.yml`). Mounting = registering the dependency and bundle rows in the web profile manifest (`~/.dsh/profiles/web/package.json`) and installing:
123
85
 
124
86
  ```sh
125
- # 挂载(dependencies + dsh.profile.bundles 注册,pnpm install;重启 GUI 后生效)
87
+ # Mount (registers dependencies + dsh.profile.bundles, pnpm install; takes effect after restarting the GUI)
126
88
  node scripts/dsh-task-board.js mount
127
89
 
128
- # 查看状态
90
+ # View status
129
91
  node scripts/dsh-task-board.js status
130
92
 
131
- # 卸载(移除注册行;重启 GUI 后恢复原状;任务数据保留)
93
+ # Unmount (removes the registered rows; restores the original GUI after restart; task data is kept)
132
94
  node scripts/dsh-task-board.js unmount
133
95
  ```
134
96
 
135
- profile 清单中注册的行:
97
+ The rows registered in the profile manifest:
136
98
 
137
99
  ```json
138
100
  {
@@ -141,74 +103,30 @@ profile 清单中注册的行:
141
103
  }
142
104
  ```
143
105
 
144
- > 注意:profile 层(bundle 行、`dsh.client` 元数据)在 dsh web 进程启动时读取,
145
- > 挂载/卸载后需要**重启 dsh web GUI** 才生效(页面刷新不够)。
146
-
147
- ## 数据存储位置
148
-
149
- - 任务台账存于浏览器 localStorage,键 `dsh.taskBoard.v1`(来源为
150
- `http://127.0.0.1:<dsh web 端口>`,同一来源跨刷新/重启持久)。
151
- - 卸载插件后数据保留;如需清除,浏览器控制台执行
152
- `localStorage.removeItem("dsh.taskBoard.v1")`。
153
- - 存储层是 `TaskStore` 接口(`src/core/store.ts`),后续可换成 IndexedDB 或
154
- host 文件通道而不动上层逻辑。
155
-
156
- ## 手动验证步骤
157
-
158
- 1. `npm run build` → `node scripts/dsh-task-board.js mount` → 刷新
159
- `http://127.0.0.1:3080`。
160
- 2. 侧边栏「新会话」下方出现「任务看板」入口行;点击 → 中间列切换为五列看板。
161
- 3. 「+ 新建任务」填标题/描述/Prompt → 卡片出现在「待办」。
162
- 4. 点卡片 → 详情可见内容与 Prompt;点「执行」→ 卡片变「进行中」(会话列表出现
163
- 以任务标题命名的会话);agent 跑完后卡片落「已完成」或「已失败」,详情执行记录
164
- 有结果与时间,可「查看会话」跳转到真实 transcript。
165
- 5. 定时任务:详情 →「定时运行」勾选启用,选预设「每 10 分钟」(cron `*/10 * * * *`),
166
- 卡片出现 定时 标识;等待下一个整 10 分钟点,观察卡片自动进入「进行中」并最终完成,
167
- 详情「上次触发」出现时间、执行记录新增一条(会话可跳转)。
168
- 6. 刷新页面/重启 DSH → 任务仍在;卸载插件 → GUI 恢复原状。
169
-
170
- ## 真实 GUI 验证记录(2026-08,dsh staging-20260808T231130Z)
171
-
172
- 截图见 `docs/e2e/`:
173
-
174
- | 截图 | 内容 |
175
- | --- | --- |
176
- | `tb-board-open.png` | 侧边栏「任务看板」入口(新会话下方)+ 五列看板视图 |
177
- | `tb-task-created.png` | 新建任务后卡片落在「待办」 |
178
- | `tb-after-run.png` | 点「执行」后卡片变「进行中」,详情显示执行记录与「查看会话」链接 |
179
- | `tb-e2e-done.png` | agent 真实跑完后卡片落「已完成」,执行记录「成功 · 已启动/已结束」 |
180
- | `tb-session-transcript.png` | 「查看会话」跳转到执行会话的真实 transcript(prompt + agent 回复、用时 2s、1 turns) |
181
- | `tb-persisted.png` | 刷新页面后任务仍在 |
182
- | `tb-rail.png` | 侧边栏折叠 rail 态入口自适应为纯图标 |
183
-
184
- 真实执行证据:执行任务「端到端执行验证」的会话以任务标题命名出现在会话列表
185
- (已完成),跳转后 transcript 显示 agent 回复「端到端验证通过」,用时 2 秒、
186
- 1 turns · 1 steps、TPS 545 tok/s。
187
-
188
- 定时任务验证(同一次会话,截图 `tb-sched-*.png`):
189
-
190
- | 截图 | 内容 |
191
- | --- | --- |
192
- | `tb-sched-2-enabled.png` | 详情「定时运行」区块:启用勾选、cron 输入、预设下拉、下次运行/上次触发信息 |
193
- | `tb-sched-4-executed.png` | cron `* * * * *` 到点后自动执行完成:卡片 定时 标识 + 1 次执行,执行记录「成功」 |
194
- | `tb-sched-5-twice.png` | 顺延到下一分钟再次自动触发:2 次执行记录,下次运行自动顺延 |
195
- | `tb-sched-7-transcript.png` | 执行记录「查看会话」跳转到真实 transcript(prompt「请只回复四个字:定时OK」→ agent 回复「定时OK」,用时 2 秒) |
196
- | `tb-sched-8-persisted.png` | 刷新页面后:定时配置与执行记录保留,调度恢复(下次运行继续顺延) |
197
-
198
- 定时触发证据:任务「定时任务验证-每分钟」在 11:47 / 11:48 / 11:49 连续三个整分钟
199
- 自动触发,全部真实执行成功;触发后「上次触发」记录触发时刻、「下次运行」顺延到
200
- 下一个 cron 匹配点;执行会话出现在会话列表并可跳转。
201
-
202
- ## 验收对照
203
-
204
- - [x] 挂载后侧边栏出现「任务看板」入口;点击切换看板,点会话项返回对话视图
205
- - [x] 新建任务(标题+描述/Prompt);刷新/重启后任务仍在(localStorage 持久化)
206
- - [x] 点卡片开详情(内容 + 执行记录);详情内有「执行」「删除」按钮
207
- - [x] 执行真实启动会话(会话列表可见 transcript);卡片状态随真实执行进度变化;
208
- 详情可跳转到执行会话
209
- - [x] 删除有确认环节,删除后本地存储同步移除
210
- - [x] 定时任务:cron 配置/预设/校验、下次运行时间、到点自动真实执行、状态回写、
211
- 定时 卡片标识、刷新后调度恢复(浏览器端调度,标签页需保持打开)
212
- - [x] 一键挂载/卸载;卸载后 GUI 恢复原状,其它 managed 段不受影响
213
- - [x] README + 覆盖存储读写/状态流转/执行触发/cron 解析/调度器的自动化测试;
214
- 真实 GUI 人工验证通过
106
+ > Note: the profile layer (bundle rows, `dsh.client` metadata) is read when the dsh web process starts, so a **restart of the dsh web GUI** is required after mount/unmount (a page refresh is not enough).
107
+
108
+ ## Data storage location
109
+
110
+ - The task ledger lives in browser localStorage under the key `dsh.taskBoard.v1` (origin `http://127.0.0.1:<dsh web port>`; same origin persists across refresh/restart).
111
+ - Data is retained after unmount; to clear it, run `localStorage.removeItem("dsh.taskBoard.v1")` in the browser console.
112
+ - The storage layer is the `TaskStore` interface (`src/core/store.ts`); it can later be swapped for IndexedDB or a host file channel without touching the upper logic.
113
+
114
+ ## Manual verification steps
115
+
116
+ 1. `npm run build` → `node scripts/dsh-task-board.js mount` → refresh `http://127.0.0.1:3080`.
117
+ 2. A "任务看板" (task board) entry row appears below "新会话" in the sidebar; click it → the middle column switches to the five-column board.
118
+ 3. "+ 新建任务" (New task) with title/description/Prompt → the card appears in 待办 (to do).
119
+ 4. Click the card → details show content and Prompt; click "执行" (Run) → the card becomes 进行中 (in progress) (a session named after the task title appears in the session list); after the agent finishes the card lands in 已完成 (done) or 已失败 (failed), the detail execution log has a result and time, and "查看会话" (View session) jumps to the real transcript.
120
+ 5. Scheduled task: details → tick "定时运行" (Scheduled run) to enable, pick the preset "每 10 分钟" (every 10 minutes, cron `*/10 * * * *`); a scheduled marker appears on the card; wait for the next whole 10-minute mark, watch the card automatically enter 进行中 (in progress) and eventually complete, with "上次触发" (last trigger) showing a time and a new execution-log row (the session is linkable).
121
+ 6. Refresh the page / restart DSH → tasks remain; unmount the plugin → the GUI restores to its original state.
122
+
123
+ ## Acceptance checklist
124
+
125
+ - After mount, a "任务看板" (task board) entry appears in the sidebar; clicking toggles the board, and clicking a session item returns to the chat view
126
+ - New task (title + description/Prompt); tasks remain after refresh/restart (localStorage persistence)
127
+ - Click a card to open details (content + execution log); the details have "执行" (Run) and "删除" (Delete) buttons
128
+ - Execution really starts a session (its transcript is visible in the session list); card status follows the real execution progress; the details can jump to the execution session
129
+ - Delete has a confirm step, and the local store is synced-removed after deletion
130
+ - Scheduled tasks: cron config/preset/validation, next-run time, auto real execution at the due time, status write-back, scheduled card marker, scheduling resumes after refresh (browser-side scheduling, the tab must stay open)
131
+ - One-click mount/unmount; after unmount the GUI restores and other managed segments are unaffected
132
+ - README + automated tests covering storage read/write, state transitions, execution trigger, cron parsing, and the scheduler
package/README.zh.md ADDED
@@ -0,0 +1,132 @@
1
+ # dsh-task-board — DSH web GUI 任务看板插件
2
+
3
+ [English](README.md) | 中文
4
+
5
+ 一个可热插拔的 DeepSeek Harness (DSH) 客户端 GUI 插件:在侧边栏「新会话」下方增加 **任务看板**入口,点击后中间列整体切换为多列看板视图;任务以 DSH 自身的会话机制 **真实执行**(`session.prompt`),执行状态实时回写卡片。
6
+
7
+ - 不修改 DSH 源码:以 cordis 插件 + 浏览器 DOM 扩展挂载(外挂形态与 `dsh-web-ui/packages/skins/skin-center` 一致)。
8
+ - 卸载即恢复原状,其它 managed 段(dsh-skin / skin-center / 个人配置)互不干扰。
9
+ - 任务数据本地持久化,刷新页面、重启 DSH 均不丢失。
10
+
11
+ ## 功能
12
+
13
+ - **侧边栏入口**:侧边栏列(旧版 `[data-pane="sidebar"]`,DSH 0.1.0-rc.6 AppFrame 布局为 `[class*="sidebarCol"]`)内、新会话按钮下方注入「任务看板」入口行(宽栏显示图标+文字,折叠 rail 显示纯图标,随 DSH 皮肤 token 自适应)。
14
+ - **多列看板**:待规划 / 待办 / 进行中 / 已完成 / 已失败 五列;卡片显示标题、描述、状态、更新时间、执行次数;顶部支持搜索过滤、新建任务、返回对话。
15
+ - **任务详情**:点卡片打开详情(标题/描述/执行 Prompt/执行记录),**不会**一点就执行;详情内提供「执行 / 重新执行」「删除(带确认)」「查看会话(跳转到执行 transcript)」以及手动移到待规划/待办。
16
+ - **真实执行**:点「执行」后,插件通过客户端 runtime 连接工作区会话(`workspaces.connectWorkspace`,空白会话复用或 host 新建),把任务标题设为会话名,以任务 Prompt 调用 `session.prompt([{ type: 'text', text }], 'queue')` 驱动真实 agent;随后订阅该会话快照,轮次真实结束后把卡片置为 已完成/已失败 并记录执行结果。执行会话会出现在会话列表,可点进对话查看真实 transcript。
17
+ - **状态回写**:卡片状态(进行中 → 完成/失败)由真实会话状态驱动;刷新页面/重启后,遗留的 running 任务会按会话现状自动对账(reconcile)。
18
+ - **定时任务**:详情面板可为任务配置定时执行——启用开关 + 5 段 cron 表达式(分 时 日 月 周,支持 `*` / `*/n` / `a-b` / 逗号列表)+ 常用预设(每天 09:00、每小时、每 10 分钟、每周一 09:00);启用即计算并持久化「下次运行时间」,卡片显示定时标识;到点自动走真实执行链路(同手动执行),执行会话照常可跳转。
19
+ - **系统提示词注入**:host 半边(`src/index.ts`)通过 `SystemPrompt.section` 注册 `plugin:task-board` 段(order 200),向每个 agent 声明本插件存在、能力与限制——插件在组合中(mount 后重启 DSH)即注入,移出组合(unmount 后重启)即消失,agent 无需任何外部文档就能知道如何与本看板协作。
20
+
21
+ ## 目录结构
22
+
23
+ ```
24
+ package.json / tsconfig.json / tsdown.config.ts # 独立仓库构建
25
+ build/tsdown.client.ts + build/web/src/platform.ts # 从 DSH checkout 复制的 client bundle 预设(与运行版本保持同步)
26
+ src/index.ts / src/invariant.ts # host 半边:仅注入 SystemPrompt section(其余无行为)
27
+ src/client/index.ts # apply(ctx):接线 runtime 服务 + 挂载 DOM
28
+ src/client/sidebar-entry.ts # 侧边栏入口注入(自愈式 MutationObserver)
29
+ src/client/board-mount.tsx # 中间列看板挂载 + 显隐切换
30
+ src/client/board/*.tsx # React 看板视图(列/卡片/详情/新建/确认)
31
+ src/client/board.module.css # 样式(--dsw-* token,随主题/皮肤自适应)
32
+ src/core/tasks.ts # 任务模型 + 状态机(纯函数)
33
+ src/core/schedule.ts # cron 解析 + 下次运行时刻(纯函数)
34
+ src/core/scheduler.ts # 浏览器调度器(每分钟 tick 触发到期任务)
35
+ src/core/store.ts # 持久化(TaskStore 接口 + localStorage 实现)
36
+ src/core/execution.ts # 真实执行服务(会话连接/prompt/结算观察)
37
+ src/core/controller.ts # 控制器(台账状态、视图状态、导航感知)
38
+ tests/*.spec.ts # 存储/状态流转/执行触发/cron/调度 自动化测试
39
+ scripts/dsh-task-board.js # 一键挂载/卸载/状态 CLI
40
+ ```
41
+
42
+ ## 为什么这样接(调研结论)
43
+
44
+ - **侧边栏没有可用的外挂槽位**:侧边栏壳只声明 `sidebar.workspaces` / `sidebar.settings` 两个 single 槽位,且已被 ui-workspace / ui-settings 占用;外部插件无法注册新槽位(声明即占有,重复声明抛错)。因此入口行走 skin 先例的 **DOM 注入**,并用 MutationObserver 自愈(React 重渲染波及该节点时同帧内重新插入,无闪烁)。
45
+ - **中间列无法通过槽位替换**:`conversation` 槽位是 single 且已被 ui-conversation 占用。看板视图以 DOM 方式挂在中间列(旧版 `[data-pane="conversation"]`,DSH 0.1.0-rc.6 AppFrame 布局为 `[class*="centerCol"]`;挂载选择器两者都保留)内(React 不管的尾部子节点),通过 `<html data-dsh-taskboard-active>` 属性切换显隐,底下的对话子树保持挂载有状态。
46
+ - **持久化用浏览器 localStorage**:客户端插件跑在浏览器里,DSH 没有浏览器可写的文件通道(与 skin-center 对 `cordis.patch.yml` 的调研结论一致);localStorage 也是 DSH 客户端自身快照存储(`createSnapshotStore` persist)的持久化方式。
47
+ - **执行走客户端 runtime**:`ctx.sessions.list` 订阅会话状态(`running` / `byId`),`ctx.workspaces.connectWorkspace()` 创建/复用会话,`session.prompt()` 真实驱动 agent,`ctx.sessions.open()` 跳转 transcript。
48
+ - **后台结算靠列表对账**:未打开的会话没有对话快照窗口(cold),所以执行结算以会话列表为准——每次列表变化都对账 running 任务;结果判定依次取「列表缺失→已取消 / 仍在跑→等待 / 对话快照可见→按 lastAgentError / 原始历史尾部→turn-error 节点证明失败 / 否则按成功」,对账幂等。
49
+ - **定时任务在浏览器端调度**:插件是纯客户端(无服务端通道),所以「到点执行」由标签页内的调度器完成——每分钟 tick 一次,页面从后台恢复可见时立即补 tick;到点触发前先把「下次运行」顺延到下一个 cron 匹配点再执行,同一 tick 不会重复触发;页面加载早期(会话列表基线未就绪)不触发,避免误执行。限制:需要标签页保持打开(关闭期间错过的调度按「错过即跳过」处理,下次打开时只补跑已顺延的到期任务);任务处于「进行中」时到点跳过本次,等下一个 cron 匹配点。
50
+ - **多标签页同源共享同一份台账**:任一标签页的增删改通过 storage 事件同步到其他标签页(`LocalStorageTaskStore.subscribeExternal`),删除的任务不会在其他标签页的内存副本里残留触发,也不会被其他标签页的后续持久化写回复活。
51
+
52
+ ## 安装
53
+
54
+ 推荐直接安装全家桶聚合包 `@linxin666/dsh-web-ui-all`(一个包装齐全部功能插件与皮肤),或单独安装本插件:
55
+
56
+ ```sh
57
+ ### 从 npm 安装(推荐)
58
+ dsh plugin --profile web add @linxin666/dsh-client-ui-task-board
59
+
60
+ ### 从仓库安装(开发调试)
61
+ git clone https://github.com/zhu1090093659/dsh-web-ui.git
62
+ cd dsh-web-ui
63
+ pnpm install && pnpm -r build
64
+ dsh plugin --profile web add link:$(pwd)/packages/dsh-task-board
65
+
66
+ ```
67
+
68
+ 安装后**重启 `dsh web`**,侧边栏「新会话」下方出现「任务看板」入口即生效;页面刷新不够,需重启进程。
69
+
70
+ ## 构建
71
+
72
+ 前置:Node ≥ 20,官方 NPM SDK 可访问(若仍使用私有 scope 认证则配置 `NPM_TOKEN` 环境变量 + 项目 `.npmrc`,见仓库 `docs/plugins.md`)。类型与运行时 API 全部来自官方 NPM SDK(`@deepseek-ai/*` devDependencies),**无需任何 DSH 源码 checkout**。
73
+
74
+ ```sh
75
+ cd ~/code/dsh-web-ui/packages/dsh-task-board
76
+ pnpm install # 首次(workspace 根执行 pnpm install)
77
+ pnpm run build # 产出 lib/index.js + lib/client.js(tsdown + shared/tsdown.client.ts 预设)
78
+ pnpm run typecheck # 类型检查(node_modules 的 SDK 包类型)
79
+ pnpm test # vitest:存储读写 / 状态流转 / 执行触发
80
+ ```
81
+
82
+ ## 挂载 / 卸载
83
+
84
+ 本插件采用官方 profile-bundle 形态(package.json 声明 `dsh.bundle.patch` + `dsh.client`,见 `cordis.patch.yml`)。挂载 = 在 web profile 清单(`~/.dsh/profiles/web/package.json`)注册依赖与 bundle 行并安装:
85
+
86
+ ```sh
87
+ # 挂载(dependencies + dsh.profile.bundles 注册,pnpm install;重启 GUI 后生效)
88
+ node scripts/dsh-task-board.js mount
89
+
90
+ # 查看状态
91
+ node scripts/dsh-task-board.js status
92
+
93
+ # 卸载(移除注册行;重启 GUI 后恢复原状;任务数据保留)
94
+ node scripts/dsh-task-board.js unmount
95
+ ```
96
+
97
+ profile 清单中注册的行:
98
+
99
+ ```json
100
+ {
101
+ "dependencies": { "@linxin666/dsh-client-ui-task-board": "link:/Users/zcl/code/dsh-web-ui/packages/dsh-task-board" },
102
+ "dsh": { "profile": { "bundles": [ "...", "@linxin666/dsh-client-ui-task-board" ] } }
103
+ }
104
+ ```
105
+
106
+ > 注意:profile 层(bundle 行、`dsh.client` 元数据)在 dsh web 进程启动时读取,挂载/卸载后需要**重启 dsh web GUI** 才生效(页面刷新不够)。
107
+
108
+ ## 数据存储位置
109
+
110
+ - 任务台账存于浏览器 localStorage,键 `dsh.taskBoard.v1`(来源为 `http://127.0.0.1:<dsh web 端口>`,同一来源跨刷新/重启持久)。
111
+ - 卸载插件后数据保留;如需清除,浏览器控制台执行 `localStorage.removeItem("dsh.taskBoard.v1")`。
112
+ - 存储层是 `TaskStore` 接口(`src/core/store.ts`),后续可换成 IndexedDB 或 host 文件通道而不动上层逻辑。
113
+
114
+ ## 手动验证步骤
115
+
116
+ 1. `npm run build` → `node scripts/dsh-task-board.js mount` → 刷新 `http://127.0.0.1:3080`。
117
+ 2. 侧边栏「新会话」下方出现「任务看板」入口行;点击 → 中间列切换为五列看板。
118
+ 3. 「+ 新建任务」填标题/描述/Prompt → 卡片出现在「待办」。
119
+ 4. 点卡片 → 详情可见内容与 Prompt;点「执行」→ 卡片变「进行中」(会话列表出现以任务标题命名的会话);agent 跑完后卡片落「已完成」或「已失败」,详情执行记录有结果与时间,可「查看会话」跳转到真实 transcript。
120
+ 5. 定时任务:详情 →「定时运行」勾选启用,选预设「每 10 分钟」(cron `*/10 * * * *`),卡片出现定时标识;等待下一个整 10 分钟点,观察卡片自动进入「进行中」并最终完成,详情「上次触发」出现时间、执行记录新增一条(会话可跳转)。
121
+ 6. 刷新页面/重启 DSH → 任务仍在;卸载插件 → GUI 恢复原状。
122
+
123
+ ## 验收对照
124
+
125
+ - 挂载后侧边栏出现「任务看板」入口;点击切换看板,点会话项返回对话视图
126
+ - 新建任务(标题+描述/Prompt);刷新/重启后任务仍在(localStorage 持久化)
127
+ - 点卡片开详情(内容 + 执行记录);详情内有「执行」「删除」按钮
128
+ - 执行真实启动会话(会话列表可见 transcript);卡片状态随真实执行进度变化;详情可跳转到执行会话
129
+ - 删除有确认环节,删除后本地存储同步移除
130
+ - 定时任务:cron 配置/预设/校验、下次运行时间、到点自动真实执行、状态回写、定时卡片标识、刷新后调度恢复(浏览器端调度,标签页需保持打开)
131
+ - 一键挂载/卸载;卸载后 GUI 恢复原状,其它 managed 段不受影响
132
+ - README + 覆盖存储读写/状态流转/执行触发/cron 解析/调度器的自动化测试