dsh-group-status 0.4.0 → 0.5.1

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.
Files changed (94) hide show
  1. package/CHANGELOG.md +128 -0
  2. package/README.en.md +10 -6
  3. package/README.md +12 -6
  4. package/lib/client.js +1913 -1804
  5. package/lib/client.js.map +1 -1
  6. package/lib/index.js +38 -8
  7. package/lib/types/build-stamp.d.ts +4 -0
  8. package/lib/types/build-stamp.d.ts.map +1 -0
  9. package/lib/types/build-stamp.js +23 -0
  10. package/lib/types/build-stamp.js.map +1 -0
  11. package/lib/types/client/BadgeSettingsCard.d.ts.map +1 -1
  12. package/lib/types/client/BadgeSettingsCard.js +8 -8
  13. package/lib/types/client/BadgeSettingsCard.js.map +1 -1
  14. package/lib/types/client/badge-field.d.ts +33 -10
  15. package/lib/types/client/badge-field.d.ts.map +1 -1
  16. package/lib/types/client/badge-field.js +35 -16
  17. package/lib/types/client/badge-field.js.map +1 -1
  18. package/lib/types/client/badge-labels.d.ts +3 -3
  19. package/lib/types/client/badge-labels.js +3 -3
  20. package/lib/types/client/badge-settings.d.ts +0 -25
  21. package/lib/types/client/badge-settings.d.ts.map +1 -1
  22. package/lib/types/client/badge-settings.js +0 -18
  23. package/lib/types/client/badge-settings.js.map +1 -1
  24. package/lib/types/client/facets.d.ts +39 -5
  25. package/lib/types/client/facets.d.ts.map +1 -1
  26. package/lib/types/client/facets.js +48 -4
  27. package/lib/types/client/facets.js.map +1 -1
  28. package/lib/types/client/group-status.d.ts +5 -0
  29. package/lib/types/client/group-status.d.ts.map +1 -1
  30. package/lib/types/client/group-status.js +25 -0
  31. package/lib/types/client/group-status.js.map +1 -1
  32. package/lib/types/client/locales.d.ts +4 -8
  33. package/lib/types/client/locales.d.ts.map +1 -1
  34. package/lib/types/client/locales.js +4 -8
  35. package/lib/types/client/locales.js.map +1 -1
  36. package/lib/types/client/rows/EmptySessions.d.ts +4 -0
  37. package/lib/types/client/rows/EmptySessions.d.ts.map +1 -0
  38. package/lib/types/client/rows/EmptySessions.js +10 -0
  39. package/lib/types/client/rows/EmptySessions.js.map +1 -0
  40. package/lib/types/client/rows/GroupBadge.d.ts +4 -4
  41. package/lib/types/client/rows/GroupBadge.d.ts.map +1 -1
  42. package/lib/types/client/rows/GroupBadge.js +10 -7
  43. package/lib/types/client/rows/GroupBadge.js.map +1 -1
  44. package/lib/types/client/rows/ListView.d.ts +24 -0
  45. package/lib/types/client/rows/ListView.d.ts.map +1 -0
  46. package/lib/types/client/rows/ListView.js +81 -0
  47. package/lib/types/client/rows/ListView.js.map +1 -0
  48. package/lib/types/client/rows/SessionTree.d.ts +4 -0
  49. package/lib/types/client/rows/SessionTree.d.ts.map +1 -0
  50. package/lib/types/client/rows/SessionTree.js +381 -0
  51. package/lib/types/client/rows/SessionTree.js.map +1 -0
  52. package/lib/types/client/rows/ViewOptionsMenu.d.ts +14 -0
  53. package/lib/types/client/rows/ViewOptionsMenu.d.ts.map +1 -0
  54. package/lib/types/client/rows/ViewOptionsMenu.js +50 -0
  55. package/lib/types/client/rows/ViewOptionsMenu.js.map +1 -0
  56. package/lib/types/client/rows/WorkspaceBrowser.d.ts +0 -5
  57. package/lib/types/client/rows/WorkspaceBrowser.d.ts.map +1 -1
  58. package/lib/types/client/rows/WorkspaceBrowser.js +8 -557
  59. package/lib/types/client/rows/WorkspaceBrowser.js.map +1 -1
  60. package/lib/types/client/rows/browser-shared.d.ts +105 -0
  61. package/lib/types/client/rows/browser-shared.d.ts.map +1 -0
  62. package/lib/types/client/rows/browser-shared.js +93 -0
  63. package/lib/types/client/rows/browser-shared.js.map +1 -0
  64. package/lib/types/client/session-actions/derived.d.ts.map +1 -1
  65. package/lib/types/client/session-actions/derived.js +13 -2
  66. package/lib/types/client/session-actions/derived.js.map +1 -1
  67. package/lib/types/client/session-watermarks.d.ts +6 -1
  68. package/lib/types/client/session-watermarks.d.ts.map +1 -1
  69. package/lib/types/client/session-watermarks.js +31 -11
  70. package/lib/types/client/session-watermarks.js.map +1 -1
  71. package/lib/types/client/toast/register.d.ts.map +1 -1
  72. package/lib/types/client/toast/register.js +102 -132
  73. package/lib/types/client/toast/register.js.map +1 -1
  74. package/lib/types/client/tree.d.ts +16 -1
  75. package/lib/types/client/tree.d.ts.map +1 -1
  76. package/lib/types/client/tree.js +20 -8
  77. package/lib/types/client/tree.js.map +1 -1
  78. package/lib/types/client/use-registered-facets.d.ts +11 -0
  79. package/lib/types/client/use-registered-facets.d.ts.map +1 -0
  80. package/lib/types/client/use-registered-facets.js +48 -0
  81. package/lib/types/client/use-registered-facets.js.map +1 -0
  82. package/lib/types/host-contract.d.ts +71 -0
  83. package/lib/types/host-contract.d.ts.map +1 -0
  84. package/lib/types/host-contract.js +127 -0
  85. package/lib/types/host-contract.js.map +1 -0
  86. package/lib/types/index.d.ts +13 -13
  87. package/lib/types/index.d.ts.map +1 -1
  88. package/lib/types/index.js +17 -8
  89. package/lib/types/index.js.map +1 -1
  90. package/package.json +16 -2
  91. package/lib/types/client/facet-visibility.d.ts +0 -17
  92. package/lib/types/client/facet-visibility.d.ts.map +0 -1
  93. package/lib/types/client/facet-visibility.js +0 -18
  94. package/lib/types/client/facet-visibility.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -6,6 +6,134 @@
6
6
 
7
7
  ## 未发布
8
8
 
9
+ ## 0.5.1 — 2026-10-27
10
+
11
+ - **refactor** 会话列表面板拆成四个组件文件:`rows/WorkspaceBrowser.tsx` 从 1562 行降到 685 行,
12
+ 树体、扁平列表、搜索结果、视图选项菜单、空态占位各自独立(`SessionTree.tsx` / `ListView.tsx` /
13
+ `ViewOptionsMenu.tsx` / `EmptySessions.tsx`),三类共享件(搜索 wire 常量、拖拽状态机、树体的 prop
14
+ 契约)收进 `browser-shared.ts`。三个列表体本来就是**互斥渲染**的分支,拆开后仍互不 import;成环由
15
+ `browser-shared.ts` 单向下指挡掉。行为不变:切分是逐段搬移,没有改写判定、排序或动画时序。
16
+
17
+ - **perf** 空闲分组不再产生新的状态对象:`summarizeGroupStatus` 对「六项全零且没有来源贡献」的组
18
+ 交回冻结的 `EMPTY_LIVE_STATUS`,`mergeLiveStatus` 把「加一份零」实现为**原样返回入参**。多层折叠
19
+ 里每层都会把子树重滚一遍,此前每滚一次都为每个空闲组造一份等值新对象;下游按引用判等的选择器于是
20
+ 每轮重渲染,而它读到的数字一个没变。合并仍不修改任何入参。
21
+
22
+ - **perf** `watermarkRows` 在第一个被截断的行处提前退出(空行必然排在组首,由 `tree.ts` 的
23
+ `sectionMembers` 保证,这条例外前提写进了它的 JSDoc);`raiseWatermarks` 整趟只拷贝一次对象,
24
+ 不再为每个抬升的分组各展开一次;`WorkspaceBrowser` 与三个列表体共用的「主视图保留了哪个会话」
25
+ 扫描改为按 list 身份记忆,不再每轮渲染各 `Object.values()` 一次(`browser-shared.ts` 的
26
+ `mainViewSessionId`)。
27
+
28
+ - **fix** `derive()` 用模块私有 Symbol 代替 `undefined` 表示「尚未投影」:投影**合法地**可能返回
29
+ `undefined`("此刻没有待处理请求"就是一次正常的空结果),旧写法让每次 `getSnapshot()` 都重跑投影;
30
+ 投影若新建 `Set`/数组,消费者每次读都拿到新引用,选择器永不收敛 —— 正是这个投影器要避免的事。
31
+
32
+ - **a11y** 徽标设置卡片的数字增减按钮不再硬编码中文 `aria-label`(`settings.count.decrease` /
33
+ `settings.count.increase` 进 zh/en 两份字典);搜索结果区补 `aria-busy`,并给「无匹配」与
34
+ 「仅显示前 N 条」加上 `role="status"`,屏幕阅读器能从"正在搜索"读到终止结果。徽标自身的
35
+ `aria-label` 与 `title` 经复核同源、且逐项覆盖可见状态点与数字,无需改动。
36
+
37
+ - **test** 补上此前**从未在本仓库跑过**的契约:`tests/apply-smoke.client.spec.ts`(宿主半边
38
+ `apply()` 不读 `ctx`、banner 仍报得出产物与进程)、`tests/facet-lifecycle.client.spec.tsx`
39
+ (登记面 → 消费存储 → React 的迟到登记 / 快照推送 / 同 id 热替换 / 注销 / dispose)、
40
+ `tests/derive.client.spec.ts`(投影身份稳定,含"返回 `undefined` 也只算一次")与
41
+ `tests/locale-keys.client.spec.ts`(中英字典键必须同集合)。`group-status` 那条「空闲组是全零」
42
+ 改为同时断言**引用**就是哨兵;`cross-plugin-summary` 补了「store 迟到注册后 hook 自愈」。
43
+ 每条新用例都做过反向验证:改坏被保护的行为即失败,改回即通过。
44
+
45
+ - **fix** 把客户端运行时依赖**逐条写进 `peerDependencies`**(12 个 `@deepseek-ai/dsh-*`,
46
+ 范围 `^0.2.1-rc.2` = `engines.dsh` 下界),闭合"声明说不支持、内核照样装"的洞。
47
+ **为什么必须这么做**:≤0.2.0 的内核**不读 `engines.dsh`**,只按 `dsh-*` peer 的范围判兼容
48
+ (0.2.1 起反过来——`engines.dsh` 单独决定,peer 不参与判定)。此前 peer 里只有
49
+ `@deepseek-ai/cordis`,于是 0.2.0 把本插件判成"兼容"并装载;而那一代没发布
50
+ `@deepseek-ai/dsh-api-remote-access`,客户端 `inject` 的 `remoteAccess` 永远拿不到 →
51
+ fiber 永久 pending → `uiWorkspace` 不再被提供 → **`ui-sidebar` / `ui-conversation` /
52
+ `ui-chat` 等 12 条一起不激活,整页 "Failed to load plugins",用户失去整个侧栏**。
53
+ 现在 0.2.0-rc.2 实测:内核打印 `skipping profile bundle "dsh-group-status": … peerDependencies {...}`,
54
+ 插件不装载,**控制台 0 错误、宿主自带侧栏照常工作**;而 0.2.1-rc.2 / rc.3 / rc.4 三代
55
+ `engines.dsh` 命中即返回,peer 不参与判定,仍全部判过、真 GUI 里分区正常渲染。
56
+ 新增用例 `tests/artifacts.node.test.mjs`「每个客户端注入包都声明为 peer,且范围等于
57
+ `engines.dsh` 的下界」把这条不变量钉住(反向验证:把任一 peer 改成 `*` 即红)。
58
+
59
+ - **docs** 跨代次验证记录(2026-10-27,`devkit/results/dsh-group-status-cross-kernel-2026-10-27.json`
60
+ 与 `devkit/results/screens/`):0.2.1-rc.2 上 gate / peer / tsc / test / 冷启动装配全绿,
61
+ 真 GUI 里分组行、会话行、View options 菜单、扁平列表、搜索命中与无匹配态均正常,
62
+ 搜索区的 `aria-busy` 与 `role="status"` 在真机可见。**0.2.0-rc.2 实测会把整个侧栏拖下去**:
63
+ 该代次没发布 `@deepseek-ai/dsh-api-remote-access`,客户端 `inject` 的 `remoteAccess` 拿不到
64
+ → fiber 永久 pending → `uiWorkspace` 不再被提供 → 侧栏 / 对话 / chat 共 12 条一起不激活,
65
+ 页面直接 "Failed to load plugins"。所以 `engines.dsh >=0.2.1-rc.2` 是**硬下界**,不是保守估计;
66
+ 0.1.7/0.2.0 的内核也不读 `engines.dsh`(只卡 `dsh-*` peer,而本包的 `dsh-*` peer 只有
67
+ `@deepseek-ai/cordis`),因此这两代上它**能被装进去**——装进去就会坏,别手工降级。
68
+ 折叠分组的活状态徽标这一轮**未判定**:隔离实例里宿主没有上报会话活状态,新/旧构建 A/B 均为空,
69
+ 故不能算通过(对照记录见 `devkit/results/screens/README.md`)。
70
+
71
+ - **chore** 构建与守卫:CI 新增 `lib/client.js` 的 gzip 体积预算(当前 77,312 字节 / 上限 84,000,
72
+ `release-invariants` job,纯 shell);`parseHostPendingKinds` 解析不到时改为抛出**点名是哪一条正则
73
+ 破了**的错误,不再静默返回空集合 —— 空集合会让"集合相等"永远成立,或退化成一条误导性的
74
+ "我们多认了 kind"漂移;`build/tools/experimental-package-policy.ts` 删掉本仓库结构上不可能走到的
75
+ 分支(没有 `packages/experimental/` 树,十个保留名在 264 个已装包里一个都不出现);产物可复现性
76
+ 检查排除被 `.gitignore` 的增量缓存 `tsconfig.tsbuildinfo`(它记的是上次构建动过哪些文件,与被比较的
77
+ 编译输出无关)。
78
+
79
+
80
+ ## 0.5.0 — 2026-10-22
81
+
82
+ - **fix** 宿主契约漂移**从此有人看着了**:`pendingInteraction.kind` 是开放集合
83
+ (`SessionPendingInteractionMap` 靠声明合并扩展,任何宿主包都能贡献自己的 kind),而本仓库的
84
+ `src/client/tree.ts` 是宿主 workspace 投影的 fork。宿主新增一种 kind 时本插件**不会**自动跟上,
85
+ 于是宿主侧栏与折叠徽标会**一起不显示**它 —— 两边口径一致所以不是"谁错了",但用户只会觉得
86
+ "这俩对不上"。而"宿主换了代"本来该由 `scripts/check-upstream.ts` 提醒,**那个脚本从来没有工作过**:
87
+ 它比对的 `src/vendor/src` 目录早就不存在了(vendored 的上游源码直接摊在 `src/` 下),上游发布包里
88
+ 也没有 `src/`(只有 `lib/`),于是它一跑就 `ENOENT: scandir 'src/vendor/src'`;而 `docs/upgrading.md`
89
+ 还让人照着它 rebase —— 一条指着不存在目录的命令比没有更糟:它让人以为"没红就是没漂移"。
90
+ 现在:同一份比对实现(`src/host-contract.ts`)被两处调用 —— `npm test` 里的
91
+ `tests/host-pending-kinds.node.test.mjs`(离线,读锁定版宿主的实现,CI 会跑)与
92
+ `pnpm check-upstream`(人看的;`--latest` 还能查 npm 上**已发布的最高版**,注意该包的 `latest`
93
+ 标签是旧的、还指着 0.0.1-rc.1,不能直接用 `npm view <pkg> version`)。守卫覆盖三件事:我们认的
94
+ kind 集合必须与宿主一致、宿主不能把我们要读的两个状态事实改名、以及"守卫自己不是摆设"(拿真实
95
+ bundle 的改造副本当反例)。另加类型层一道:`Rows.tsx` 的 `assertNever` 让"新增 kind 却没给行内
96
+ 表现"直接编译不过。
97
+
98
+ - **breaking** 删除设置项 `showScheduledInBadge` 与 `showWaitingReviewInBadge`:**外部来源的显隐不再由本插件管**。
99
+ 这两个字段把别人家的域名(定时任务 / 等待评审)、来源名(dsh-later / dsh-gitea-dispatch)连图标形状
100
+ ("时钟" / "沙漏")全都写死在**消费方**的 `Config`、设置卡片与文案里,与本插件「不认识任何具体来源」的
101
+ 立身之本直接矛盾 —— facet 协议把适配方向翻正了,配置面却没跟着翻。而且它**已经是错的**:dsh-gitea-dispatch
102
+ 自其 #60 起让徽标跟随自己的 `waitingIconStyle`,三档里两档不是沙漏,卡片却仍在承诺"沙漏";对方没装时,
103
+ 那句"关闭后不再画"更是空话。
104
+ 现在的规则只有一条:**登记即显示,不注册即不显示**。要给用户一个"关掉它"的开关,请加在**你自己的**
105
+ 配置卡片里。协议成员 `settingKey` 同时废弃(v1 仍接受、不报错,但本插件不再读取)。
106
+ **升级影响**:profile 里残留的这两个旧值不再被读取,等同回到默认「显示」(默认全开,最坏情况是某个来源
107
+ 重新出现,不会留下坏数据)。曾考虑的另一种收口(消费方保留 `disabledFacets: string[]` + 卡片遍历登记面)
108
+ 只是把来源名从文案换成 id,机制仍长在消费方身上,故未采用;取舍过程写进 `docs/facet-protocol.md`。
109
+ - **refactor** 徽标设置卡片的开关顺序改为**与徽标画点一致**(待审批 → 进行中 → 已完成)。此前是
110
+ 进行中 → 待审批 → 已完成,而徽标与悬停明细都是待审批在前;用户的操作场景恰是"我看到徽标第 N 个图标,
111
+ 想关掉它"。同一族毛病 #25① 已在点行与明细之间修过一次,卡片是当时漏掉的第三个面。单一事实来源是
112
+ `badge-field.ts` 的 `ALL_BADGE_FIELDS`,并由 `tests/badge-settings-card.client.spec.tsx` 钉住
113
+ (含"卡片文案里不得出现任何提供方名字与形状词")。
114
+ - **refactor** 删除 `facetVisibleBySettings` 与 `facet-visibility.ts`;`useVisibleFacets` 更名
115
+ `useRegisteredFacets`(它不再筛任何东西,只负责"订阅 + 读登记面",见下一条目为何必须收进一个 hook)。
116
+
117
+ - **fix** 提供方**晚于首渲染**注册的状态源永远进不了折叠徽标:`WorkspaceBrowser` 订阅了
118
+ facet 存储,却把 `useSyncExternalStore` 的返回值丢掉,`useMemo` 的依赖里只有设置项——
119
+ 于是登记面变化只换来一次重渲染,渲染算的仍是**上一次**的登记面。表现是「徽标少一家、
120
+ 无任何报错、刷新页面就好了」,而刷新只是碰巧让注册赶在了首渲染之前。宿主不保证插件
121
+ `apply` 与侧栏挂载的先后,所以这条按加载时序随机命中。修法是把订阅 + 读表 + 按设置筛
122
+ 收进 `use-visible-facets.ts` 一个 hook,让"只用信号、不用值"在结构上写不出来。这条接缝
123
+ 此前测不到(能渲染整条路径的 `tests/workspace-browser.client.spec.tsx` 在本仓库是跳过的),
124
+ 新增 `tests/use-visible-facets.client.spec.tsx` 5 例覆盖,并用变异测试验过非空洞性:把依赖
125
+ 里的版本号拿掉,「晚到的注册」与「晚到的注销」两条会红。
126
+ - **fix** 登记面从**模块级**单例改为挂在 `globalThis` 上的**进程级**共享表。宿主热替换只
127
+ 换代被替换的那个模块(`dsh-client-modules` 的 `invalidate()` 不级联到依赖方,也不重跑
128
+ 别人的 `apply`),于是本插件一旦被换成新实例就持有一张**空表**:提供方那一次性登记留在
129
+ 被丢弃的旧表上,徽标从此少一家,且只有刷新页面才好。开发环境用 `link:` 装插件、反复
130
+ 重建 `lib/`,这条几乎必然发生。现在换代只是"再拿一次同一张表";`registerGroupStatusFacet`
131
+ 也改为**现取**当前那张表,而不是用模块加载时抄下的引用。那把全局键同时是现场诊断入口:
132
+ `globalThis.__dshGroupStatusFacetRegistry__.list()` 一眼看出注册到底落没落,判据写进
133
+ `docs/facet-protocol.md` 新增的「登记面的生命周期」一节。
134
+ - **test** `tests/facets.node.test.mjs` 补 3 例:共享表重复取不新建、模块级 `registry` 常量
135
+ 就是那张共享表、换代后新注册只落新表不落被丢弃的旧表。
136
+
9
137
  ## 0.4.0 — 2026-10-20
10
138
 
11
139
  - **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 source 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.
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, settingKey, order, // all optional
105
+ merge, label, renderIcon, order, // all optional
104
106
  })
105
107
  ctx.effect(() => () => unregister?.(), 'my-plugin: group status facet')
106
108
  ```
@@ -178,12 +180,14 @@ dsh plugin --profile web remove dsh-group-status
178
180
 
179
181
  | Item | Value |
180
182
  |---|---|
181
- | DSH core | `0.2.1-rc.2` |
182
- | peer dependency | `@deepseek-ai/cordis ~4.0.5` |
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` |
183
185
  | Upstream base | `@deepseek-ai/dsh-client-ui-workspace 0.2.1-rc.2` (source vendored into `src/`) |
184
186
  | Install shape | fork override: same slots registered, stock row disabled via `cordis.patch.yml` |
185
187
  | Optional partners | dsh-later (schedule summary), dsh-gitea-dispatch (waiting-review summary) |
186
188
 
189
+ Those 12 peers are not metadata. Cores at or below 0.2.0 **do not read `engines.dsh`** — they judge compatibility purely from `@deepseek-ai/dsh*` peer ranges. Without the enumeration, 0.2.0 considers this package compatible and installs it; that generation never published `@deepseek-ai/dsh-api-remote-access`, so the client `inject` for `remoteAccess` never resolves, the fiber stays pending, `uiWorkspace` is never provided, and `ui-sidebar` / `ui-conversation` / `ui-chat` — 12 entries in all — fail to activate. The page becomes "Failed to load plugins" and the user loses the entire sidebar. With the peers declared, 0.2.0-rc.2 measured as `skipping profile bundle`, and the host is unharmed; from 0.2.1 on, `engines.dsh` decides alone and peers are ignored, so in-window generations are unaffected.
190
+
187
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.
188
192
 
189
193
  ---
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
- 按状态关掉后,对应的来源完全退出折叠行的聚合提示——不画点/图标、不计入徽标数字、不进悬停明细、不参与「是否显示徽标」的判断。**会话行自身的状态点不受影响**:那是行级状态,不是分组提示。`showHoverDetails` 关闭后,悬停卡只显示标题、路径与创建时间。
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, settingKey, order, // 全部可选
107
+ merge, label, renderIcon, order, // 全部可选
106
108
  })
107
109
  ctx.effect(() => () => unregister?.(), 'my-plugin: group status facet')
108
110
  ```
@@ -180,14 +182,18 @@ dsh plugin --profile web remove dsh-group-status
180
182
 
181
183
  | 项 | 值 |
182
184
  |---|---|
183
- | DSH 内核 | `0.2.1-rc.2` |
184
- | peer 依赖 | `@deepseek-ai/cordis ~4.0.5` |
185
+ | DSH 内核 | 声明 `>=0.2.1-rc.2 <0.3.0-0`;实测 `0.2.1-rc.2` / `rc.3` / `rc.4` 全绿 |
186
+ | peer 依赖 | `@deepseek-ai/cordis ~4.0.5` + 12 个 `@deepseek-ai/dsh-*`,范围 `^0.2.1-rc.2` |
185
187
  | 上游基线 | `@deepseek-ai/dsh-client-ui-workspace 0.2.1-rc.2`(源码已 vendored 进本仓库 `src/`)|
186
188
  | 安装形态 | fork 覆盖包:同槽位注册 + `cordis.patch.yml` 禁用官方行 |
187
189
  | 可选搭档 | dsh-later(定时任务摘要)、dsh-gitea-dispatch(等待评审摘要)|
188
190
 
191
+ peer 里那 12 条**不是元数据**:≤0.2.0 的内核不读 `engines.dsh`,只按 `@deepseek-ai/dsh*` peer 的范围判兼容。不逐条声明时,0.2.0 会把本包判成「兼容」并装进去 —— 而那一代没有 `@deepseek-ai/dsh-api-remote-access`,客户端 `inject` 的 `remoteAccess` 永远拿不到,fiber 永久 pending,`uiWorkspace` 不再被提供,`ui-sidebar` / `ui-conversation` / `ui-chat` 等 12 条一起不激活,**整页 "Failed to load plugins",用户失去整个侧栏**。声明之后,0.2.0-rc.2 实测是内核直接 `skipping profile bundle`,宿主不受损;而 0.2.1 起 `engines.dsh` 命中即返回、peer 不参与判定,窗口内代次不受影响。
192
+
189
193
  上游一换代就得按[升级手册](./docs/upgrading.md) rebase 一次;上游改槽位名、组件签名或上下文契约时,本包不会自动跟上。
190
194
 
195
+ 其中**会静默失效**的那部分(我们认的待处理 kind 集合、我们从宿主读的两个状态事实)有守卫兜着:`tests/host-pending-kinds.node.test.mjs` 直接读锁定版宿主的实现来比对,宿主一改就红;人看的版本是 `pnpm check-upstream`(加 `--latest` 还能查 npm 上已发布的最高版)。
196
+
191
197
  ---
192
198
 
193
199
  ## 开发