dsh-m 0.9.16 → 0.9.18
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 +419 -0
- package/README.en.md +103 -237
- package/README.md +104 -244
- package/docs/DESIGN.md +3 -1
- package/lib/cli.js +1 -1
- package/lib/client.js +3 -3
- package/lib/core/market.js +10 -2
- package/lib/core/registry.js +33 -1
- package/lib/tools.js +1 -1
- package/package.json +2 -1
- package/registry.json +89 -209
package/README.md
CHANGED
|
@@ -4,252 +4,92 @@
|
|
|
4
4
|
[](https://www.npmjs.com/package/dsh-m)
|
|
5
5
|
[](../../actions/workflows/registry.yml)
|
|
6
6
|
[](./LICENSE)
|
|
7
|
-
[](#faq)
|
|
8
8
|
|
|
9
9
|
[English](./README.en.md) · 中文
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
dsh-m 是 DeepSeek Harness(DSH)的插件市场:**收录 · 安装 · 卸载 · 升级**,全部本机完成——无服务端、无账号。侧栏「插件市场」即开即用,agent 工具与 CLI 同源同语义。
|
|
12
|
+
|
|
13
|
+
**亮点**
|
|
14
|
+
|
|
15
|
+
- **双 profile**:同一包装入 Web(`web`)与官方 Desktop(`desktop`),管理对象始终跟随宿主当前 profile;
|
|
16
|
+
- **双清单市场**:4,000+ 条社区目录(awesome-dsh-plugin)为默认清单,叠加手工精选,分区浏览、卡片即点即装;
|
|
17
|
+
- **三端同源**:GUI 面板、8 个 `dshm_*` agent 工具与 `dshm` CLI 共享同一套数据与语义;
|
|
18
|
+
- **安全基线**:npm 精确版本 integrity 校验、GitHub 锁定 commit SHA、委派官方 pluginManager,构建脚本逐键精确放行。
|
|
12
19
|
|
|
13
20
|
<div align="center">
|
|
14
21
|
<img src="https://raw.githubusercontent.com/iasiv5/dsh-m/main/docs/images/marketplace.webp" alt="侧栏「插件市场」面板——市场视图:社区 / 精选 / 收藏三分区、分类 chips 与插件卡片(已实测 / 已安装徽标、npm 与 GitHub 详情链接)" width="100%">
|
|
15
|
-
<p><sub>侧栏「插件市场」·
|
|
22
|
+
<p><sub>侧栏「插件市场」· 市场视图:社区、精选与收藏分区,浏览插件并查看兼容与安装状态</sub></p>
|
|
16
23
|
</div>
|
|
17
24
|
|
|
18
|
-
##
|
|
25
|
+
## 目录
|
|
19
26
|
|
|
20
|
-
|
|
27
|
+
- [环境要求](#环境要求)
|
|
28
|
+
- [30 秒上手](#30-秒上手)
|
|
29
|
+
- [界面(侧栏「插件市场」)](#界面侧栏插件市场)
|
|
30
|
+
- [Agent 工具(8 个)](#agent-工具8-个)
|
|
31
|
+
- [CLI](#cli)
|
|
32
|
+
- [社区清单(awesome-dsh-plugin 目录)](#社区清单awesome-dsh-plugin-目录)
|
|
33
|
+
- [精选清单(registry.json)](#精选清单registryjson)
|
|
34
|
+
- [文档](#文档)
|
|
35
|
+
- [FAQ](#faq)
|
|
21
36
|
|
|
22
|
-
|
|
23
|
-
安装并启用 DSH 插件 dsh-m:
|
|
24
|
-
1. 执行 `dsh plugin --profile web add dsh-m`
|
|
25
|
-
2. 重启 DSH Web 使插件加载(按部署方式重启对应的 DSH user unit;unit 名称不要硬编码)
|
|
26
|
-
3. 轮询 `curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:3080`,直到恢复 200
|
|
27
|
-
4. 执行 `curl -s -X POST http://127.0.0.1:3080/dshm -H 'content-type: application/json' -d '{"method":"ping"}'`,确认返回 `plugin: dsh-m`
|
|
28
|
-
5. 完成后提醒我刷新页面,点击侧栏底部的「插件市场」
|
|
29
|
-
```
|
|
37
|
+
本页不展开版本变更,完整历史见 [`CHANGELOG.md`](https://github.com/iasiv5/dsh-m/blob/main/CHANGELOG.md)。
|
|
30
38
|
|
|
31
|
-
|
|
39
|
+
## 环境要求
|
|
40
|
+
|
|
41
|
+
- Node.js ≥ 22(宿主侧);
|
|
42
|
+
- DSH Web 或官方 Desktop(支持的宿主代际见 [FAQ 支持矩阵](#faq));
|
|
43
|
+
- 无需额外服务或账号,安装与管理全部本机完成。
|
|
44
|
+
|
|
45
|
+
## 30 秒上手
|
|
32
46
|
|
|
33
|
-
|
|
47
|
+
1. 在 DSH 官方插件管理界面点击「添加插件」。
|
|
48
|
+
2. 输入包名 `dsh-m`,按网络情况选择安装源,然后点击「安装」。
|
|
49
|
+
3. 安装完成后按宿主生命周期使插件生效:DSH Web 重启后刷新页面;官方 Desktop 退出并重新打开应用。
|
|
50
|
+
4. 加载完成后,从侧栏底部打开「插件市场」。
|
|
51
|
+
|
|
52
|
+
<div align="center">
|
|
53
|
+
<img src="https://raw.githubusercontent.com/iasiv5/dsh-m/main/docs/images/official-plugin-install.webp" alt="DSH 官方插件管理界面:添加插件对话框中填写 dsh-m,并选择安装源" width="86%">
|
|
54
|
+
<p><sub>推荐方式 · 在 DSH 官方插件管理界面添加并安装 dsh-m</sub></p>
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
> **升级提示:** 当前官方插件管理界面提示暂不支持自动更新;若通过该界面升级,请先卸载 `dsh-m` 再安装新版,具体以界面最新提示为准。
|
|
34
58
|
|
|
35
59
|
## 界面(侧栏「插件市场」)
|
|
36
60
|
|
|
37
61
|
| 视图 | 能力 |
|
|
38
62
|
|---|---|
|
|
39
|
-
| **市场** |
|
|
40
|
-
| **操作记录** |
|
|
41
|
-
| **已装** | 当前 profile
|
|
42
|
-
| **设置** |
|
|
63
|
+
| **市场** | 社区(4,000+ 条)/ 精选 / 收藏三分区,各分区独立保留分类、搜索、排序与分页状态;卡片点开详情 Modal,安装进度与结果就地显示。 |
|
|
64
|
+
| **操作记录** | 安装、升级、卸载、开关统一进入全局操作日志,状态不挂卡片;宿主重载后自动恢复未完成操作。 |
|
|
65
|
+
| **已装** | 当前 profile 实装列表:来源标注、运行相位徽标、一键开关、升级与两段式确认卸载。 |
|
|
66
|
+
| **设置** | 精选清单配置与状态、社区目录开关、dsh-m 自更新。 |
|
|
43
67
|
|
|
44
68
|
<div align="center">
|
|
45
69
|
<img src="https://raw.githubusercontent.com/iasiv5/dsh-m/main/docs/images/settings.webp" alt="设置视图——社区清单状态卡(目录版本 / 获取线路 / 收录条目)、精选清单配置卡(地址草稿与强制刷新 / 校验并应用 / 恢复默认 / 下载默认清单)与关于卡" width="86%">
|
|
46
70
|
<p><sub>设置视图 · 社区清单状态、精选清单配置与 dsh-m 自更新</sub></p>
|
|
47
71
|
</div>
|
|
48
72
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
### 0.9.16 变更:精选策展五桶分类法 + 严筛收录(23→19)+ 新收录 DSH TUI
|
|
52
|
-
|
|
53
|
-
- **策展分类法**:精选区分类从功能五分类(市场/工具/界面/搜索/其他)改为**策展五桶**——装机必备 / 崔添翼精选 / 我的自研 / 腾讯轻量云专区 / 观察区(chips 按此序,腾讯轻量云垫后)。分类语义从「插件是什么」转为「为什么值得进精选」;重叠归属按 装机必备 > 崔添翼精选 > 自研 > 腾讯轻量云 优先级归桶,功能属性转 tags 保留检索,旧分类值仍可作开放 slug 命中自定义源(ADR-0004 修订)。
|
|
54
|
-
- **严筛收录 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 推荐出处。
|
|
55
|
-
- **同版本携带**(本地增强随发版收编):desktop 安装 enable 阶段失败自动重试一次(高频装卸/插件树重载竞速实证)+ 失败文案按 packageResult 精确化;市场页「缓存快照」横幅退役——stale 状态由设置页社区卡承接,浏览页不再提示临时缓存状态。
|
|
56
|
-
|
|
57
|
-
### 0.9.15 变更:安装进度/终态就地进详情 Modal
|
|
58
|
-
|
|
59
|
-
- **场景**:从详情 Modal 点「安装」后,安装信息(pnpm 阶段进度行、「变更完成」横幅/toast)都渲染在面板底层,隔着 Modal 遮罩半透明透出——弹窗内只有按钮转圈,看不出装到哪一步(实机截图反馈 2026-10-02)。卸载无此问题:不弹 Modal,状态本来就挂在已装卡片上。
|
|
60
|
-
- **变更**:安装进行中,Modal 内直接挂进度行(复用 host status 轮询:阶段/进度条/当前包);终态在 Modal 内就地显示结果行——成功附版本与构建脚本说明 + 重启提示(desktop 给官方应用生命周期指引),失败/守卫拦截附原因且按钮回到可重试,「已跳过」中性呈现;Modal 打开时底层同源进度行让位(关闭 Modal 后照常回归)。信息全部派生自全局操作记录与安装结果,「状态不挂卡片」的所有权模型不变(DESIGN §2.6)。
|
|
61
|
-
|
|
62
|
-
### 0.9.14 变更(市场秒开四件套 + 详情 Modal 安装命令显隐)
|
|
63
|
-
|
|
64
|
-
- **市场秒开四件套**:针对「每次打开市场必现『加载收录清单中…』」的加速组合拳——
|
|
65
|
-
- **SWR 先回缓存**:精选清单与社区目录的 TTL 过期不再同步等网络——磁盘缓存存在即**立即返回快照**(社区侧照常显示「缓存快照」横幅,绝不冒充最新),后台单飞自愈,下次打开即新;「强制刷新」按钮语义不变(始终同步强刷,社区卡不连坐)。
|
|
66
|
-
- **线路粘性**:默认双线路(GitHub 原始文件 → jsDelivr 镜像)按缓存记录的**上次成功线路**排序——镜像成功过就先走镜像,不再每次白等主线路失败(大陆网络实测每次冷打开省 10-20s 等待)。
|
|
67
|
-
- **探测缓存落盘**:页条目 npm/GitHub 版本探测缓存从纯内存改为磁盘信封(`latest/`,跨重启存活)——DSH 服务重启后首次打开市场不再重放探测。
|
|
68
|
-
- **客户端快照**:默认首页响应存浏览器本地(10 分钟 TTL),打开面板先渲染上次数据再后台换新——加载 spinner 仅首次使用(无任何快照)出现。
|
|
69
|
-
- **详情 Modal「安装命令」折叠行按上下文显隐**:
|
|
70
|
-
- **场景**:折叠行命令推导写死 `dsh plugin --profile web add …`,社区条目的上游 install 原文也同为 --profile web 语义——两个来源都不看当前宿主 profile。desktop 上下文里照抄会把包装进 web profile(当前界面看不见);已安装条目还挂着命令纯属噪音(实机截图实证:desktop + dsh-m 自身条目,`已安装` 徽章与命令同屏)。
|
|
71
|
-
- **变更**:desktop 上下文与已安装条目**整行隐藏**;web 未安装条目行为不变(CLI bootstrap 路径保留,「30 秒上手」同款命令)。desktop 装机正路是弹窗内「安装」按钮(官方 pluginManager 委派,ADR 0005 纪律)。不做「精简命令去掉 --profile」——显式 `--profile web` 是 0.9.0 拍板的设计(README「profile 目标」节),裸命令的默认 profile 语义含糊,精简反而更差。
|
|
72
|
-
|
|
73
|
-
### 0.9.13 变更:desktop 角标悬停文案更新(主人拍板)
|
|
74
|
-
|
|
75
|
-
- 旧文案「当前 DSH profile:{name}(Desktop 首发仅支持只读市场、安装新包与开关)」在 0.9.8 开放升级/卸载/自升级后已过时;按主人拍板改为「**当前生效 Profile**」(en: Active profile)。
|
|
76
|
-
|
|
77
|
-
### 0.9.12 变更:0.9.11 的重发
|
|
78
|
-
|
|
79
|
-
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 完全一致:设置页「强制刷新」不再连坐社区清单卡。**
|
|
80
|
-
|
|
81
|
-
### 0.9.11 修复:设置页「强制刷新」不再连坐社区清单卡(force 语义只属精选链)
|
|
82
|
-
|
|
83
|
-
- **场景**:弱网下点精选清单的「强制刷新」,社区清单卡跟着变「不可用 + 获取超时」——根因是 host 把 `force` 一路透传给社区目录 summary,强制重开获取 flight;弱网下 flight 3s 完不成,waiter 超时返回占位摘要(flight 本身在后台 30s hard cap 内继续,跑完即自愈)。
|
|
84
|
-
- **修复**:`registry` 的 force 不再透传社区 summary——「强制刷新」语义只属精选链(registry 链);社区目录走自己的 TTL/共享 flight(首次打开等边界场景在极差网络下仍可能瞬时超时,但强刷不再触发)。
|
|
85
|
-
|
|
86
|
-
### 0.9.10 修复:Desktop 自升级撞上官方供应链等待期(minimumReleaseAge)→ 诚实指引发成可读
|
|
87
|
-
|
|
88
|
-
- **场景**:点升级角标走官方管理器时,desktop profile 的 pnpm 供应链策略(`minimumReleaseAge`,发布满 24h 才可安装)拒绝了刚发布的版本——`ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION`。**这是策略在正确工作**(防供应链攻击的发布等待期),不是故障;但 dsh-m 此前把它当普通失败甩一屏 pnpm 原文。
|
|
89
|
-
- **修复**:管理器结果判定识别该策略码,翻译成诚实指引——点名等待期内的条目与发布时刻、按策略推算「预计何时可重试」,并给出等待期内的替代路径(DSH Web 安装同版本)。绝不做策略绕过(等待期是防供应链攻击的红线,dsh-market #732 同态度)。
|
|
90
|
-
- 附带:community 获取链 ⑨ 的挂起上限断言 2s→10s(全量套件并行定时器饥饿下两次闪断;契约「不永久挂起」不变)。
|
|
91
|
-
|
|
92
|
-
### 0.9.9 修复:备用线路接住后不再弹红色「主线路失败」提示(提示收敛)
|
|
93
|
-
|
|
94
|
-
- **场景**:默认精选清单双线路(raw → jsDelivr)里主线路 `default-raw` 失败、备用线路成功接管时,设置页仍弹红色「远端提示:default-raw 失败:fetch failed…可稍后重试或检查网络后重试」——对着已经自愈的数据报警,还带着不成立的建议(大陆网络下 raw 间歇不可达是常态,这正是备用线路存在的原因)。
|
|
95
|
-
- **修复**:后续线路成功 = 先行失败已自愈,`errors` 不再携带(设置页「生效来源」行已如实标注当前线路,如「GitHub 镜像(备用)」);全线路失败落 cache/bundled 时错误照常保留——那才是需要行动的信号。custom 链(自定义源失败回退缓存)行为不变,仍然提示。
|
|
96
|
-
- 顺带补了 default 链的测试缝(`defaultRoutes` 覆写),双线路收敛与全挂保留各有回归门。
|
|
97
|
-
|
|
98
|
-
### 0.9.8 修复:Desktop 包操作全面接通官方管理器(安装恒 no-manager;升级/卸载/自升级开放)
|
|
99
|
-
|
|
100
|
-
- **安装恒失败的根因**:Host API 的 desktop 安装分支调 `desktopInstall(id, cfg, opts)` 漏传第 4 参 deps——`getService` 根本没进适配器,desktop 安装恒报「官方 pluginManager 服务不可用(fail-closed)」(100% 必现,与时机无关)。工具面 `dshm_install` 同病。
|
|
101
|
-
- **服务解析与 dsh-market 同源**(借鉴其 official-desktop 接线,本机两轮覆盖安装实证):探测改双上下文(webServer 注入回调的 hostCtx 优先)+ cordis inject 惰性拉起兜底(短超时)——官方 pluginManager 是惰性服务,未被拉起前一次性 get 恒 undefined;仍缺席才结构化拒绝(绝不文件级回退的红线不动)。
|
|
102
|
-
- **能力表扩充(主人裁决,借鉴 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 生命周期归官方壳)。
|
|
103
|
-
- GUI 与工具面(dshm_install / dshm_uninstall / dshm_upgrade)三入口同批接线。
|
|
104
|
-
|
|
105
|
-
### 0.9.7 修复:Desktop 下点升级角标弹红色「升级失败」(能力表拒绝应为指导而非报错)
|
|
106
|
-
|
|
107
|
-
- **根因**:0.9.1 的升级角标点击后一律调 `self-upgrade`;Desktop 能力表按设计 409 结构化拒绝,但客户端把 409 当普通失败渲染成红色「升级失败」横幅——按能力表这根本不是失败,是「该走官方入口」的指引。
|
|
108
|
-
- **修复**:`api()` 透传能力表拒绝的结构化字段(code/action/profile/guidance),角标点击收到 409 时改出**中性 info 横幅**展示官方入口指引(guidance 单一事实源仍在服务端 `active-profile.ts`,客户端零复制);info 横幅停留 12s。Web 端真实失败仍走红色 err 横幅,行为不变。
|
|
109
|
-
|
|
110
|
-
### 0.9.6 修复:「清除已完成」对失败记录无声 no-op
|
|
111
|
-
|
|
112
|
-
- **根因**:0.7.0 评审共识把「失败/已跳过」排除在清除范围外(保留供回看),于是按钮对着一条失败记录点击毫无反应、也无任何反馈——Windows 实机被当成 bug 上报(2026-10-01)。显式点击清除不是「静默抹掉」,旧共识被推翻。
|
|
113
|
-
- **修复**:「清除已结束」(原「清除已完成」)现在清除**全部终态**(done/warned/failed/superseded),在途态(queued/running/input)不受影响;没有可清终态时按钮置灰并带说明 tooltip,不再无声 no-op。单条 ✕ 照旧逐条删除。
|
|
114
|
-
- **英文文案**同步改为 "Clear ended"。
|
|
115
|
-
|
|
116
|
-
### 0.9.5 修复:Desktop 下 GUI 读路径漏接 active profile(已装页恒显 web)
|
|
117
|
-
|
|
118
|
-
- **根因**:0.9.0 双 profile 接线时,Host API 的 `installed` / `market` 两个读路径漏传 active profile——`listInstalledWithMeta` / `listMarket` 内部落回 `webProfileDir()`:Desktop 下已装页恒显「web profile 尚未安装任何插件」、市场「已安装」徽标恒空(agent 工具面 `dshm_list` 同链路已接线,故只有 GUI 错)。
|
|
119
|
-
- **修复**:两处补齐 `profileDir: profile.dir` + `profile: profile.name`(与 tools 面同款,profileContext 单一事实源);registry/社区缓存随 `profile` 参数自动落到 desktop 段。
|
|
120
|
-
- **文案**:已装空态/加载态与 profile 提示里的「web profile」硬编码改为 profile 中性表述(实际路径照旧展示)。
|
|
121
|
-
|
|
122
|
-
### 0.9.4 修复:Windows Desktop 全屏后头部不可点(tab / 还原键被系统标题栏吞掉)
|
|
123
|
-
|
|
124
|
-
- **根因**:Desktop(Windows)以 `titleBarStyle:hidden + titleBarOverlay` 运行——窗口顶部 40px 是壳的全宽 `-webkit-app-region:drag` 拖拽带(按布局参与拖拽判定、无视 z-index 与绘制顺序),右上角另有系统绘制的 — □ ✕ 悬浮于一切内容之上。面板全屏后头部(tab、还原/关闭键)正好落进这条带:点击被窗口拖拽吞掉、还原键被系统键遮挡,全屏无法退出。
|
|
125
|
-
- **修复**:与壳自家 overlay 同款对策——消费壳在 `html` 上设的 `--dsh-windows-titlebar-height` 让出该带(全屏态 `top:var(…)`;浮动态 `padding-top:max(24px,var(…))` 顺带修掉矮窗口下浮板顶边被带压住的边缘情况)。
|
|
126
|
-
- **Web 零漂移**:DSH Web / 浏览器无此变量,回落 0px,行为与 0.9.3 完全一致。
|
|
127
|
-
|
|
128
|
-
### 0.9.3 修复:Windows 原生适配(Windows 宿主实机回归)
|
|
129
|
-
|
|
130
|
-
- **registry 原子写**:临时文件名此前用 `split('/')` 从绝对路径取尾段,而 Windows 路径分隔符是 `\`——取到的是整条路径(内嵌 `\` 即目录分隔符),临时文件 open 必败且被吞,cache 与 accepted metadata 写入**静默全失败**;改用 `basename()`,三平台一致。
|
|
131
|
-
- **本地文件清单地址解析**:`C:\…` 盘符与 `\\server\share` UNC 此前被误当 URL scheme(报「只允许 HTTPS」的误导性错误),`file://C:/…` 会归一成无盘符悬空路径必 ENOENT;现 POSIX 绝对 / Windows 盘符 / UNC 三形态均正确解析为 file kind。
|
|
132
|
-
- **构建**:`node_modules/.bin/tsc` 是 POSIX sh shim,Windows 下 `spawnSync ENOENT`;改用当前 Node 直跑 TypeScript 的 JS 入口,`npm run build` 三平台一致。
|
|
133
|
-
- **测试面**:Windows 实机全量 829 用例 41 败 → **0**(821 pass / 8 skipped);POSIX 进程组/SIGTERM 时序、symlink 权限、平台路径断言、固定 sleep 时序假设逐项标注 skip 或平台无关化/有界轮询,测试契约不变。
|
|
134
|
-
|
|
135
|
-
### 0.9.2 修复:跨服务重启后头部角标停留旧版本
|
|
136
|
-
|
|
137
|
-
- **一键重启确认新进程后就地刷新**:boot id 确认 DSH Web 已恢复的瞬间,面板立即重取 ping——`dsh-m vX.Y.Z` 角标与 profile chip 同步到新进程数据,不再停留旧版本(0.9.1 实测:芯片升级 + 重启后仍显 v0.9.0)。
|
|
138
|
-
- **页面回前台时重取**:面板常开、服务在后台被外部重启的场景,`visibilitychange` 回前台即重取 ping(零轮询成本)。
|
|
139
|
-
- **角标版本护栏**:self-check 判定携带的版本与当前进程不符(旧进程残留判定)时一律静默,杜绝「v0.9.1 ⬆ v0.9.1」式误渲染。
|
|
140
|
-
|
|
141
|
-
### 0.9.1 新增:头部版本角标升级提示(有更新才点亮)
|
|
142
|
-
|
|
143
|
-
- **静默口径**:面板头部 `dsh-m vX.Y.Z` 角标常态维持 0.7.5 起的静态展示——已是最新、检查失败、本地 dev 版领先 npm(ahead)一律不打扰(ahead 仅在悬停 title 里提示「本地开发版」)。
|
|
144
|
-
- **仅 outdated 点亮**:`self-check`(npm latest vs 装机版本,只读)判定有新版本时,角标点亮为 warn 态并显示 `⬆ v<最新>`;点击即触发 `self-upgrade`(同一 mutation session + 装后守卫),成功后出「⚡ 一键重启」横幅。Desktop 下点击按能力表结构化拒绝(409,带官方生命周期指引)。
|
|
145
|
-
- **TTL 缓存 + 版本护栏**:检查结果在浏览器 localStorage 缓存 30 分钟,开面板不重复打 npm registry;升级重启后缓存按版本号自动作废。检查失败静默,不弹任何错误。
|
|
146
|
-
|
|
147
|
-
### 0.9.0 新增:官方 Desktop(双 profile)支持
|
|
148
|
-
|
|
149
|
-
- **同一包、两个 profile**:dsh-m 现在可装入官方 Desktop 的 `desktop` profile(`~/.dsh/profiles/desktop`),与 Web 的 `web` profile 并列;市场目录、面板与 agent 工具同一套,管理对象始终是宿主当前 profile(官方 `profileContext` 单一事实源)。
|
|
150
|
-
- **入口信任检查改委派官方**:`/dshm` 全部 method(含 ping 与未知 method)在读取请求体之前委派官方 `connection.requestRejection()` 判定(trustedHosts / loopback / 跨站 / `Origin: null` 语义随宿主),被拒请求零 body 消耗、零业务调用;宿主缺该能力时 fail-closed 全拒。**行为变化**:旧版自制守卫「缺 Origin 一律 403」不再存在——Desktop 桥合法剥除 Origin 的请求按官方语义放行,无凭据的健康检查探针从「一律 403」变为「按宿主信任判定」。
|
|
151
|
-
- **Desktop 首发能力表**:只读市场 + **安装新包**(委派官方 `pluginManager.installBundle`,完整性/锁/生效相位归官方)+ **开关**(委派官方管理器,服务缺席结构化拒绝、绝不文件级 fallback);**升级 / 卸载 / dsh-m 自更新 / 一键重启**在 Desktop 结构化拒绝(409,带官方入口指引——官方暂无 upgrade API,重启归 Electron 生命周期);构建脚本按官方 `pendingBuilds` 名单精确重试,绝不全量放行。
|
|
152
|
-
- **读模型与缓存按 profile 隔离**:市场安装标注、已装列表、README 预览只读当前 profile;registry / 社区清单 / accepted-source 缓存按 profile 分段(web 沿用旧路径,零迁移零清空);收藏与操作记录按浏览器 origin 各自独立,Web 与 Desktop 不自动同步。
|
|
153
|
-
- **CLI 恒作用于 web profile**:`--profile web` 显式声明;`--profile desktop` 明确拒绝并指引官方 Desktop 插件管理页。
|
|
154
|
-
- **如实声明**:Desktop 实机(Win/macOS)E2E 未跑,`registry.json` verified 数组**不新增** Desktop 代际(实测后按收录纪律补录);Desktop 下不做 dsh-m 文件级装后守卫(app.asar 打包布局探测盲区),以官方结果判定 + `listBundles` 复读替代。
|
|
155
|
-
|
|
156
|
-
### 0.8.5 修复
|
|
157
|
-
|
|
158
|
-
- **dshm_upgrade 守卫拦截假成功**:升级命中装后守卫拦截时(如 link/file 来源插件无法自动回退),文本输出误渲染为「✅ undefined 已升级(最新)」;现如实输出拦截原因、补偿终态与修复依据,与卡片标题(守卫拦截)一致。
|
|
159
|
-
|
|
160
|
-
### 0.8.4 变更:分类标签随界面语言双语化
|
|
161
|
-
|
|
162
|
-
- **社区分类**:已知 23 个分类的英文名直接取上游目录 `categories.en`,英文界面下分类 chips 与详情/收藏 Modal 的分类行显示英文;缺英文名的上游新分类回退中文,仍按原样渲染进临时组,等发版收录。中文界面不变。
|
|
163
|
-
- **精选分类**:五个分类 chip 改走双语字典(市场/工具/界面/搜索/其他 ⇄ Market/Tools/UI/Search/Other),与详情 Modal 口径一致。
|
|
164
|
-
- **实现**:summary 新增 `categoryLabelsEn`(`communityOutcome` 从上游目录派生,缺 en 的 id 不进映射,不手养第二张表),客户端按界面语言合并取值。0.8.1–0.8.3 为本地迭代号,无独立变更面,不单列。
|
|
165
|
-
|
|
166
|
-
### 0.8.0 变更:设置页重做(对齐双清单分区定位)
|
|
167
|
-
|
|
168
|
-
- **信息架构**:社区清单(from awesome-dsh-plugin)→ 精选清单(registry.json)→ dsh-m 自身 → 关于;「主清单」的 UI 可见名统一为「精选清单」。
|
|
169
|
-
- **社区目录开关**:新增 GUI 开关(live 生效,即时切换无确认;关闭态整卡收为一行说明);新增 `set-community` API。
|
|
170
|
-
- **精选清单瘦身**:状态字段 7 行收敛为 4 行(配置地址合并、删除写死的「缓存策略」行);「配置状态」仅异常时出现;按钮组精简为「强制刷新 / 校验并应用 / 恢复默认 / 下载默认清单」,「检查条目可达性」从 GUI 移除(`registry-diagnose` API 保留)。
|
|
171
|
-
- **文案修正**:自定义源说明明确「整体替换主清单、仅影响『精选』区」;删除与实际不符的 TTL 写死描述(`timeoutMs`/`cacheTtlMin` 仍走 config 配置)。
|
|
172
|
-
- **dsh-m 自身**:本地 dev 版领先 npm 发布时改显「本地为开发版」而非误导性的旧「npm 最新」(新增 `ahead` 字段)。
|
|
173
|
-
- **关于**:文案对齐当前定位,新增 GitHub 仓库与问题反馈链接。
|
|
73
|
+
变更生效与重启(仅 Web):
|
|
174
74
|
|
|
175
|
-
|
|
75
|
+
- 安装 / 卸载 / 升级完成后,市场页与已装页自动同步最新状态,无需关闭重开面板;
|
|
76
|
+
- 随后出现「⚡ 一键重启」横幅:受 systemd 管理时经 DSH launcher 的 `appExit` 交还服务的 `Restart` 策略拉起,无 `appExit` 的宿主按设计兜底;
|
|
77
|
+
- 客户端按 boot id 确认新进程后关闭横幅,页面经 DSH Web 自身的后台重连恢复,不强制整页刷新;
|
|
78
|
+
- 安装过程实时显示 pnpm 进度(解析 → 下载 → 链接 → 构建)。
|
|
176
79
|
|
|
177
|
-
|
|
178
|
-
- **版本角标同色**:v 版本号不再用主文字亮色,与 dsh-m 名称统一为次级灰。
|
|
179
|
-
- **垂直节奏收敛**:窗口控制组按钮 26→28px 与 tab 按钮等高;版本角标微调至 24px 高;最大化/还原图标统一 12px;标题字重 700→600。
|
|
180
|
-
|
|
181
|
-
### 0.7.9 修复
|
|
182
|
-
|
|
183
|
-
- **分类 chips 顺序恒定**:退役「激活分类置前」的换序逻辑(此前每点一个被折叠裁掉的分类,它就会跳到首位,顺序随点击不断变化)。替换为:激活分类落在收起态裁剪区时自动展开完整分类行——「当前激活的分类始终可见」目标不变,顺序从此稳定;同一激活分类下手动收起会被尊重,换选其他被裁掉的分类或点「全部」时重置。
|
|
184
|
-
|
|
185
|
-
### 0.7.8 变更
|
|
186
|
-
|
|
187
|
-
- **修复「最大化没作用」的根因——CSS 热更自愈**:面板样式表此前只在首次注入(`#dshm-css` 存在即跳过),服务热更后旧 bundle 留下的样式表不含新类名规则(全屏/窗口控制组),导致新功能「点了没反应」、按钮裸奔成原生样式。现给注入的样式表带内容哈希(djb2)版本标记,bundle 更新后重新打开面板即自动替换旧样式,无需刷新页面。
|
|
188
|
-
- **窗口控制组重新配色**:去掉浮起底色,改透明底 + 发丝外框(与搜索清除钮同一配色语言),单格加宽 34→44px 防误触;关闭悬停仍为红色警示。
|
|
189
|
-
|
|
190
|
-
### 0.7.7 变更
|
|
191
|
-
|
|
192
|
-
- **移植 dsh-market 的全屏功能**:面板头部新增「最大化/还原」(连体窗口控制组设计:最大化 + 关闭等宽两格、发丝分隔线、统一 SVG 线条图标;关闭悬停红色警示)。全屏铺满视口、去圆角,状态 localStorage 记忆,Esc 关面板语义不变。
|
|
193
|
-
- 0.7.6 补记:版本角标去粗体、去点击复制(改静态展示);吸顶分类行上沿镂空修复(sticky 锚点上移抵消容器 padding);关闭/清除按钮改框线平面风。
|
|
194
|
-
|
|
195
|
-
### 0.7.5 变更
|
|
196
|
-
|
|
197
|
-
- **头部版本 chip 改显 dsh-m 自身版本**(`dsh-m v0.7.5`,点击复制;DSH 运行版本看设置页与 `dshm ping`)。
|
|
198
|
-
- **× 关闭/清除按钮统一重绘**:搜索清除、详情 Modal 关闭、操作记录行移除三处改用 SVG 线条图标 + 悬停浅底的专用按钮样式;搜索清除钮悬浮于输入框右缘(胶囊内对齐)。
|
|
199
|
-
- **修复 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)需再追加。
|
|
200
|
-
|
|
201
|
-
### 0.7.4 变更
|
|
202
|
-
|
|
203
|
-
- **面板 tab 回退旧版分段按钮风格**(0.7.2 误改下划线样式,按主人要求还原圆角按钮组 + 高亮态)。
|
|
204
|
-
- **搜索框通长**:修复搜索容器缺 `display:flex` 导致输入框未拉伸的问题,恢复整行宽度。
|
|
205
|
-
- **筛选按钮与页号跳转控件重新配色**:筛选按钮改浮起面板底色 + 方角与分类 chips 区分(激活态品牌色描边);页号输入改胶囊形细描边,「跳转」用品牌色文字钮。
|
|
206
|
-
- **吸顶分类行彻底不透**:背景直接使用不透明底色 token(此前的 color-mix 半透明配方在深色主题下仍会透出下方卡片文字),保留底部分隔线。
|
|
207
|
-
|
|
208
|
-
### 0.7.3 变更(含 0.7.2)
|
|
209
|
-
|
|
210
|
-
- **首页布局复刻 dsh-market**:市场页改为「分区 chips → 整宽搜索行 → 分类 chips + 行尾筛选弹层」结构;筛选弹层独立样式(方角矩形 + 前置 chevron),收纳排序字段(npm 下载量/Star 数/收录日期)、排列方向与每页条数(原排序下拉与分页器条数选择退役)。
|
|
211
|
-
- **收藏卡可点开详情**:修复收藏区卡片点击无响应——收藏快照字段不全,打开时按 id 从两分区内存 → market API → 快照三级解析完整条目,详情 Modal 与安装链路(含兼容确认)全量复用。
|
|
212
|
-
- **翻页页号跳转**:页码行新增页号输入框,输入有效页号回车或点「跳转」直达。
|
|
213
|
-
- **吸顶分类行毛玻璃**:滚动时吸顶的分类行加 backdrop blur 与底部分隔线,下方卡片文字不再透出干扰。
|
|
214
|
-
- **按需求移除**:「发现社区/申请收录」行(dsh-m 不支持收录功能)、「任务」按钮(操作记录面板恢复常驻)、「刷新」按钮(强制刷新在设置页)。
|
|
215
|
-
- 说明:收录条目不携带宿主版本要求字段,dsh-market 的「宿主版本」筛选项无数据源,未复刻。
|
|
216
|
-
|
|
217
|
-
### 0.7.1 修复
|
|
218
|
-
|
|
219
|
-
- **社区条目可安装**:修复 0.7.0 回归——社区区里的条目点安装报「registry 中没有该条目」(安装按收录 id 只查主清单,未查社区目录);现与升级路径同构,主清单 miss 时按 id 查社区目录再装。
|
|
220
|
-
- **市场页第一行紧凑化**:搜索框、刷新、排序(社区区)并入分区 chips 行右侧;信息性来源横幅(「官方默认收录清单 / 自定义收录清单 / 来源为本地缓存」)退役——其「共 {count} 条」计数从未接线(恒显 0);错误态「收录清单不可用」与社区兜底/陈旧提示保留。
|
|
221
|
-
|
|
222
|
-
### 0.7.0 新增
|
|
223
|
-
|
|
224
|
-
- **分区制市场**([ADR-0004](./docs/adr/0004-zoned-market-display.md)):数据层双清单合并不变,展示层按「社区(默认)/ 精选 / 收藏」三分区呈现;`dshm_search` 与 `dshm search` 改用 `--source community|primary|all` + `--offset` 真翻页(默认 10 条),`primary_only` 退役。
|
|
225
|
-
- **搜索相关性**:NFKC 归一化 + 中西文边界 + 字段加权(name/npm > owner > 描述 > 分类 > tags),多词同字段全命中;id 整串精确匹配最高优先。
|
|
226
|
-
- **操作记录 + 恢复执行器**、**本地收藏 + 下架清理**、**详情 Modal + 截图灯箱**、社区卡 byline/deprecated 徽章/目录版本快照兜底(不参与 outdated 判定)。
|
|
227
|
-
|
|
228
|
-
### 0.4.0 新增
|
|
229
|
-
|
|
230
|
-
- **开关(Enablement Toggle)**:已装卡片一键启停,内部自动路由行覆盖(单行插件,即时生效)或 Bundle 选择(多行插件);写路径委派官方 `pluginManager` 服务、缺席时降级 loader 直操作([ADR-0001](./docs/adr/0001-delegate-with-fallback-for-plugin-manager.md))。
|
|
231
|
-
- **运行相位徽标**:loader fiber 状态投影,failed 一眼可见。
|
|
232
|
-
- **保护名单**:`dsh-m` 自身与官方宿主命脉 16 项不可开关、不可卸载(升级不受影响)。
|
|
233
|
-
- **精确构建放行**:needs-builds 拦截后按 pnpm 待决名单逐键放行,全量放行降为兜底并如实标注([ADR-0002](./docs/adr/0002-precise-build-approval.md))。
|
|
234
|
-
- **peer 兼容预检**:安装/升级前校验 `@deepseek-ai/dsh(-*)` peers 与运行时版本(GitHub 源明示未检);不兼容时 GUI 弹确认、agent 回结构化结果、CLI `--force`。
|
|
235
|
-
- **实测版本清单(verified)**:registry 条目可选 `verified` 数组记录实测过的 DSH 运行时版本——实测声明而非预测声明,只展示不拦截。
|
|
236
|
-
- **bundle 身份验证**:装后检测无补丁层的包并警告「已装入为纯依赖」。
|
|
237
|
-
|
|
238
|
-
### 0.4.x 退役
|
|
239
|
-
|
|
240
|
-
- **元数据源竞速**:0.4.0 曾引入 npmjs / npmmirror ping 竞速选择元数据读取源,现整体移除(含 `probeEnabled` / `probeTimeoutMs` / `probeCacheTtlMin` 三个设置项与设置页展示)。官方同款探测只服务于「安装对话框 registry 默认预选」,dsh-m 无此交互;实测宿主机 npmjs 稳定更快,探测恒等默认行为。元数据读取固定走 npmjs,与安装链路(profile `.npmrc` 默认源)一致。
|
|
80
|
+
Desktop 的变更经官方应用生命周期生效——安装完成后退出并重新打开应用即可。重启链路的机制细节与实机核验记录见 [`docs/DESIGN.md`](https://github.com/iasiv5/dsh-m/blob/main/docs/DESIGN.md)。
|
|
241
81
|
|
|
242
82
|
## Agent 工具(8 个)
|
|
243
83
|
|
|
244
84
|
| 工具 | 用途 |
|
|
245
85
|
|---|---|
|
|
246
|
-
| `dshm_search` |
|
|
86
|
+
| `dshm_search` | 搜精选与社区清单(对话内出卡片) |
|
|
247
87
|
| `dshm_list` | 列已装插件(市场/非市场标注) |
|
|
248
|
-
| `dshm_install` |
|
|
88
|
+
| `dshm_install` | 按清单 id 安装(装前 peer 兼容预检;不兼容时回结构化结果,用户确认后 `force` 重试) |
|
|
249
89
|
| `dshm_uninstall` | 卸载(先确认;不删数据,报告残留路径) |
|
|
250
90
|
| `dshm_outdated` | 检查最新版本 |
|
|
251
91
|
| `dshm_upgrade` | 升级到最新 |
|
|
252
|
-
| `dshm_toggle` |
|
|
92
|
+
| `dshm_toggle` | 切换插件运行状态(默认先确认,用户同句已明确可直接执行) |
|
|
253
93
|
| `dshm_restart` | 一键重启 DSH Web(先征得同意) |
|
|
254
94
|
|
|
255
95
|
## CLI
|
|
@@ -266,48 +106,59 @@ dshm restart --yes
|
|
|
266
106
|
|
|
267
107
|
清单不可用时 `registry` / `search` / `outdated` 打印配置与实际生效地址并退出码 1;`list` 仍列出已装插件。CLI 固定独立缓存命名空间,不影响 Web 端。
|
|
268
108
|
|
|
269
|
-
**profile
|
|
109
|
+
**profile 目标**:CLI 恒作用于 web profile——`--profile web` 为显式声明;`--profile desktop` 直接拒绝(Desktop 的插件管理走官方 Desktop 应用)。无图形界面的宿主也可用官方 `dsh` CLI 安装插件:`dsh plugin --profile web add dsh-m`。
|
|
270
110
|
|
|
271
|
-
|
|
111
|
+
> `npm install -g dsh-m` 只安装 `dshm` CLI(终端管理用),**不会**把插件注册进 web profile;与通过官方插件管理界面安装不冲突,可并存。
|
|
272
112
|
|
|
273
|
-
|
|
113
|
+
## 社区清单(awesome-dsh-plugin 目录)
|
|
274
114
|
|
|
275
|
-
|
|
115
|
+
**社区清单是 dsh-m 的默认清单**:锚定 npm 包 [`dsh-plugin-catalog`](https://www.npmjs.com/package/dsh-plugin-catalog)(CC0-1.0,awesome-dsh-plugin 全量目录,4,000+ 条)。其上叠加手工 curated 的**精选清单**(registry.json),数据层合并去重(**精选清单恒优先**,重名条目社区侧让位),展示层按「社区 / 精选」分区呈现(ADR-0004)——社区区不再显示与精选清单重复的条目,精选区保持策展序单页直出。
|
|
276
116
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
5. 「恢复默认」一键回到官方清单。
|
|
282
|
-
|
|
283
|
-
规则与边界:严格 v1 schema(未知字段 / 非法 ID / 超限 / 重复一律拒绝,不截断);副本是独立快照,**不会自动同步**官方新条目;自定义源失败时保留其最近一次成功缓存,绝不静默回退官方清单;切换后旧自定义源缓存会被清理(默认缓存保留);自定义清单未经官方 CI 校验,请确认来源可信再安装;完整本地路径只在设置页显示,工具与卡片只显示短状态。
|
|
284
|
-
|
|
285
|
-
安全基线:拉取仅 HTTPS(loopback HTTP 除外)+ 重定向逐跳校验 + 体积上限 + 超时;npm 安装按精确版本 dist integrity 对照 pnpm lockfile 校验,不一致 fail closed 并回滚;GitHub 安装强制锁定 commit SHA;pnpm 构建脚本被拦时按策略放行并明确报告。
|
|
286
|
-
|
|
287
|
-
## 社区清单(awesome-dsh-plugin 目录,0.5.0)
|
|
288
|
-
|
|
289
|
-
除手工 curated 的主清单外,市场还会叠加一层**只读的社区清单**:锚定 npm 包 [`dsh-plugin-catalog`](https://www.npmjs.com/package/dsh-plugin-catalog)(CC0-1.0,awesome-dsh-plugin 全量目录,4,000+ 条),数据层与主清单合并去重(**主清单恒优先**,重名条目社区侧让位),展示层按「社区 / 精选」分区呈现(ADR-0004)——社区区不再显示与主清单重复的条目,精选区保持策展序单页直出。
|
|
117
|
+
<div align="center">
|
|
118
|
+
<img src="https://raw.githubusercontent.com/iasiv5/dsh-m/main/docs/images/community-catalog.webp" alt="市场视图社区分区——社区 / 精选 / 收藏分区 tabs、搜索行与带计数的开放分类 chips" width="86%">
|
|
119
|
+
<p><sub>社区清单 · 默认落地分区:分区 tabs、常驻搜索与带计数的开放分类 chips</sub></p>
|
|
120
|
+
</div>
|
|
290
121
|
|
|
291
122
|
- **数据获取**:dist-tags 探测最新版本 → jsDelivr 按精确版本直取 → npmmirror → unpkg 三线路兜底;版本未变不重拉正文,TTL 内跳过探测。失败回落 `<缓存目录>/awesome/` 运行时缓存先展示(先回缓存、后台自愈)——过期数据绝不冒充最新;缓存状态(缓存快照/目录版本/获取线路/更新时间)在**设置页**可见,浏览页不打扰。
|
|
292
123
|
- **开关与锁定**:设置页 `communityCatalog` 开关(默认开,live 生效)、`communityCatalogPin` 可锁定目录版本(精确 semver);CLI 用 `DSHM_COMMUNITY_CATALOG=0` 退出、`DSHM_COMMUNITY_CATALOG_PIN` 锁版本。
|
|
293
124
|
- **分类与搜索**:社区分类是开放集(已知 23 个分类带中英双语标签:中文由包内单一事实源维护、英文取上游目录,按界面语言下发);搜索走相关性加权管线(中英文双匹配);社区区排序可切(下载量/Star/收录日期 × 升降,默认下载量降序,无下载量 ≠ 0 下载)。
|
|
294
|
-
-
|
|
125
|
+
- **安装语义**:社区条目与精选条目走同一安装链路(npm 锁精确版本 / GitHub 锁 commit SHA);市场浏览页只对 npm 条目做更新探测,GitHub 条目不做页面级探测(匿名配额 60 次/小时不可控)。
|
|
295
126
|
- **已装页预算(best-effort)**:已装页对 GitHub 来源插件做更新检查,单次请求 ≤25 个、宿主进程滚动 1 小时 ≤50 个(仅被动检查;主动安装/升级不受限);超限条目如实标注「检查未完成」而不冒充「全部最新」。独立 CLI 进程不共享宿主内预算,并发场景不承诺 60 次/小时绝不耗尽。
|
|
296
127
|
- **能力披露**:社区条目的 capabilities/红线只出现在详情折叠区(**缺省 = 未扫描 ≠ 未检出**),卡片不打标;截图仅在详情层加载并经客户端白名单校验。
|
|
297
|
-
-
|
|
128
|
+
- **非安全审查警示**:社区目录为全量收录,**未经安全审查**——安装前请自行确认插件来源与能力;精选清单的策展与 CI 校验不适用于社区条目。
|
|
298
129
|
|
|
299
|
-
##
|
|
130
|
+
## 精选清单(registry.json)
|
|
300
131
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
132
|
+
精选清单手工 curated,叠加在社区清单之上(重名条目恒优先),按**策展五桶**分类:装机必备 / 崔添翼精选 / iasi自研 / 腾讯轻量云专区 / 观察区,当前收录 DSH Skins、DSH TUI、ModSearch、Better Sidebar、DSH Context 等插件。
|
|
133
|
+
|
|
134
|
+
<div align="center">
|
|
135
|
+
<img src="https://raw.githubusercontent.com/iasiv5/dsh-m/main/docs/images/curated-registry.webp" alt="市场视图精选分区——社区 / 精选 / 收藏分区 tabs 与策展五桶分类 chips(装机必备 / 崔添翼精选 / iasi自研 / 腾讯轻量云专区 / 观察区)" width="86%">
|
|
136
|
+
<p><sub>精选清单 · 策展五桶分类:装机必备 / 崔添翼精选 / iasi自研 / 腾讯轻量云专区 / 观察区</sub></p>
|
|
137
|
+
</div>
|
|
307
138
|
|
|
308
|
-
|
|
139
|
+
清单运行时经 **GitHub 原始文件(raw @main)→ GitHub 镜像(jsDelivr CDN,备用线路)** 双线路获取(按上次成功线路自适应排序),失败回落本地 60 分钟 TTL 缓存与包内快照——清单更新与插件发版**解耦**,push 后最多等一个缓存周期(可在设置页强制刷新)。增补 / 修订条目直接改 `registry.json` 发 PR,CI 自动校验:严格 schema、npm 包与 GitHub 仓库存在性、重复 id、URL 可达性。
|
|
309
140
|
|
|
310
|
-
|
|
141
|
+
**自定义精选清单(整体替换默认清单)**:设置页支持单一自定义 registry 地址,**整体替换**默认精选清单(不合并),且**仅影响精选区**——社区目录不受影响:
|
|
142
|
+
|
|
143
|
+
1. 「下载默认清单」得到一份官方清单副本;
|
|
144
|
+
2. 自行编辑副本(增删条目);
|
|
145
|
+
3. 在设置页填入副本地址并「校验并应用」——支持 **HTTPS URL**、本机**绝对路径 / `file://`**(HTTP 仅限 127.0.0.1/localhost 本机调试);
|
|
146
|
+
4. 校验失败(字段错误、路径不存在、超过 2 MiB / 1,000 条等)不会保存配置,当前生效清单保持不变;应用成功**即时生效,无需重启**(仅首次部署新版本 dsh-m 需要一次重启);
|
|
147
|
+
5. 「恢复默认」一键回到官方清单。
|
|
148
|
+
|
|
149
|
+
规则与边界:严格 v1 schema(未知字段 / 非法 ID / 超限 / 重复一律拒绝,不截断);副本是独立快照,**不会自动同步**官方新条目;自定义源失败时保留其最近一次成功缓存,绝不静默回退官方清单;切换后旧自定义源缓存会被清理(默认缓存保留);自定义清单未经官方 CI 校验,请确认来源可信再安装;完整本地路径只在设置页显示,工具与卡片只显示短状态。
|
|
150
|
+
|
|
151
|
+
安全基线:拉取仅 HTTPS(loopback HTTP 除外)+ 重定向逐跳校验 + 体积上限 + 超时;npm 安装按精确版本 dist integrity 对照 pnpm lockfile 校验,不一致 fail closed 并回滚;GitHub 安装强制锁定 commit SHA;pnpm 构建脚本被拦时按策略放行并明确报告。
|
|
152
|
+
|
|
153
|
+
## 文档
|
|
154
|
+
|
|
155
|
+
| 文档 | 什么时候读 |
|
|
156
|
+
|---|---|
|
|
157
|
+
| [CHANGELOG.md](https://github.com/iasiv5/dsh-m/blob/main/CHANGELOG.md) | 查看任意版本的变更明细(双语,自 0.4.x 起完整收录) |
|
|
158
|
+
| [docs/DESIGN.md](https://github.com/iasiv5/dsh-m/blob/main/docs/DESIGN.md) | 设计共识、面板行为细则、双代兼容与重启链路;开发与发版流程见其 §6 |
|
|
159
|
+
| [docs/adr/](https://github.com/iasiv5/dsh-m/tree/main/docs/adr) | 架构决策记录:委派与降级、精确构建放行、社区清单合并、分区市场、双 profile |
|
|
160
|
+
| [docs/registry-copy-guide.md](https://github.com/iasiv5/dsh-m/blob/main/docs/registry-copy-guide.md) | 为精选清单条目撰写 description 与 tags |
|
|
161
|
+
| [docs/plans/](https://github.com/iasiv5/dsh-m/tree/main/docs/plans) | 各版本实施计划存档 |
|
|
311
162
|
|
|
312
163
|
## FAQ
|
|
313
164
|
|
|
@@ -315,19 +166,28 @@ node scripts/validate-registry.mjs
|
|
|
315
166
|
main 上的中间提交可能不稳定。dsh-m 只跟踪 **release / tag**(优先 `releases/latest`,无 release 回退 tags 列表),安装时锁定 tag 指向的 commit SHA。
|
|
316
167
|
|
|
317
168
|
**1.5 官方 Desktop 上能用哪些功能?**
|
|
318
|
-
Desktop(desktop profile
|
|
169
|
+
Desktop(desktop profile)支持浏览市场、**安装新包**和插件开关。自 0.9.8 起,升级、卸载与 dsh-m 自更新也已委派官方 `pluginManager`;服务不可用时会返回结构化拒绝与操作指引。一键重启仍由官方 Desktop 应用生命周期负责,请退出并重新打开应用。市场安装标注与已装列表只反映 Desktop 当前 profile;收藏和操作记录不与 Web 同步。
|
|
319
170
|
|
|
320
171
|
**2. 卸载 dsh-m 会删我的数据吗?**
|
|
321
172
|
不会。只移除 profile 中的包引用(卸载前先下线运行中的界面),并把疑似残留路径报告给你。
|
|
322
173
|
|
|
323
174
|
**3. 自定义清单会让市场变慢吗?**
|
|
324
|
-
|
|
175
|
+
市场列表是服务端分页(每页 24/48/96 可选),1,000 条清单第一页也只查询当前页的最新版本,浏览仍然流畅。
|
|
325
176
|
|
|
326
177
|
**4. 自定义源挂了怎么办?**
|
|
327
|
-
|
|
178
|
+
优先使用该源最近一次成功的缓存(设置页「生效来源」会如实标注);完全没有缓存时市场会提示清单不可用,已安装插件仍可正常管理。修正地址或恢复默认即可。
|
|
328
179
|
|
|
329
180
|
**5. 支持哪些 DSH Web 版本?**
|
|
330
|
-
|
|
181
|
+
|
|
182
|
+
| DSH 版本 | 设置服务通路 | 核验状态 |
|
|
183
|
+
|---|---|---|
|
|
184
|
+
| `0.1.2-rc.1` | 形态探测降级 cordis 配置通路 | 契约核对 |
|
|
185
|
+
| `0.1.5-rc.1` / `rc.2` | `register()` scope 通路 | 已核对;rc.1 另有 `/dshm` ping 与带认证页面 `303 → 200` 实测 |
|
|
186
|
+
| `0.1.7-rc.1` / `rc.2` | Config `.volatile()` 字段 + `settings.update` + `loader/volatile-update` 事件 | 已核对;两个 rc 的 dsh-settings 逐字节一致,一套实现通吃 |
|
|
187
|
+
| `0.2.0-rc.1` / `rc.2` | 同 `0.1.7` 通路 | `rc.2` 为当前实机运行代际,重启链路于 2026-10-01 实机核验 |
|
|
188
|
+
|
|
189
|
+
- 通路在运行时按**形态探测**选择,不按版本号分支;未识别的形态自动降级 cordis 配置文件通路,市场主功能不受影响。实现细节见 [`docs/DESIGN.md`](https://github.com/iasiv5/dsh-m/blob/main/docs/DESIGN.md) §12。
|
|
190
|
+
- systemd 部署需为 unit 配置 `Restart=on-failure` 或 `Restart=always`,否则请使用部署方的手动重启方式。
|
|
331
191
|
|
|
332
192
|
## License
|
|
333
193
|
|
package/docs/DESIGN.md
CHANGED
|
@@ -131,7 +131,7 @@ npm 安装 / GitHub 安装 / 升级 / 自升级 / 卸载是**同一个事务模
|
|
|
131
131
|
- **更新语义加固(0.5.0)**:`isNewerVersion` 从自定义折叠比较切换为 `semver.gt`(prerelease < 正式版的标准语义——旧实现把 `1.2.3-beta.1` 的数字尾段参与比较、误判为大于 `1.2.3`;semver 已是运行时依赖),补回归测试钉死降级/相等/prerelease/build 边界;GitHub `/tags` 回退路径的 annotated tag 由 tag object sha 修正为经 `commits/{ref}` 解引用的 commit sha(与 release 路径同语义);GitHub 匿名配额的页面级探测边界按 Q46 收敛(社区 github 条目不做页面级 REST 探测);`githubTagSha` 走 `commits/{ref}` 自动解引用 annotated tag(peeled 语义已正确),同样补测试钉死。
|
|
132
132
|
- **实测版本清单(0.4.0,术语「实测版本清单」)**:registry 条目可选 `verified: string[]`(精确 semver),来自各仓库对照源的实测声明;只展示与收录质量提示,**不做安装拦截依据**。
|
|
133
133
|
- **元数据源竞速(0.4.0 引入,0.4.x 退役)**:曾照搬官方 `dsh-client-ui-plugin-manager` 的 `PluginRegistryProbe`(npmjs/npmmirror `/-/ping` 竞速选元数据读取源)。退役理由:官方竞速只服务于「安装对话框 registry 默认预选」这一交互,dsh-m 无此交互;host 实测 npmjs(~175ms)稳定快于 npmmirror(~360-1400ms),探测恒等默认值;且元数据读取已有 TTL cache + deadline 预算。npmjs 真不可达时按官方 host 语义补**失败驱动 fallback**(对 network/timeout/not-found/no-matching-version 顺序重试镜像),不再引入主动探测。残留 `probeEnabled/probeTimeoutMs/probeCacheTtlMin` 配置键被非 strict Config schema 静默忽略,无需迁移。
|
|
134
|
-
- **重启**:内置**一键重启**。在服务管理器托管的 DSH 进程内,只有确认 unit 的 `Restart=on-failure` / `Restart=always` 且 `75` 未被 `SuccessExitStatus` / `RestartPreventExitStatus` 覆盖时,才调用 launcher 提供的 `appExit(75)`;策略未知或不满足时改用 manager-owned transient `systemd-run` 调用 `systemctl`,不猜测或硬编码 unit 名称,也不在即将停止的 cgroup 内 detached spawn `systemctl`。无 systemd/appExit 时再退回 detached-helper 兼容路径。安装/卸载/升级完成后 GUI 弹「需重启生效 [一键重启]」横幅;客户端以 boot id 确认替换进程后关闭横幅,交由 DSH Web
|
|
134
|
+
- **重启**:内置**一键重启**。在服务管理器托管的 DSH 进程内,只有确认 unit 的 `Restart=on-failure` / `Restart=always` 且 `75` 未被 `SuccessExitStatus` / `RestartPreventExitStatus` 覆盖时,才调用 launcher 提供的 `appExit(75)`;策略未知或不满足时改用 manager-owned transient `systemd-run` 调用 `systemctl`,不猜测或硬编码 unit 名称,也不在即将停止的 cgroup 内 detached spawn `systemctl`。无 systemd/appExit 时再退回 detached-helper 兼容路径。安装/卸载/升级完成后 GUI 弹「需重启生效 [一键重启]」横幅;客户端以 boot id 确认替换进程后关闭横幅,交由 DSH Web 自身后台连接恢复,不强制整页刷新;工具返回重启提示。链路已在 DSH Web `0.2.0-rc.2` 实机核验(2026-10-01):探测 unit `Restart=` 策略后经 `appExit` 交还 systemd,`status=75/TEMPFAIL` 退出由 Restart 策略接住自动拉起,服务恢复后页面后台重连、面板全功能可用。历史口径:`0.1.5-rc.1` 已核验 `/dshm` ping 与带认证 `303 → 200`;`0.1.2-rc.1` 按契约核对 + 形态探测兜底收录(verified 数组)。0.9.2 起客户端在 boot id 确认后就地刷新头部角标,并在 `visibilitychange` 回前台时重取 ping;连续安装/卸载由 profile 事务测试面(补偿事务、装后守卫等 813 用例)与 0.4.0→0.4.2 连续发布实证覆盖。
|
|
135
135
|
- **安全基线(5 条)**:
|
|
136
136
|
1. 所有拉取仅 HTTPS + 响应大小上限 + 超时;
|
|
137
137
|
2. npm 安装校验 integrity;
|
|
@@ -275,3 +275,5 @@ DSH 0.1.7 把 settings 服务重塑为 `@deepseek-ai/dsh-settings` 的 `Settings
|
|
|
275
275
|
3. **新 API 不调 `configure({ auto: false })`**——保留 `autoGenerate`(默认开),设置页由宿主按 volatile 字段自动生成;
|
|
276
276
|
4. **`.volatile()` 受控调用**——仅当 schemastery 有该方法时标记(0.1.5-rc.3 精确 pin 3.18.2 无此方法,老 runtime 不受影响);方法重复包裹会 throw,每字段只调一次;
|
|
277
277
|
5. **写省略 `expectedRevision`**——与旧 API 相同的末写胜语义,并发防护由 controller 串行队列 + `lastSelfWrite` 回声去重承担。
|
|
278
|
+
|
|
279
|
+
实测代际与核验记录(README「支持哪些 DSH Web 版本」矩阵的数据源):`0.1.2-rc.1`、`0.1.5-rc.1/rc.2`、`0.1.7-rc.1/rc.2`、`0.2.0-rc.1/rc.2` 公开包契约均已核对,`0.2.0-rc.2` 为当前实机运行代际。0.1.7 适配的 live E2E(2026-09-28 回写):装机与 `/dshm` 工具链活性已在 `0.1.7-rc.2` 实证——0.4.0 → 0.4.2 连续三个版本发布收编,跨两次服务重启后 `dshm list/upgrade` 全链路可用。**遗留核验项**:设置页写值持久化未单独对照(0.1.7 起用户层设置存储迁移;dsh-m 自身 config 已观察到以 `cordis.patch.yml` 持久化形态存在,GUI 写值 → 重启对照留待首次实际使用设置面板时顺手完成)。
|
package/lib/cli.js
CHANGED
package/lib/client.js
CHANGED
|
@@ -205,7 +205,7 @@ var init_market_state = __esm({
|
|
|
205
205
|
CURATED_LABELS = {
|
|
206
206
|
essentials: "\u88C5\u673A\u5FC5\u5907",
|
|
207
207
|
"cui-picks": "\u5D14\u6DFB\u7FFC\u7CBE\u9009",
|
|
208
|
-
"self-dev": "\
|
|
208
|
+
"self-dev": "iasi\u81EA\u7814",
|
|
209
209
|
"tencent-lighthouse": "\u817E\u8BAF\u8F7B\u91CF\u4E91\u4E13\u533A",
|
|
210
210
|
watchlist: "\u89C2\u5BDF\u533A"
|
|
211
211
|
};
|
|
@@ -1175,7 +1175,7 @@ var ZH = {
|
|
|
1175
1175
|
"cat.all": "\u5168\u90E8",
|
|
1176
1176
|
"cat.essentials": "\u88C5\u673A\u5FC5\u5907",
|
|
1177
1177
|
"cat.cui-picks": "\u5D14\u6DFB\u7FFC\u7CBE\u9009",
|
|
1178
|
-
"cat.self-dev": "\
|
|
1178
|
+
"cat.self-dev": "iasi\u81EA\u7814",
|
|
1179
1179
|
"cat.tencent-lighthouse": "\u817E\u8BAF\u8F7B\u91CF\u4E91\u4E13\u533A",
|
|
1180
1180
|
"cat.watchlist": "\u89C2\u5BDF\u533A",
|
|
1181
1181
|
"zone.community": "\u793E\u533A",
|
|
@@ -1435,7 +1435,7 @@ var EN = {
|
|
|
1435
1435
|
"cat.all": "All",
|
|
1436
1436
|
"cat.essentials": "Essentials",
|
|
1437
1437
|
"cat.cui-picks": "Cui Picks",
|
|
1438
|
-
"cat.self-dev": "Self-dev",
|
|
1438
|
+
"cat.self-dev": "iasi Self-dev",
|
|
1439
1439
|
"cat.tencent-lighthouse": "Tencent Lighthouse",
|
|
1440
1440
|
"cat.watchlist": "Watchlist",
|
|
1441
1441
|
"zone.community": "Community",
|
package/lib/core/market.js
CHANGED
|
@@ -471,14 +471,22 @@ export async function listMarket(cfg = {}, opts = {}, deps = {}) {
|
|
|
471
471
|
? merged.filter((entry) => !isCommunityEntry(entry))
|
|
472
472
|
: merged;
|
|
473
473
|
const counts = zeroCounts();
|
|
474
|
-
for (const entry of zoned)
|
|
474
|
+
for (const entry of zoned) {
|
|
475
475
|
counts[entry.category] = (counts[entry.category] ?? 0) + 1;
|
|
476
|
+
// 0.9.17 次级策展桶:跨桶条目在每个归属桶里都计一次(Σcounts 可大于去重总数);
|
|
477
|
+
// 社区条目无 alsoCategories(开放集 string),cast 到 RegistryEntry 侧读取
|
|
478
|
+
const also = entry.alsoCategories;
|
|
479
|
+
for (const extra of also ?? []) {
|
|
480
|
+
counts[extra] = (counts[extra] ?? 0) + 1;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
476
483
|
const cat = opts.category ?? null;
|
|
477
484
|
// 相关性搜索(0.7.0 Task 3):归一化分词 + 字段加权评分;0 分不返回;
|
|
478
485
|
// id 整串精确匹配保证命中(收藏 stale 检测依赖)。
|
|
479
486
|
const terms = tokenizeSearchText(normalizeSearchText(opts.query ?? ''));
|
|
480
487
|
const filtered = zoned.filter((entry) => {
|
|
481
|
-
|
|
488
|
+
const also = entry.alsoCategories ?? [];
|
|
489
|
+
if (cat && entry.category !== cat && !also.includes(cat))
|
|
482
490
|
return false;
|
|
483
491
|
if (terms.length === 0)
|
|
484
492
|
return true;
|
package/lib/core/registry.js
CHANGED
|
@@ -124,7 +124,7 @@ export function parseRegistryAddress(raw) {
|
|
|
124
124
|
}
|
|
125
125
|
// ---------- 严格 v1 校验 ----------
|
|
126
126
|
const TOP_LEVEL_KEYS = new Set(['version', 'plugins']);
|
|
127
|
-
const ENTRY_KEYS = new Set(['id', 'name', 'description', 'category', 'tags', 'source', 'npm', 'github', 'homepage', 'icon', 'verified']);
|
|
127
|
+
const ENTRY_KEYS = new Set(['id', 'name', 'description', 'category', 'tags', 'source', 'npm', 'github', 'homepage', 'icon', 'verified', 'alsoCategories']);
|
|
128
128
|
/** 精确 semver 判定(与 versions.ts EXACT_VERSION_RE 同语义;接受 prerelease/build,拒绝 range/前缀)。 */
|
|
129
129
|
const EXACT_SEMVER_RE = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
|
|
130
130
|
function semverParse(value) {
|
|
@@ -307,6 +307,37 @@ export function validateRegistry(raw) {
|
|
|
307
307
|
verified = list;
|
|
308
308
|
}
|
|
309
309
|
}
|
|
310
|
+
// alsoCategories(0.9.17):可选次级策展桶——值 ∈ CATEGORIES、不含主 category、去重;
|
|
311
|
+
// 空数组 = 无次级归属(不产生键)
|
|
312
|
+
let alsoCategories;
|
|
313
|
+
if (e.alsoCategories !== undefined) {
|
|
314
|
+
if (!Array.isArray(e.alsoCategories)) {
|
|
315
|
+
errors.push(`${where}.alsoCategories: 必须是字符串数组`);
|
|
316
|
+
}
|
|
317
|
+
else {
|
|
318
|
+
const list = [];
|
|
319
|
+
const seenAlso = new Set();
|
|
320
|
+
e.alsoCategories.forEach((c, ci) => {
|
|
321
|
+
const cs = typeof c === 'string' ? c : '';
|
|
322
|
+
if (!CATEGORIES.includes(cs)) {
|
|
323
|
+
errors.push(`${where}.alsoCategories[${ci}]: 无效 ${JSON.stringify(c)}(须为策展桶)`);
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
if (cs === category) {
|
|
327
|
+
errors.push(`${where}.alsoCategories[${ci}]: 与主 category 重复 ${cs}`);
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
if (seenAlso.has(cs)) {
|
|
331
|
+
errors.push(`${where}.alsoCategories[${ci}]: 重复 ${cs}`);
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
seenAlso.add(cs);
|
|
335
|
+
list.push(cs);
|
|
336
|
+
});
|
|
337
|
+
if (list.length > 0)
|
|
338
|
+
alsoCategories = list;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
310
341
|
plugins.push({
|
|
311
342
|
id,
|
|
312
343
|
name,
|
|
@@ -319,6 +350,7 @@ export function validateRegistry(raw) {
|
|
|
319
350
|
...(entryHomepage !== undefined ? { homepage: entryHomepage } : {}),
|
|
320
351
|
...(entryIcon !== undefined ? { icon: entryIcon } : {}),
|
|
321
352
|
...(verified !== undefined ? { verified } : {}),
|
|
353
|
+
...(alsoCategories !== undefined ? { alsoCategories } : {}),
|
|
322
354
|
});
|
|
323
355
|
});
|
|
324
356
|
return { ok: errors.length === 0, errors, registry: errors.length === 0 ? { version: 1, plugins } : null };
|