dsh-workflow-map 0.0.0-stage → 0.3.2
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.
- package/CHANGELOG.md +98 -0
- package/LICENSE +21 -0
- package/README.en.md +447 -0
- package/README.md +423 -2
- package/client.js +9673 -0
- package/cordis.patch.yml +11 -0
- package/docs/OPEN-SOURCE-GUIDE.md +256 -0
- package/docs/screenshot-detail.png +0 -0
- package/docs/screenshot.png +0 -0
- package/icon.svg +6 -0
- package/index.js +12 -0
- package/lib/index.js +974 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +65 -4
- package/src/client/Branches.js +241 -0
- package/src/client/FlowColumn.js +572 -0
- package/src/client/FlowEffects.js +677 -0
- package/src/client/HotInject.js +628 -0
- package/src/client/MainFlow.js +359 -0
- package/src/client/NodeCard.js +545 -0
- package/src/client/NodeDetail.js +569 -0
- package/src/client/ProgressUnder.js +216 -0
- package/src/client/RightPage.js +285 -0
- package/src/client/Settings.js +212 -0
- package/src/client/StepColumn.js +479 -0
- package/src/client/StepDetail.js +250 -0
- package/src/client/export.js +280 -0
- package/src/client/panel.js +1911 -0
- package/src/client/pulse.js +126 -0
- package/src/client/store.js +1090 -0
- package/src/client/theme.js +1164 -0
- package/src/fold.mjs +2633 -0
- package/src/orchestrator.mjs +426 -0
- package/src/route.js +621 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
`dsh-workflow-map` 的所有重要变更记录在此。
|
|
4
|
+
格式遵循 [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),版本号遵循 [SemVer](https://semver.org/)。
|
|
5
|
+
|
|
6
|
+
## [0.3.1] - 2026-10-28
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
|
|
10
|
+
- **`soft` 配色的同类残留**。0.3.0 已让 `brand` 配色下运行中卡片的外框跟随品牌色,
|
|
11
|
+
但 `soft` 配色的规则仍只认单页改版之前的选择器(`.wf-step-item > .wf-step-card` / `.wf-node`),
|
|
12
|
+
于是切到 `soft` 时运行中单元的外框仍是默认彩虹渐变、状态环仍停在品牌蓝、
|
|
13
|
+
卫星圆点与连线的流光也没换色。现在 `soft` 与 `brand` 一样同时命名现役选择器——
|
|
14
|
+
`.wf-unit[data-status='running']>.wf-unit-center>.wf-unit-card::after`、`.wf-unit-ring`、
|
|
15
|
+
`.wf-sat[data-live='true']::after` 与 `.wf-sat-row[data-live='true'] .wf-sat-line`——
|
|
16
|
+
三处一并跟随 `--wf-soft-1` / `--wf-soft-2`。
|
|
17
|
+
- 对应的浏览器量测从「记录缺陷」改为「断言修复」:`settings.soft.keepsRainbowRing`
|
|
18
|
+
换成 `settings.soft.frameMigrated` 与 `settings.soft.ringColor`,两者都用期望色
|
|
19
|
+
`rgb(127, 147, 184)` 比对;同一份期望里也存了它的十六进制写法 `#7f93b8`。
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- `docs/screenshot.png`(1400×900)与 `docs/screenshot-detail.png`(1500×950)
|
|
24
|
+
用当前代码重新渲染,替换为修复后的界面。
|
|
25
|
+
|
|
26
|
+
### Tests
|
|
27
|
+
|
|
28
|
+
- 离线自测 **10 套 / 1507 条断言**、浏览器量测 **10 套 / 308 条断言**,全部通过。
|
|
29
|
+
|
|
30
|
+
### Notes
|
|
31
|
+
|
|
32
|
+
- 仅改浏览器半(`src/client/*.js` 与重建的 `client.js`)与文档,**宿主半未改动**:
|
|
33
|
+
升级后 **F5 刷新页面**即可,不需要重启 DSH 进程。
|
|
34
|
+
|
|
35
|
+
## [0.3.0] - 2026-10-27
|
|
36
|
+
|
|
37
|
+
首个公开发布版本。相比内部迭代期,这一版把面板从「开发中的实验界面」收敛成可日常使用的形态。
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
|
|
41
|
+
- **热注入的完整撤回链路**:历史行在「待会话拾取」状态时出现「撤回」按钮,走 `POST /dsh-workflow/unsteer`
|
|
42
|
+
→ 宿主的 `agent.inbox.remove(messageId)`;`/steer` 的响应同时带回它写下的 `messageId`。
|
|
43
|
+
撤回后刷新页面状态依然正确:折叠会重放宿主的收件箱变动(`agent/inbox/spliced` 记录的是**位置**,
|
|
44
|
+
所以需要维护一份收件箱台账才能定位到具体是哪一行)。旧检查点按契约丢弃重建。
|
|
45
|
+
- **会话标签栏入口**:在会话区顶部标签栏新增一个席位,与左栏图标、主内容区共用同一份面板、
|
|
46
|
+
同一份轮询、同一份设置。
|
|
47
|
+
- **热注入入口常驻化**:页头入口改为醒目的品牌色按钮;右页注入器底部新增可回车直发的常驻输入条,
|
|
48
|
+
不必先展开面板才能发。
|
|
49
|
+
- **进度估算的诚实化**:只要待办清单有已完成行,百分比就取该实测比值,模型自报不再参与显示值计算
|
|
50
|
+
(自报仅作为无实测行时的备选);时间基线冷启动时改用计划自身的步序推算,避免首个进行中的步只剩一条空流光。
|
|
51
|
+
|
|
52
|
+
### Fixed
|
|
53
|
+
|
|
54
|
+
- **多个分步同时显示为「进行中」**:折叠时取「第一个 running 行」,而规划阶段的合成步要等到
|
|
55
|
+
计划开启才收尾,导致它长期占用 running 状态、后续每一步再叠一个。现在每个折叠事件后
|
|
56
|
+
收敛为唯一 running 行;进度上报也归属到待办表里真正 `in_progress` 的那一行。
|
|
57
|
+
- **地图分步与对话里的待办表不一致**:折叠只增不删,重新规划或改写标题后旧行会残留。
|
|
58
|
+
现在视图严格按最新待办表产出分步,表里已不存在的行与其节点一并移除。
|
|
59
|
+
- **已完成的步显示「0 工具 0 文件」**:三个叠加的问题——按标题匹配导致改写文案后旧行变孤儿、
|
|
60
|
+
新建行未写入步骤键、全局节点上限按「丢弃最老」执行而最老的恰属已完成步。
|
|
61
|
+
现已改为就地改名并迁移节点、统一赋值步骤键、并从节点最多的步开始淘汰(单步永不被清空)。
|
|
62
|
+
- **被拒绝的审批仍标「需确认」**:审批被拒时该行仍需人工处理,原实现把任何「已决议」都当成已结束。
|
|
63
|
+
现改为「已询问,或已决议但未放行」都算未决;同时修掉了状态修复函数遗漏 `outcome` 字段的问题
|
|
64
|
+
(否则一次重启就会把这个语义抹掉)。
|
|
65
|
+
- **唯一流光**:只有唯一那一行的进度条与连接线跑动画,其余即使状态是 running 也只是静态填充。
|
|
66
|
+
|
|
67
|
+
### Changed
|
|
68
|
+
|
|
69
|
+
- **面板布局改为单页**:原先的左右双列(分步列 + 流程列)合并为一个视图——串行主流程在中间,
|
|
70
|
+
每步两侧以圆形接口表示该类工具/文件,点击后在右页展开详情。两列之间的跨列曲线随之移除。
|
|
71
|
+
- **移除「预计剩余时间」**:进度条第二行只保留「N 分钟前估计」(这个数字有多旧),
|
|
72
|
+
不再预测还需要多久。宿主侧相应的计算与字段一并移除。
|
|
73
|
+
- **移除实验性的输入框覆盖层**:该方案多轮实测无法稳定覆盖宿主渲染的输入框,
|
|
74
|
+
改为在会话标签栏席位用样式规则让位,切回对话页自动恢复。
|
|
75
|
+
|
|
76
|
+
### Tests
|
|
77
|
+
|
|
78
|
+
- 离线自测 **10 套**,合计 **1505 条断言**。
|
|
79
|
+
- 浏览器量测 **10 套**,合计 **308 条断言**(真实 CSS + 真实事件,覆盖几何、动画、剪贴板、
|
|
80
|
+
键盘与降级路径)。
|
|
81
|
+
- 真实日志只读回归:批量折叠历史会话日志、零失败;另有四条硬约束审计。
|
|
82
|
+
|
|
83
|
+
### Known issues
|
|
84
|
+
|
|
85
|
+
- 品牌配色的「运行中卡片外框」仍沿用默认彩虹渐变(选择器未迁移)。仅影响外观,
|
|
86
|
+
进度条与其余元素已正确换色。
|
|
87
|
+
- 类型页副标题会原样印出未替换的 `{count}` 占位符。仅影响文案。
|
|
88
|
+
|
|
89
|
+
### Notes
|
|
90
|
+
|
|
91
|
+
- **宿主半改动需要重启 DSH 进程**;浏览器半改动 **F5 即生效**(profile 使用符号链接安装时)。
|
|
92
|
+
- 输入框(composer)由宿主渲染,不属于本插件;插件只在会话标签页席位让它让位。
|
|
93
|
+
|
|
94
|
+
## 更早的内部迭代
|
|
95
|
+
|
|
96
|
+
0.3.0 之前的版本为内部迭代,未对外发布,因此不在此列出逐条记录。
|
|
97
|
+
所涉及的能力(会话投影、计划读取、HTTP 视图路由、面板骨架、进度条、节点详情、设置与导出)
|
|
98
|
+
均已并入 0.3.0。
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 dsh-workflow-map contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.en.md
ADDED
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
# dsh-workflow-map
|
|
2
|
+
|
|
3
|
+
English · [**简体中文**](README.md)
|
|
4
|
+
|
|
5
|
+
A DeepSeek Harness plugin that renders the current session as an interactive step-by-step workflow map.
|
|
6
|
+
|
|
7
|
+
Three entry points share one data source and one set of components: the sidebar panel item
|
|
8
|
+
(`sidebar.panellist`), the main content area (`main`), and the session tab bar (`conversation.view`).
|
|
9
|
+
The panel folds session events into a step sequence, showing each step's status, progress, tool calls
|
|
10
|
+
and file operations, and can inject prompts into the next step of a running session.
|
|
11
|
+
|
|
12
|
+

|
|
13
|
+
|
|
14
|
+
*Left: the selected sidebar entry. Centre: the serial main flow (one unit card per step, round interfaces
|
|
15
|
+
on both sides for tool/file types; the running unit is highlighted with a flowing frame). Right: the page
|
|
16
|
+
opened for a step (type list, step detail). Bottom: the persistent injection bar.*
|
|
17
|
+
|
|
18
|
+

|
|
19
|
+

|
|
20
|
+

|
|
21
|
+

|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 1. What problem it solves
|
|
26
|
+
|
|
27
|
+
Long tasks grow session logs to thousands of events. Answering "which step is it on", "what did this
|
|
28
|
+
step do" and "how much is done" means scrolling back through those logs. This plugin presents those
|
|
29
|
+
three facts on one screen, with every data source and decision rule traceable.
|
|
30
|
+
|
|
31
|
+
### Layout
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
┌──────────────────────────────┬───────────────────┐
|
|
35
|
+
│ session 4/10 · 46% ⚙ │
|
|
36
|
+
├──────────────────────────────┼───────────────────┤
|
|
37
|
+
│ ◯─┐ 01/10 skeleton and registration │ step 5 detail │
|
|
38
|
+
│ │ ▓▓▓▓▓▓▓▓▓▓ 100% reported │ ──────────────── │
|
|
39
|
+
│ │ │ files this step used │
|
|
40
|
+
│ ◯─┘ 02/10 host projection │ ● md type 4 calls │
|
|
41
|
+
│ │ ▓▓▓▓▓▓▓▓▓▓ 100% reported │ ● js type 2 calls │
|
|
42
|
+
│ │ │ ● pwsh type 2 calls │
|
|
43
|
+
│ ◯─┐ 05/10 browser shell <- running (highlighted) │
|
|
44
|
+
│ │ ▓▓▓▓▓░░░░░ ~58% estimated │ step 5 detail │
|
|
45
|
+
│ │ estimated 3 min ago │ what it delivered │
|
|
46
|
+
│ │ │ ● done │
|
|
47
|
+
│ ◯─┘ 06/10 step cards and rail │ 12 tools 12 files │
|
|
48
|
+
│ ▓▓▓░░░░░░░ ~36% estimated │ ──────────────── │
|
|
49
|
+
│ │ inject [........] │
|
|
50
|
+
└──────────────────────────────┴───────────────────┘
|
|
51
|
+
main flow (one unit per step, round type interfaces on both sides) right page (opens on click)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
> Diagram, not a screenshot; see the screenshot above for the real UI.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## 2. Capabilities
|
|
59
|
+
|
|
60
|
+
The four capabilities below map onto four regions of the UI: injection (header button and the right
|
|
61
|
+
page input), progress (the rail under each card), layout (main flow and side interfaces), and state
|
|
62
|
+
encoding (animation and colour).
|
|
63
|
+
|
|
64
|
+
### 2.1 Hot injection (steer / unsteer)
|
|
65
|
+
|
|
66
|
+
This section states the write semantics, state determination and failure semantics of the injection channel.
|
|
67
|
+
All three are derived from session log events; the front end does not guess.
|
|
68
|
+
**Write semantics**: `POST /dsh-workflow/steer` calls the host's `agent.steer(message)`; the message
|
|
69
|
+
enters the session inbox queue `next-step` and is claimed by the next step **after the current turn
|
|
70
|
+
ends**. The call does not trigger `cancel`, so the running turn is not interrupted.
|
|
71
|
+
|
|
72
|
+
| Endpoint | Method | Semantics |
|
|
73
|
+
|---|---|---|
|
|
74
|
+
| `/dsh-workflow/steer` | POST | Write one prompt to `next-step`; the response returns the generated `messageId` |
|
|
75
|
+
| `/dsh-workflow/unsteer` | POST | Call `agent.inbox.remove()` with the `messageId`, removing a message that is **not yet claimed** |
|
|
76
|
+
|
|
77
|
+
**State determination** (mutually exclusive, all derived from the log, never guessed by the UI):
|
|
78
|
+
|
|
79
|
+
| State | Determined by |
|
|
80
|
+
|---|---|
|
|
81
|
+
| Awaiting pickup | `agent/inbox/spliced` exists and no `user/message` with the same id |
|
|
82
|
+
| Picked up | A `user/message` with the same id exists (the turn claimed it) |
|
|
83
|
+
| Revoked | `agent/inbox/spliced { outcome: "canceled" }` exists and the id was never claimed |
|
|
84
|
+
|
|
85
|
+
HTTP 200 only means the message reached the inbox; it does **not** mean the session has read it. The
|
|
86
|
+
"awaiting pickup" versus "picked up" distinction comes from the log events above. A revoke's durable
|
|
87
|
+
record is the splice **position**, not the message id, so the fold keeps an inbox ledger (replaying
|
|
88
|
+
splices with the host's own `inboxProjectionDefinition` semantics) to identify which row was removed.
|
|
89
|
+
|
|
90
|
+
Failure semantics: document-level errors always return JSON and never throw into the HTTP layer.
|
|
91
|
+
Common codes: `400` missing field / non-JSON body, `404` unknown session, `409` session not running or
|
|
92
|
+
message already claimed, `413` text over 2000 chars or body over 64 KiB, `503` the host does not expose
|
|
93
|
+
the capability.
|
|
94
|
+
|
|
95
|
+
### 2.2 Progress estimation
|
|
96
|
+
|
|
97
|
+
This section states the percentage priority order, the algorithm and cap of each source, and the definition
|
|
98
|
+
of the staleness field. The rule is implemented by `percentFor` in `src/fold.mjs`.
|
|
99
|
+
|
|
100
|
+
Each step's percentage is resolved by the following **priority** (`percentFor` in `src/fold.mjs`):
|
|
101
|
+
| Priority | Source | Rule | Cap |
|
|
102
|
+
|---|---|---|---|
|
|
103
|
+
| 1 | Todo table `todos` | `round(completed / total * 100)`; when a self-report exists, this measured value is still what is returned | 99 |
|
|
104
|
+
| 2 | Model self-report `model` | Only when the todo table has no countable rows: the **larger** of the `stepProgress/report` percentage and the self-report high-water mark | 100 |
|
|
105
|
+
| 3 | Time baseline `baseline` | `elapsed / median(finished-step durations in this session) * 100` | 90 |
|
|
106
|
+
| 4 | Plan ordinal `baseline:steps` | Cold start with `current step / total steps * 100` when no durations exist | 90 |
|
|
107
|
+
| - | `none` | None of the four is available | No number shown |
|
|
108
|
+
|
|
109
|
+
Constraint: an unfinished step never shows 100 %; a finished (done or failed) step is pinned to 100 %.
|
|
110
|
+
|
|
111
|
+
The choice follows verifiability: the todo table is an objective count, a model self-report is not. So
|
|
112
|
+
whenever the todo table has completed rows, the percentage is that measured ratio (both branches of that
|
|
113
|
+
`percentFor` expression yield `measured`); the self-report is a fallback only when no row can be measured.
|
|
114
|
+
The high-water record `step.maxPercent` is still kept and never rolled back, but it no longer takes part in
|
|
115
|
+
computing the displayed value.
|
|
116
|
+
|
|
117
|
+
A second line under the rail reads `estimated N minutes ago`, i.e. `view.asOf - step.lastEstimateAt`.
|
|
118
|
+
It describes how **stale** the number is, distinguishing "being updated" from "unchanged for a long time".
|
|
119
|
+
The line is not rendered when the field is absent.
|
|
120
|
+
|
|
121
|
+
### 2.3 Single-page layout
|
|
122
|
+
|
|
123
|
+
One vertical main flow, one unit per step; each unit carries round interfaces on both sides, one per
|
|
124
|
+
tool or file type.
|
|
125
|
+
|
|
126
|
+
| Dimension | Rule |
|
|
127
|
+
|---|---|
|
|
128
|
+
| Side assignment | Read-type (`read` / `grep` / `glob` / path queries) on the left; write and execute (`edit` / `write` / `pwsh`) on the right |
|
|
129
|
+
| Capacity per side | 2 interfaces |
|
|
130
|
+
| Overflow | Extra types are not drawn; the unit states "N more types are not drawn on the sides" |
|
|
131
|
+
| Connector | A straight line between interface and unit |
|
|
132
|
+
| Details | Click an interface -> the right page lists that type's calls; click a unit -> the right page shows that step's record |
|
|
133
|
+
|
|
134
|
+
A single page was chosen over columns for continuity: switching steps in a two-column layout moves two
|
|
135
|
+
scroll regions at once, whereas here the main flow does not shift when the right page opens or closes.
|
|
136
|
+
|
|
137
|
+
### 2.4 Visual state encoding
|
|
138
|
+
|
|
139
|
+
The running unit and the single connector pointing at it use a flowing gradient; every other unit stays
|
|
140
|
+
statically filled even when its status is `running` (for example, when it is not the live one). Durations
|
|
141
|
+
and thresholds live in `src/client/theme.js`:
|
|
142
|
+
|
|
143
|
+
| Element | Implementation | Period |
|
|
144
|
+
|---|---|---|
|
|
145
|
+
| Running unit frame | `::after` multi-stop linear gradient plus a position animation | 2.6 s |
|
|
146
|
+
| Running unit ring | Opacity pulse | 1.6 s |
|
|
147
|
+
| Progress fill | Background position | 1.5 s |
|
|
148
|
+
| Activity dots | Three dots breathing out of phase | 1.2 s |
|
|
149
|
+
|
|
150
|
+
`data-motion="static"` (the "reduce motion" setting, or the OS `prefers-reduced-motion: reduce`) sets
|
|
151
|
+
every animation inside the panel to `none`, and `document.getAnimations()` returns an empty set;
|
|
152
|
+
`data-idle="1"` (session idle) sets animations to `paused` while keeping the current frame. The two are
|
|
153
|
+
not the same thing.
|
|
154
|
+
|
|
155
|
+
### 2.5 One implementation, three seats
|
|
156
|
+
|
|
157
|
+
All three entries register the same component, the same polling and the same preferences record - there is
|
|
158
|
+
no second implementation. The session-tab entry additionally carries a box-less marker so a `:has()` rule
|
|
159
|
+
can collapse the host's composer on that page; switching back unmounts the view and the composer returns.
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## 3. Installation
|
|
164
|
+
|
|
165
|
+
> **Prerequisites for installing from the market**: two conditions must both hold. (1) `dsh-workflow-map`
|
|
166
|
+
> is published on npm (currently `0.3.1`). (2) The `awesome-dsh-plugin` PR is merged **and** the market index
|
|
167
|
+
> (`dsh-plugin-catalog`, served via jsDelivr) has refreshed and picked up the entry.
|
|
168
|
+
> Once both hold, install from the **DSH market** (Plugins > Discover) by searching `workflow`, no terminal needed.
|
|
169
|
+
> If it is not indexed yet, use the command line below (3.2) to install the same package; both routes are equivalent.
|
|
170
|
+
|
|
171
|
+
### 3.1 Install through the agent
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
install dsh-workflow-map with plugin_manager, path is <absolute path to the plugin>
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
A returned `application: applied` means it took effect; no other value does.
|
|
178
|
+
|
|
179
|
+
### 3.2 Command line
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
cd "$HOME/.dsh/profiles/desktop"
|
|
183
|
+
pnpm add dsh-workflow-map
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
```powershell
|
|
187
|
+
# One command into the desktop profile (the bundled DSH CLI forwards the rest to that profile's pnpm; use the full path if it is not on PATH)
|
|
188
|
+
dsh plugin --profile desktop add dsh-workflow-map
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Then append `"dsh-workflow-map"` to the `dsh.profile.bundles` array in that directory's `package.json`.
|
|
192
|
+
|
|
193
|
+
### 3.3 Local source
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
cd "$HOME/.dsh/profiles/desktop"
|
|
197
|
+
pnpm add "dsh-workflow-map@link:/path/to/dsh-workflow-map"
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
`link:` creates a symlink, so source edits are reflected on disk immediately.
|
|
201
|
+
|
|
202
|
+
### 3.4 Verify the install
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
# 1) the package is on disk
|
|
206
|
+
ls "$HOME/.dsh/profiles/desktop/node_modules/dsh-workflow-map"
|
|
207
|
+
|
|
208
|
+
# 2) the host view endpoint works (expect HTTP 200 and a JSON body)
|
|
209
|
+
curl -i "http://127.0.0.1:<GUI port>/dsh-workflow/state?sessionId=<session id>"
|
|
210
|
+
|
|
211
|
+
# 3) the UI: a clickable sidebar icon, a panel in the main area, a same-named tab in the session tab bar
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## 4. How changes take effect
|
|
217
|
+
|
|
218
|
+
The plugin has two halves with different load times:
|
|
219
|
+
|
|
220
|
+
| Half | Contains | Takes effect | Why |
|
|
221
|
+
|---|---|---|---|
|
|
222
|
+
| Browser half | `client.js` (built from `src/client/*.js`) | **Page refresh (F5)** | Front-end code loads per request |
|
|
223
|
+
| Host half | `lib/index.js`, `src/fold.mjs`, `src/route.js` | **Restart the DSH process** | ESM module cache cannot be replaced in-process |
|
|
224
|
+
|
|
225
|
+
Restart once after the first install; afterwards UI-only changes need no restart.
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## 5. Data boundary
|
|
230
|
+
|
|
231
|
+
### 5.1 What is read
|
|
232
|
+
|
|
233
|
+
- **Session event log**: `todo/write`, `tool/call`, `tool/result`, `step/start|end`, `turn/start|end`,
|
|
234
|
+
`stepProgress/report`, `user/message`, `assistant/message`, `approval/*`, `agent/inbox/*` and others.
|
|
235
|
+
Event types not listed return the same state reference with no copy.
|
|
236
|
+
- **PAE plan file**: `<project>/.pae/<sessionId>/orchestrator.json`. Read-only, cached by `mtime:size` and
|
|
237
|
+
re-parsed only when the file changes; the parsed result is deep-frozen. A missing file, a partial write or
|
|
238
|
+
malformed fields yield `null` and degrade to the todo table only, never throwing.
|
|
239
|
+
|
|
240
|
+
### 5.2 What is not read
|
|
241
|
+
|
|
242
|
+
- **File bodies**. Fields such as `content`, `old_str` and `new_str` never enter the state, so how much
|
|
243
|
+
the agent writes does not grow the panel's state.
|
|
244
|
+
- **The network**. The plugin makes no outbound requests; all data comes from local processes and files.
|
|
245
|
+
|
|
246
|
+
### 5.3 Truncation and limits
|
|
247
|
+
|
|
248
|
+
| Item | Limit | On overflow |
|
|
249
|
+
|---|---|---|
|
|
250
|
+
| Arguments / result text | 200 characters each | The UI states "host cap 200 characters" |
|
|
251
|
+
| Nodes per step | 300 | Keep head and tail, drop the middle into `truncated.stepNodes` |
|
|
252
|
+
| Nodes per session | 1200 | Evict starting from the step with the most nodes; no step is ever emptied |
|
|
253
|
+
| Injection history | 40 rows | Keep the newest |
|
|
254
|
+
| Approval records | 40 rows | Keep the newest |
|
|
255
|
+
| Titles | 120 characters | Truncated with an ellipsis |
|
|
256
|
+
|
|
257
|
+
Eviction deliberately does not start with the oldest: the oldest nodes usually belong to finished steps,
|
|
258
|
+
so time-based eviction would empty historical steps.
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## 6. Interaction
|
|
263
|
+
|
|
264
|
+
| Action | Result |
|
|
265
|
+
|---|---|
|
|
266
|
+
| Click a unit | The right page shows that step's record (report, artifacts, stats) |
|
|
267
|
+
| Click a round interface | The right page lists that type's calls |
|
|
268
|
+
| Click a call row | Expand the full arguments, result and error in place |
|
|
269
|
+
| `Esc` | Close the right page, not the panel |
|
|
270
|
+
| Gear | Open settings: palette, motion, detail depth, node limit |
|
|
271
|
+
| Copy control | Copy path / command / snapshot, with a receipt that restores after 1.5 s |
|
|
272
|
+
|
|
273
|
+
Settings:
|
|
274
|
+
|
|
275
|
+
| Item | Values | Effect |
|
|
276
|
+
|---|---|---|
|
|
277
|
+
| Palette `palette` | `rainbow` / `brand` / `soft` | Switches accent colours and gradients |
|
|
278
|
+
| Motion `motion` | `full` / `always` / `static` | `full` follows session activity; `always` plays even when idle; `static` turns everything off |
|
|
279
|
+
| Detail depth `detail` | `summary` / `title` | `title` hides the rail's second line |
|
|
280
|
+
| Node limit `nodeLimit` | 30 / 60 / 120 / 0 | `0` means unlimited |
|
|
281
|
+
|
|
282
|
+
Preferences live in one `localStorage` record; a corrupted or outdated record degrades field by field to the
|
|
283
|
+
defaults without blocking rendering.
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## 7. Export
|
|
288
|
+
|
|
289
|
+
The gear offers four exports: copy / download times Markdown / JSON. The exported snapshot contains the
|
|
290
|
+
steps, their status, the percentage source, the node list and the report artifact paths - never file bodies.
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
## 8. Compatibility and constraints
|
|
295
|
+
|
|
296
|
+
- **DeepSeek Harness** 0.2.x or newer (relies on session projections and `webServer` route registration).
|
|
297
|
+
- **Node.js** ≥ 20。
|
|
298
|
+
- The three endpoints mount on the host's existing port; **no new listener** is opened.
|
|
299
|
+
- The composer is rendered by the host and is not part of this plugin. The plugin neither replaces nor
|
|
300
|
+
overlays it; it only yields space on the session-tab page through a stylesheet rule.
|
|
301
|
+
- The fold path never reads a clock: every time value in the view comes from event timestamps, so the same
|
|
302
|
+
event sequence always yields the same view (replayable).
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
## 9. Development
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
# after editing src/client/*.js, rebuild the browser half
|
|
310
|
+
node tools/build-client.mjs
|
|
311
|
+
|
|
312
|
+
# offline self-tests (10 suites, 1507 assertions)
|
|
313
|
+
node tools/selftest-fold.mjs # fold semantics
|
|
314
|
+
node tools/selftest-host.mjs # registration, schema, projection wiring
|
|
315
|
+
node tools/selftest-orchestrator.mjs # plan file reading and merging
|
|
316
|
+
node tools/selftest-shape.mjs # package shape, config, files whitelist
|
|
317
|
+
node tools/selftest-panel.mjs # render tree, styles, interaction
|
|
318
|
+
node tools/selftest-detail.mjs # node and step details
|
|
319
|
+
node tools/selftest-effects.mjs # animation and motion fallback
|
|
320
|
+
node tools/selftest-settings.mjs # settings and export
|
|
321
|
+
node tools/probe-route.mjs # HTTP routes (real loopback)
|
|
322
|
+
node tools/probe-steer.mjs # injection / revoke channel
|
|
323
|
+
|
|
324
|
+
# read-only regression over real logs
|
|
325
|
+
node tools/check-real-injects.mjs # fold historical logs in bulk
|
|
326
|
+
node tools/audit-real.mjs # four-constraint audit
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
Browser measurements (needs a Chromium; the scripts auto-detect Chrome / Edge; 308 assertions):
|
|
330
|
+
|
|
331
|
+
```bash
|
|
332
|
+
pwsh -File tools/measure-panel.ps1
|
|
333
|
+
pwsh -File tools/measure-timing.ps1
|
|
334
|
+
pwsh -File tools/measure-inject.ps1
|
|
335
|
+
pwsh -File tools/measure-dock.ps1
|
|
336
|
+
pwsh -File tools/measure-flow.ps1
|
|
337
|
+
pwsh -File tools/measure-effects.ps1
|
|
338
|
+
pwsh -File tools/measure-branches.ps1
|
|
339
|
+
pwsh -File tools/measure-detail.ps1
|
|
340
|
+
pwsh -File tools/measure-settings.ps1
|
|
341
|
+
pwsh -File tools/measure-main.ps1
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
`client.js` is a build artifact (its first line carries a GENERATED marker) and must not be edited by hand.
|
|
345
|
+
`tools/retired/` holds historical scripts for removed UI; they are not part of the verification chain.
|
|
346
|
+
|
|
347
|
+
---
|
|
348
|
+
|
|
349
|
+
## 10. Key constants
|
|
350
|
+
|
|
351
|
+
Every threshold is defined once and asserted by the tests, so this table cannot drift from the code:
|
|
352
|
+
|
|
353
|
+
| Constant | Value | Location | Meaning |
|
|
354
|
+
|---|---|---|---|
|
|
355
|
+
| `NODES_PER_STEP` | 300 | `src/fold.mjs` | Nodes per step |
|
|
356
|
+
| `NODES_TOTAL` | 1200 | `src/fold.mjs` | Nodes per session |
|
|
357
|
+
| `TEXT_LIMIT` | 200 | `src/fold.mjs` | Argument and result text |
|
|
358
|
+
| `TITLE_LIMIT` | 120 | `src/fold.mjs` | Titles |
|
|
359
|
+
| `INJECT_LIMIT` | 40 | `src/fold.mjs` | Injection history retained |
|
|
360
|
+
| `APPROVAL_LIMIT` | 40 | `src/fold.mjs` | Approval records retained |
|
|
361
|
+
| `WF_SIDE_SLOTS` | 2 | `src/client/theme.js` | Interfaces per side |
|
|
362
|
+
| `WF_STEP_RAIL` | 6 | `src/client/theme.js` | Progress rail height (px) |
|
|
363
|
+
| `WF_FLOW_CAP` | 60 | `src/client/theme.js` | Default call-list window |
|
|
364
|
+
| Request body | 2000 chars / 64 KiB | `src/route.js` | Injection request limit |
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
368
|
+
## 11. Known issues
|
|
369
|
+
|
|
370
|
+
Both defects recorded in 0.3.0 are closed:
|
|
371
|
+
|
|
372
|
+
| Original # | Symptom | Status |
|
|
373
|
+
|---|---|---|
|
|
374
|
+
| 1 | With the brand palette the running unit's frame used the default gradient | Fixed (`8bf6f2c`); the same residue under the `soft` palette was fixed in 0.3.1 |
|
|
375
|
+
| 2 | The type page subtitle showed an unsubstituted `{count}` placeholder | Fixed (`8bf6f2c`) |
|
|
376
|
+
|
|
377
|
+
There are no known functional defects at present. Changes to the host half need a DSH process restart;
|
|
378
|
+
that is how activation works, not a defect.
|
|
379
|
+
|
|
380
|
+
---
|
|
381
|
+
|
|
382
|
+
## 12. Layout
|
|
383
|
+
|
|
384
|
+
```
|
|
385
|
+
dsh-workflow-map/
|
|
386
|
+
├─ index.js package entry (re-exports lib/index.js)
|
|
387
|
+
├─ lib/index.js host half: session projection + three HTTP endpoints
|
|
388
|
+
├─ src/
|
|
389
|
+
│ ├─ fold.mjs events -> state -> view (pure, no clock, no IO)
|
|
390
|
+
│ ├─ orchestrator.mjs read-only PAE plan file
|
|
391
|
+
│ ├─ route.js /state · /steer · /unsteer
|
|
392
|
+
│ └─ client/ browser-half sources (inlined into one file at build)
|
|
393
|
+
├─ client.js build artifact
|
|
394
|
+
├─ cordis.patch.yml mount declaration
|
|
395
|
+
├─ locale/{zh,en}.json dictionaries
|
|
396
|
+
├─ docs/ release guide
|
|
397
|
+
└─ tools/ self-tests · probes · browser measurements
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
---
|
|
401
|
+
|
|
402
|
+
## 13. FAQ
|
|
403
|
+
|
|
404
|
+
**Can it show several sessions at once?**
|
|
405
|
+
The panel shows the current session only. Switching sessions switches the content; nothing is merged or tiled.
|
|
406
|
+
|
|
407
|
+
**Does it slow DSH down?**
|
|
408
|
+
The fold is pure with no IO; the view is derived from state, and state has hard limits (300 nodes per step,
|
|
409
|
+
1200 per session). Polling compares `rev` first and returns 304 without rebuilding when nothing changed.
|
|
410
|
+
File bodies never enter the state.
|
|
411
|
+
|
|
412
|
+
**Why does the percentage sometimes stay still for a long time?**
|
|
413
|
+
The number only moves when new events arrive. When neither the todo table nor the report updates, the time
|
|
414
|
+
baseline creeps up but is capped at 90 %. The second line ("estimated N minutes ago") states how stale it is.
|
|
415
|
+
|
|
416
|
+
**Why does an unfinished step never reach 100 %?**
|
|
417
|
+
The todo table caps at 99 and the time baseline at 90; only a done/failed status pins 100 %. This keeps
|
|
418
|
+
"nearly there" from being confused with "already there".
|
|
419
|
+
|
|
420
|
+
**Does it upload my code?**
|
|
421
|
+
No. The plugin makes no network requests; it reads only the local session log and the `.pae` plan file.
|
|
422
|
+
|
|
423
|
+
**Can I install only the UI and skip the host half?**
|
|
424
|
+
No. Both halves belong to one package: `dsh.profile.bundles` registers the host row, and the browser half is
|
|
425
|
+
loaded by that row.
|
|
426
|
+
|
|
427
|
+
**Can I turn animation off?**
|
|
428
|
+
Set motion to `static` in the settings, or enable "reduce motion" in the OS; both set every animation inside
|
|
429
|
+
the panel to `none`.
|
|
430
|
+
|
|
431
|
+
---
|
|
432
|
+
|
|
433
|
+
## 14. License
|
|
434
|
+
|
|
435
|
+
MIT. Commercial use, modification and redistribution are permitted; keep the copyright notice.
|
|
436
|
+
|
|
437
|
+
---
|
|
438
|
+
|
|
439
|
+
## 15. Reporting an issue
|
|
440
|
+
|
|
441
|
+
The following helps locate a problem:
|
|
442
|
+
|
|
443
|
+
1. DSH version and plugin version (`version` in `package.json`);
|
|
444
|
+
2. The response body of `GET /dsh-workflow/state?sessionId=<id>` - **it contains task titles and file
|
|
445
|
+
paths, so redact before posting**;
|
|
446
|
+
3. A screenshot of the panel where it goes wrong;
|
|
447
|
+
4. For fold-related issues, include the relevant event sequence from that session log.
|