dsh-group-status 0.5.1 → 0.5.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 +46 -0
- package/README.en.md +138 -135
- package/README.md +140 -135
- package/docs/facet-protocol.md +274 -0
- package/docs/media/glyph-completed.svg +3 -0
- package/docs/media/glyph-pending.svg +3 -0
- package/docs/media/glyph-running.svg +6 -0
- package/docs/media/screenshot-folders.png +0 -0
- package/docs/media/screenshot-hover.png +0 -0
- package/docs/upgrading.md +241 -0
- package/lib/client.js +5 -2
- package/lib/client.js.map +1 -1
- package/lib/types/client/navigation.d.ts +23 -8
- package/lib/types/client/navigation.d.ts.map +1 -1
- package/lib/types/client/navigation.js +20 -3
- package/lib/types/client/navigation.js.map +1 -1
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,52 @@
|
|
|
6
6
|
|
|
7
7
|
## 未发布
|
|
8
8
|
|
|
9
|
+
## 0.5.2 — 2026-11-05
|
|
10
|
+
|
|
11
|
+
- **fix** 内核 `0.2.2` 线前瞻适配(Issues #43,经 `0.2.2-alpha.2` 发布产物对照,无破坏性变更):
|
|
12
|
+
① `startSession` 的草稿意图判定不再只看 `prompt` / `clearPreviousDraft: true` —— `whenDraftExists`
|
|
13
|
+
(`replace | append | keep`,`DraftInitializationOptions` 在 0.2.2 新增的三态)单独出现时同样初始化
|
|
14
|
+
草稿,并把两代字段一并原样透传给 `requestDraftInitialization`(旧宿主忽略、新宿主生效),两字段语义
|
|
15
|
+
分叉后导航层不再漏判;② 空白会话复用改为 preset 感知(与 rc.4→alpha.2 定稿措辞一致):列出其它
|
|
16
|
+
preset 的空白不再被无 `agentPreset` 的请求复用,命名 preset 的请求只命中列同值或无 preset 的空白;
|
|
17
|
+
③ peer 的 `^0.2.1-rc.2` 按 semver 预发布规则匹配不到 `0.2.2-alpha.x`(`0.2.2` 正式版会自动纳入),
|
|
18
|
+
alpha 线提前验证需临时补 `|| ^0.2.2-alpha.2` 且**不入仓** —— 不变式与原因见升级手册「兼容声明
|
|
19
|
+
为什么长这样」一节。新增本仓库 spec `tests/navigation-draft-blank.client.spec.ts`(8 用例,纯对象
|
|
20
|
+
stub 驱动真实 `UiWorkspaceService`)看守 ①②;spec 实跑数 183 → 191,README 数字同步。
|
|
21
|
+
- **docs** 升级手册「上游代次跟踪」的漂移表按 2026-11-02 复核更新:两处已对齐、一处(`connectBlank`
|
|
22
|
+
的不可达早退)确认无行为差不跟;「约定」一节的前提修正 —— `navigation.ts` 从此有本地用例覆盖,
|
|
23
|
+
逐 rc 跟改不再受「无法证明没坏」约束,但升基线仍按触发清单走。「测试基线」的合计数改为可核实的
|
|
24
|
+
实跑值,跳过的上游 spec 数 7 → 9(与 `vitest.config.ts`、README 对齐)。
|
|
25
|
+
- **docs** 中英两份 README 按「装 → 认徽标 → 配 → 出问题查什么」重排:安装回到使用之前,新增
|
|
26
|
+
「徽标不出现时」排错表(没重启、内核在窗口外、四档计数全为 0、低于 `countThreshold`、搭档
|
|
27
|
+
插件未注册),并补上此前只写在代码注释里的两条用户可见事实:计数超过 99 显示 `99+`、外部
|
|
28
|
+
来源之间的次序由各方的 `order` 决定。本机 `link:` 安装从用户路径移进「开发」。
|
|
29
|
+
同时修掉与实现不符的陈述:设置项是 5 个(曾写「7 个」)、外部来源在本页没有专用开关
|
|
30
|
+
(同篇另一处曾说「两个来源各有一个专用设置项」)、Node 与 spec 用例数按实跑值、跳过的上游
|
|
31
|
+
spec 是 9 个(曾写 7)、`status.waitingReview` / `status.scheduled` 等 5 个文案键已随
|
|
32
|
+
`legacy/` 删除不再列为本包新增、`rc.4` 的用例通过不等于行为一致(差异见升级手册)。
|
|
33
|
+
- **docs** 一处事实一个家:facet 契约细节归 [`docs/facet-protocol.md`](docs/facet-protocol.md),
|
|
34
|
+
README 只留方向、最小注册示例与指针;12 条 peer 的因果链归 [`docs/upgrading.md`](docs/upgrading.md)
|
|
35
|
+
新增的「兼容声明为什么长这样」一节,README 兼容性段只给结论。
|
|
36
|
+
- **test** 新增 [`tests/readme-facts.node.test.mjs`](tests/readme-facts.node.test.mjs)(8 例):
|
|
37
|
+
README 的版本徽章 == `package.json` 的 `version`;设置表的字段与默认值 == `src/index.ts` 的
|
|
38
|
+
`Config`;用例数 == 实跑数量(Node 侧静态计数再用 `node --test` 交叉验证,Vitest 侧读 JSON
|
|
39
|
+
reporter);用户文档不含工单号、已删除的实现名与内网地址;相对引用存在且图片落在 `files`
|
|
40
|
+
白名单内;`extract-notes.mjs` 依赖的特性小节仍在。
|
|
41
|
+
- **chore** `package.json`:`description` 不再把「定时任务」「等待评审」列成本插件的档位
|
|
42
|
+
(它们是提供方注册的状态源,本包不含对应字段);`files` 白名单补 `docs`,此前发布 tarball 里
|
|
43
|
+
没有截图与两份文档,README 的图片在包内视角是断链。
|
|
44
|
+
|
|
45
|
+
- **docs** 徽标读法表加「图标」列:三枚 SVG(待审批黄点、进行中转圈、已完成绿点)按
|
|
46
|
+
`StateDot` 的几何复刻(实心点是 10px 槽位里的 6px 圆,转圈是 14px 的环 + 约 72° 的弧、
|
|
47
|
+
轨道 25% 不透明度),颜色取自仓库自带实机截图的像素(`#F59E0B` / `#9AA0A5` / `#22C55E`),
|
|
48
|
+
与截图同为暗色主题。产物由 [`scripts/make-badge-glyphs.mjs`](scripts/make-badge-glyphs.mjs)
|
|
49
|
+
生成,形状与取色的出处写在脚本头注释里。「叫法」列保留黄点/转圈/绿点这些说法,图标不做
|
|
50
|
+
唯一信息源(纯文本视图与读屏都还要能读)。外部来源的图标不复刻:形状归提供方,本包不替别家存资产。
|
|
51
|
+
- **test** `tests/readme-facts.node.test.mjs` 加一条:README 用到的三枚 SVG 必须能由脚本逐字节
|
|
52
|
+
复现(比对后无论是否一致都把工作区还原,`npm test` 不留改动)。手改 SVG 会让图标与组件脱钩,
|
|
53
|
+
这条把它挡在提交前。Node 用例数 49 → 50。
|
|
54
|
+
|
|
9
55
|
## 0.5.1 — 2026-10-27
|
|
10
56
|
|
|
11
57
|
- **refactor** 会话列表面板拆成四个组件文件:`rows/WorkspaceBrowser.tsx` 从 1562 行降到 685 行,
|
package/README.en.md
CHANGED
|
@@ -2,193 +2,180 @@
|
|
|
2
2
|
|
|
3
3
|
<img src="icon.svg" width="72" alt="dsh-group-status"/>
|
|
4
4
|
|
|
5
|
-
# dsh-group-status
|
|
5
|
+
# dsh-group-status: aggregated status badge for collapsed groups
|
|
6
6
|
|
|
7
7
|
[中文](./README.md) | **English**
|
|
8
8
|
|
|
9
|
-
[](https://github.com/dsh-plugin-collection/dsh-group-status)
|
|
10
10
|
[](LICENSE)
|
|
11
11
|
[](https://github.com/deepseek-ai/deepseek-harness)
|
|
12
12
|
|
|
13
13
|
</div>
|
|
14
14
|
|
|
15
|
-
> In the DSH sidebar,
|
|
15
|
+
> In the DSH sidebar, collapsing a workspace group hides the status of every session inside it: running sessions, sessions awaiting approval, sessions awaiting an answer. This plugin adds one aggregated badge to the collapsed folder row (yellow dot for pending, spinner for running, green dot for unread completed, optional external status glyphs, plus a count). Hovering the row lists each tier separately. Nothing is drawn while the group is expanded; its child rows already show their own state.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Feature overview
|
|
20
|
+
|
|
21
|
+
- **Visible while collapsed**: the badge appears only on collapsed groups; once expanded, each child row carries its own state. Nested groups aggregate the whole subtree.
|
|
22
|
+
- **Same source of truth as session rows**: the three state dots reuse the stock `StateDot` and the row-level derivation. Blank and archived sessions are skipped.
|
|
23
|
+
- **Optional cross-plugin aggregation**: other plugins register their own status sources (scheduled tasks, waiting PR reviews). This plugin contains no branch keyed on a specific source.
|
|
24
|
+
- **Usable with zero config**: 5 settings cover the three tiers, hover details, and the count threshold. All of them default to "show".
|
|
25
|
+
- **No stock files modified**: this package registers the same slot and disables the stock row in the profile patch. Not one file of the published upstream package is touched.
|
|
26
|
+
- **Localized**: follows the DSH UI language (中文 / English). Wording for an external status source comes from that source's own plugin.
|
|
27
|
+
- **Accessible**: the badge is `role="img"`, its `aria-label` matches the hover `title`, and state differences are not carried by color alone.
|
|
16
28
|
|
|
17
29
|
---
|
|
18
30
|
|
|
19
31
|
## Preview
|
|
20
32
|
|
|
21
|
-
|
|
33
|
+
The `tmp` group below holds 1 running session (spinner), 1 completed (green dot), and 1 scheduled task (clock), counting `3`:
|
|
22
34
|
|
|
23
35
|
<p align="center">
|
|
24
|
-
<img src="docs/media/screenshot-folders.png" width="267" alt="Collapsed
|
|
36
|
+
<img src="docs/media/screenshot-folders.png" width="267" alt="Collapsed tmp group in the sidebar: spinner, green dot, clock glyph and the number 3"/>
|
|
25
37
|
</p>
|
|
26
38
|
|
|
27
|
-
|
|
39
|
+
Hovering the folder row appends the per-tier lines under the path and creation time:
|
|
28
40
|
|
|
29
41
|
<p align="center">
|
|
30
|
-
<img src="docs/media/screenshot-hover.png" width="300" alt="Hover card: 1
|
|
42
|
+
<img src="docs/media/screenshot-hover.png" width="300" alt="Hover card: 1 waiting for answer · 1 running"/>
|
|
31
43
|
</p>
|
|
32
44
|
|
|
33
|
-
> The badge reuses DSH's native `StateDot`, so colors stay identical to the session rows. Both images are real screenshots.
|
|
34
|
-
|
|
35
45
|
---
|
|
36
46
|
|
|
37
|
-
##
|
|
47
|
+
## Install
|
|
38
48
|
|
|
39
|
-
|
|
49
|
+
```bash
|
|
50
|
+
dsh plugin --profile web add dsh-group-status
|
|
51
|
+
```
|
|
40
52
|
|
|
41
|
-
|
|
42
|
-
|---|---|---|
|
|
43
|
-
| Yellow dot | Pending approval / plan review / answer inside | warning (same as rows) |
|
|
44
|
-
| Spinner | Running sessions inside, incl. running subagents | ongoing (`StateDot` animation) |
|
|
45
|
-
| Green dot | Completed-unread sessions inside | done (same as the row) |
|
|
46
|
-
| Clock | Scheduled tasks inside (data from dsh-later) | purple · orange (≤5 min) · red (overdue) |
|
|
47
|
-
| Hourglass | Sessions waiting for a PR review (data from dsh-gitea-dispatch) | amber · red (the CI wait window lapsed) |
|
|
53
|
+
The sidebar is replaced as a whole bundle, so **`dsh web` must restart** after an install. Saving a setting applies immediately and needs no restart.
|
|
48
54
|
|
|
49
|
-
|
|
55
|
+
To remove it (both profile patch entries are withdrawn together and the stock session row comes back; restart again):
|
|
50
56
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
- **Expanding defers to the rows**: the aggregate badge only renders while collapsed; expanded groups keep their per-row statuses with no duplication.
|
|
55
|
-
- **Accessible**: the badge is `role="img"` with a localized `aria-label` (e.g. `1 Waiting for answer · 1 Running`) and the same text as its `title`. Waiting and overdue are **two different sentences** (`Waiting for review` / `Waiting for review (overdue)`), not one sentence in two colours.
|
|
56
|
-
- **Only scheduled reminders pulse.** A lapsed review wait does not animate, matching how dsh-gitea-dispatch draws its own session-row icon for that state: it stops the animation on purpose (its words: "stillness means no longer expecting"), and its `overdue` means only that CI stopped waiting, not that the review failed. A pulsing folder next to a still row icon would state the same fact twice. The red colour stays, same token as the publisher.
|
|
57
|
+
```bash
|
|
58
|
+
dsh plugin --profile web remove dsh-group-status
|
|
59
|
+
```
|
|
57
60
|
|
|
58
|
-
|
|
61
|
+
This package changes no file inside the published upstream package: it registers the same slot and disables the stock `ui-workspace` row in the profile patch. For the local `link:` install used while editing code, see [Development](#development).
|
|
59
62
|
|
|
60
|
-
|
|
63
|
+
---
|
|
61
64
|
|
|
62
|
-
|
|
63
|
-
|---|---|---|
|
|
64
|
-
| `showRunningInBadge` | `true` | Whether the folded badge shows the "running" spinning dot |
|
|
65
|
-
| `showPendingInBadge` | `true` | Whether the folded badge shows the "pending" yellow dot (approval / plan review / waiting for answer) |
|
|
66
|
-
| `showCompletedInBadge` | `true` | Whether the folded badge shows a green "completed" dot |
|
|
67
|
-
| `showHoverDetails` | `true` | Whether the hover card shows the aggregated status detail lines |
|
|
68
|
-
| `countThreshold` | `2` | The count is shown on the badge only when the total is >= this value (default 2, i.e. omits the count when it equals 1 — the dots already convey "something is happening"; set to 1 to always show) |
|
|
65
|
+
## Verify
|
|
69
66
|
|
|
70
|
-
|
|
67
|
+
1. Collapse a group that contains a running or pending session: the badge appears after the folder name.
|
|
68
|
+
2. Hover the folder row: the detail lines appear, with the same wording as the badge `aria-label`.
|
|
69
|
+
3. Expand the group: the badge disappears.
|
|
70
|
+
4. The browser console reports no errors.
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
---
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
## When the badge does not show
|
|
75
75
|
|
|
76
|
-
|
|
76
|
+
| Symptom | Cause |
|
|
77
|
+
|---|---|
|
|
78
|
+
| Nothing changed after install | `dsh web` was not restarted (the sidebar is replaced as a whole bundle) |
|
|
79
|
+
| The package was never loaded | The DSH kernel is outside `engines.dsh`, so the kernel answers `skipping profile bundle` (verified on `0.2.0-rc.2`) and the sidebar keeps stock behavior |
|
|
80
|
+
| The group does have running or pending sessions, but no badge while collapsed | All four counted tiers are 0 (pending, running, completed, external contributions). Blank and archived sessions are not counted |
|
|
81
|
+
| Dots but no number | The count is below `countThreshold` (default 2) |
|
|
82
|
+
| No scheduled-task or waiting-review glyph | The companion plugin is not installed, not enabled, or it turned that status source off itself (visibility of an external source belongs to its owner) |
|
|
77
83
|
|
|
78
84
|
---
|
|
79
85
|
|
|
80
|
-
##
|
|
86
|
+
## Reading the badge
|
|
81
87
|
|
|
82
|
-
|
|
83
|
-
- **Same source of truth as rows**: priority, colors and wording all reuse the row derivation and `StateDot`; blank and archived sessions are skipped.
|
|
84
|
-
- **Cross-plugin aggregation** (optional): scheduled tasks from dsh-later, waiting PR reviews from dsh-gitea-dispatch — works fine with neither installed.
|
|
85
|
-
- **Usable with zero config**: sensible defaults out of the box; 7 settings let you fine-tune which sources appear in the folded badge, hover details, and count display.
|
|
86
|
-
- **No stock files touched**: not a single file of the published `dsh-client-ui-workspace` is modified; all changes live in this repo's source, and the profile patch is two lines (add this package, disable the stock row).
|
|
87
|
-
- **Localized**: follows the DSH UI language (中文 / English) by reusing the stock locale keys. This package adds `status.waitingReview`, `status.scheduled`, a fallback `status.needsAttention` for facets that ship no wording, and the three waiting-review states `status.waitingReviewOverdue` / `status.waitingReviewImminent` / `status.waitingReviewLeft`.
|
|
88
|
+
This plugin draws three session state tiers:
|
|
88
89
|
|
|
89
|
-
|
|
90
|
+
| Icon | Shape | Meaning | Color source |
|
|
91
|
+
|---|---|---|---|
|
|
92
|
+
| <img src="docs/media/glyph-pending.svg" width="10" height="10" alt=""/> | Yellow dot | The group has a session awaiting approval, plan review, or an answer | `StateDot` `warning`, same as session rows |
|
|
93
|
+
| <img src="docs/media/glyph-running.svg" width="14" height="14" alt=""/> | Spinner | The group has a running session (including running subagents) | `StateDot` `ongoing` |
|
|
94
|
+
| <img src="docs/media/glyph-completed.svg" width="10" height="10" alt=""/> | Green dot | The group has a completed session that is still unread | `StateDot` `done`, same as session rows |
|
|
90
95
|
|
|
91
|
-
|
|
96
|
+
The icons are reconstructions: geometry follows `StateDot` (a 6px core inside a 10px slot, and a 14px ring with an arc of about 72 degrees), colors are sampled from the two real screenshots above, both taken in the dark theme. [scripts/make-badge-glyphs.mjs](scripts/make-badge-glyphs.mjs) generates them. In the UI the spinner keeps rotating (one turn per 1.5s), so a static image can only be one frame. The running UI is the authority on colors; this package keeps no color table of its own.
|
|
92
97
|
|
|
93
|
-
|
|
98
|
+
External status sources supply their own glyph and color tier. This plugin decides neither their shape nor whether they pulse, so those two glyphs are not reconstructed here: they belong to the plugins that own them.
|
|
94
99
|
|
|
95
|
-
|
|
100
|
+
- **Count** = pending + running (including running subagents) + completed + whatever each external source reports. Above 99 it shows `99+`; below `countThreshold` the number is omitted and only the dots are drawn.
|
|
101
|
+
- **Order**: pending, running, external sources, completed. The relative order among external sources comes from their own `order`. Hover details use the same order as the dots, one line per tier, for example `1 waiting for answer · 1 running`. The waiting-review line carries the PR number and remaining time, supplied by its owner.
|
|
102
|
+
- **Collapsed only**: no badge is drawn while a group is expanded. Nested groups aggregate the whole subtree, so a collapsed parent reports the sum over all descendant groups.
|
|
103
|
+
- **Accessibility**: the badge is `role="img"`, the `aria-label` and the hover `title` carry the same localized wording, and states such as "overdue" are distinguished by wording, not by color alone.
|
|
104
|
+
- **Pulse is per source**: whether an external source pulses is declared by that source. It never affects the whole badge, the count, or the host session state dot.
|
|
96
105
|
|
|
97
|
-
|
|
98
|
-
const gs = require('dsh-group-status/client')
|
|
99
|
-
const unregister = gs?.registerGroupStatusFacet?.({
|
|
100
|
-
protocol: gs.GROUP_STATUS_FACET_PROTOCOL_VERSION,
|
|
101
|
-
id: 'my-plugin.review', // '<package>.<state>'
|
|
102
|
-
subscribe: store.subscribe, // an external-store face, not a React hook
|
|
103
|
-
getSnapshot: store.getSnapshot,
|
|
104
|
-
fold: (snapshot, sessionIds, now) => ({ count, tone, pulse, data }),
|
|
105
|
-
merge, label, renderIcon, order, // all optional
|
|
106
|
-
})
|
|
107
|
-
ctx.effect(() => () => unregister?.(), 'my-plugin: group status facet')
|
|
108
|
-
```
|
|
106
|
+
---
|
|
109
107
|
|
|
110
|
-
|
|
111
|
-
- Icon and wording belong to the owner (`renderIcon` / `label`): what a state looks like, and whether a lapsed wait should sit still or pulse, is its knowledge. Previously this plugin inferred it from state names and ended up contradicting the owner, which draws `overdue` **statically** while the badge pulsed.
|
|
112
|
-
- A collapsed parent spans the whole subtree, so same-facet folds get merged again. That is why `fold` returns structured `data` rather than text: text cannot be merged. Without `merge` the default rule applies (counts add, the more urgent tone wins, `data` is dropped).
|
|
113
|
-
- When this plugin is absent or disabled `require` throws: catch it and carry on, your own features are unaffected.
|
|
114
|
-
- Same-id conflicts are settled **by origin, not by registration order** (the host does not order plugin `apply`): the owner always wins over a custodial (`legacy`) registrant.
|
|
108
|
+
## Settings
|
|
115
109
|
|
|
116
|
-
|
|
110
|
+
Sidebar **Plugins** → **dsh-group-status** (the config form on the bundle page):
|
|
117
111
|
|
|
118
|
-
|
|
112
|
+
| Field | Default | Description |
|
|
113
|
+
|---|---|---|
|
|
114
|
+
| `showRunningInBadge` | `true` | Whether the collapsed badge shows the running spinner |
|
|
115
|
+
| `showPendingInBadge` | `true` | Whether it shows the yellow dot for approval / plan review / waiting for answer |
|
|
116
|
+
| `showCompletedInBadge` | `true` | Whether it shows the green completed dot |
|
|
117
|
+
| `showHoverDetails` | `true` | Whether the hover card shows the aggregated detail lines |
|
|
118
|
+
| `countThreshold` | `2` | Show the number only when the count reaches this value; set 1 to always show it |
|
|
119
119
|
|
|
120
|
-
|
|
120
|
+
Turning a tier off removes it from the collapsed row entirely: no dot, no contribution to the count, no hover line, and it no longer keeps the badge visible. The state dot on a session row is unaffected, because that is row-level state. With `showHoverDetails` off, the hover card shows only the title, path, and creation time.
|
|
121
121
|
|
|
122
|
-
|
|
123
|
-
|---|---|
|
|
124
|
-
| `dsh-gitea-dispatch.waiting-review` | registered by dsh-gitea-dispatch itself (its issue #47) |
|
|
125
|
-
| `dsh-later.schedule` | registered by dsh-later itself (its issue #36) |
|
|
122
|
+
Saving applies immediately. The Host writes the values into the `config` of the `dsh-group-status` entry in the profile patch, so they survive a reload. When the settings cannot be read (for example the Host exposes no settings service), the defaults apply: unread is not the same as turned off. Unknown fields left over in a profile are not read, so their effect equals the default.
|
|
126
123
|
|
|
127
|
-
|
|
124
|
+
External sources deliberately have no switch on this page: this plugin knows no specific source, so its config surface must not carry another plugin's domain names or icon shapes either. To silence a source, use that plugin's own settings card; when it turns the source off it stops registering, and the badge loses that item. See "Who owns visibility" in [`docs/facet-protocol.md`](docs/facet-protocol.md) (Chinese only).
|
|
128
125
|
|
|
129
|
-
> ⚠️ Cross-plugin **value imports** do not work in this project (measured: `Could not resolve "dsh-group-status"`: a client bundle is a self-contained closure factory). Owners therefore use only the runtime symbols from `require('dsh-group-status/client')` and never `import` this package's types; copying the structural declarations from the protocol doc is enough.
|
|
130
126
|
---
|
|
131
127
|
|
|
132
|
-
##
|
|
133
|
-
|
|
134
|
-
### Install into DSH
|
|
135
|
-
|
|
136
|
-
**npm install (recommended, pre-built, no auth required):**
|
|
128
|
+
## Companion plugins (optional)
|
|
137
129
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
130
|
+
| Plugin | What the collapsed badge gains | Availability |
|
|
131
|
+
|---|---|---|
|
|
132
|
+
| [dsh-later](https://github.com/dsh-plugin-collection/dsh-later) | Scheduled tasks in the group (clock glyph; color tier and wording owned by dsh-later) | Public npm |
|
|
133
|
+
| `dsh-gitea-dispatch` | PRs awaiting review in the group (hourglass glyph; color tier and wording owned by dsh-gitea-dispatch) | Not published to public npm, see its own repository |
|
|
142
134
|
|
|
143
|
-
|
|
135
|
+
The plugin works normally with neither installed. The waiting-review data comes entirely from the facet that `dsh-gitea-dispatch` registers; this plugin maintains no wording or color tier for it.
|
|
144
136
|
|
|
145
|
-
|
|
146
|
-
dsh plugin --profile web add "github:dsh-plugin-collection/dsh-group-status"
|
|
147
|
-
# restart dsh web
|
|
148
|
-
```
|
|
137
|
+
---
|
|
149
138
|
|
|
150
|
-
|
|
139
|
+
## Compatibility
|
|
151
140
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
141
|
+
| Item | Value |
|
|
142
|
+
|---|---|
|
|
143
|
+
| DSH kernel | `engines.dsh: >=0.2.1-rc.2 <0.3.0-0` |
|
|
144
|
+
| Verified generations | `0.2.1-rc.2` / `rc.3` / `rc.4` (gating, cold boot assembly, type check and the full suite pass on all three; real GUI acceptance was additionally done on rc.2) |
|
|
145
|
+
| Peer dependencies | `@deepseek-ai/cordis ~4.0.5` plus 12 `@deepseek-ai/dsh-*` packages (range `^0.2.1-rc.2`) |
|
|
146
|
+
| Upstream baseline | `@deepseek-ai/dsh-client-ui-workspace 0.2.1-rc.2`, source taken from the published package into this repo's `src/` |
|
|
156
147
|
|
|
157
|
-
|
|
158
|
-
# restart dsh web
|
|
159
|
-
```
|
|
148
|
+
On `rc.4` the **behavior** has drifted from the baseline (blank session reuse and draft initialization semantics). This package's fork still follows the baseline generation, so those improvements do not reach users: loading cleanly is not the same as behaving identically. The per-item differences and the triggers to act on them live in [docs/upgrading.md](docs/upgrading.md), section "上游代次跟踪".
|
|
160
149
|
|
|
161
|
-
|
|
150
|
+
The 12 peer entries are not metadata. Kernels that do not read `engines.dsh` decide compatibility from the peer ranges alone, and a missing entry lets an old kernel load this package and fail the whole page. The mechanism is recorded in [docs/upgrading.md](docs/upgrading.md), section "兼容声明为什么长这样".
|
|
162
151
|
|
|
163
|
-
|
|
152
|
+
---
|
|
164
153
|
|
|
165
|
-
|
|
166
|
-
2. Hover the folder row → the detail lines appear (matching the badge's wording);
|
|
167
|
-
3. Expand the group → the badge disappears and child rows show their own statuses;
|
|
168
|
-
4. No errors in the browser console.
|
|
154
|
+
## For plugin authors: registering a status source
|
|
169
155
|
|
|
170
|
-
|
|
156
|
+
A collapsed group badge can show state owned by another plugin, and the direction is inverted: **the owner registers its facts in**, while this plugin's aggregation and render paths know no specific source.
|
|
171
157
|
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
|
|
158
|
+
```js
|
|
159
|
+
const gs = require('dsh-group-status/client')
|
|
160
|
+
const unregister = gs?.registerGroupStatusFacet?.({
|
|
161
|
+
protocol: gs.GROUP_STATUS_FACET_PROTOCOL_VERSION,
|
|
162
|
+
id: 'my-plugin.review', // '<package>.<state>'
|
|
163
|
+
subscribe: store.subscribe, // an external store surface, not a React hook
|
|
164
|
+
getSnapshot: store.getSnapshot,
|
|
165
|
+
fold: (snapshot, sessionIds, now) => ({ count, tone, pulse, data }),
|
|
166
|
+
label, renderIcon, order, // optional: wording, glyph and order belong to the provider
|
|
167
|
+
})
|
|
168
|
+
ctx.effect(() => () => unregister?.(), 'my-plugin: group status facet')
|
|
175
169
|
```
|
|
176
170
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
| DSH core | declares `>=0.2.1-rc.2 <0.3.0-0`; verified on `0.2.1-rc.2` / `rc.3` / `rc.4` |
|
|
184
|
-
| peer dependencies | `@deepseek-ai/cordis ~4.0.5` plus 12 `@deepseek-ai/dsh-*` at `^0.2.1-rc.2` |
|
|
185
|
-
| Upstream base | `@deepseek-ai/dsh-client-ui-workspace 0.2.1-rc.2` (source vendored into `src/`) |
|
|
186
|
-
| Install shape | fork override: same slots registered, stock row disabled via `cordis.patch.yml` |
|
|
187
|
-
| Optional partners | dsh-later (schedule summary), dsh-gitea-dispatch (waiting-review summary) |
|
|
171
|
+
- The five required members (`protocol` / `id` / `subscribe` / `getSnapshot` / `fold`) already render: `N Needs attention` plus a generic dot colored by tone. Your internal id is never read out to the user.
|
|
172
|
+
- Glyph and wording belong to the provider: what the state looks like, and whether an overdue one should stay still or pulse, is the provider's knowledge.
|
|
173
|
+
- `fold` returns structured `data`, not text, because a collapsed parent group covers the whole subtree and same-named folds have to be merged again. Text cannot be merged.
|
|
174
|
+
- When this plugin is not installed or not enabled, `require` throws. Catching that error is enough.
|
|
175
|
+
- Same-id conflicts resolve by origin, independent of registration order: the state owner always wins over a stand-in registrant.
|
|
176
|
+
- Cross-plugin **value imports** do not work in this project (the client bundle is a self-contained closure factory), so providers use only the runtime symbols from `require('dsh-group-status/client')` and never import this package's types.
|
|
188
177
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
Every upstream generation requires a manual rebase — see the [upgrade runbook](./docs/upgrading.md). If upstream renames a slot, changes a component signature or the context contract, this package will not follow on its own.
|
|
178
|
+
The full contract, every `FacetFold` field, the default merge, lifecycle and degradation, and the version rules are in [docs/facet-protocol.md](docs/facet-protocol.md) (Chinese only), including why the surface is `subscribe` / `getSnapshot` rather than a React hook.
|
|
192
179
|
|
|
193
180
|
---
|
|
194
181
|
|
|
@@ -196,34 +183,50 @@ Every upstream generation requires a manual rebase — see the [upgrade runbook]
|
|
|
196
183
|
|
|
197
184
|
```sh
|
|
198
185
|
pnpm install
|
|
199
|
-
pnpm build # tsc
|
|
186
|
+
pnpm build # tsc type check + tsdown bundle → lib/
|
|
200
187
|
pnpm watch # rebuild on src/ changes (a dsh web restart is still required)
|
|
201
|
-
pnpm test #
|
|
202
|
-
pnpm test:spec #
|
|
188
|
+
pnpm test # test:node (node --test, 50 cases) + test:spec (vitest + jsdom, 191 cases)
|
|
189
|
+
pnpm test:spec # spec suite only
|
|
190
|
+
pnpm check-upstream # upstream generation tracking (add --latest for the highest published version)
|
|
203
191
|
```
|
|
204
192
|
|
|
205
|
-
|
|
193
|
+
### Local install while developing
|
|
194
|
+
|
|
195
|
+
You do not need to publish a package to test changes; mount this checkout into the local profile with `link:`:
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
git clone https://github.com/dsh-plugin-collection/dsh-group-status.git
|
|
199
|
+
cd dsh-group-status
|
|
200
|
+
pnpm install && pnpm build
|
|
201
|
+
dsh plugin --profile web add "link:$PWD"
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
`pnpm watch` rebuilds on `src/` changes, and each rebuild still requires a `dsh web` restart.
|
|
205
|
+
|
|
206
|
+
Besides the vendored upstream copies, `tests/` holds this repository's own cases for the aggregation: counting, mutual exclusion among pending kinds, subagents, blank and archived skipping, external source registration and unregistration, hover wording. 9 upstream specs only run inside the DSH monorepo; the reasons are listed one by one at the top of [vitest.config.ts](vitest.config.ts).
|
|
206
207
|
|
|
207
|
-
|
|
208
|
+
The part of the host contract that can **fail silently** (the pending-kind set this plugin accepts, and the two state facts read from the host) is compared against the locked host implementation by [tests/host-pending-kinds.node.test.mjs](tests/host-pending-kinds.node.test.mjs), so a host change turns it red. README facts that drift with the code (version badge, setting fields and defaults, test case counts, forbidden wording) are guarded by [tests/readme-facts.node.test.mjs](tests/readme-facts.node.test.mjs).
|
|
208
209
|
|
|
209
210
|
---
|
|
210
211
|
|
|
211
212
|
## Known limitations
|
|
212
213
|
|
|
213
|
-
- **
|
|
214
|
-
- **One
|
|
215
|
-
- **
|
|
216
|
-
- **The count is coarser than the details**:
|
|
217
|
-
- **
|
|
214
|
+
- **An upstream generation change needs a manual rebase**: this package vendors upstream source and does not use a stable public API. When the host changes a slot name, component signature, or context contract, follow [docs/upgrading.md](docs/upgrading.md).
|
|
215
|
+
- **One more full measurement pass per state change**: the aggregate count shares its derivation with the expanded state, so an expanded group must be measured too, because its ancestors use its numbers. On very large groups (hundreds of sessions) that pass costs one more traversal plus an upward roll, guarded by the performance cases in `tests/group-status.client.spec.ts`.
|
|
216
|
+
- **External glyphs depend entirely on their providers**: a missing companion plugin simply means one fewer glyph; it never affects the core badge. When a provider ships no wording, the line falls back to the generic "needs attention".
|
|
217
|
+
- **The count is coarser than the details**: an external source contributes the number it reports, and this plugin does not redefine another source's counting basis.
|
|
218
|
+
- **Sidebar collapsed state only**: neither the session state machine nor the row-level badge rules change.
|
|
219
|
+
- **Countdown precision is one minute**: the badge re-renders only when a provider's store notifies, so a second-level readout would sit stale on an old value.
|
|
218
220
|
|
|
219
221
|
---
|
|
220
222
|
|
|
221
|
-
##
|
|
223
|
+
## Documentation
|
|
222
224
|
|
|
223
|
-
|
|
225
|
+
- [docs/facet-protocol.md](docs/facet-protocol.md): the cross-plugin status source protocol (required reading for providers)
|
|
226
|
+
- [docs/upgrading.md](docs/upgrading.md): upstream baseline, local change list, rebase and verification, generation tracking, why the compatibility declaration looks like this
|
|
227
|
+
- [src/client/cross-plugin-summary.ts](src/client/cross-plugin-summary.ts): the provider-side template, with its design notes in the file header
|
|
224
228
|
|
|
225
|
-
|
|
226
|
-
- [Cross-plugin summary template](./src/client/cross-plugin-summary.ts) — the provider-side skeleton itself; its header is the design note and carries the measured "copy, do not import" evidence
|
|
229
|
+
Both documents are currently Chinese only.
|
|
227
230
|
|
|
228
231
|
## License
|
|
229
232
|
|