dsh-m 0.9.17 → 0.9.19

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 ADDED
@@ -0,0 +1,435 @@
1
+ # 更新日志 · Changelog
2
+
3
+ dsh-m 的完整版本历史,双语维护:**中文在前,英文在后**,同版本号对齐;各语言区块内按版本倒序排列。发版时请在两个区块各补一条目。
4
+
5
+ The full release history of dsh-m, maintained bilingually: **Chinese first, English second**, aligned by version; entries within each section are newest-first. When releasing, prepend an entry to both sections.
6
+
7
+ ---
8
+
9
+ ## 中文
10
+
11
+ ### 0.9.19 变更:供应链等待期「锁文件校验」实证修复——委派前预检 + 全量违规解析 + 账实分裂明示
12
+
13
+ - **根因(本机 2026-10-03 00:15 实证)**:pnpm 11.7 对 desktop profile 做**锁文件级**供应链校验(`Verifying lockfile against supply-chain policies (180 entries)`),而它给每次成功安装自动追加的 `minimumReleaseAgeExclude` **非 scoped 独立精确条目不被这次校验认可**(`dsh-m@0.9.18` 即被拒;scoped 的 `'@iasiv5/dsh-quota-watch@0.1.13'` 则认可)——装过一个「太新」版本后,**等待期内任何官方包操作都会被这个旁包条目拦死**,与本次目标无关;且校验失败前目标包已被写入 node_modules、官方管理器只回滚 manifest/lockfile → 界面显示新版 active、操作记录却是失败(**「账实分裂」**),下次包操作还会把插件静默回退。
14
+ - **委派前预检(`releaseAgePrecheck`,只读、零文件级红线不破、fail-open)**:npm 源安装/升级在委派官方管理器前,对目标版本与锁内「不被校验认可的独立精确排除条目」逐个核对 registry 发布时刻,任一未满等待期 → 结构化 `release-age-wait` 拒绝(含各自可重试时刻),不再产生半写状态;发布时刻不可得 / 策略不可读 / 命中有效排除条目(包名级、`||` 复合、scoped 独立精确)→ 放行,pnpm 仍是最终执行者。
15
+ - **失败翻译换新(替代 0.9.10 单条解析)**:解析全部违规条目,按「本次目标 vs 锁内旁包」分述发布时刻与可重试时刻——旁包连坐不再被冒充成目标被拦;移除「改用 DSH Web 安装」的失配指引。`DesktopOpsError` 新增结构化 `details`(violations/targetViolating/splitState/blockers)。
16
+ - **账实分裂复读**:等待期失败后复读实装状态,node_modules 已是目标版本而 manifest 仍旧版时,在错误信息中明示「下次包操作会回退到旧版,等待期满重新升级即可对齐」。
17
+ - **接线**:desktop install / self-upgrade 调用点补穿 `profileDir`(升级路径此前已有)。
18
+
19
+ ### 0.9.18 变更:精选收录 DSH Market + README 重构与变更日志外迁
20
+
21
+ - **新收录 DSH Market**(npm `dshmarket`,精选 18→19):三方可视化插件市场——浏览、搜索社区插件并一键安装,主题一键热切换;主桶装机必备、次桶崔添翼精选(`alsoCategories` 次级归属)。文案按收录规范三句式,三方条目不设 `verified`。
22
+ - **文档面重构**:README/README.en 重写为精简结构(亮点、TOC、环境要求、文档索引、支持矩阵 FAQ),推荐安装路径改为 DSH 官方插件管理界面(附截图与升级限制提示);本变更日志自 README 外迁(双语维护);Desktop FAQ 对齐 0.9.8 后能力面;DESIGN §3/§12 补实机核验与实测代际记录。
23
+ - **附带**:registry 守卫测试条数 18→19;`package.json` files 新增 CHANGELOG.md 随包发布。
24
+
25
+ ### 0.9.17 变更:策展桶次级归属(一插件跨桶)+「iasi自研」更名
26
+
27
+ - **次级归属 `alsoCategories`**:收录条目可声明次级策展桶——chips 计数与桶过滤按「主桶 ∪ 次桶」计(跨桶条目在每个桶里都出现),详情页分类标签仍随主桶。首批双席位:**better-sidebar**(装机必备 ⊕ 崔添翼精选)、**dsh-m**(装机必备 ⊕ iasi自研);better-sidebar 原第 5 个「崔添翼精选」tag 由真实席位取代(tags 回归 ≤4 软规范)。
28
+ - **更名**:策展桶「我的自研」→「**iasi自研**」(slug `self-dev` 不变,chips/工具/CLI/详情标签四端同步)。
29
+ - **例行过渡**:schema 加字段后旧客户端校验拒收新 registry → 回落缓存/包内快照显示旧数据,升级即愈。
30
+
31
+ ### 0.9.16 变更:精选策展五桶分类法 + 严筛收录(23→19)+ 新收录 DSH TUI
32
+
33
+ - **策展分类法**:精选区分类从功能五分类(市场/工具/界面/搜索/其他)改为**策展五桶**——装机必备 / 崔添翼精选 / iasi自研 / 腾讯轻量云专区 / 观察区(chips 按此序,腾讯轻量云垫后)。分类语义从「插件是什么」转为「为什么值得进精选」;重叠归属按 装机必备 > 崔添翼精选 > 自研 > 腾讯轻量云 优先级归桶,功能属性转 tags 保留检索,旧分类值仍可作开放 slug 命中自定义源(ADR-0004 修订)。
34
+ - **严筛收录 23→19**:通道五件套(lark/qqbot/weixin/wecom/dingtalk)退出精选——社区层(4,000+ 条)仍收录可装,只是退出策展位;新增收录 **DSH TUI**(崔添翼 9/26 X 推荐:终端 TUI 客户端,`dsh-tui`,走 DSH 客户端契约 ctx.remote);better-sidebar 因优先级归装机必备,以 tag「崔添翼精选」保留 9/27 推荐出处。
35
+ - **同版本携带**(本地增强随发版收编):desktop 安装 enable 阶段失败自动重试一次(高频装卸/插件树重载竞速实证)+ 失败文案按 packageResult 精确化;市场页「缓存快照」横幅退役——stale 状态由设置页社区卡承接,浏览页不再提示临时缓存状态。
36
+
37
+ ### 0.9.15 变更:安装进度/终态就地进详情 Modal
38
+
39
+ - **场景**:从详情 Modal 点「安装」后,安装信息(pnpm 阶段进度行、「变更完成」横幅/toast)都渲染在面板底层,隔着 Modal 遮罩半透明透出——弹窗内只有按钮转圈,看不出装到哪一步(实机截图反馈 2026-10-02)。卸载无此问题:不弹 Modal,状态本来就挂在已装卡片上。
40
+ - **变更**:安装进行中,Modal 内直接挂进度行(复用 host status 轮询:阶段/进度条/当前包);终态在 Modal 内就地显示结果行——成功附版本与构建脚本说明 + 重启提示(desktop 给官方应用生命周期指引),失败/守卫拦截附原因且按钮回到可重试,「已跳过」中性呈现;Modal 打开时底层同源进度行让位(关闭 Modal 后照常回归)。信息全部派生自全局操作记录与安装结果,「状态不挂卡片」的所有权模型不变(DESIGN §2.6)。
41
+
42
+ ### 0.9.14 变更(市场秒开四件套 + 详情 Modal 安装命令显隐)
43
+
44
+ - **市场秒开四件套**:针对「每次打开市场必现『加载收录清单中…』」的加速组合拳——
45
+ - **SWR 先回缓存**:精选清单与社区目录的 TTL 过期不再同步等网络——磁盘缓存存在即**立即返回快照**(社区侧照常显示「缓存快照」横幅,绝不冒充最新),后台单飞自愈,下次打开即新;「强制刷新」按钮语义不变(始终同步强刷,社区卡不连坐)。
46
+ - **线路粘性**:默认双线路(GitHub 原始文件 → jsDelivr 镜像)按缓存记录的**上次成功线路**排序——镜像成功过就先走镜像,不再每次白等主线路失败(大陆网络实测每次冷打开省 10-20s 等待)。
47
+ - **探测缓存落盘**:页条目 npm/GitHub 版本探测缓存从纯内存改为磁盘信封(`latest/`,跨重启存活)——DSH 服务重启后首次打开市场不再重放探测。
48
+ - **客户端快照**:默认首页响应存浏览器本地(10 分钟 TTL),打开面板先渲染上次数据再后台换新——加载 spinner 仅首次使用(无任何快照)出现。
49
+ - **详情 Modal「安装命令」折叠行按上下文显隐**:
50
+ - **场景**:折叠行命令推导写死 `dsh plugin --profile web add …`,社区条目的上游 install 原文也同为 --profile web 语义——两个来源都不看当前宿主 profile。desktop 上下文里照抄会把包装进 web profile(当前界面看不见);已安装条目还挂着命令纯属噪音(实机截图实证:desktop + dsh-m 自身条目,`已安装` 徽章与命令同屏)。
51
+ - **变更**:desktop 上下文与已安装条目**整行隐藏**;web 未安装条目行为不变(CLI bootstrap 路径保留,「30 秒上手」同款命令)。desktop 装机正路是弹窗内「安装」按钮(官方 pluginManager 委派,ADR 0005 纪律)。不做「精简命令去掉 --profile」——显式 `--profile web` 是 0.9.0 拍板的设计(README「profile 目标」节),裸命令的默认 profile 语义含糊,精简反而更差。
52
+
53
+ ### 0.9.13 变更:desktop 角标悬停文案更新(主人拍板)
54
+
55
+ - 旧文案「当前 DSH profile:{name}(Desktop 首发仅支持只读市场、安装新包与开关)」在 0.9.8 开放升级/卸载/自升级后已过时;按主人拍板改为「**当前生效 Profile**」(en: Active profile)。
56
+
57
+ ### 0.9.12 变更:0.9.11 的重发
58
+
59
+ 0.9.11 在 npmjs 遭遇幽灵发布:OIDC 发布被受理并 **staged**(CLI exit 0、provenance 已上 Transparency Log),但从未 commit 进注册表——GET 404、同版本重发 409 `Cannot publish over previously staged version`。等待自愈无果后按标准解法换号重发。**内容与 0.9.11 完全一致:设置页「强制刷新」不再连坐社区清单卡。**
60
+
61
+ ### 0.9.11 修复:设置页「强制刷新」不再连坐社区清单卡(force 语义只属精选链)
62
+
63
+ - **场景**:弱网下点精选清单的「强制刷新」,社区清单卡跟着变「不可用 + 获取超时」——根因是 host 把 `force` 一路透传给社区目录 summary,强制重开获取 flight;弱网下 flight 3s 完不成,waiter 超时返回占位摘要(flight 本身在后台 30s hard cap 内继续,跑完即自愈)。
64
+ - **修复**:`registry` 的 force 不再透传社区 summary——「强制刷新」语义只属精选链(registry 链);社区目录走自己的 TTL/共享 flight(首次打开等边界场景在极差网络下仍可能瞬时超时,但强刷不再触发)。
65
+
66
+ ### 0.9.10 修复:Desktop 自升级撞上官方供应链等待期(minimumReleaseAge)→ 诚实指引发成可读
67
+
68
+ - **场景**:点升级角标走官方管理器时,desktop profile 的 pnpm 供应链策略(`minimumReleaseAge`,发布满 24h 才可安装)拒绝了刚发布的版本——`ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION`。**这是策略在正确工作**(防供应链攻击的发布等待期),不是故障;但 dsh-m 此前把它当普通失败甩一屏 pnpm 原文。
69
+ - **修复**:管理器结果判定识别该策略码,翻译成诚实指引——点名等待期内的条目与发布时刻、按策略推算「预计何时可重试」,并给出等待期内的替代路径(DSH Web 安装同版本)。绝不做策略绕过(等待期是防供应链攻击的红线,dsh-market #732 同态度)。
70
+ - 附带:community 获取链 ⑨ 的挂起上限断言 2s→10s(全量套件并行定时器饥饿下两次闪断;契约「不永久挂起」不变)。
71
+
72
+ ### 0.9.9 修复:备用线路接住后不再弹红色「主线路失败」提示(提示收敛)
73
+
74
+ - **场景**:默认精选清单双线路(raw → jsDelivr)里主线路 `default-raw` 失败、备用线路成功接管时,设置页仍弹红色「远端提示:default-raw 失败:fetch failed…可稍后重试或检查网络后重试」——对着已经自愈的数据报警,还带着不成立的建议(大陆网络下 raw 间歇不可达是常态,这正是备用线路存在的原因)。
75
+ - **修复**:后续线路成功 = 先行失败已自愈,`errors` 不再携带(设置页「生效来源」行已如实标注当前线路,如「GitHub 镜像(备用)」);全线路失败落 cache/bundled 时错误照常保留——那才是需要行动的信号。custom 链(自定义源失败回退缓存)行为不变,仍然提示。
76
+ - 顺带补了 default 链的测试缝(`defaultRoutes` 覆写),双线路收敛与全挂保留各有回归门。
77
+
78
+ ### 0.9.8 修复:Desktop 包操作全面接通官方管理器(安装恒 no-manager;升级/卸载/自升级开放)
79
+
80
+ - **安装恒失败的根因**:Host API 的 desktop 安装分支调 `desktopInstall(id, cfg, opts)` 漏传第 4 参 deps——`getService` 根本没进适配器,desktop 安装恒报「官方 pluginManager 服务不可用(fail-closed)」(100% 必现,与时机无关)。工具面 `dshm_install` 同病。
81
+ - **服务解析与 dsh-market 同源**(借鉴其 official-desktop 接线,本机两轮覆盖安装实证):探测改双上下文(webServer 注入回调的 hostCtx 优先)+ cordis inject 惰性拉起兜底(短超时)——官方 pluginManager 是惰性服务,未被拉起前一次性 get 恒 undefined;仍缺席才结构化拒绝(绝不文件级回退的红线不动)。
82
+ - **能力表扩充(主人裁决,借鉴 dsh-market 策略)**:desktop 的 upgrade(installBundle 覆盖安装)/ uninstall(removeBundle)/ self-upgrade(installBundle('dsh-m@latest'))全部开放——dshmarket 正是这样完成 dsh-m 0.9.3→0.9.4/0.9.5 两轮升级的;判定纪律沿用(application/stage 为准、overridden 非失败、build-blocked 结构化回传 pendingBuilds、listBundles 复读不冒充成功)。restart 继续拒绝(Electron 生命周期归官方壳)。
83
+ - GUI 与工具面(dshm_install / dshm_uninstall / dshm_upgrade)三入口同批接线。
84
+
85
+ ### 0.9.7 修复:Desktop 下点升级角标弹红色「升级失败」(能力表拒绝应为指导而非报错)
86
+
87
+ - **根因**:0.9.1 的升级角标点击后一律调 `self-upgrade`;Desktop 能力表按设计 409 结构化拒绝,但客户端把 409 当普通失败渲染成红色「升级失败」横幅——按能力表这根本不是失败,是「该走官方入口」的指引。
88
+ - **修复**:`api()` 透传能力表拒绝的结构化字段(code/action/profile/guidance),角标点击收到 409 时改出**中性 info 横幅**展示官方入口指引(guidance 单一事实源仍在服务端 `active-profile.ts`,客户端零复制);info 横幅停留 12s。Web 端真实失败仍走红色 err 横幅,行为不变。
89
+
90
+ ### 0.9.6 修复:「清除已完成」对失败记录无声 no-op
91
+
92
+ - **根因**:0.7.0 评审共识把「失败/已跳过」排除在清除范围外(保留供回看),于是按钮对着一条失败记录点击毫无反应、也无任何反馈——Windows 实机被当成 bug 上报(2026-10-01)。显式点击清除不是「静默抹掉」,旧共识被推翻。
93
+ - **修复**:「清除已结束」(原「清除已完成」)现在清除**全部终态**(done/warned/failed/superseded),在途态(queued/running/input)不受影响;没有可清终态时按钮置灰并带说明 tooltip,不再无声 no-op。单条 ✕ 照旧逐条删除。
94
+ - **英文文案**同步改为 "Clear ended"。
95
+
96
+ ### 0.9.5 修复:Desktop 下 GUI 读路径漏接 active profile(已装页恒显 web)
97
+
98
+ - **根因**:0.9.0 双 profile 接线时,Host API 的 `installed` / `market` 两个读路径漏传 active profile——`listInstalledWithMeta` / `listMarket` 内部落回 `webProfileDir()`:Desktop 下已装页恒显「web profile 尚未安装任何插件」、市场「已安装」徽标恒空(agent 工具面 `dshm_list` 同链路已接线,故只有 GUI 错)。
99
+ - **修复**:两处补齐 `profileDir: profile.dir` + `profile: profile.name`(与 tools 面同款,profileContext 单一事实源);registry/社区缓存随 `profile` 参数自动落到 desktop 段。
100
+ - **文案**:已装空态/加载态与 profile 提示里的「web profile」硬编码改为 profile 中性表述(实际路径照旧展示)。
101
+
102
+ ### 0.9.4 修复:Windows Desktop 全屏后头部不可点(tab / 还原键被系统标题栏吞掉)
103
+
104
+ - **根因**:Desktop(Windows)以 `titleBarStyle:hidden + titleBarOverlay` 运行——窗口顶部 40px 是壳的全宽 `-webkit-app-region:drag` 拖拽带(按布局参与拖拽判定、无视 z-index 与绘制顺序),右上角另有系统绘制的 — □ ✕ 悬浮于一切内容之上。面板全屏后头部(tab、还原/关闭键)正好落进这条带:点击被窗口拖拽吞掉、还原键被系统键遮挡,全屏无法退出。
105
+ - **修复**:与壳自家 overlay 同款对策——消费壳在 `html` 上设的 `--dsh-windows-titlebar-height` 让出该带(全屏态 `top:var(…)`;浮动态 `padding-top:max(24px,var(…))` 顺带修掉矮窗口下浮板顶边被带压住的边缘情况)。
106
+ - **Web 零漂移**:DSH Web / 浏览器无此变量,回落 0px,行为与 0.9.3 完全一致。
107
+
108
+ ### 0.9.3 修复:Windows 原生适配(Windows 宿主实机回归)
109
+
110
+ - **registry 原子写**:临时文件名此前用 `split('/')` 从绝对路径取尾段,而 Windows 路径分隔符是 `\`——取到的是整条路径(内嵌 `\` 即目录分隔符),临时文件 open 必败且被吞,cache 与 accepted metadata 写入**静默全失败**;改用 `basename()`,三平台一致。
111
+ - **本地文件清单地址解析**:`C:\…` 盘符与 `\\server\share` UNC 此前被误当 URL scheme(报「只允许 HTTPS」的误导性错误),`file://C:/…` 会归一成无盘符悬空路径必 ENOENT;现 POSIX 绝对 / Windows 盘符 / UNC 三形态均正确解析为 file kind。
112
+ - **构建**:`node_modules/.bin/tsc` 是 POSIX sh shim,Windows 下 `spawnSync ENOENT`;改用当前 Node 直跑 TypeScript 的 JS 入口,`npm run build` 三平台一致。
113
+ - **测试面**:Windows 实机全量 829 用例 41 败 → **0**(821 pass / 8 skipped);POSIX 进程组/SIGTERM 时序、symlink 权限、平台路径断言、固定 sleep 时序假设逐项标注 skip 或平台无关化/有界轮询,测试契约不变。
114
+
115
+ ### 0.9.2 修复:跨服务重启后头部角标停留旧版本
116
+
117
+ - **一键重启确认新进程后就地刷新**:boot id 确认 DSH Web 已恢复的瞬间,面板立即重取 ping——`dsh-m vX.Y.Z` 角标与 profile chip 同步到新进程数据,不再停留旧版本(0.9.1 实测:芯片升级 + 重启后仍显 v0.9.0)。
118
+ - **页面回前台时重取**:面板常开、服务在后台被外部重启的场景,`visibilitychange` 回前台即重取 ping(零轮询成本)。
119
+ - **角标版本护栏**:self-check 判定携带的版本与当前进程不符(旧进程残留判定)时一律静默,杜绝「v0.9.1 ⬆ v0.9.1」式误渲染。
120
+
121
+ ### 0.9.1 新增:头部版本角标升级提示(有更新才点亮)
122
+
123
+ - **静默口径**:面板头部 `dsh-m vX.Y.Z` 角标常态维持 0.7.5 起的静态展示——已是最新、检查失败、本地 dev 版领先 npm(ahead)一律不打扰(ahead 仅在悬停 title 里提示「本地开发版」)。
124
+ - **仅 outdated 点亮**:`self-check`(npm latest vs 装机版本,只读)判定有新版本时,角标点亮为 warn 态并显示 `⬆ v<最新>`;点击即触发 `self-upgrade`(同一 mutation session + 装后守卫),成功后出「⚡ 一键重启」横幅。Desktop 下点击按能力表结构化拒绝(409,带官方生命周期指引)。
125
+ - **TTL 缓存 + 版本护栏**:检查结果在浏览器 localStorage 缓存 30 分钟,开面板不重复打 npm registry;升级重启后缓存按版本号自动作废。检查失败静默,不弹任何错误。
126
+
127
+ ### 0.9.0 新增:官方 Desktop(双 profile)支持
128
+
129
+ - **同一包、两个 profile**:dsh-m 现在可装入官方 Desktop 的 `desktop` profile(`~/.dsh/profiles/desktop`),与 Web 的 `web` profile 并列;市场目录、面板与 agent 工具同一套,管理对象始终是宿主当前 profile(官方 `profileContext` 单一事实源)。
130
+ - **入口信任检查改委派官方**:`/dshm` 全部 method(含 ping 与未知 method)在读取请求体之前委派官方 `connection.requestRejection()` 判定(trustedHosts / loopback / 跨站 / `Origin: null` 语义随宿主),被拒请求零 body 消耗、零业务调用;宿主缺该能力时 fail-closed 全拒。**行为变化**:旧版自制守卫「缺 Origin 一律 403」不再存在——Desktop 桥合法剥除 Origin 的请求按官方语义放行,无凭据的健康检查探针从「一律 403」变为「按宿主信任判定」。
131
+ - **Desktop 首发能力表**:只读市场 + **安装新包**(委派官方 `pluginManager.installBundle`,完整性/锁/生效相位归官方)+ **开关**(委派官方管理器,服务缺席结构化拒绝、绝不文件级 fallback);**升级 / 卸载 / dsh-m 自更新 / 一键重启**在 Desktop 结构化拒绝(409,带官方入口指引——官方暂无 upgrade API,重启归 Electron 生命周期);构建脚本按官方 `pendingBuilds` 名单精确重试,绝不全量放行。
132
+ - **读模型与缓存按 profile 隔离**:市场安装标注、已装列表、README 预览只读当前 profile;registry / 社区清单 / accepted-source 缓存按 profile 分段(web 沿用旧路径,零迁移零清空);收藏与操作记录按浏览器 origin 各自独立,Web 与 Desktop 不自动同步。
133
+ - **CLI 恒作用于 web profile**:`--profile web` 显式声明;`--profile desktop` 明确拒绝并指引官方 Desktop 插件管理页。
134
+ - **如实声明**:Desktop 实机(Win/macOS)E2E 未跑,`registry.json` verified 数组**不新增** Desktop 代际(实测后按收录纪律补录);Desktop 下不做 dsh-m 文件级装后守卫(app.asar 打包布局探测盲区),以官方结果判定 + `listBundles` 复读替代。
135
+
136
+ ### 0.8.5 修复
137
+
138
+ - **dshm_upgrade 守卫拦截假成功**:升级命中装后守卫拦截时(如 link/file 来源插件无法自动回退),文本输出误渲染为「✅ undefined 已升级(最新)」;现如实输出拦截原因、补偿终态与修复依据,与卡片标题(守卫拦截)一致。
139
+
140
+ ### 0.8.4 变更:分类标签随界面语言双语化
141
+
142
+ - **社区分类**:已知 23 个分类的英文名直接取上游目录 `categories.en`,英文界面下分类 chips 与详情/收藏 Modal 的分类行显示英文;缺英文名的上游新分类回退中文,仍按原样渲染进临时组,等发版收录。中文界面不变。
143
+ - **精选分类**:五个分类 chip 改走双语字典(市场/工具/界面/搜索/其他 ⇄ Market/Tools/UI/Search/Other),与详情 Modal 口径一致。
144
+ - **实现**:summary 新增 `categoryLabelsEn`(`communityOutcome` 从上游目录派生,缺 en 的 id 不进映射,不手养第二张表),客户端按界面语言合并取值。0.8.1–0.8.3 为本地迭代号,无独立变更面,不单列。
145
+
146
+ ### 0.8.0 变更:设置页重做(对齐双清单分区定位)
147
+
148
+ - **信息架构**:社区清单(from awesome-dsh-plugin)→ 精选清单(registry.json)→ dsh-m 自身 → 关于;「主清单」的 UI 可见名统一为「精选清单」。
149
+ - **社区目录开关**:新增 GUI 开关(live 生效,即时切换无确认;关闭态整卡收为一行说明);新增 `set-community` API。
150
+ - **精选清单瘦身**:状态字段 7 行收敛为 4 行(配置地址合并、删除写死的「缓存策略」行);「配置状态」仅异常时出现;按钮组精简为「强制刷新 / 校验并应用 / 恢复默认 / 下载默认 registry.json」,「检查条目可达性」从 GUI 移除(`registry-diagnose` API 保留)。
151
+ - **文案修正**:自定义源说明明确「整体替换主清单、仅影响『精选』区」;删除与实际不符的 TTL 写死描述(`timeoutMs`/`cacheTtlMin` 仍走 config 配置)。
152
+ - **dsh-m 自身**:本地 dev 版领先 npm 发布时改显「本地为开发版」而非误导性的旧「npm 最新」(新增 `ahead` 字段)。
153
+ - **关于**:文案对齐当前定位,新增 GitHub 仓库与问题反馈链接。
154
+
155
+ ### 0.7.10 美化
156
+
157
+ - **头部三段分组**:标题与 tab 导航之间加发丝竖分隔线,「标题 | 导航 | 状态+窗口控制」边界清晰。
158
+ - **版本角标同色**:v 版本号不再用主文字亮色,与 dsh-m 名称统一为次级灰。
159
+ - **垂直节奏收敛**:窗口控制组按钮 26→28px 与 tab 按钮等高;版本角标微调至 24px 高;最大化/还原图标统一 12px;标题字重 700→600。
160
+
161
+ ### 0.7.9 修复
162
+
163
+ - **分类 chips 顺序恒定**:退役「激活分类置前」的换序逻辑(此前每点一个被折叠裁掉的分类,它就会跳到首位,顺序随点击不断变化)。替换为:激活分类落在收起态裁剪区时自动展开完整分类行——「当前激活的分类始终可见」目标不变,顺序从此稳定;同一激活分类下手动收起会被尊重,换选其他被裁掉的分类或点「全部」时重置。
164
+
165
+ ### 0.7.8 变更
166
+
167
+ - **修复「最大化没作用」的根因——CSS 热更自愈**:面板样式表此前只在首次注入(`#dshm-css` 存在即跳过),服务热更后旧 bundle 留下的样式表不含新类名规则(全屏/窗口控制组),导致新功能「点了没反应」、按钮裸奔成原生样式。现给注入的样式表带内容哈希(djb2)版本标记,bundle 更新后重新打开面板即自动替换旧样式,无需刷新页面。
168
+ - **窗口控制组重新配色**:去掉浮起底色,改透明底 + 发丝外框(与搜索清除钮同一配色语言),单格加宽 34→44px 防误触;关闭悬停仍为红色警示。
169
+
170
+ ### 0.7.7 变更
171
+
172
+ - **移植 dsh-market 的全屏功能**:面板头部新增「最大化/还原」(连体窗口控制组设计:最大化 + 关闭等宽两格、发丝分隔线、统一 SVG 线条图标;关闭悬停红色警示)。全屏铺满视口、去圆角,状态 localStorage 记忆,Esc 关面板语义不变。
173
+ - 0.7.6 补记:版本角标去粗体、去点击复制(改静态展示);吸顶分类行上沿镂空修复(sticky 锚点上移抵消容器 padding);关闭/清除按钮改框线平面风。
174
+
175
+ ### 0.7.5 变更
176
+
177
+ - **头部版本 chip 改显 dsh-m 自身版本**(`dsh-m v0.7.5`,点击复制;DSH 运行版本看设置页与 `dshm ping`)。
178
+ - **× 关闭/清除按钮统一重绘**:搜索清除、详情 Modal 关闭、操作记录行移除三处改用 SVG 线条图标 + 悬停浅底的专用按钮样式;搜索清除钮悬浮于输入框右缘(胶囊内对齐)。
179
+ - **修复 dsh-market 的 peer 告警**:`@deepseek-ai/dsh-tools` peer 由 `*`(semver 严格口径不匹配 rc 预发布版本)改为显式 range `^0.1.7-rc.2 || ^0.2.0-rc.1 || >=0.2.0`;未来更新的 rc 线(如 0.3.0-rc.x)需再追加。
180
+
181
+ ### 0.7.4 变更
182
+
183
+ - **面板 tab 回退旧版分段按钮风格**(0.7.2 误改下划线样式,按主人要求还原圆角按钮组 + 高亮态)。
184
+ - **搜索框通长**:修复搜索容器缺 `display:flex` 导致输入框未拉伸的问题,恢复整行宽度。
185
+ - **筛选按钮与页号跳转控件重新配色**:筛选按钮改浮起面板底色 + 方角与分类 chips 区分(激活态品牌色描边);页号输入改胶囊形细描边,「跳转」用品牌色文字钮。
186
+ - **吸顶分类行彻底不透**:背景直接使用不透明底色 token(此前的 color-mix 半透明配方在深色主题下仍会透出下方卡片文字),保留底部分隔线。
187
+
188
+ ### 0.7.3 变更(含 0.7.2)
189
+
190
+ - **首页布局复刻 dsh-market**:市场页改为「分区 chips → 整宽搜索行 → 分类 chips + 行尾筛选弹层」结构;筛选弹层独立样式(方角矩形 + 前置 chevron),收纳排序字段(npm 下载量/Star 数/收录日期)、排列方向与每页条数(原排序下拉与分页器条数选择退役)。
191
+ - **收藏卡可点开详情**:修复收藏区卡片点击无响应——收藏快照字段不全,打开时按 id 从两分区内存 → market API → 快照三级解析完整条目,详情 Modal 与安装链路(含兼容确认)全量复用。
192
+ - **翻页页号跳转**:页码行新增页号输入框,输入有效页号回车或点「跳转」直达。
193
+ - **吸顶分类行毛玻璃**:滚动时吸顶的分类行加 backdrop blur 与底部分隔线,下方卡片文字不再透出干扰。
194
+ - **按需求移除**:「发现社区/申请收录」行(dsh-m 不支持收录功能)、「任务」按钮(操作记录面板恢复常驻)、「刷新」按钮(强制刷新在设置页)。
195
+ - 说明:收录条目不携带宿主版本要求字段,dsh-market 的「宿主版本」筛选项无数据源,未复刻。
196
+
197
+ ### 0.7.1 修复
198
+
199
+ - **社区条目可安装**:修复 0.7.0 回归——社区区里的条目点安装报「registry 中没有该条目」(安装按收录 id 只查主清单,未查社区目录);现与升级路径同构,主清单 miss 时按 id 查社区目录再装。
200
+ - **市场页第一行紧凑化**:搜索框、刷新、排序(社区区)并入分区 chips 行右侧;信息性来源横幅(「官方默认收录清单 / 自定义收录清单 / 来源为本地缓存」)退役——其「共 {count} 条」计数从未接线(恒显 0);错误态「收录清单不可用」与社区兜底/陈旧提示保留。
201
+
202
+ ### 0.7.0 新增
203
+
204
+ - **分区制市场**([ADR-0004](./docs/adr/0004-zoned-market-display.md)):数据层双清单合并不变,展示层按「社区(默认)/ 精选 / 收藏」三分区呈现;`dshm_search` 与 `dshm search` 改用 `--source community|primary|all` + `--offset` 真翻页(默认 10 条),`primary_only` 退役。
205
+ - **搜索相关性**:NFKC 归一化 + 中西文边界 + 字段加权(name/npm > owner > 描述 > 分类 > tags),多词同字段全命中;id 整串精确匹配最高优先。
206
+ - **操作记录 + 恢复执行器**、**本地收藏 + 下架清理**、**详情 Modal + 截图灯箱**、社区卡 byline/deprecated 徽章/目录版本快照兜底(不参与 outdated 判定)。
207
+
208
+ ### 0.4.0 新增
209
+
210
+ - **开关(Enablement Toggle)**:已装卡片一键启停,内部自动路由行覆盖(单行插件,即时生效)或 Bundle 选择(多行插件);写路径委派官方 `pluginManager` 服务、缺席时降级 loader 直操作([ADR-0001](./docs/adr/0001-delegate-with-fallback-for-plugin-manager.md))。
211
+ - **运行相位徽标**:loader fiber 状态投影,failed 一眼可见。
212
+ - **保护名单**:`dsh-m` 自身与官方宿主命脉 16 项不可开关、不可卸载(升级不受影响)。
213
+ - **精确构建放行**:needs-builds 拦截后按 pnpm 待决名单逐键放行,全量放行降为兜底并如实标注([ADR-0002](./docs/adr/0002-precise-build-approval.md))。
214
+ - **peer 兼容预检**:安装/升级前校验 `@deepseek-ai/dsh(-*)` peers 与运行时版本(GitHub 源明示未检);不兼容时 GUI 弹确认、agent 回结构化结果、CLI `--force`。
215
+ - **实测版本清单(verified)**:registry 条目可选 `verified` 数组记录实测过的 DSH 运行时版本——实测声明而非预测声明,只展示不拦截。
216
+ - **bundle 身份验证**:装后检测无补丁层的包并警告「已装入为纯依赖」。
217
+
218
+ ### 0.4.x 退役
219
+
220
+ - **元数据源竞速**:0.4.0 曾引入 npmjs / npmmirror ping 竞速选择元数据读取源,现整体移除(含 `probeEnabled` / `probeTimeoutMs` / `probeCacheTtlMin` 三个设置项与设置页展示)。官方同款探测只服务于「安装对话框 registry 默认预选」,dsh-m 无此交互;实测宿主机 npmjs 稳定更快,探测恒等默认行为。元数据读取固定走 npmjs,与安装链路(profile `.npmrc` 默认源)一致。
221
+
222
+ ---
223
+
224
+ ## English
225
+
226
+ ### Changed in 0.9.19 — supply-chain release-age: pre-delegation gate, full violation parsing, split-state disclosure
227
+
228
+ - **Root cause (observed 2026-10-03 00:15 on this machine)**: pnpm 11.7 runs a **lockfile-wide** supply-chain verification on desktop installs (`Verifying lockfile against supply-chain policies (180 entries)`), and the standalone exact `minimumReleaseAgeExclude` entries it auto-appends after each successful install are **not honored by that verification when unscoped** (`dsh-m@0.9.18` flagged; scoped `'@iasiv5/dsh-quota-watch@0.1.13'` honored) — so one freshly installed version bricks every package operation for 24h, regardless of the current target. The target package gets written into node_modules before the verification fails while the official manager rolls back only manifest/lockfile → **"split state"**: the UI shows the new version active, the operation record says failed, and the next operation silently downgrades the plugin.
229
+ - **Pre-delegation gate (`releaseAgePrecheck`; read-only, fail-open)**: npm installs/upgrades now check the target version and untrusted lockfile exclude entries against registry publish times **before** delegating; anything inside its waiting window is refused up front as structured `release-age-wait` with per-entry ready times — no more half-written states. Missing publish data / unreadable policy / entries covered by effective selectors (package-level, `||` compound, scoped standalone exact) → proceed; pnpm remains the final enforcer.
230
+ - **Failure translation rewritten** (replacing the 0.9.10 single-match parser): all violations are parsed and reported as "target vs lockfile bystanders" with their own publish times and retry deadlines; the misleading "install via DSH Web instead" hint is gone. `DesktopOpsError` gained structured `details` (violations/targetViolating/splitState/blockers).
231
+ - **Split-state re-read**: after a release-age failure the installed state is re-read; when node_modules already holds the target version while the manifest still records the old one, the error explains the upcoming silent downgrade and how to converge.
232
+ - **Wiring**: desktop install / self-upgrade call sites now pass `profileDir` (upgrade already did).
233
+
234
+ ### Changed in 0.9.18 — DSH Market added to Curated + README restructure, changelog extracted
235
+
236
+ - **DSH Market added** (npm `dshmarket`, Curated 18→19): a third-party visual plugin market — browse, search community plugins, and one-click install; one-click live theme switching. Primary bucket Essentials, secondary Cui's Picks (via `alsoCategories`). Copy follows the registry guide; third-party entries carry no `verified` claims.
237
+ - **Docs restructure**: README/README.en rewritten into a lean shape (highlights, TOC, requirements, documentation index, support-matrix FAQ); the recommended install path is now DSH's official plugin manager (with a screenshot and the upgrade caveat); this changelog moved out of the READMEs (bilingual); the Desktop FAQ reflects the post-0.9.8 capability table; DESIGN §3/§12 gained live-verification and tested-generation records.
238
+ - **Also**: the registry guard test moved 18→19; CHANGELOG.md now ships in the npm package (package.json files).
239
+
240
+ ### Changed in 0.9.17 — secondary curated-bucket membership (one plugin across buckets) + the "iasi自研" rename
241
+
242
+ - **Secondary buckets `alsoCategories`**: curated entries can now declare a secondary curated bucket — chip counts and bucket filtering count "primary ∪ secondary" (a cross-bucket entry appears in every bucket it belongs to), while the detail page's category labels still follow the primary bucket. First dual seats: **better-sidebar** (Essentials ⊕ Cui's Picks) and **dsh-m** (Essentials ⊕ iasi In-house); better-sidebar's former fifth "崔添翼精选" tag is replaced by the real seat (tags return to the ≤4 soft rule).
243
+ - **Rename**: curated bucket "我的自研" (My in-house) → "**iasi自研**" (slug `self-dev` unchanged; synced across chips / tools / CLI / detail labels).
244
+ - **Routine transition**: once the schema gains a field, old clients reject the new registry on validation → they fall back to cache / bundled snapshot and show old data; upgrading fixes it.
245
+
246
+ ### Changed in 0.9.16 — curated five-bucket taxonomy + stricter curation (23→19) + DSH TUI added
247
+
248
+ - **Curated taxonomy**: the Curated zone's categories change from the functional five (Market/Tools/UI/Search/Other) to five curated buckets — Essentials / Cui's Picks / iasi In-house / Tencent Lighthouse / Watchlist (chips in this order, Tencent Lighthouse last). Category semantics shift from "what the plugin is" to "why it deserves curation"; overlapping membership is bucketed by priority Essentials > Cui's Picks > In-house > Tencent Lighthouse, functional attributes move into tags for search, and old category values still hit custom sources as open slugs (ADR-0004 revision).
249
+ - **Stricter curation 23→19**: the channel five (lark/qqbot/weixin/wecom/dingtalk) leave Curated — still listed and installable in the community layer (4,000+ entries), just off the curated stage; **DSH TUI** is added (Cui's 9/26 X recommendation: a terminal TUI client, `dsh-tui`, speaking the DSH client contract ctx.remote); better-sidebar is bucketed to Essentials by priority and keeps its 9/27 recommendation provenance via the "Cui's Picks" tag.
250
+ - **Same-version carry-over** (local enhancements folded into the release): desktop installs retry the enable stage once on failure (proven against high-frequency install/uninstall and plugin-tree reload races) + failure copy keyed precisely to packageResult; the market page's "cached snapshot" banner retires — stale status is now carried by the settings page's community card, and browse pages no longer show transient cache state.
251
+
252
+ ### Changed in 0.9.15 — install progress/result now live inside the detail modal
253
+
254
+ - **Scenario**: clicking Install in the detail modal rendered all install feedback (the pnpm phase line, the "changes applied" banner/toast) on the panel layer beneath, half-visible through the modal mask — inside the modal the button just spun, with no sense of progress (live screenshot feedback, 2026-10-02). Uninstall never had this problem: no modal is involved and status already lives on the installed card.
255
+ - **Change**: while an install runs, the modal hosts the progress line itself (same host-status polling: phase / bar / current package); terminal states render an inline result row — success with version + build-script notes and a restart hint (desktop gets the official app lifecycle guide), failure / guard block with the reason and a re-enabled retry button, "skipped" presented neutrally; while the modal is open the underlying twin line steps aside (and returns once the modal closes). Everything still derives from the global operation log and the install result — the "state lives off cards" ownership model is unchanged (DESIGN §2.6).
256
+
257
+ ### Changed in 0.9.14 (instant-open quartet + context-aware "Install command" row)
258
+
259
+ - **Instant-open quartet** — a fix combo for the marketplace spinner that used to show on every panel open:
260
+ - **SWR (serve-stale-while-revalidate)**: expired TTL no longer blocks on the network — the disk cache is returned immediately as a snapshot (the community zone keeps its honest "cached snapshot" banner; never pretending to be fresh), a background single-flight refreshes it for the next open. "Force refresh" semantics unchanged (always synchronous; community card stays decoupled).
261
+ - **Route stickiness**: the default two-route chain (GitHub raw → jsDelivr mirror) is ordered by the **last successful route** recorded in the cache — once the mirror has worked it goes first, instead of re-paying the raw timeout on every cold open (~10-20s saved per cold open on CN networks).
262
+ - **Persistent probe cache**: per-page npm/GitHub latest-version probes now persist to a disk envelope (`latest/`, survives restarts) — no probe replay on the first open after a DSH service restart.
263
+ - **Client snapshot**: the default first page is cached browser-locally (10-min TTL); opening the panel renders the last response first and refreshes in the background — the spinner now only appears on the very first use (no snapshot yet).
264
+ - **Detail modal "Install command" row is context-aware**:
265
+ - **Scenario**: the row's derived command hardcodes `dsh plugin --profile web add …`, and community entries' upstream `install` text carries the same web-profile semantics — neither source looks at the current host profile. Copying it on Desktop installs into the web profile (invisible in the current UI); for already-installed entries the command is pure noise (live screenshot evidence: desktop + the dsh-m self entry, `installed` badge and the command on screen together).
266
+ - **Change**: the row is hidden entirely on desktop and for installed entries; web + not-installed keeps today's behavior (the CLI bootstrap path, same command as Quick start). The sanctioned Desktop path is the modal's own Install button (official pluginManager delegation, ADR 0005 discipline). No "simplify by dropping --profile": the explicit `--profile web` flag is a settled 0.9.0 decision (see the "profile target" section), and a bare `dsh plugin add` has ambiguous default-profile semantics — not simpler, just worse.
267
+
268
+ ### Changed in 0.9.13 — desktop chip hover copy updated (owner decision)
269
+
270
+ - The old copy "当前 DSH profile:{name}(Desktop 首发仅支持只读市场、安装新包与开关)" was stale after 0.9.8 opened upgrades/uninstall/self-upgrade; per owner decision it now reads "当前生效 Profile" (Active profile).
271
+
272
+ ### Changed in 0.9.12 — re-issue of 0.9.11
273
+
274
+ 0.9.11 hit a npmjs ghost publish: the OIDC publish was accepted and **staged** (CLI exit 0, provenance published to the transparency log) but never committed into the registry — GET 404, and re-publishing the same version is rejected with 409 `Cannot publish over previously staged version`. After waiting out any propagation, the standard workaround applies: re-issue under a new number. **Content is identical to 0.9.11: settings force-refresh no longer takes down the community catalog card.**
275
+
276
+ ### Fixed in 0.9.11 — Settings "force refresh" no longer takes down the community catalog card (force semantics belong to the curated chain only)
277
+
278
+ - **Scenario**: on a weak network, clicking the curated registry card's force refresh also flipped the community catalog card to "unavailable / fetch timeout" — the host forwarded `force` into the community summary, restarting its fetch flight; under a weak network the flight couldn't finish within the 3s waiter, which returned the timeout placeholder (the flight itself keeps running under its 30s hard cap and self-heals).
279
+ - **Fix**: the `registry` force is no longer forwarded to the community summary — force semantics belong to the curated chain; the community catalog keeps its own TTL/shared-flight cadence (a first-ever load on a terrible network can still transiently time out, but force refresh no longer triggers it).
280
+
281
+ ### Fixed in 0.9.10 — Desktop self-upgrade hitting the official supply-chain release-age policy now yields an honest wait guide
282
+
283
+ - **Scenario**: clicking the upgrade chip routes through the official manager, whose pnpm supply-chain policy (`minimumReleaseAge`, releases must age 24h before installation) rejected the just-published version — `ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION`. **The policy is working as designed** (anti-supply-chain-attack release waiting period); dsh-m just dumped a screen of raw pnpm output as a generic failure.
284
+ - **Fix**: the manager-result judgment recognizes the policy code and translates it into an honest guide — naming the pending entry and its publish time, deriving when a retry will pass, and offering the interim path (install the same version from DSH Web). No policy bypass, ever (the waiting period is the anti-attack red line; same stance as dsh-market #732).
285
+ - Also: community chain ⑨ hang-cap assertion 2s→10s (timer starvation under the full parallel suite tripped it twice; the "never hangs forever" contract is unchanged).
286
+
287
+ ### Fixed in 0.9.9 — No more red "primary route failed" notice once the mirror line took over (notice convergence)
288
+
289
+ - **Scenario**: with the default dual-line registry (raw → jsDelivr), when the primary `default-raw` failed and the mirror succeeded, the settings page still showed a red "Remote notice: default-raw 失败:fetch failed…可稍后重试或检查网络后重试" — alarming against data that had already self-healed, with advice that didn't apply (intermittent raw.githubusercontent.com unreachability is exactly why the mirror line exists).
290
+ - **Fix**: a later line succeeding means the earlier failure self-healed — `errors` no longer carries it (the "effective source" row already states the live line, e.g. "GitHub 镜像(备用)"). When ALL lines fail into cache/bundled, the errors are still kept — that's the actionable signal. The custom chain (custom source failing into cache) keeps its warning, unchanged.
291
+ - Added a test seam for the default chain (`defaultRoutes` override); regression gates cover both convergence and the keep-on-total-failure cases.
292
+
293
+ ### Fixed in 0.9.8 — Desktop package operations fully wired to the official manager (install always failed; upgrade/uninstall/self-upgrade opened)
294
+
295
+ - **Why every install failed**: the Host API's desktop install branch called `desktopInstall(id, cfg, opts)` without the 4th `deps` argument — `getService` never reached the adapter, so desktop installs always failed with "official pluginManager service unavailable (fail-closed)" (100% reproducible, timing irrelevant). The `dshm_install` tool had the same defect.
296
+ - **Service resolution aligned with dsh-market** (borrowed from its official-desktop wiring, proven on this machine by two managed upgrades): the probe now checks both contexts (the hostCtx from the webServer inject callback first) and falls back to a short-timeout cordis `inject` to lazily wake the official service — `pluginManager` is lazy, so a one-shot `get` returns undefined until something used it. Only a genuinely absent service still refuses (the no-file-level-fallback red line is untouched).
297
+ - **Capability table widened (owner decision, following dsh-market strategy)**: desktop upgrade (installBundle over the installed bundle), uninstall (removeBundle) and self-upgrade (installBundle('dsh-m@latest')) are now delegated to the official manager — exactly how dshmarket performed the dsh-m 0.9.3→0.9.4/0.9.5 upgrades on this machine. Judgment discipline unchanged (application/stage first, overridden is not a failure, build-blocked returns structured pendingBuilds, listBundles re-read never fakes success). restart stays refused (Electron lifecycle belongs to the shell).
298
+ - All three entry points (GUI, installed-view actions, and the dshm_install / dshm_uninstall / dshm_upgrade tools) are wired in the same pass.
299
+
300
+ ### Fixed in 0.9.7 — Upgrade chip on Desktop showed a red "upgrade failed" banner (capability refusal is guidance, not an error)
301
+
302
+ - **Root cause**: the 0.9.1 upgrade chip always calls `self-upgrade`; the Desktop capability table refuses by design with a structured 409, but the client rendered that 409 like any other failure — a red "upgrade failed" banner. Per the capability table this is not a failure, it's a pointer to the official entry.
303
+ - **Fix**: `api()` now forwards the structured refusal fields (code/action/profile/guidance); on a 409 the chip click shows a **neutral info banner** with the official-entry guidance (the guidance text's single source stays server-side in `active-profile.ts`, zero duplication in the client); info banners stay for 12s. Real failures on Web still use the red error banner — unchanged.
304
+
305
+ ### Fixed in 0.9.6 — "Clear finished" silently no-opped on failed records
306
+
307
+ - **Root cause**: the 0.7.0 review consensus excluded failed/superseded records from clearing (kept for review), so clicking the button against a failed record did nothing with zero feedback — reported as a bug from the real Windows host (2026-10-01). An explicit clear click is not a "silent wipe"; the old consensus is overruled.
308
+ - **Fix**: "Clear ended" (formerly "Clear finished") now clears **all terminal states** (done/warned/failed/superseded); in-flight records (queued/running/input) are untouched. When there is nothing terminal to clear, the button is disabled with an explanatory tooltip instead of silently no-oping. The per-row ✕ still removes single records.
309
+ - English copy updated accordingly.
310
+
311
+ ### Fixed in 0.9.5 — GUI read paths missed the active profile on Desktop (Installed tab always showed web)
312
+
313
+ - **Root cause**: the 0.9.0 dual-profile wiring missed the `installed` / `market` read paths in the Host API — `listInstalledWithMeta` / `listMarket` fell back to `webProfileDir()`: on Desktop the Installed tab always said "no plugins installed in this web profile" and the market "installed" badges stayed empty (the agent-tool surface `dshm_list` was wired correctly, so only the GUI was wrong).
314
+ - **Fix**: both now pass `profileDir: profile.dir` + `profile: profile.name` (same as the tools surface; profileContext as the single source of truth); registry/community cache segments follow the `profile` parameter automatically.
315
+ - **Copy**: the hardcoded "web profile" in the installed empty/loading states and the profile hint is now profile-neutral (the actual path is still shown).
316
+
317
+ ### Fixed in 0.9.4 — Fullscreen header eaten by the Windows Desktop titlebar (tabs / restore unreachable)
318
+
319
+ - **Root cause**: on Windows Desktop the shell runs `titleBarStyle:hidden + titleBarOverlay` — the top 40px of the window is a full-width `-webkit-app-region:drag` band (drag hits are decided by layout and ignore z-index / paint order), and the OS-drawn — □ ✕ caption buttons float above everything. The maximized panel header landed inside that band: tab clicks were swallowed by window dragging and the restore/close buttons were covered by the system buttons — no way back.
320
+ - **Fix**: the same approach the shell uses for its own overlays — consume the `--dsh-windows-titlebar-height` variable the shell sets on `html` (fullscreen `top:var(…)`; floating `padding-top:max(24px,var(…))`, which also fixes the short-window edge case where the floating panel's top edge sat under the band).
321
+ - **Zero drift on Web**: browsers / DSH Web have no such variable — it falls back to 0px, byte-identical to 0.9.3.
322
+
323
+ ### Fixed in 0.9.3 — Windows native support (verified on a real Windows host)
324
+
325
+ - **Registry atomic writes**: temp file names were derived with `split('/')`, but Windows paths separate with `\` — the "basename" came out as the entire path, the temp-file open always failed silently, and every cache / accepted-metadata write silently failed; now uses `basename()`, identical on all three platforms.
326
+ - **Local-file registry address parsing**: `C:\…` drive paths and `\\server\share` UNC were misread as URL schemes (with a misleading "HTTPS only" error), and `file://C:/…` normalized to a drive-less dangling path that always failed with ENOENT; all three local forms (POSIX absolute / Windows drive / UNC) now parse correctly as file kind.
327
+ - **Build**: `node_modules/.bin/tsc` is a POSIX sh shim; on Windows `spawnSync` failed with ENOENT — the build now runs TypeScript's JS entry with the current Node, identical on all platforms.
328
+ - **Test surface**: on a real Windows host the full 829-case suite went from 41 failures to **0** (821 pass / 8 skipped); POSIX-only contracts (process-group/SIGTERM timing, symlink privileges, platform path assertions, fixed-sleep timing) are now labeled skips, platform-neutral, or poll-based — test contracts unchanged.
329
+
330
+ ### Fixed in 0.9.2 — Header chip stuck on the old version after a service restart
331
+
332
+ - **In-place refresh once the restart is confirmed**: the moment the boot id confirms DSH Web is back, the panel re-fetches ping — the `dsh-m vX.Y.Z` chip and the profile chip sync to the new process's data instead of lingering on the old version (observed on 0.9.1: chip upgrade + restart still showed v0.9.0).
333
+ - **Refetch when the page becomes visible again**: with the panel left open while the service is restarted externally, returning to the tab refetches ping via `visibilitychange` (zero polling cost).
334
+ - **Chip version guard**: a self-check verdict whose version doesn't match the current process (stale verdict from the old process) is treated as silent, preventing "v0.9.1 ⬆ v0.9.1"-style misrenders.
335
+
336
+ ### New in 0.9.1 — Header version chip upgrade notice (lights up only when an update exists)
337
+
338
+ - **Silent by default**: the panel-header `dsh-m vX.Y.Z` chip keeps the static look introduced in 0.7.5 — up to date, failed check, or a local dev build ahead of npm (ahead) never interrupt (ahead only shows a "local dev build" hint in the hover title).
339
+ - **Lights up only when outdated**: when `self-check` (npm latest vs the installed version, read-only) finds a newer version, the chip turns into a warn state showing `⬆ v<latest>`; clicking it runs `self-upgrade` (same mutation session + post-install guard) and a "⚡ Restart" banner follows on success. On Desktop the click is rejected structurally by the capability table (409, with official lifecycle guidance).
340
+ - **TTL cache + version guard**: check results are cached in browser localStorage for 30 minutes so opening the panel doesn't hit npm every time; after an upgrade + restart the cache auto-invalidates by version. Failed checks stay silent — no error is shown.
341
+
342
+ ### New in 0.9.0 — Official Desktop (dual profile) support
343
+
344
+ - **One package, two profiles**: dsh-m now installs into the official Desktop's `desktop` profile (`~/.dsh/profiles/desktop`) alongside the Web `web` profile; the catalog, panel, and agent tools are shared, and everything manages the host's current profile (official `profileContext` as the single source of truth).
345
+ - **Entrust admission to the host**: every `/dshm` method (including ping and unknown methods) delegates to the official `connection.requestRejection()` before any body is read (trustedHosts / loopback / cross-site / `Origin: null` semantics come from the host); rejected requests consume no body and call no business logic; hosts without the capability fail closed. **Behavior change**: the old home-grown "missing Origin → 403" guard is gone — Origin-less requests from the Desktop bridge are admitted per official semantics, and unauthenticated health probes now follow host trust instead of a blanket 403.
346
+ - **Desktop first-release capability table**: read-only market + **installing new packages** (delegated to the official `pluginManager.installBundle`; integrity, locking, and application phases stay with the official manager) + **toggles** (delegated; structured refusal when the service is absent, never a file-level fallback); **upgrade / uninstall / self-update / one-click restart** return structured 409 refusals with official-entry guidance (no official upgrade API exists; restarts belong to the Electron lifecycle); build scripts retry with the exact official `pendingBuilds` list — never an allow-all.
347
+ - **Per-profile read model and cache**: market installed-badges, the installed list, and README previews only read the current profile; registry / community / accepted-source caches are segmented per profile (web keeps its legacy paths — zero migration, zero clearing); favorites and operation logs stay per browser origin and do not sync between Web and Desktop.
348
+ - **CLI always targets the web profile**: `--profile web` is explicit; `--profile desktop` is rejected with a pointer to the official Desktop plugin management page.
349
+ - **Honest limitations**: Desktop on-device (Win/macOS) E2E has not been run; the `registry.json` verified arrays gain **no** Desktop generation (to be recorded after real testing); dsh-m's file-level post-install guard is skipped on Desktop (app.asar probing blind spot) and replaced by official result checks plus a `listBundles` re-read.
350
+
351
+ ### Fixed in 0.8.5
352
+
353
+ - **dshm_upgrade fake success on guard blocks**: when an upgrade hit the post-install guard (e.g. link/file-sourced plugins cannot be auto-rolled-back), the text output was mis-rendered as "✅ undefined 已升级(最新)"; it now reports the block reason, compensation status and repair basis honestly, consistent with the card title (Guard block).
354
+
355
+ ### Changed in 0.8.4 — Category labels now follow the UI language
356
+
357
+ - **Community categories**: English names for the 23 known categories come straight from the upstream catalog's `categories.en`; under the English UI, category chips and the category row in detail/favorite modals show English. Upstream categories without an English name fall back to Chinese and keep rendering as raw slugs in the temporary group until labels land in a release. The Chinese UI is unchanged.
358
+ - **Curated categories**: the five chips now go through the bilingual dictionary (Market/Tools/UI/Search/Other ⇄ 市场/工具/界面/搜索/其他), consistent with the detail modal.
359
+ - **Implementation**: the summary carries `categoryLabelsEn` (derived from the upstream catalog in `communityOutcome`; ids without English are omitted — no second hand-maintained table), and the client merges per UI language. 0.8.1–0.8.3 were local iteration numbers with no separate changelog surface.
360
+
361
+ ### Changed in 0.8.0 — Settings page redo (aligned with the zoned dual-catalog positioning)
362
+
363
+ - **Information architecture**: Community catalog (from awesome-dsh-plugin) → Curated registry (registry.json) → dsh-m itself → About; the primary registry's user-facing name is now unified as "Curated registry".
364
+ - **Community catalog toggle**: a new GUI switch (live effect, instant, no confirm; when off the whole card collapses to one line); new `set-community` API.
365
+ - **Curated registry slimmed**: status fields consolidated from 7 rows to 4 (merged address, removed the hard-coded "caching" row); config status only appears when abnormal; buttons reduced to "Force refresh / Validate & apply / Restore default / Download default registry"; "Check entries reachability" removed from the GUI (`registry-diagnose` API kept).
366
+ - **Copy fixes**: the custom-source note now says it replaces the whole primary registry and only affects the Curated zone; removed the hard-coded TTL description that didn't match reality (`timeoutMs`/`cacheTtlMin` remain config-file settings).
367
+ - **dsh-m itself**: when the local dev build is ahead of npm, show "local dev build" instead of the misleading old "npm latest" (new `ahead` field).
368
+ - **About**: copy aligned with the current positioning, plus GitHub repo and issue-tracker links.
369
+
370
+ ### Polished in 0.7.10
371
+
372
+ - **Head split into three groups**: a hairline divider between the title and tab navigation — "title | nav | status + window controls" reads clearly.
373
+ - **Version badge unified color**: the v-number no longer uses the bright primary text color; it matches the dsh-m name in secondary gray.
374
+ - **Vertical rhythm consolidated**: window-control cells 26→28px to match tab height; version badge adjusted to 24px; maximize/restore icons unified at 12px; title weight 700→600.
375
+
376
+ ### Fixed in 0.7.9
377
+
378
+ - **Category chips keep a stable order**: retired the "promote active to front" reordering (every click on a clipped category used to jump it to first place). Instead, when the active category falls inside the collapsed clip region, the row auto-expands so the active filter stays visible — same goal, stable order; a manual collapse under the same active category is respected, and picking another clipped category or "All" resets it.
379
+
380
+ ### Changed in 0.7.8
381
+
382
+ - **Root cause fix for "maximize does nothing" — CSS hot-update self-healing**: the panel stylesheet was only injected once (`#dshm-css` present → skip), so after a hot update the stale stylesheet lacked rules for new classes (fullscreen/window controls) — new features appeared dead and buttons rendered as unstyled natives. The injected stylesheet now carries a content hash (djb2); reopening the panel after a bundle update swaps in the fresh styles automatically, no page refresh needed.
383
+ - **Window-control group recolored**: dropped the raised surface for a transparent background + hairline outline (same language as the search clear button); cells widened 34→44px against mis-clicks; close keeps its red hover.
384
+
385
+ ### Changed in 0.7.7
386
+
387
+ - **Fullscreen ported from dsh-market**: a maximize/restore control joins the panel head as a unified window-control group (equal-width maximize + close cells, hairline divider, shared SVG line icons; close tints red on hover). Fullscreen fills the viewport without rounded corners, the state is remembered in localStorage, and Esc still closes the panel.
388
+ - 0.7.6 catch-up: version badge de-bolded and made static (no copy-on-click); sticky category row's top gap fixed (sticky anchor shifted to offset container padding); close/clear buttons moved to the outlined flat style.
389
+
390
+ ### Changed in 0.7.5
391
+
392
+ - **Header version chip now shows dsh-m's own version** (`dsh-m v0.7.5`, click to copy; the DSH runtime version lives in Settings and `dshm ping`).
393
+ - **× close/clear buttons redrawn**: search clear, detail-modal close, and operation-row remove now use an SVG line icon on a dedicated hover-tinted button; the search clear button floats inside the pill's right edge.
394
+ - **Fixed the dsh-market peer warning**: `@deepseek-ai/dsh-tools` peer changed from `*` (strict semver never matches rc prereleases) to the explicit range `^0.1.7-rc.2 || ^0.2.0-rc.1 || >=0.2.0`; newer rc lines (e.g. 0.3.0-rc.x) need another entry.
395
+
396
+ ### Changed in 0.7.4
397
+
398
+ - **Panel tabs reverted to the classic segmented style** (0.7.2 mistakenly introduced underline tabs; the rounded button group with a highlighted active tab is back).
399
+ - **Full-width search**: fixed the search wrapper missing `display:flex`, which kept the input from stretching to the row.
400
+ - **Filter button and page-jump control recolored**: the filter button now uses an elevated surface with squared corners to stand apart from the pill category chips (accent outline when open); the page input is a slim pill with a hairline border and an accent-colored "Go" text button.
401
+ - **Sticky category row fully opaque**: the background now uses the opaque base token directly (the previous color-mix translucency still let card text bleed through on the dark theme); the bottom divider stays.
402
+
403
+ ### Changed in 0.7.3 (includes 0.7.2)
404
+
405
+ - **Home layout modeled after dsh-market**: the market view becomes "zone chips → full-width search row → category chips with a trailing Filter popover"; the popover gets its own look (rounded rectangle + leading chevron) and holds sort field (npm downloads/stars/date added), direction, and page size (the old sort dropdown and pager page-size select are retired).
406
+ - **Favorites cards open the detail modal**: fixed favorites-zone cards not responding to clicks — favorite snapshots lack full fields, so opening resolves the complete entry by id (in-memory zones → market API → snapshot fallback), reusing the detail modal and the full install path (peer confirm included).
407
+ - **Page-number jump**: the pager gains a page input — type a valid page and hit Enter or "Go" to jump.
408
+ - **Frosted sticky category row**: the sticky row now blurs content beneath it (backdrop blur + divider), so card text no longer bleeds through.
409
+ - **Removed by request**: the "discover/request listing" line (dsh-m does not accept listings), the "Tasks" button (operations panel is always visible again), and the "Refresh" button (force refresh lives in Settings).
410
+ - Note: registry entries carry no host-version requirement field, so dsh-market's "host version" filter has no data source here and was not replicated.
411
+
412
+ ### Fixed in 0.7.1
413
+
414
+ - **Community entries are installable again**: fixes a 0.7.0 regression where installing a community listing failed with "registry 中没有该条目" (install-by-id only consulted the primary registry, never the community catalog); the path now mirrors upgrades — on a primary miss the catalog is searched by id.
415
+ - **Compact market header**: search, refresh, and sort (community zone) move into the zone chips row; informational source banners ("official default registry / custom registry / served from local cache") are retired — their "{count} listings" figure was never wired up (always 0); the "registry unavailable" error and community fallback/stale hints remain.
416
+
417
+ ### New in 0.7.0
418
+
419
+ - **Zoned market** ([ADR-0004](./docs/adr/0004-zoned-market-display.md)): the dual-catalog data merge stays, but the display splits into Community (default) / Curated / Favorites zones; `dshm_search` and `dshm search` switch to `--source community|primary|all` + `--offset` real pagination (default 10 cards) — `primary_only` is retired.
420
+ - **Relevance search**: NFKC normalization + CJK↔Latin boundaries + field weighting (name/npm > owner > description > category > tags), multi-term same-field matching; whole-id exact match takes top priority.
421
+ - **Operation log + resume executor**, **local favorites + delisted cleanup**, **detail modal + screenshot lightbox**, community byline/deprecated badges/catalog-snapshot version fallback (never used for outdated).
422
+
423
+ ### New in 0.4.0
424
+
425
+ - **Enablement toggle**: one-click on/off per installed card; internally routed to a row override (single-row plugins, applies live) or bundle selection (multi-row); the write path delegates to the official `pluginManager` service and falls back to direct loader operations when absent ([ADR-0001](./docs/adr/0001-delegate-with-fallback-for-plugin-manager.md)).
426
+ - **Live phase badges**: a projection of loader fiber state — failed plugins are visible at a glance.
427
+ - **Protection roster**: `dsh-m` itself plus the 16 official host lifeline modules cannot be toggled or uninstalled (upgrades unaffected).
428
+ - **Precise build approval**: when pnpm blocks build scripts, only the pending list is approved key-by-key; the allow-everything fallback is labeled honestly ([ADR-0002](./docs/adr/0002-precise-build-approval.md)).
429
+ - **Peer compatibility precheck**: install/upgrade validates `@deepseek-ai/dsh(-*)` peers against the runtime version before touching the profile (GitHub sources state the check was skipped); on mismatch the GUI asks, the agent tool returns structured data, the CLI takes `--force`.
430
+ - **Verified runtimes**: an optional `verified` array per registry entry records DSH runtimes actually tested — a claim of record, not a prediction; display-only, never gates installs.
431
+ - **Bundle identity check**: post-install warning when a package lands without a patch layer ("installed as a plain dependency").
432
+
433
+ ### Retired in 0.4.x
434
+
435
+ - **Metadata source probe**: 0.4.0 introduced an npmjs / npmmirror ping race to pick the metadata read source; it has been removed entirely (including the `probeEnabled` / `probeTimeoutMs` / `probeCacheTtlMin` settings and the settings-page display). The official counterpart probe only pre-selects a registry in the interactive install dialog, which dsh-m does not have, and npmjs measured consistently faster from the host, so the probe always equaled the default. Metadata reads now always use npmjs, matching the install path (profile `.npmrc` default).