dsh-group-status 0.4.0 → 0.5.0
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 +57 -0
- package/README.en.md +6 -4
- package/README.md +8 -4
- package/lib/client.js +172 -98
- package/lib/client.js.map +1 -1
- package/lib/index.js +7 -4
- package/lib/types/client/BadgeSettingsCard.d.ts.map +1 -1
- package/lib/types/client/BadgeSettingsCard.js +6 -6
- package/lib/types/client/BadgeSettingsCard.js.map +1 -1
- package/lib/types/client/badge-field.d.ts +33 -10
- package/lib/types/client/badge-field.d.ts.map +1 -1
- package/lib/types/client/badge-field.js +35 -16
- package/lib/types/client/badge-field.js.map +1 -1
- package/lib/types/client/badge-labels.d.ts +3 -3
- package/lib/types/client/badge-labels.js +3 -3
- package/lib/types/client/badge-settings.d.ts +0 -25
- package/lib/types/client/badge-settings.d.ts.map +1 -1
- package/lib/types/client/badge-settings.js +0 -18
- package/lib/types/client/badge-settings.js.map +1 -1
- package/lib/types/client/facets.d.ts +39 -5
- package/lib/types/client/facets.d.ts.map +1 -1
- package/lib/types/client/facets.js +48 -4
- package/lib/types/client/facets.js.map +1 -1
- package/lib/types/client/locales.d.ts +0 -8
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/client/locales.js +0 -8
- package/lib/types/client/locales.js.map +1 -1
- package/lib/types/client/rows/GroupBadge.d.ts +4 -4
- package/lib/types/client/rows/GroupBadge.d.ts.map +1 -1
- package/lib/types/client/rows/GroupBadge.js +10 -7
- package/lib/types/client/rows/GroupBadge.js.map +1 -1
- package/lib/types/client/rows/WorkspaceBrowser.d.ts.map +1 -1
- package/lib/types/client/rows/WorkspaceBrowser.js +12 -11
- package/lib/types/client/rows/WorkspaceBrowser.js.map +1 -1
- package/lib/types/client/tree.d.ts +16 -1
- package/lib/types/client/tree.d.ts.map +1 -1
- package/lib/types/client/tree.js +20 -8
- package/lib/types/client/tree.js.map +1 -1
- package/lib/types/client/use-registered-facets.d.ts +11 -0
- package/lib/types/client/use-registered-facets.d.ts.map +1 -0
- package/lib/types/client/use-registered-facets.js +48 -0
- package/lib/types/client/use-registered-facets.js.map +1 -0
- package/lib/types/host-contract.d.ts +57 -0
- package/lib/types/host-contract.d.ts.map +1 -0
- package/lib/types/host-contract.js +84 -0
- package/lib/types/host-contract.js.map +1 -0
- package/lib/types/index.d.ts +7 -10
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +7 -4
- package/lib/types/index.js.map +1 -1
- package/package.json +2 -1
- package/lib/types/client/facet-visibility.d.ts +0 -17
- package/lib/types/client/facet-visibility.d.ts.map +0 -1
- package/lib/types/client/facet-visibility.js +0 -18
- package/lib/types/client/facet-visibility.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,63 @@
|
|
|
6
6
|
|
|
7
7
|
## 未发布
|
|
8
8
|
|
|
9
|
+
## 0.5.0 — 2026-10-22
|
|
10
|
+
|
|
11
|
+
- **fix** 宿主契约漂移**从此有人看着了**:`pendingInteraction.kind` 是开放集合
|
|
12
|
+
(`SessionPendingInteractionMap` 靠声明合并扩展,任何宿主包都能贡献自己的 kind),而本仓库的
|
|
13
|
+
`src/client/tree.ts` 是宿主 workspace 投影的 fork。宿主新增一种 kind 时本插件**不会**自动跟上,
|
|
14
|
+
于是宿主侧栏与折叠徽标会**一起不显示**它 —— 两边口径一致所以不是"谁错了",但用户只会觉得
|
|
15
|
+
"这俩对不上"。而"宿主换了代"本来该由 `scripts/check-upstream.ts` 提醒,**那个脚本从来没有工作过**:
|
|
16
|
+
它比对的 `src/vendor/src` 目录早就不存在了(vendored 的上游源码直接摊在 `src/` 下),上游发布包里
|
|
17
|
+
也没有 `src/`(只有 `lib/`),于是它一跑就 `ENOENT: scandir 'src/vendor/src'`;而 `docs/upgrading.md`
|
|
18
|
+
还让人照着它 rebase —— 一条指着不存在目录的命令比没有更糟:它让人以为"没红就是没漂移"。
|
|
19
|
+
现在:同一份比对实现(`src/host-contract.ts`)被两处调用 —— `npm test` 里的
|
|
20
|
+
`tests/host-pending-kinds.node.test.mjs`(离线,读锁定版宿主的实现,CI 会跑)与
|
|
21
|
+
`pnpm check-upstream`(人看的;`--latest` 还能查 npm 上**已发布的最高版**,注意该包的 `latest`
|
|
22
|
+
标签是旧的、还指着 0.0.1-rc.1,不能直接用 `npm view <pkg> version`)。守卫覆盖三件事:我们认的
|
|
23
|
+
kind 集合必须与宿主一致、宿主不能把我们要读的两个状态事实改名、以及"守卫自己不是摆设"(拿真实
|
|
24
|
+
bundle 的改造副本当反例)。另加类型层一道:`Rows.tsx` 的 `assertNever` 让"新增 kind 却没给行内
|
|
25
|
+
表现"直接编译不过。
|
|
26
|
+
|
|
27
|
+
- **breaking** 删除设置项 `showScheduledInBadge` 与 `showWaitingReviewInBadge`:**外部来源的显隐不再由本插件管**。
|
|
28
|
+
这两个字段把别人家的域名(定时任务 / 等待评审)、来源名(dsh-later / dsh-gitea-dispatch)连图标形状
|
|
29
|
+
("时钟" / "沙漏")全都写死在**消费方**的 `Config`、设置卡片与文案里,与本插件「不认识任何具体来源」的
|
|
30
|
+
立身之本直接矛盾 —— facet 协议把适配方向翻正了,配置面却没跟着翻。而且它**已经是错的**:dsh-gitea-dispatch
|
|
31
|
+
自其 #60 起让徽标跟随自己的 `waitingIconStyle`,三档里两档不是沙漏,卡片却仍在承诺"沙漏";对方没装时,
|
|
32
|
+
那句"关闭后不再画"更是空话。
|
|
33
|
+
现在的规则只有一条:**登记即显示,不注册即不显示**。要给用户一个"关掉它"的开关,请加在**你自己的**
|
|
34
|
+
配置卡片里。协议成员 `settingKey` 同时废弃(v1 仍接受、不报错,但本插件不再读取)。
|
|
35
|
+
**升级影响**:profile 里残留的这两个旧值不再被读取,等同回到默认「显示」(默认全开,最坏情况是某个来源
|
|
36
|
+
重新出现,不会留下坏数据)。曾考虑的另一种收口(消费方保留 `disabledFacets: string[]` + 卡片遍历登记面)
|
|
37
|
+
只是把来源名从文案换成 id,机制仍长在消费方身上,故未采用;取舍过程写进 `docs/facet-protocol.md`。
|
|
38
|
+
- **refactor** 徽标设置卡片的开关顺序改为**与徽标画点一致**(待审批 → 进行中 → 已完成)。此前是
|
|
39
|
+
进行中 → 待审批 → 已完成,而徽标与悬停明细都是待审批在前;用户的操作场景恰是"我看到徽标第 N 个图标,
|
|
40
|
+
想关掉它"。同一族毛病 #25① 已在点行与明细之间修过一次,卡片是当时漏掉的第三个面。单一事实来源是
|
|
41
|
+
`badge-field.ts` 的 `ALL_BADGE_FIELDS`,并由 `tests/badge-settings-card.client.spec.tsx` 钉住
|
|
42
|
+
(含"卡片文案里不得出现任何提供方名字与形状词")。
|
|
43
|
+
- **refactor** 删除 `facetVisibleBySettings` 与 `facet-visibility.ts`;`useVisibleFacets` 更名
|
|
44
|
+
`useRegisteredFacets`(它不再筛任何东西,只负责"订阅 + 读登记面",见下一条目为何必须收进一个 hook)。
|
|
45
|
+
|
|
46
|
+
- **fix** 提供方**晚于首渲染**注册的状态源永远进不了折叠徽标:`WorkspaceBrowser` 订阅了
|
|
47
|
+
facet 存储,却把 `useSyncExternalStore` 的返回值丢掉,`useMemo` 的依赖里只有设置项——
|
|
48
|
+
于是登记面变化只换来一次重渲染,渲染算的仍是**上一次**的登记面。表现是「徽标少一家、
|
|
49
|
+
无任何报错、刷新页面就好了」,而刷新只是碰巧让注册赶在了首渲染之前。宿主不保证插件
|
|
50
|
+
`apply` 与侧栏挂载的先后,所以这条按加载时序随机命中。修法是把订阅 + 读表 + 按设置筛
|
|
51
|
+
收进 `use-visible-facets.ts` 一个 hook,让"只用信号、不用值"在结构上写不出来。这条接缝
|
|
52
|
+
此前测不到(能渲染整条路径的 `tests/workspace-browser.client.spec.tsx` 在本仓库是跳过的),
|
|
53
|
+
新增 `tests/use-visible-facets.client.spec.tsx` 5 例覆盖,并用变异测试验过非空洞性:把依赖
|
|
54
|
+
里的版本号拿掉,「晚到的注册」与「晚到的注销」两条会红。
|
|
55
|
+
- **fix** 登记面从**模块级**单例改为挂在 `globalThis` 上的**进程级**共享表。宿主热替换只
|
|
56
|
+
换代被替换的那个模块(`dsh-client-modules` 的 `invalidate()` 不级联到依赖方,也不重跑
|
|
57
|
+
别人的 `apply`),于是本插件一旦被换成新实例就持有一张**空表**:提供方那一次性登记留在
|
|
58
|
+
被丢弃的旧表上,徽标从此少一家,且只有刷新页面才好。开发环境用 `link:` 装插件、反复
|
|
59
|
+
重建 `lib/`,这条几乎必然发生。现在换代只是"再拿一次同一张表";`registerGroupStatusFacet`
|
|
60
|
+
也改为**现取**当前那张表,而不是用模块加载时抄下的引用。那把全局键同时是现场诊断入口:
|
|
61
|
+
`globalThis.__dshGroupStatusFacetRegistry__.list()` 一眼看出注册到底落没落,判据写进
|
|
62
|
+
`docs/facet-protocol.md` 新增的「登记面的生命周期」一节。
|
|
63
|
+
- **test** `tests/facets.node.test.mjs` 补 3 例:共享表重复取不新建、模块级 `registry` 常量
|
|
64
|
+
就是那张共享表、换代后新注册只落新表不落被丢弃的旧表。
|
|
65
|
+
|
|
9
66
|
## 0.4.0 — 2026-10-20
|
|
10
67
|
|
|
11
68
|
- **upgrade** 依赖基线从 DSH `0.2.0-rc.2` 升到 `0.2.1-rc.2`:Cordis peer 改为 `~4.0.5`,Schemastery 与全部 `@deepseek-ai/dsh-*` 开发依赖升到对应版本;客户端 `dsh.client.inject` 加入 `@deepseek-ai/dsh-api-remote-access`。`tsc`、`tsdown`、27 个 Node 用例与 165 个 Vitest 用例全绿。
|
package/README.en.md
CHANGED
|
@@ -64,12 +64,14 @@ Rules:
|
|
|
64
64
|
| `showRunningInBadge` | `true` | Whether the folded badge shows the "running" spinning dot |
|
|
65
65
|
| `showPendingInBadge` | `true` | Whether the folded badge shows the "pending" yellow dot (approval / plan review / waiting for answer) |
|
|
66
66
|
| `showCompletedInBadge` | `true` | Whether the folded badge shows a green "completed" dot |
|
|
67
|
-
| `showScheduledInBadge` | `true` | Whether the folded badge shows the "scheduled" clock icon (data from dsh-later) |
|
|
68
|
-
| `showWaitingReviewInBadge` | `true` | Whether the folded badge shows the "waiting for review" hourglass icon (data from dsh-gitea-dispatch) |
|
|
69
67
|
| `showHoverDetails` | `true` | Whether the hover card shows the aggregated status detail lines |
|
|
70
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) |
|
|
71
69
|
|
|
72
|
-
Switching a
|
|
70
|
+
Switching a tier off takes it out of the folded row's aggregate entirely — no dot/icon, no contribution to the badge count, no hover detail line, and it no longer keeps the badge alive. **The state dot on a session row itself is unaffected**: that is row-level state, not a folder hint. With `showHoverDetails` off, the hover card shows only the title, path, and creation time.
|
|
71
|
+
|
|
72
|
+
**External sources (e.g. "waiting for review", "scheduled") have no switch on this page, on purpose.** This plugin knows no concrete source, so its config face 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 is off, it simply does not register its facet, and the badge loses that glyph. See "Who owns visibility" in [`docs/facet-protocol.md`](docs/facet-protocol.md).
|
|
73
|
+
|
|
74
|
+
> ⚠️ As of this change the `showScheduledInBadge` / `showWaitingReviewInBadge` fields are removed (they hard-coded names and icon shapes on behalf of dsh-later / dsh-gitea-dispatch). Values left in the profile are no longer read and behave as the default "show".
|
|
73
75
|
|
|
74
76
|
Saving applies it live, with no refresh; the Host writes it into the profile patch's `dsh-group-status` entry `config`, so it survives a page reload. When the settings face cannot be read (e.g. the Host serves no settings service), it falls back to the default "show", matching the schema default — failing to read a config is not the user turning it off.
|
|
75
77
|
|
|
@@ -100,7 +102,7 @@ const unregister = gs?.registerGroupStatusFacet?.({
|
|
|
100
102
|
subscribe: store.subscribe, // an external-store face, not a React hook
|
|
101
103
|
getSnapshot: store.getSnapshot,
|
|
102
104
|
fold: (snapshot, sessionIds, now) => ({ count, tone, pulse, data }),
|
|
103
|
-
merge, label, renderIcon,
|
|
105
|
+
merge, label, renderIcon, order, // all optional
|
|
104
106
|
})
|
|
105
107
|
ctx.effect(() => () => unregister?.(), 'my-plugin: group status facet')
|
|
106
108
|
```
|
package/README.md
CHANGED
|
@@ -66,12 +66,14 @@
|
|
|
66
66
|
| `showRunningInBadge` | `true` | 折叠徽标是否显示「进行中」转圈 |
|
|
67
67
|
| `showPendingInBadge` | `true` | 折叠徽标是否显示「待审批 / 待评审 / 待回答」黄点 |
|
|
68
68
|
| `showCompletedInBadge` | `true` | 折叠徽标是否显示「已完成」绿点 |
|
|
69
|
-
| `showScheduledInBadge` | `true` | 折叠徽标是否显示「定时任务」时钟图标(数据来自 dsh-later) |
|
|
70
|
-
| `showWaitingReviewInBadge` | `true` | 折叠徽标是否显示「等待评审」沙漏图标(数据来自 dsh-gitea-dispatch) |
|
|
71
69
|
| `showHoverDetails` | `true` | 悬停卡是否显示聚合状态明细行 |
|
|
72
70
|
| `countThreshold` | `2` | 徽标数字显示阈值:数量 >= 此值时才显示数字(默认 2,即 count=1 时省略——点已表达"有东西在发生";设为 1 则始终显示) |
|
|
73
71
|
|
|
74
|
-
|
|
72
|
+
按状态关掉后,对应档位完全退出折叠行的聚合提示——不画点/图标、不计入徽标数字、不进悬停明细、不参与「是否显示徽标」的判断。**会话行自身的状态点不受影响**:那是行级状态,不是分组提示。`showHoverDetails` 关闭后,悬停卡只显示标题、路径与创建时间。
|
|
73
|
+
|
|
74
|
+
**外部来源(如「等待评审」「定时任务」)在这一页没有开关**,这是有意的:本插件不认识任何具体来源,所以配置面里也不该有别人家的域名与图标形状。要关某个来源,去**那个插件自己**的设置卡片;它关掉时不注册 facet,徽标自然就没有那一格。详见 [`docs/facet-protocol.md`](docs/facet-protocol.md) 的「显隐归谁」。
|
|
75
|
+
|
|
76
|
+
> ⚠️ 本次起 `showScheduledInBadge` / `showWaitingReviewInBadge` 两个字段已删除(它们曾替 dsh-later / dsh-gitea-dispatch 写死名字与图标形状)。profile 里残留的旧值不再被读取,等同回到默认「显示」。
|
|
75
77
|
|
|
76
78
|
点「保存」后即时生效,无需刷新;设置由宿主写进 profile patch 的 `dsh-group-status` 条目 `config`,刷新页面后仍在。设置面读不到时(例如宿主未提供设置服务)回落为默认「显示」,与 schema 默认值同源——读不到配置不等于用户关掉了。
|
|
77
79
|
|
|
@@ -102,7 +104,7 @@ const unregister = gs?.registerGroupStatusFacet?.({
|
|
|
102
104
|
subscribe: store.subscribe, // 外部存储面,不是 React hook
|
|
103
105
|
getSnapshot: store.getSnapshot,
|
|
104
106
|
fold: (snapshot, sessionIds, now) => ({ count, tone, pulse, data }),
|
|
105
|
-
merge, label, renderIcon,
|
|
107
|
+
merge, label, renderIcon, order, // 全部可选
|
|
106
108
|
})
|
|
107
109
|
ctx.effect(() => () => unregister?.(), 'my-plugin: group status facet')
|
|
108
110
|
```
|
|
@@ -188,6 +190,8 @@ dsh plugin --profile web remove dsh-group-status
|
|
|
188
190
|
|
|
189
191
|
上游一换代就得按[升级手册](./docs/upgrading.md) rebase 一次;上游改槽位名、组件签名或上下文契约时,本包不会自动跟上。
|
|
190
192
|
|
|
193
|
+
其中**会静默失效**的那部分(我们认的待处理 kind 集合、我们从宿主读的两个状态事实)有守卫兜着:`tests/host-pending-kinds.node.test.mjs` 直接读锁定版宿主的实现来比对,宿主一改就红;人看的版本是 `pnpm check-upstream`(加 `--latest` 还能查 npm 上已发布的最高版)。
|
|
194
|
+
|
|
191
195
|
---
|
|
192
196
|
|
|
193
197
|
## 开发
|
package/lib/client.js
CHANGED
|
@@ -211,30 +211,17 @@ window.__ModuleLoader__.load({
|
|
|
211
211
|
*/
|
|
212
212
|
/** Loader 条目 id —— 设置页的寻址键,也是宿主 `describe()` 的 ns。 */
|
|
213
213
|
const ENTRY_ID = "dsh-group-status";
|
|
214
|
-
/**
|
|
215
|
-
* 一个 facet 是否被设置关掉。
|
|
216
|
-
*
|
|
217
|
-
* - 没有 `settingKey` → 始终参与(缺省是"显示",与其余开关的默认值同源)。
|
|
218
|
-
* - 声明了但不是布尔开关键 → 同样按显示处理:拼错的键不该让一个状态整块消失。
|
|
219
|
-
*/
|
|
220
|
-
function facetVisibleBySettings(settings, settingKey) {
|
|
221
|
-
if (settingKey === void 0) return true;
|
|
222
|
-
const value = settings[settingKey];
|
|
223
|
-
return typeof value === "boolean" ? value : true;
|
|
224
|
-
}
|
|
225
214
|
/** 默认值:与 `Config` 各字段的 schema 默认同源(全部显示,数字阈值 2 即 count=1 时省略)。 */
|
|
226
215
|
const DEFAULT_BADGE_SETTINGS = Object.freeze({
|
|
227
216
|
showCompletedInBadge: true,
|
|
228
217
|
showRunningInBadge: true,
|
|
229
218
|
showPendingInBadge: true,
|
|
230
|
-
showScheduledInBadge: true,
|
|
231
|
-
showWaitingReviewInBadge: true,
|
|
232
219
|
showHoverDetails: true,
|
|
233
220
|
countThreshold: 2
|
|
234
221
|
});
|
|
235
222
|
/** 两个设置对象是否逐字段相等(用于发布前比较,避免无谓通知)。 */
|
|
236
223
|
function settingsEqual(a, b) {
|
|
237
|
-
return a.showCompletedInBadge === b.showCompletedInBadge && a.showRunningInBadge === b.showRunningInBadge && a.showPendingInBadge === b.showPendingInBadge && a.
|
|
224
|
+
return a.showCompletedInBadge === b.showCompletedInBadge && a.showRunningInBadge === b.showRunningInBadge && a.showPendingInBadge === b.showPendingInBadge && a.showHoverDetails === b.showHoverDetails && a.countThreshold === b.countThreshold;
|
|
238
225
|
}
|
|
239
226
|
/** 从原始快照派生:只有**显式 false** 才隐藏,缺失/非法一律显示(countThreshold 默认 2)。 */
|
|
240
227
|
function resolveFromSnapshot(snap) {
|
|
@@ -253,8 +240,6 @@ window.__ModuleLoader__.load({
|
|
|
253
240
|
showCompletedInBadge: getBool("showCompletedInBadge", true),
|
|
254
241
|
showRunningInBadge: getBool("showRunningInBadge", true),
|
|
255
242
|
showPendingInBadge: getBool("showPendingInBadge", true),
|
|
256
|
-
showScheduledInBadge: getBool("showScheduledInBadge", true),
|
|
257
|
-
showWaitingReviewInBadge: getBool("showWaitingReviewInBadge", true),
|
|
258
243
|
showHoverDetails: getBool("showHoverDetails", true),
|
|
259
244
|
countThreshold: getNumber("countThreshold", 2)
|
|
260
245
|
};
|
|
@@ -434,12 +419,52 @@ window.__ModuleLoader__.load({
|
|
|
434
419
|
};
|
|
435
420
|
}
|
|
436
421
|
/**
|
|
437
|
-
*
|
|
422
|
+
* 挂在 `globalThis` 上的登记表面的键名。
|
|
423
|
+
*
|
|
424
|
+
* 它同时是**现场诊断入口**:宿主里可以直接
|
|
425
|
+
* `globalThis.__dshGroupStatusFacetRegistry__.list().map(e => e.facet.id)` 读出"此刻到底
|
|
426
|
+
* 有哪些状态源登记上了"——「我注册了为什么没显示」不该只能靠猜(协议文档点名的那类
|
|
427
|
+
* 不可诊断失败)。
|
|
428
|
+
*/
|
|
429
|
+
const SHARED_REGISTRY_KEY = "__dshGroupStatusFacetRegistry__";
|
|
430
|
+
/**
|
|
431
|
+
* 取(并首次创建)**进程级**共享的登记表面。
|
|
432
|
+
*
|
|
433
|
+
* ## 为什么不能是模块级
|
|
434
|
+
*
|
|
435
|
+
* 提供方把 facet 注册进来是一次性的:它在自己的 `apply` 里 `require` 本插件的 client
|
|
436
|
+
* 入口、登记完就把注销函数挂在 effect 上。而宿主的热替换(HMR、`reload(id, rev)`)
|
|
437
|
+
* **只换代被替换的那个模块**——`dsh-client-modules` 的 `invalidate()` 只删自己那一行的
|
|
438
|
+
* factory 与 loadCache,不级联到"谁 require 过它"(依赖方不会重跑 apply)。
|
|
439
|
+
*
|
|
440
|
+
* 于是模块级单例在这里必然失效:本插件被换成新实例 → 新实例建一张**空表** → 提供方
|
|
441
|
+
* 那份注册留在被丢弃的旧表上 → 徽标从此少一家,且**只有刷新页面才好**。开发环境天天
|
|
442
|
+
* 重建 `lib/`,这条几乎必然发生。
|
|
443
|
+
*
|
|
444
|
+
* 挂到 `globalThis` 上之后,换代只是"再拿一次同一张表":注册跨换代存活,`facetStore()`
|
|
445
|
+
* 在新实例里 `rewire()` 时照样订阅到那些来源。提供方被换代时按同 id 覆盖登记(见
|
|
446
|
+
* {@link FacetRegistry.register} 的来源决胜),不会重复计数。
|
|
447
|
+
*
|
|
448
|
+
* @returns 全进程唯一的登记表面。
|
|
449
|
+
*/
|
|
450
|
+
function sharedFacetRegistry() {
|
|
451
|
+
const host = globalThis;
|
|
452
|
+
const existing = host[SHARED_REGISTRY_KEY];
|
|
453
|
+
if (existing !== void 0) return existing;
|
|
454
|
+
const created = createFacetRegistry();
|
|
455
|
+
host[SHARED_REGISTRY_KEY] = created;
|
|
456
|
+
return created;
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* 生产用的单例登记表面。
|
|
438
460
|
*
|
|
439
461
|
* 与 {@link createFacetRegistry} 分开,是为了让测试能对着一张干净的表断言协议行为,
|
|
440
462
|
* 而不会被别的用例或别的插件登记的 facet 污染。
|
|
463
|
+
*
|
|
464
|
+
* ⚠️ 它只是 {@link sharedFacetRegistry} 在**本模块首次加载时**取到的那份引用;跨模块实例
|
|
465
|
+
* 存活的是 globalThis 上那一张,所以运行期一律经 {@link sharedFacetRegistry} 现取。
|
|
441
466
|
*/
|
|
442
|
-
const registry =
|
|
467
|
+
const registry = sharedFacetRegistry();
|
|
443
468
|
/**
|
|
444
469
|
* 本插件 client 入口对外的登记函数(provider 侧唯一需要认识的符号)。
|
|
445
470
|
*
|
|
@@ -448,13 +473,14 @@ window.__ModuleLoader__.load({
|
|
|
448
473
|
* 返回值形状保持稳定,provider 的 dispose 路径不必区分成败。
|
|
449
474
|
*/
|
|
450
475
|
function registerGroupStatusFacet(facet) {
|
|
451
|
-
const
|
|
476
|
+
const target = sharedFacetRegistry();
|
|
477
|
+
const result = target.register(facet);
|
|
452
478
|
if (!result.ok) {
|
|
453
479
|
if (!(result.reason === "superseded" && facetOrigin(facet) === "legacy")) reportRejection(result);
|
|
454
480
|
return () => void 0;
|
|
455
481
|
}
|
|
456
482
|
return () => {
|
|
457
|
-
|
|
483
|
+
target.remove(result.id, facet);
|
|
458
484
|
};
|
|
459
485
|
}
|
|
460
486
|
/**
|
|
@@ -575,19 +601,39 @@ window.__ModuleLoader__.load({
|
|
|
575
601
|
}
|
|
576
602
|
//#endregion
|
|
577
603
|
//#region src/client/badge-field.ts
|
|
578
|
-
/**
|
|
604
|
+
/**
|
|
605
|
+
* 每个开关控制的是徽标上的哪一枚点。
|
|
606
|
+
*
|
|
607
|
+
* 单一事实来源:设置卡片里给每行画的**预览点**与折叠徽标实际画的那三枚点,都从这里取。
|
|
608
|
+
* 两处各写一套的话迟早会漂,而漂了的后果不是"多一个点少一个点",是**卡片预览与徽标说的
|
|
609
|
+
* 不是一回事**(同一族毛病:#25① 修过点行与明细的顺序,#37 又发现配置面里混着别人家的语义)。
|
|
610
|
+
*
|
|
611
|
+
* 对应关系与 `rows/GroupBadge.tsx` 一致:待审批 = warning 黄点、进行中 = ongoing 转圈、
|
|
612
|
+
* 已完成 = done 绿点。外部来源的点**不在这里** —— 它们由来源自己画(`renderIcon`),
|
|
613
|
+
* 也不在本插件的卡片上(显隐归来源自己)。
|
|
614
|
+
*/
|
|
615
|
+
const BADGE_FIELD_DOT_STATE = {
|
|
616
|
+
showPendingInBadge: "warning",
|
|
617
|
+
showRunningInBadge: "ongoing",
|
|
618
|
+
showCompletedInBadge: "done"
|
|
619
|
+
};
|
|
620
|
+
/**
|
|
621
|
+
* 卡片字段名(与 `src/index.ts` 的 `Config` 同名同义)。
|
|
622
|
+
*
|
|
623
|
+
* ⚠️ 只有本插件自己的语义。曾有 `showScheduledInBadge` / `showWaitingReviewInBadge`
|
|
624
|
+
* 两个字段替 dsh-later / dsh-gitea-dispatch 写死名字与图标形状,现已删除:外部来源的
|
|
625
|
+
* 显隐归来源自己(不注册就是不显示)。
|
|
626
|
+
*/
|
|
579
627
|
const BADGE_FIELDS = {
|
|
580
628
|
showCompletedInBadge: "showCompletedInBadge",
|
|
581
629
|
showRunningInBadge: "showRunningInBadge",
|
|
582
630
|
showPendingInBadge: "showPendingInBadge",
|
|
583
|
-
showScheduledInBadge: "showScheduledInBadge",
|
|
584
|
-
showWaitingReviewInBadge: "showWaitingReviewInBadge",
|
|
585
631
|
showHoverDetails: "showHoverDetails",
|
|
586
632
|
countThreshold: "countThreshold"
|
|
587
633
|
};
|
|
588
634
|
/**
|
|
589
|
-
*
|
|
590
|
-
*
|
|
635
|
+
* 草稿文本解析成开关状态:比较的是模型给的**文本**,不是存储值 ——
|
|
636
|
+
* 别把字符串 `'false'` 当成布尔 `false`(`'false' !== false` 恒真)。
|
|
591
637
|
*/
|
|
592
638
|
function isDraftEnabled(text) {
|
|
593
639
|
return text !== "false";
|
|
@@ -616,13 +662,21 @@ window.__ModuleLoader__.load({
|
|
|
616
662
|
} : void 0
|
|
617
663
|
};
|
|
618
664
|
}
|
|
619
|
-
/**
|
|
665
|
+
/** 各字段的字段转换规格。 */
|
|
666
|
+
const showCompletedField = makeBooleanField(BADGE_FIELDS.showCompletedInBadge, true);
|
|
667
|
+
const showRunningField = makeBooleanField(BADGE_FIELDS.showRunningInBadge, true);
|
|
668
|
+
/**
|
|
669
|
+
* 所有字段规格。
|
|
670
|
+
*
|
|
671
|
+
* ⚠️ 顺序**必须**与徽标画点的顺序一致(`rows/GroupBadge.tsx`:待审批 → 进行中 → 已完成;
|
|
672
|
+
* 外部来源排在已完成之前,但它们不在本插件的卡片上)。用户操作场景就是"我看到徽标第 N
|
|
673
|
+
* 个图标,想关掉它",卡片顺序错位会让人怀疑两处是两套事实 —— 同一族毛病 #25① 已经在
|
|
674
|
+
* 点行与明细之间修过一次。回归用例:`tests/badge-settings-card.client.spec.tsx`。
|
|
675
|
+
*/
|
|
620
676
|
const ALL_BADGE_FIELDS = [
|
|
621
|
-
makeBooleanField(BADGE_FIELDS.showCompletedInBadge, true),
|
|
622
|
-
makeBooleanField(BADGE_FIELDS.showRunningInBadge, true),
|
|
623
677
|
makeBooleanField(BADGE_FIELDS.showPendingInBadge, true),
|
|
624
|
-
|
|
625
|
-
|
|
678
|
+
showRunningField,
|
|
679
|
+
showCompletedField,
|
|
626
680
|
makeBooleanField(BADGE_FIELDS.showHoverDetails, true),
|
|
627
681
|
{
|
|
628
682
|
field: BADGE_FIELDS.countThreshold,
|
|
@@ -642,7 +696,7 @@ window.__ModuleLoader__.load({
|
|
|
642
696
|
];
|
|
643
697
|
//#endregion
|
|
644
698
|
//#region \0dsh-css:src/client/BadgeSettingsCard.module.css.mjs
|
|
645
|
-
const css$4 = ".dhp54G_section{min-width:0;padding:16px 0}.dhp54G_section:last-child{padding-bottom:0}.dhp54G_heading{color:var(--dsw-alias-label-primary);margin:0;font-size:13px;font-weight:600;line-height:1.5}.dhp54G_badgeField{gap:6px;padding:12px 0;display:grid}.dhp54G_badgeToggleRow{color:var(--dsw-alias-label-primary);justify-content:space-between;align-items:flex-start;gap:16px;font-size:13px;line-height:1.5;display:flex}.dhp54G_badgeToggleLabel{flex:1;min-width:0}.dhp54G_badgeNumberControl{align-items:center;gap:4px;display:flex}.dhp54G_badgeNumberButton{width:28px;height:28px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-elevated,#2a2a2a);border:1px solid var(--dsw-alias-border-primary,#555);cursor:pointer;user-select:none;border-radius:6px;justify-content:center;align-items:center;padding:0;font-size:16px;font-weight:600;line-height:1;display:flex}.dhp54G_badgeNumberButton:hover:not(:disabled){border-color:var(--dsw-alias-border-focus,#0078d4);background:var(--dsw-alias-bg-hover,#3a3a3a)}.dhp54G_badgeNumberButton:active:not(:disabled){background:var(--dsw-alias-bg-active,#4a4a4a)}.dhp54G_badgeNumberButton:disabled{opacity:.3;cursor:not-allowed}.dhp54G_badgeNumberValue{text-align:center;min-width:24px;color:var(--dsw-alias-label-primary);font-size:13px;font-weight:500}.dhp54G_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}";
|
|
699
|
+
const css$4 = ".dhp54G_section{min-width:0;padding:16px 0}.dhp54G_section:last-child{padding-bottom:0}.dhp54G_heading{color:var(--dsw-alias-label-primary);margin:0;font-size:13px;font-weight:600;line-height:1.5}.dhp54G_badgeField{gap:6px;padding:12px 0;display:grid}.dhp54G_badgeToggleRow{color:var(--dsw-alias-label-primary);justify-content:space-between;align-items:flex-start;gap:16px;font-size:13px;line-height:1.5;display:flex}.dhp54G_badgeSpecimen{vertical-align:-2px;align-items:center;margin-right:6px;display:inline-flex}.dhp54G_badgeToggleLabel{flex:1;min-width:0}.dhp54G_badgeNumberControl{align-items:center;gap:4px;display:flex}.dhp54G_badgeNumberButton{width:28px;height:28px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-elevated,#2a2a2a);border:1px solid var(--dsw-alias-border-primary,#555);cursor:pointer;user-select:none;border-radius:6px;justify-content:center;align-items:center;padding:0;font-size:16px;font-weight:600;line-height:1;display:flex}.dhp54G_badgeNumberButton:hover:not(:disabled){border-color:var(--dsw-alias-border-focus,#0078d4);background:var(--dsw-alias-bg-hover,#3a3a3a)}.dhp54G_badgeNumberButton:active:not(:disabled){background:var(--dsw-alias-bg-active,#4a4a4a)}.dhp54G_badgeNumberButton:disabled{opacity:.3;cursor:not-allowed}.dhp54G_badgeNumberValue{text-align:center;min-width:24px;color:var(--dsw-alias-label-primary);font-size:13px;font-weight:500}.dhp54G_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}";
|
|
646
700
|
const tagId$4 = "dsh-group-status/BadgeSettingsCard.module.css";
|
|
647
701
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$4) + "]") === null) {
|
|
648
702
|
const tag = document.createElement("style");
|
|
@@ -656,6 +710,7 @@ window.__ModuleLoader__.load({
|
|
|
656
710
|
"badgeNumberButton": "dhp54G_badgeNumberButton",
|
|
657
711
|
"badgeNumberControl": "dhp54G_badgeNumberControl",
|
|
658
712
|
"badgeNumberValue": "dhp54G_badgeNumberValue",
|
|
713
|
+
"badgeSpecimen": "dhp54G_badgeSpecimen",
|
|
659
714
|
"badgeToggleLabel": "dhp54G_badgeToggleLabel",
|
|
660
715
|
"badgeToggleRow": "dhp54G_badgeToggleRow",
|
|
661
716
|
"heading": "dhp54G_heading",
|
|
@@ -736,21 +791,29 @@ window.__ModuleLoader__.load({
|
|
|
736
791
|
id: badgeSectionId,
|
|
737
792
|
children: t("settings.badge.section")
|
|
738
793
|
}),
|
|
739
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToggleRow, {
|
|
740
|
-
field: BADGE_FIELDS.showRunningInBadge,
|
|
741
|
-
text: fieldText(BADGE_FIELDS.showRunningInBadge),
|
|
742
|
-
label: t("settings.badge.showRunning"),
|
|
743
|
-
hint: t("settings.badge.showRunningHint"),
|
|
744
|
-
state,
|
|
745
|
-
actions
|
|
746
|
-
}),
|
|
747
794
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToggleRow, {
|
|
748
795
|
field: BADGE_FIELDS.showPendingInBadge,
|
|
749
796
|
text: fieldText(BADGE_FIELDS.showPendingInBadge),
|
|
750
797
|
label: t("settings.badge.showPending"),
|
|
751
798
|
hint: t("settings.badge.showPendingHint"),
|
|
752
799
|
state,
|
|
753
|
-
actions
|
|
800
|
+
actions,
|
|
801
|
+
specimen: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, {
|
|
802
|
+
state: BADGE_FIELD_DOT_STATE.showPendingInBadge,
|
|
803
|
+
size: 12
|
|
804
|
+
})
|
|
805
|
+
}),
|
|
806
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToggleRow, {
|
|
807
|
+
field: BADGE_FIELDS.showRunningInBadge,
|
|
808
|
+
text: fieldText(BADGE_FIELDS.showRunningInBadge),
|
|
809
|
+
label: t("settings.badge.showRunning"),
|
|
810
|
+
hint: t("settings.badge.showRunningHint"),
|
|
811
|
+
state,
|
|
812
|
+
actions,
|
|
813
|
+
specimen: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, {
|
|
814
|
+
state: BADGE_FIELD_DOT_STATE.showRunningInBadge,
|
|
815
|
+
size: 12
|
|
816
|
+
})
|
|
754
817
|
}),
|
|
755
818
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToggleRow, {
|
|
756
819
|
field: BADGE_FIELDS.showCompletedInBadge,
|
|
@@ -758,23 +821,11 @@ window.__ModuleLoader__.load({
|
|
|
758
821
|
label: t("settings.badge.showCompleted"),
|
|
759
822
|
hint: t("settings.badge.showCompletedHint"),
|
|
760
823
|
state,
|
|
761
|
-
actions
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
label: t("settings.badge.showScheduled"),
|
|
767
|
-
hint: t("settings.badge.showScheduledHint"),
|
|
768
|
-
state,
|
|
769
|
-
actions
|
|
770
|
-
}),
|
|
771
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToggleRow, {
|
|
772
|
-
field: BADGE_FIELDS.showWaitingReviewInBadge,
|
|
773
|
-
text: fieldText(BADGE_FIELDS.showWaitingReviewInBadge),
|
|
774
|
-
label: t("settings.badge.showWaitingReview"),
|
|
775
|
-
hint: t("settings.badge.showWaitingReviewHint"),
|
|
776
|
-
state,
|
|
777
|
-
actions
|
|
824
|
+
actions,
|
|
825
|
+
specimen: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, {
|
|
826
|
+
state: BADGE_FIELD_DOT_STATE.showCompletedInBadge,
|
|
827
|
+
size: 12
|
|
828
|
+
})
|
|
778
829
|
})
|
|
779
830
|
]
|
|
780
831
|
}),
|
|
@@ -813,15 +864,18 @@ window.__ModuleLoader__.load({
|
|
|
813
864
|
]
|
|
814
865
|
});
|
|
815
866
|
}
|
|
816
|
-
/** 单行开关:label + Switch + hint
|
|
817
|
-
function ToggleRow({ field, text, label, hint, state, actions }) {
|
|
867
|
+
/** 单行开关:label + Switch + hint。`specimen` 是行首那枚预览点(可选)。 */
|
|
868
|
+
function ToggleRow({ field, text, label, hint, state, actions, specimen }) {
|
|
818
869
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
819
870
|
className: BadgeSettingsCard_module_css_default.badgeField,
|
|
820
871
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
821
872
|
className: BadgeSettingsCard_module_css_default.badgeToggleRow,
|
|
822
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.
|
|
873
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
823
874
|
className: BadgeSettingsCard_module_css_default.badgeToggleLabel,
|
|
824
|
-
children:
|
|
875
|
+
children: [specimen !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
876
|
+
className: BadgeSettingsCard_module_css_default.badgeSpecimen,
|
|
877
|
+
children: specimen
|
|
878
|
+
}), label]
|
|
825
879
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
|
|
826
880
|
checked: isDraftEnabled(text),
|
|
827
881
|
label,
|
|
@@ -1773,6 +1827,12 @@ window.__ModuleLoader__.load({
|
|
|
1773
1827
|
function owningGroupKey(workspaces, sessionId) {
|
|
1774
1828
|
return workspaces.find((workspace) => workspace.sessionIds.includes(sessionId))?.workspaceId ?? "";
|
|
1775
1829
|
}
|
|
1830
|
+
/** 宿主认的 kind 集合(查表用)。 */
|
|
1831
|
+
const PENDING_INTERACTION_KIND_SET = /* @__PURE__ */ new Set([
|
|
1832
|
+
"approval",
|
|
1833
|
+
"plan-review",
|
|
1834
|
+
"question"
|
|
1835
|
+
]);
|
|
1776
1836
|
function mainSessionId(list) {
|
|
1777
1837
|
return Object.values(list.byId).find((session) => (session.retainedBy.mainView ?? 0) > 0)?.id;
|
|
1778
1838
|
}
|
|
@@ -1956,12 +2016,7 @@ window.__ModuleLoader__.load({
|
|
|
1956
2016
|
}
|
|
1957
2017
|
/** Keep navigation presentation independent from domain-owned interaction objects. */
|
|
1958
2018
|
function visiblePendingKind(kind) {
|
|
1959
|
-
|
|
1960
|
-
case "approval":
|
|
1961
|
-
case "plan-review":
|
|
1962
|
-
case "question": return kind;
|
|
1963
|
-
default: return;
|
|
1964
|
-
}
|
|
2019
|
+
return kind !== void 0 && PENDING_INTERACTION_KIND_SET.has(kind) ? kind : void 0;
|
|
1965
2020
|
}
|
|
1966
2021
|
function runningChildCount(list, parentId, statuses) {
|
|
1967
2022
|
return list.projectionsBySession[parentId]?.values.subagentCatalog?.reduce((count, child) => count + ((statuses.get(child.id)?.running ?? list.byId[child.id]?.running) === true ? 1 : 0), 0) ?? 0;
|
|
@@ -2875,22 +2930,50 @@ window.__ModuleLoader__.load({
|
|
|
2875
2930
|
return raised;
|
|
2876
2931
|
}
|
|
2877
2932
|
//#endregion
|
|
2878
|
-
//#region src/client/
|
|
2933
|
+
//#region src/client/use-registered-facets.ts
|
|
2879
2934
|
/**
|
|
2880
|
-
*
|
|
2935
|
+
* 把登记面读成「这一轮渲染该折哪些来源」的**唯一**一处接线。
|
|
2936
|
+
*
|
|
2937
|
+
* ## 为什么单独成文
|
|
2881
2938
|
*
|
|
2882
|
-
*
|
|
2883
|
-
*
|
|
2939
|
+
* 这一步此前直接写在 `rows/WorkspaceBrowser.tsx` 里,两行:
|
|
2940
|
+
*
|
|
2941
|
+
* ```ts
|
|
2942
|
+
* useSyncExternalStore(facetsStore.subscribe, facetsStore.getVersion, …) // 返回值丢掉
|
|
2943
|
+
* const facets = useMemo(() => visibleFacets(facetsStore.list(), settings), [settings])
|
|
2944
|
+
* ```
|
|
2945
|
+
*
|
|
2946
|
+
* 看着没问题——订阅了、也 memo 了。实际是**订阅通知只重渲染、不重算**:
|
|
2947
|
+
* `useSyncExternalStore` 的返回值被丢掉,`useMemo` 的依赖里就没有任何东西随登记面变化,
|
|
2948
|
+
* 于是那次重渲染原样拿回**上一次**的登记面。提供方在自己的 `apply` 里注册,而宿主不保证
|
|
2949
|
+
* `apply` 与本组件首渲染的先后:注册**晚于**首渲染时,facet 明明登记上了,却永远进不了
|
|
2950
|
+
* 徽标——不报错、不红测试(能渲染这条路径的那份上游 spec 在本仓库是跳过的,见
|
|
2951
|
+
* `vitest.config.ts` 的 `MONOREPO_ONLY_SPECS`),只能靠刷新页面碰运气。
|
|
2952
|
+
*
|
|
2953
|
+
* 版本号必须**同时**当两件事用:① 触发重渲染的信号,② memo 的依赖。这里把它收进一个
|
|
2954
|
+
* hook,让「只用①、丢掉②」在结构上写不出来,并且让这条接缝能被 `@testing-library/react`
|
|
2955
|
+
* 直接覆盖(本文件零宿主 import,宿主依赖闭包进不来)。
|
|
2956
|
+
*
|
|
2957
|
+
* ## 为什么现在不再按设置筛
|
|
2958
|
+
*
|
|
2959
|
+
* 旧版本这里会过一道 `visibleFacets(list, settings)`,按 `facet.settingKey` 查本插件的
|
|
2960
|
+
* 布尔开关。那意味着**本插件的配置面里写着别人家的语义**(`showScheduledInBadge` /
|
|
2961
|
+
* `showWaitingReviewInBadge`,连图标形状都替对方写死),与"本插件不认识任何来源"直接
|
|
2962
|
+
* 矛盾。现在外部来源的显隐归**来源自己**:它想被关掉就不注册 facet,登记面即所见。
|
|
2963
|
+
* 本插件的开关只管自己那三档会话状态(见 `badge-settings.ts`)。
|
|
2964
|
+
*
|
|
2965
|
+
* @module dsh-group-status/client/use-registered-facets
|
|
2966
|
+
*/
|
|
2967
|
+
/**
|
|
2968
|
+
* 当前登记的来源,按登记面顺序(已按 `order` 排好)。
|
|
2884
2969
|
*
|
|
2885
|
-
*
|
|
2886
|
-
* "要不要画徽标"因此天然同源。放到渲染阶段会出现"label 里有、计数里没有",而那正是
|
|
2887
|
-
* 徽标最容易被怀疑撒谎的地方。
|
|
2970
|
+
* 引用在版本号不变时保持稳定:登记面是低频事件,重算成本 = O(facet × 组内会话)。
|
|
2888
2971
|
*
|
|
2889
|
-
* @
|
|
2972
|
+
* @param store - facet 消费侧存储(`facetStore()` 单例)。
|
|
2890
2973
|
*/
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
return
|
|
2974
|
+
function useRegisteredFacets(store) {
|
|
2975
|
+
const version = (0, react.useSyncExternalStore)(store.subscribe, store.getVersion, store.getServerVersion);
|
|
2976
|
+
return (0, react.useMemo)(() => [...store.list()], [version]);
|
|
2894
2977
|
}
|
|
2895
2978
|
//#endregion
|
|
2896
2979
|
//#region src/client/badge-labels.ts
|
|
@@ -2933,9 +3016,9 @@ window.__ModuleLoader__.load({
|
|
|
2933
3016
|
* Accessible label for a folded group's aggregated status, reusing the
|
|
2934
3017
|
* session-row locale keys so both surfaces read identically.
|
|
2935
3018
|
*
|
|
2936
|
-
*
|
|
2937
|
-
* `
|
|
2938
|
-
*
|
|
3019
|
+
* 按设置过滤:本插件那三档会话状态按设置逐项过滤;**外部来源不参与过滤** —— 登记了就
|
|
3020
|
+
* 一定出现在这里,没登记就不在折果里,所以 `aria-label` 与徽标视觉天然一致,不必在这里
|
|
3021
|
+
* 再判一次设置(本插件也没有替别人家存的开关)。
|
|
2939
3022
|
*/
|
|
2940
3023
|
function groupLiveLabel(s, t, settings, now = Date.now()) {
|
|
2941
3024
|
const parts = [];
|
|
@@ -3115,10 +3198,10 @@ window.__ModuleLoader__.load({
|
|
|
3115
3198
|
*
|
|
3116
3199
|
* Count matches the dots: host-side sessions plus every registered facet's own count.
|
|
3117
3200
|
*
|
|
3118
|
-
* `settings`
|
|
3119
|
-
*
|
|
3120
|
-
*
|
|
3121
|
-
*
|
|
3201
|
+
* `settings` 只过滤**本插件自己的**三档会话状态:关掉的档位不画点、不计数、不进
|
|
3202
|
+
* aria-label、不参与「是否显示徽标」的判断。会话行自身的状态点不受影响:那是行级状态,
|
|
3203
|
+
* 不是分组提示。**外部来源在这里没有开关可关** —— 它们要么注册了(一定显示),要么没
|
|
3204
|
+
* 注册(根本不在登记面上)。要关某个来源,去那个插件自己的设置卡片:显隐是来源的决定。
|
|
3122
3205
|
*
|
|
3123
3206
|
* `now` 缺省取渲染时刻(与 `WorkspaceBrowser` 为相对时间读的时钟同一姿态):文案里的
|
|
3124
3207
|
* 剩余时长以此计算,只在提供方 store 通知时随渲染更新。
|
|
@@ -3133,8 +3216,8 @@ window.__ModuleLoader__.load({
|
|
|
3133
3216
|
if (pending === 0 && active === 0 && completed === 0 && facetTotal === 0) return null;
|
|
3134
3217
|
const label = groupLiveLabel(s, t, settings, now);
|
|
3135
3218
|
const dots = [];
|
|
3136
|
-
if (pending > 0) dots.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state:
|
|
3137
|
-
if (active > 0) dots.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state:
|
|
3219
|
+
if (pending > 0) dots.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: BADGE_FIELD_DOT_STATE.showPendingInBadge }, "warn"));
|
|
3220
|
+
if (active > 0) dots.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: BADGE_FIELD_DOT_STATE.showRunningInBadge }, "run"));
|
|
3138
3221
|
const urgentClass = Rows_module_css_default.groupBadgeUrgent ?? "";
|
|
3139
3222
|
for (const entry of s.facets.values()) {
|
|
3140
3223
|
const glyph = facetGlyph(entry, t, now);
|
|
@@ -3144,7 +3227,7 @@ window.__ModuleLoader__.load({
|
|
|
3144
3227
|
children: glyph
|
|
3145
3228
|
}, entry.facet.id));
|
|
3146
3229
|
}
|
|
3147
|
-
if (completed > 0) dots.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state:
|
|
3230
|
+
if (completed > 0) dots.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: BADGE_FIELD_DOT_STATE.showCompletedInBadge }, "done"));
|
|
3148
3231
|
const count = pending + active + completed + facetTotal;
|
|
3149
3232
|
const countLabel = count > 99 ? "99+" : count >= settings.countThreshold ? String(count) : "";
|
|
3150
3233
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
@@ -4370,8 +4453,7 @@ window.__ModuleLoader__.load({
|
|
|
4370
4453
|
const panelActive = usePanelInfo((info) => info.activePanelId !== null);
|
|
4371
4454
|
const badgeSettings = useBadgeSettings((settings) => settings);
|
|
4372
4455
|
const statuses = useSessionStatus((s) => s);
|
|
4373
|
-
|
|
4374
|
-
const facets = (0, react.useMemo)(() => visibleFacets(facetsStore.list(), badgeSettings), [badgeSettings]);
|
|
4456
|
+
const facets = useRegisteredFacets(facetsStore);
|
|
4375
4457
|
const current = panelActive ? void 0 : Object.values(list.byId).find((session) => (session.retainedBy.mainView ?? 0) > 0)?.id;
|
|
4376
4458
|
const revealGroup = revealSessionId === void 0 || !workspaceReady ? void 0 : owningGroupKey(workspaces, revealSessionId);
|
|
4377
4459
|
const [storedWatermarks, setStoredWatermarks] = (0, react.useState)({});
|
|
@@ -6042,10 +6124,6 @@ window.__ModuleLoader__.load({
|
|
|
6042
6124
|
"settings.badge.showPendingHint": "关闭后,等待审批 / 计划评审 / 等待回答的会话不再画黄点,也不再计入折叠徽标的数字与悬停明细。",
|
|
6043
6125
|
"settings.badge.showCompleted": "显示「已完成」绿点",
|
|
6044
6126
|
"settings.badge.showCompletedHint": "关闭后,「已完成」的会话不再画绿点,也不再计入折叠徽标的数字与悬停明细。会话行自身的绿点不受影响。",
|
|
6045
|
-
"settings.badge.showScheduled": "显示「定时任务」时钟",
|
|
6046
|
-
"settings.badge.showScheduledHint": "关闭后,带定时提醒的会话(来自 dsh-later)不再画时钟图标,也不再计入折叠徽标的数字与悬停明细。",
|
|
6047
|
-
"settings.badge.showWaitingReview": "显示「等待评审」沙漏",
|
|
6048
|
-
"settings.badge.showWaitingReviewHint": "关闭后,等待代码评审的会话(来自 dsh-gitea-dispatch)不再画沙漏图标,也不再计入折叠徽标的数字与悬停明细。",
|
|
6049
6127
|
"settings.hover.section": "悬停明细",
|
|
6050
6128
|
"settings.hover.showDetails": "显示状态明细行",
|
|
6051
6129
|
"settings.hover.showDetailsHint": "关闭后,悬停卡只显示工作区标题、路径和创建时间——不再显示聚合状态明细行。",
|
|
@@ -6187,10 +6265,6 @@ window.__ModuleLoader__.load({
|
|
|
6187
6265
|
"settings.badge.showPendingHint": "When off, Sessions waiting for approval / plan review / answer stop drawing the yellow dot and drop out of the collapsed badge count and its hover details.",
|
|
6188
6266
|
"settings.badge.showCompleted": "Show the completed dot",
|
|
6189
6267
|
"settings.badge.showCompletedHint": "When off, completed Sessions stop drawing the dot and drop out of the collapsed badge count and its hover details. The Session row's own dot is unaffected.",
|
|
6190
|
-
"settings.badge.showScheduled": "Show the scheduled icon",
|
|
6191
|
-
"settings.badge.showScheduledHint": "When off, Sessions with scheduled reminders (from dsh-later) stop drawing the clock icon and drop out of the collapsed badge count and its hover details.",
|
|
6192
|
-
"settings.badge.showWaitingReview": "Show the waiting-for-review icon",
|
|
6193
|
-
"settings.badge.showWaitingReviewHint": "When off, Sessions waiting for code review (from dsh-gitea-dispatch) stop drawing the hourglass icon and drop out of the collapsed badge count and its hover details.",
|
|
6194
6268
|
"settings.hover.section": "Hover details",
|
|
6195
6269
|
"settings.hover.showDetails": "Show status detail lines",
|
|
6196
6270
|
"settings.hover.showDetailsHint": "When off, the hover card shows only the workspace title, path, and creation time — no aggregated status lines.",
|