dsh-m 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +104 -0
- package/README.md +61 -23
- package/docs/DESIGN.md +172 -0
- package/lib/cli.js +134 -63
- package/lib/client.js +1254 -217
- package/lib/core/dsh-cli.js +118 -10
- package/lib/core/host-api.js +285 -0
- package/lib/core/httpx.js +93 -36
- package/lib/core/installed.js +69 -4
- package/lib/core/market.js +481 -104
- package/lib/core/npm-integrity.js +141 -0
- package/lib/core/progress.js +113 -0
- package/lib/core/registry-check.js +111 -0
- package/lib/core/registry-controller.js +321 -0
- package/lib/core/registry.js +634 -98
- package/lib/core/versions.js +80 -9
- package/lib/host.js +22 -161
- package/lib/tools.js +56 -41
- package/package.json +4 -2
- package/registry.json +95 -7
- package/DESIGN.md +0 -140
package/README.en.md
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# dsh-m — Plugin Marketplace for DeepSeek Harness
|
|
2
|
+
|
|
3
|
+
[](../../releases)
|
|
4
|
+
[](https://www.npmjs.com/package/dsh-m)
|
|
5
|
+
[](../../actions/workflows/registry.yml)
|
|
6
|
+
[](./LICENSE)
|
|
7
|
+
[](#faq)
|
|
8
|
+
|
|
9
|
+
English · [中文](./README.md)
|
|
10
|
+
|
|
11
|
+
A DeepSeek Harness (DSH) plugin marketplace with a customizable registry: **browse, install, uninstall, upgrade** — all local. Ships as a DSH web plugin: the "Plugin Marketplace" sidebar entry opens a three-view panel, backed by seven `dshm_*` agent tools and the `dshm` CLI.
|
|
12
|
+
|
|
13
|
+
## Quick start
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
npm install -g dsh-m # or: dsh plugin --profile web add dsh-m@<version>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
1. **Restart DSH Web** after installing (one-click restart works too).
|
|
20
|
+
2. Refresh the page and click "**Plugin Marketplace**" at the bottom of the sidebar.
|
|
21
|
+
|
|
22
|
+
The default registry includes DSH Skins, DSH Web Search, the Lark / QQ / Weixin / WeCom / DingTalk channel bridges, and dsh-m itself.
|
|
23
|
+
|
|
24
|
+
## Panel
|
|
25
|
+
|
|
26
|
+
| View | Capabilities |
|
|
27
|
+
|---|---|
|
|
28
|
+
| **Market** | Card flow with search and category filters (server-side filtering + pagination, 50 per page — even a 1,000-entry registry probes the current page only); expandable details; "Install" — npm sources pin the latest exact version, GitHub sources pin the release/tag commit |
|
|
29
|
+
| **Installed** | What your web profile actually has, annotated "via market / non-market"; update badges, upgrade, two-step confirm uninstall; 📖 README preview (64KB cap) |
|
|
30
|
+
| **Settings** | Registry address draft with "Validate & apply / Restore default / Download default registry.json / Check entries reachability"; configured vs active address and status at a glance; force refresh; dsh-m self-update |
|
|
31
|
+
|
|
32
|
+
After any mutation a "⚡ Restart" banner appears — restart goes through the systemd unit (same-origin checked, detached-helper fallback) and polls by boot id until the service is back. Installs stream live pnpm progress (resolve → download → link → build).
|
|
33
|
+
|
|
34
|
+
## Agent tools (7)
|
|
35
|
+
|
|
36
|
+
| Tool | Purpose |
|
|
37
|
+
|---|---|
|
|
38
|
+
| `dshm_search` | Search the curated registry (renders cards in chat) |
|
|
39
|
+
| `dshm_list` | List installed plugins (market / non-market annotated) |
|
|
40
|
+
| `dshm_install` | Install by listing id |
|
|
41
|
+
| `dshm_uninstall` | Uninstall (confirm first; data kept, leftovers reported) |
|
|
42
|
+
| `dshm_outdated` | Check for newer versions |
|
|
43
|
+
| `dshm_upgrade` | Upgrade to the latest |
|
|
44
|
+
| `dshm_restart` | Restart DSH Web (with user consent) |
|
|
45
|
+
|
|
46
|
+
## CLI
|
|
47
|
+
|
|
48
|
+
```sh
|
|
49
|
+
dshm search [--query topic] [--category ui]
|
|
50
|
+
dshm list | outdated | registry
|
|
51
|
+
dshm install --id dsh-web-search
|
|
52
|
+
dshm upgrade --pkg dsh-web-search --yes
|
|
53
|
+
dshm uninstall --pkg dsh-web-search --yes
|
|
54
|
+
dshm restart --yes
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
When the registry is unavailable, `registry` / `search` / `outdated` print the configured vs active address and exit 1; `list` still shows installed plugins. The CLI uses its own cache namespace and never touches the Web side's.
|
|
58
|
+
|
|
59
|
+
## Registry
|
|
60
|
+
|
|
61
|
+
`registry.json` is hand-curated and served at runtime via **raw.githubusercontent / jsDelivr `@main`** (local 60-min TTL cache + bundled snapshot fallback) — listing updates are decoupled from plugin releases. To add or amend a listing, edit `registry.json` and open a PR; CI validates the strict schema, npm/GitHub existence, duplicate ids and URL reachability.
|
|
62
|
+
|
|
63
|
+
**Custom registry (overrides the official one)**: the Settings tab supports a single custom registry address that **replaces** the default registry (no merging):
|
|
64
|
+
|
|
65
|
+
1. "Download default registry.json" gives you a copy of the official listing;
|
|
66
|
+
2. edit the copy yourself (add/remove entries);
|
|
67
|
+
3. paste its address in Settings and hit "Validate & apply" — an **HTTPS URL**, a local **absolute path / `file://`** (HTTP only for 127.0.0.1/localhost debugging);
|
|
68
|
+
4. validation failures (bad fields, missing path, over 2 MiB / 1,000 entries, …) are never saved — the currently active registry stays; a successful apply takes effect **immediately, no restart** (only the first deploy of a new dsh-m version needs one restart);
|
|
69
|
+
5. "Restore default" switches back to the official registry in one click.
|
|
70
|
+
|
|
71
|
+
Rules and limits: strict v1 schema (unknown fields / invalid ids / oversized values / duplicates reject the whole file, never truncated); the copy is a standalone snapshot and does **not** auto-sync with the official listing; a failing custom source keeps its own last good cache and never silently falls back to the official registry; old custom-source caches are cleaned after switching (the default cache is kept); custom registries are not validated by official CI — install only from sources you trust; full local paths appear only on the Settings tab, tools and cards show short statuses.
|
|
72
|
+
|
|
73
|
+
Security baseline: HTTPS-only fetches (loopback HTTP excepted) with per-hop redirect checks, size caps and timeouts; npm installs verify the exact version's dist integrity against the pnpm lockfile — mismatches fail closed and roll back; GitHub installs pinned to commit SHA; pnpm build scripts are allowed-by-policy with an explicit report when unblocked.
|
|
74
|
+
|
|
75
|
+
## Development
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
npm ci
|
|
79
|
+
npm run build # tsc (host/core/cli) + esbuild (client, tree-shaking off)
|
|
80
|
+
npm run typecheck
|
|
81
|
+
node scripts/validate-registry.mjs
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
For local iteration use a `link:` dependency (same trick as dsh-skins): point the profile dependency at this repo, then `npm run build` + restart.
|
|
85
|
+
|
|
86
|
+
Release: `npm version patch|minor|major && git push --tags` → OIDC trusted publishing.
|
|
87
|
+
|
|
88
|
+
## FAQ
|
|
89
|
+
|
|
90
|
+
**1. Why don't GitHub-sourced update hints follow main?**
|
|
91
|
+
Intermediate commits on main can be unstable. dsh-m tracks **releases / tags** only (`releases/latest` first, tags list as fallback) and pins the commit SHA the tag points to.
|
|
92
|
+
|
|
93
|
+
**2. Does uninstalling dsh-m delete my data?**
|
|
94
|
+
No. Only the package reference in the profile is removed (live UI disabled first), and suspected leftover paths are reported to you.
|
|
95
|
+
|
|
96
|
+
**3. Will a custom registry slow the market down?**
|
|
97
|
+
Listings over 200 entries trigger a performance notice. The market list is server-paginated (50 per page); even a 1,000-entry registry queries latest versions for the current page only.
|
|
98
|
+
|
|
99
|
+
**4. What if my custom source goes down?**
|
|
100
|
+
dsh-m serves its last successful cache for that source and marks it as cached; with no cache at all the market shows "registry unavailable" while installed plugins stay manageable. Fix the address or restore the default anytime.
|
|
101
|
+
|
|
102
|
+
## License
|
|
103
|
+
|
|
104
|
+
MIT
|
package/README.md
CHANGED
|
@@ -1,32 +1,43 @@
|
|
|
1
|
-
# dsh-m —
|
|
1
|
+
# dsh-m — DeepSeek Harness 插件市场
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](../../releases)
|
|
4
|
+
[](https://www.npmjs.com/package/dsh-m)
|
|
5
|
+
[](../../actions/workflows/registry.yml)
|
|
6
|
+
[](./LICENSE)
|
|
7
|
+
[](#faq)
|
|
4
8
|
|
|
5
|
-
|
|
9
|
+
[English](./README.en.md) · 中文
|
|
6
10
|
|
|
7
|
-
|
|
11
|
+
可自定义收录清单(Registry)的 DeepSeek Harness (DSH) 插件市场:**收录 · 安装 · 卸载 · 升级**,全部本机完成。以 DSH web 插件形态运行——侧栏「插件市场」打开三视图面板,同时提供 `dshm_*` agent 工具与 `dshm` CLI。
|
|
8
12
|
|
|
9
|
-
|
|
10
|
-
|
|
13
|
+
## 30 秒上手
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
npm install -g dsh-m # 或 dsh plugin --profile web add dsh-m@<version>
|
|
11
17
|
```
|
|
12
18
|
|
|
13
|
-
|
|
19
|
+
1. 安装后**重启 DSH Web**(一键重启亦可)。
|
|
20
|
+
2. 刷新页面,点击侧栏底部的「**插件市场**」。
|
|
21
|
+
|
|
22
|
+
默认收录清单里的插件包括:DSH Skins、DSH Web Search、Lark / QQ / 微信 / 企业微信 / 钉钉通道桥,以及 dsh-m 自身。
|
|
14
23
|
|
|
15
|
-
##
|
|
24
|
+
## 界面(侧栏「插件市场」)
|
|
16
25
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
26
|
+
| 视图 | 能力 |
|
|
27
|
+
|---|---|
|
|
28
|
+
| **市场** | 收录卡片流;关键词搜索、分类筛选(服务端过滤 + 分页,每页 50 条,1,000 条清单也只探测当前页);卡片展开详情与「安装」;npm 源锁定最新精确版本,GitHub 源锁定 release/tag 指向的 commit |
|
|
29
|
+
| **已装** | web profile 实装列表,标注「市场安装 / 非市场安装」;可升级徽标、升级、两段式确认卸载;📖 README 预览(64KB 截断) |
|
|
30
|
+
| **设置** | registry 地址草稿 +「校验并应用 / 恢复默认 / 下载默认 registry.json / 检查条目可达性」;配置地址、生效来源与状态一目了然;强制刷新;dsh-m 自更新 |
|
|
20
31
|
|
|
21
|
-
|
|
32
|
+
安装 / 卸载 / 升级完成后出现「⚡ 一键重启」横幅——重启走 systemd 单元(同源校验,兜底 detached helper),按 boot id 轮询直至服务恢复。安装过程实时显示 pnpm 进度(解析 → 下载 → 链接 → 构建)。
|
|
22
33
|
|
|
23
|
-
## Agent
|
|
34
|
+
## Agent 工具(7 个)
|
|
24
35
|
|
|
25
36
|
| 工具 | 用途 |
|
|
26
37
|
|---|---|
|
|
27
38
|
| `dshm_search` | 搜收录清单(对话内出卡片) |
|
|
28
|
-
| `dshm_list` |
|
|
29
|
-
| `dshm_install` | 按收录 id
|
|
39
|
+
| `dshm_list` | 列已装插件(市场/非市场标注) |
|
|
40
|
+
| `dshm_install` | 按收录 id 安装 |
|
|
30
41
|
| `dshm_uninstall` | 卸载(先确认;不删数据,报告残留路径) |
|
|
31
42
|
| `dshm_outdated` | 检查最新版本 |
|
|
32
43
|
| `dshm_upgrade` | 升级到最新 |
|
|
@@ -34,32 +45,59 @@ npm install -g dsh-m # 或由你的 DSH 插件市场/手动装进 web profile
|
|
|
34
45
|
|
|
35
46
|
## CLI
|
|
36
47
|
|
|
37
|
-
```
|
|
48
|
+
```sh
|
|
38
49
|
dshm search [--query 主题] [--category ui]
|
|
39
|
-
dshm list
|
|
40
|
-
dshm outdated
|
|
50
|
+
dshm list | outdated | registry
|
|
41
51
|
dshm install --id dsh-web-search
|
|
42
52
|
dshm upgrade --pkg dsh-web-search --yes
|
|
43
53
|
dshm uninstall --pkg dsh-web-search --yes
|
|
44
54
|
dshm restart --yes
|
|
45
55
|
```
|
|
46
56
|
|
|
57
|
+
清单不可用时 `registry` / `search` / `outdated` 打印配置与实际生效地址并退出码 1;`list` 仍列出已装插件。CLI 固定独立缓存命名空间,不影响 Web 端。
|
|
58
|
+
|
|
47
59
|
## 收录清单(registry)
|
|
48
60
|
|
|
49
|
-
`registry.json` 手工 curated,运行时经 **
|
|
61
|
+
`registry.json` 手工 curated,运行时经 **raw.githubusercontent / jsDelivr `@main`** 分发(本地 60 分钟 TTL 缓存 + 包内快照兜底)——收录更新与插件发版**解耦**。收录 / 修订直接改 `registry.json` 发 PR,CI 自动校验:严格 schema、npm 包与 GitHub 仓库存在性、重复 id、URL 可达性。
|
|
62
|
+
|
|
63
|
+
**自定义收录清单(可覆盖官方清单)**:设置页支持单一自定义 registry 地址,**整体覆盖**默认清单(不合并):
|
|
64
|
+
|
|
65
|
+
1. 「下载默认 registry.json」得到一份官方清单副本;
|
|
66
|
+
2. 自行编辑副本(增删条目);
|
|
67
|
+
3. 在设置页填入副本地址并「校验并应用」——支持 **HTTPS URL**、本机**绝对路径 / `file://`**(HTTP 仅限 127.0.0.1/localhost 本机调试);
|
|
68
|
+
4. 校验失败(字段错误、路径不存在、超过 2 MiB / 1,000 条等)不会保存配置,当前生效清单保持不变;应用成功**即时生效,无需重启**(仅首次部署新版本 dsh-m 需要一次重启);
|
|
69
|
+
5. 「恢复默认」一键回到官方清单。
|
|
70
|
+
|
|
71
|
+
规则与边界:严格 v1 schema(未知字段 / 非法 ID / 超限 / 重复一律拒绝,不截断);副本是独立快照,**不会自动同步**官方新条目;自定义源失败时保留其最近一次成功缓存,绝不静默回退官方清单;切换后旧自定义源缓存会被清理(默认缓存保留);自定义清单未经官方 CI 校验,请确认来源可信再安装;完整本地路径只在设置页显示,工具与卡片只显示短状态。
|
|
50
72
|
|
|
51
|
-
安全基线:拉取仅 HTTPS + 体积上限 + 超时;npm
|
|
73
|
+
安全基线:拉取仅 HTTPS(loopback HTTP 除外)+ 重定向逐跳校验 + 体积上限 + 超时;npm 安装按精确版本 dist integrity 对照 pnpm lockfile 校验,不一致 fail closed 并回滚;GitHub 安装强制锁定 commit SHA;pnpm 构建脚本被拦时按策略放行并明确报告。
|
|
52
74
|
|
|
53
75
|
## 开发
|
|
54
76
|
|
|
55
|
-
```
|
|
77
|
+
```sh
|
|
56
78
|
npm ci
|
|
57
|
-
npm run build # tsc(host/core/cli)+ esbuild(client,tree-shaking
|
|
79
|
+
npm run build # tsc(host/core/cli)+ esbuild(client,tree-shaking 已关闭)
|
|
58
80
|
npm run typecheck
|
|
59
81
|
node scripts/validate-registry.mjs
|
|
60
82
|
```
|
|
61
83
|
|
|
62
|
-
|
|
84
|
+
本地调试推荐 `link:` 模式(与 dsh-skins 相同):profile 依赖指向本仓库目录,`npm run build` + 重启即生效。
|
|
85
|
+
|
|
86
|
+
发版:`npm version patch|minor|major && git push --tags` → OIDC trusted publishing 自动发布。
|
|
87
|
+
|
|
88
|
+
## FAQ
|
|
89
|
+
|
|
90
|
+
**1. 为什么 GitHub 来源的更新提示不走 main HEAD?**
|
|
91
|
+
main 上的中间提交可能不稳定。dsh-m 只跟踪 **release / tag**(优先 `releases/latest`,无 release 回退 tags 列表),安装时锁定 tag 指向的 commit SHA。
|
|
92
|
+
|
|
93
|
+
**2. 卸载 dsh-m 会删我的数据吗?**
|
|
94
|
+
不会。只移除 profile 中的包引用(卸载前先下线运行中的界面),并把疑似残留路径报告给你。
|
|
95
|
+
|
|
96
|
+
**3. 自定义清单会让市场变慢吗?**
|
|
97
|
+
收录超过 200 条时会提示性能边界。市场列表是服务端分页(每页 50 条),1,000 条清单第一页也只查询当前页的最新版本,浏览仍然流畅。
|
|
98
|
+
|
|
99
|
+
**4. 自定义源挂了怎么办?**
|
|
100
|
+
优先使用该源最近一次成功的缓存并标记「缓存来源」;完全没有缓存时市场显示「收录清单不可用」,已安装插件仍可正常管理。修正地址或恢复默认即可。
|
|
63
101
|
|
|
64
102
|
## License
|
|
65
103
|
|
package/docs/DESIGN.md
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# dsh-m v1 设计共识(grilling 定稿)
|
|
2
|
+
|
|
3
|
+
> 2026-09-04 与 owner 三轮对齐的完整共识。实现以本文档为准;与本文冲突的实现细节以本文档为准。
|
|
4
|
+
|
|
5
|
+
## 1. 定位与形态
|
|
6
|
+
|
|
7
|
+
- **dsh-m** = 个人自用的 DSH(DeepSeek Harness)插件市场。
|
|
8
|
+
- 形态:**一个 DSH web 插件**(旗舰是 Web GUI)+ **7 个 agent 工具** + **薄 CLI `dshm`**,全部在同一个 npm 包里,不搞 monorepo。
|
|
9
|
+
- npm 包名 `dsh-m`(已占位发布 0.0.x),插件 id `dsh-m`,显示名 **DSH Marketplace**。
|
|
10
|
+
- 管理对象:**只管 DSH 插件**,不管 Agent Skills(skills 归 skillhub)。
|
|
11
|
+
- 与 `@cocofhu/skillhub` **完全独立并存**:不读不写它的数据与配置,仅在实现机制上借鉴(其源码镜像见 §10)。
|
|
12
|
+
- 单机自用:无服务端、无账号、无提交入口;收录变更 = 改本仓库的 registry(他人可发 PR)。
|
|
13
|
+
|
|
14
|
+
## 2. Registry(收录清单)
|
|
15
|
+
|
|
16
|
+
### 2.1 载体与分发(v1.1 可自定义 registry 定稿)
|
|
17
|
+
- repo 内**单文件 `registry.json`**,手工 curated,版本号**不写死**(运行时实查 npm/GitHub)。
|
|
18
|
+
- **默认源**获取顺序:raw.githubusercontent `@main` → jsDelivr `@main` → 默认 TTL 缓存 → npm 包内快照兜底。收录更新与插件发版**解耦**。
|
|
19
|
+
- **自定义覆盖源(单一地址,整体覆盖,不合并)**:`registryUrl` 为空 = 官方默认清单;非空 = 一个 HTTPS URL(或 loopback HTTP,仅本机管理员信任边界,不承诺 DNS rebinding 防护)或 DSH Web 主机上的本地普通文件(绝对路径 / `file://`,`realpath` + `O_NOFOLLOW` 同 fd 读取与复核,严格 UTF-8,2 MiB 原始字节上限)。自定义源失败只回退**该源自己的缓存**,绝不静默改用官方清单;无可缓存数据时返回空清单 + 不可用状态。
|
|
20
|
+
- **「新增插件」流程**:设置页下载默认 `registry.json` → 用户自行编辑副本 → 填入副本地址「校验并应用」。副本是独立快照,不自动同步官方新条目。
|
|
21
|
+
- **严格 v1 schema**:顶层只允许 `version/plugins`,条目只允许 `id/name/description/category/tags/source/npm/github/homepage/icon`;未知字段、非法 ID/npm/GitHub/URL、重复 ID/tag、字段超限、`plugins` 超过 1,000 条均拒绝整份清单(不截断、不部分加载);超过 200 条提示性能边界。
|
|
22
|
+
- **缓存模型**:cache 按 namespace 分目录(Host 与 Agent tools 用 `host/`,独立 CLI 用 `cli/`,互不删除),按带算法版本的 cacheKey 分文件(`CacheFile v2`:原子临时文件 + fsync + rename,0700/0600,symlink 拒写,同 key 进程内写锁)。**候选验证只写候选 cache,绝不 prune 旧源**;settings 写入成功后才 `commitActiveSource`:先原子写 accepted-source metadata(`host/active-source.json`,仅 Host),再清理非当前 custom cache;metadata 失败不 prune、prune 失败保留旧 cache,均只降级为 warning,不撤销已生效的配置。切换后只保留默认缓存与当前 custom 缓存。
|
|
23
|
+
- **统一安全 HTTP**:所有 JSON/text/HEAD 请求共享同一 primitive——手动重定向(每跳校验协议、最多 3 跳、循环检测、signal 传播、返回最终 URL)+ 响应大小上限 + 超时。
|
|
24
|
+
- **live 语义**:registry 地址是 live 设置,应用成功即时生效(无需重启);只有**首次部署新 Host 代码**需要一次用户确认后的 DSH Web 重启。`timeoutMs`/`cacheTtlMin` 亦为 live 读取;agent 框架注册时的静态工具 deadline 不承诺热更新。
|
|
25
|
+
|
|
26
|
+
### 2.2 Schema(v1 定稿,严格校验)
|
|
27
|
+
|
|
28
|
+
规则补充(与 `scripts/validate-registry.mjs`、`tests/registry.test.mjs` 同源实现):
|
|
29
|
+
- `id`:小写字母/数字开头,仅小写字母、数字、`.`、`_`、`-`,≤64 字符且清单内唯一;
|
|
30
|
+
- `name` ≤100、`description` ≤500、`tags` ≤10 个且单个 ≤30 字符、tag 不重复;超限拒绝,不截断;
|
|
31
|
+
- npm 包名:标准 scoped/unscoped 形状(≤214 字符,不接受版本/range/URL/空白);GitHub:`owner/repo`(owner ≤39、repo ≤100);
|
|
32
|
+
- `homepage`/`icon`:HTTPS、≤2,048 字符、无 userinfo;
|
|
33
|
+
- registry 地址规范化:trim 外层空白、拒控制字符与 userinfo、去 fragment 留 query、拒绝已知凭据 query key(`token`/`access_token`/`api_key`/`password`/`secret`)。
|
|
34
|
+
```jsonc
|
|
35
|
+
{
|
|
36
|
+
"version": 1,
|
|
37
|
+
"plugins": [
|
|
38
|
+
{
|
|
39
|
+
"id": "dsh-skins", // slug,唯一
|
|
40
|
+
"name": "DSH Skins",
|
|
41
|
+
"description": "中文描述", // v1 只有中文
|
|
42
|
+
"category": "ui", // market|tools|ui|search|media|other 六选一
|
|
43
|
+
"tags": ["主题"],
|
|
44
|
+
"source": "github", // npm|github
|
|
45
|
+
"npm": "可选;source=npm 时必填",
|
|
46
|
+
"github": "owner/repo", // source=github 时必填;npm 条目也可附
|
|
47
|
+
"homepage": "https://...",
|
|
48
|
+
"icon": "可选;覆盖自动头像"
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### 2.3 CI 校验(`.github/workflows/registry.yml`)
|
|
55
|
+
`registry.json`、`src/**`、`tests/**`、`scripts/**`、`package.json`、lockfile 或 workflow 本身变更时触发:
|
|
56
|
+
1. `npm run build`(TypeScript + esbuild + bundle marker,含 `lib/cli.js`);
|
|
57
|
+
2. `npm test`(Node 内置 test runner 全量契约测试);
|
|
58
|
+
3. schema 合法(复用 `lib/core/registry.js` 的严格 `validateRegistry`,与运行时同一套规则);
|
|
59
|
+
4. npm 条目可查;GitHub 条目 repo 存在;`icon`/`homepage` URL 可达(icon 允许为空)。
|
|
60
|
+
自定义 registry 不经过官方 CI——设置页对自定义源展示未校验信任提示。
|
|
61
|
+
|
|
62
|
+
## 3. 安装 / 卸载 / 升级 / 重启
|
|
63
|
+
|
|
64
|
+
底层原语(本机实证):`dsh plugin --profile web add|remove|update`(转发 pnpm,作用于 `$DSH_HOME/profiles/web`)。**profile 的 `package.json` 就是唯一事实源**——不引入任何额外状态文件。
|
|
65
|
+
|
|
66
|
+
- **安装(npm 源)**:装最新版并以**精确版本锁定**(不用 `^` 范围;用户指定版本必须为精确 semver,经该精确版本 endpoint 查询)。安装前对 profile 的 `package.json` / `pnpm-lock.yaml` / `pnpm-workspace.yaml` 做字节快照;安装后核验 importer 依赖为该精确版本,并在 lockfile `packages` 条目中比对与 npm dist 一致的 `resolution.integrity`——缺失或不一致 **fail closed** 并执行 **best-effort dependency rollback**(原子恢复快照 + `pnpm install --frozen-lockfile`;恢复失败同时报告两类错误并提示人工修复)。不声称 node_modules 与间接依赖已字节级回滚。
|
|
67
|
+
- **安装(GitHub 源)**:解析并**锁定 commit SHA**(`github:owner/repo#sha`),skillhub 同款。
|
|
68
|
+
- **已装识别**:读 profile `package.json` dependencies,与 registry 匹配 → 标注「市场安装」;不匹配的也列出,标注「非市场安装 / 来源未知」。卸载/升级对两类都可用。
|
|
69
|
+
- **卸载**:live-disable(先让 client bundle 下线,避免 404)→ `dsh plugin remove`。**不清理插件产生的数据/配置**,但把检测到的疑似残留路径(如 `~/.dsh/<plugin>.json`)列出报告。
|
|
70
|
+
- **升级**:**按需检查**(`dshm_outdated` / `dshm_list` 时实时比对本地版本 vs npm latest / GitHub main),半自动——展示升级计划,确认后执行。**不做后台定时器**。
|
|
71
|
+
- **自更新**:dsh-m 对自己同样做版本比对 + 提示升级(设置页呈现)。
|
|
72
|
+
- **重启**:内置**一键重启**,复用 skillhub 验证过的重启路径(本机 `dsh-web.service` 是转发 shim,不新建 systemd 单元、不监听 3080)。安装/卸载/升级完成后 GUI 弹「需重启生效 [一键重启]」横幅,工具返回重启提示。
|
|
73
|
+
- **安全基线(5 条)**:
|
|
74
|
+
1. 所有拉取仅 HTTPS + 响应大小上限 + 超时;
|
|
75
|
+
2. npm 安装校验 integrity;
|
|
76
|
+
3. GitHub 安装强制 pinned SHA;
|
|
77
|
+
4. pnpm 构建脚本被拦时,沿用 skillhub 的 `dangerouslyAllowAllBuilds` 重试,但**必须明确报告**「该插件需要执行构建脚本」;
|
|
78
|
+
5. 不做签名/验签体系(自用,明确不做)。
|
|
79
|
+
|
|
80
|
+
## 4. GUI(旗舰,v1 必须做好)
|
|
81
|
+
|
|
82
|
+
3 个视图,卡片展开式详情(不做独立详情页),**中文优先**,跟随 DSH Web 深色主题:
|
|
83
|
+
|
|
84
|
+
1. **市场页**(默认):registry 卡片流;搜索/分类为**服务端过滤**(Host 强制 `withLatest=true`、每页 50、1,000 条清单第一页只探测当前页);`MarketPanel` 是市场/已装数据唯一 owner(请求 generation + AbortController 丢弃旧响应);分页控件 + 超过 200 条性能提示 + 默认/自定义/缓存/不可用短提示(不含本地路径);卡片详情保留 README markdown 预览与 npm/GitHub 官方外链。
|
|
85
|
+
2. **已装页**:profile 实际安装列表,标注来源(市场/非市场/未知);registry 不可用时仍列出已装并标记;「可升级 → x.y.z」徽标 +「升级」;「卸载」。
|
|
86
|
+
3. **设置页**:registry 地址草稿 +「校验并应用」(先校验候选再写 settings,失败不落盘)/「恢复默认」/「下载默认 registry.json」(不改当前配置)/「检查条目可达性」(probe 统计 + 最多 100 条 issue,只读不改配置);同时展示配置地址、当前生效配置、生效来源与 configStatus(含 rejected/回滚原因与维护性 warnings);完整本地路径仅在此页显示。registry 配置为 **live 生效,不出现安装类重启横幅**;安装/卸载/升级仍保留重启横幅。
|
|
87
|
+
|
|
88
|
+
技术:`src/client.js` 经 **esbuild** 打包为 `lib/client.js`;`window.__ModuleLoader__.load({ id: "dsh-m", factory })` 注册;**React 从 module loader require**(零额外运行时依赖);manifest 注入 `@deepseek-ai/dsh-client-runtime`、`@deepseek-ai/dsh-client-ui-slots`、`@deepseek-ai/dsh-client-ui-settings`。
|
|
89
|
+
图标:GitHub 来源自动用 `https://github.com/<owner>.png?size=64`;`icon` 字段可覆盖;npm-only 条目首字母色块回退。
|
|
90
|
+
|
|
91
|
+
## 5. Agent 工具(host)与 CLI
|
|
92
|
+
|
|
93
|
+
- 工具前缀 `dshm_`,共 7 个:`dshm_search` / `dshm_list` / `dshm_install` / `dshm_uninstall` / `dshm_outdated` / `dshm_upgrade` / `dshm_restart`。Agent tools 运行于 Host 进程,与 Web GUI **共用 `host` namespace 缓存与 active config**;`dshm_search` 走服务端过滤(metadata-only,`withLatest=false`、limit ≤80),返回不含本地路径的短 summary。
|
|
94
|
+
- CLI bin `dshm`:同名同义命令集(`dshm list|search|install|uninstall|outdated|upgrade|restart`),固定 `cli` namespace。`registry`/`search`/`outdated` 在清单不可用时打印配置/实际生效地址并 **exit 1**;`list` 仍列出已装并标记不可用;本地终端可显示完整路径。
|
|
95
|
+
- 本地 API:`POST /dshm` 单路由 method 分发;除 `ping` 外全部要求 JSON Content-Type + `trustedRestartRequest` host 等价同源防护;typed 错误映射 400/403/404/405/413/415/422/500;`registry-config-apply` 校验失败 422;清单不可用的 `registry`/`market` 仍返回 200 + 结构化状态。
|
|
96
|
+
- 实现顺序:**GUI 先行,CLI 收尾**(核心逻辑同一层,CLI 是薄封装)。
|
|
97
|
+
|
|
98
|
+
## 6. 仓库与发版
|
|
99
|
+
|
|
100
|
+
- 单包结构;现有 `.github/workflows/publish.yml`(tag `v*` → OIDC trusted publishing)**一字不改**。
|
|
101
|
+
- 发版 = `npm version patch|minor|major && git push --tags`。
|
|
102
|
+
- npm 包 `dsh-m` 的 `files` 覆盖:`lib/`(`host.js` + `client.js` + `cli.js`)、`registry.json`(离线快照)、`cordis.patch.yml`、双语 README 与 `DESIGN.md`;`scripts/assert-pack.mjs` 对 `npm pack --dry-run --json` 做机器断言。
|
|
103
|
+
|
|
104
|
+
## 7. 首批收录
|
|
105
|
+
|
|
106
|
+
- `dsh-skins`(github 源)、`dsh-web-search`(实现时核实其 npm/GitHub 身份后录入)。
|
|
107
|
+
- **skillhub 不进首批**。
|
|
108
|
+
- 核心 `deepseek-harness-*` 包永不收录。
|
|
109
|
+
|
|
110
|
+
## 8. 里程碑(GUI 先行)
|
|
111
|
+
|
|
112
|
+
- **M0 脚手架**:单包结构(TS + esbuild)、manifest(`dsh.client` + `cordis.patch.yml` + `dsh.bundle.patch`)、构建脚本。
|
|
113
|
+
- **M1 core 层**:registry 拉取/缓存/覆盖、profile 读取、install/uninstall/upgrade/outdated 封装(spawn `dsh` CLI,非 shell 拼接,超时 + SIGTERM,保留末 256KB 输出)。
|
|
114
|
+
- **M2 GUI**:3 视图 + 卡片展开 + 重启横幅。
|
|
115
|
+
- **M3 host 工具**:7 个 `dshm_*` + cordis patch 注册。
|
|
116
|
+
- **M4 CLI**:`dshm` bin。
|
|
117
|
+
- **M5 收尾**:registry CI workflow、首批收录两条、自更新、发 `0.1.0`。
|
|
118
|
+
|
|
119
|
+
## 9. 决策记录(三轮 19 条)
|
|
120
|
+
|
|
121
|
+
| # | 决策 | 结论 |
|
|
122
|
+
|---|------|------|
|
|
123
|
+
| Q1 | 形态 | DSH 插件主体;**GUI 旗舰(Q9 修订:比 CLI 重要,v1 必须做好)**+ 工具 + 薄 CLI |
|
|
124
|
+
| Q2 | 管理范围 | 只管插件,skills 归 skillhub |
|
|
125
|
+
| Q3 | registry 维护 | repo 内手工 curated;版本不写死 |
|
|
126
|
+
| Q4 | 安装来源 | npm 优先 + GitHub 兜底,schema 留 `source` |
|
|
127
|
+
| Q5 | 自用边界 | 单机自用,收录靠 repo/PR,无服务端 |
|
|
128
|
+
| Q6 | 升级提示 | v1 包含,半自动;全自动后台升级不做 |
|
|
129
|
+
| Q7 | 与 skillhub 关系 | 完全独立并存 |
|
|
130
|
+
| Q8 | 重启 | 内置一键重启,复用已验证路径 |
|
|
131
|
+
| Q9 | v1 边界 | ✏️ 修订:GUI 必须进 v1 且优先级最高 |
|
|
132
|
+
| Q10 | registry 分发 | 运行时拉 `@main` + TTL 缓存 + 包内快照兜底 |
|
|
133
|
+
| Q11 | schema | 精简中文 schema(icon 经 Q22 修订为可选覆盖) |
|
|
134
|
+
| Q12 | pin 策略 | npm 精确版本;GitHub 锁 SHA |
|
|
135
|
+
| Q13 | 已装识别 | 读 profile package.json,零额外状态 |
|
|
136
|
+
| Q14 | 卸载语义 | 删包不删数据,报告残留 |
|
|
137
|
+
| Q15 | 命名 | `dshm_` 前缀 / `dshm` bin |
|
|
138
|
+
| Q16 | 升级检查时机 | 纯按需 + 自更新检查进 v1 |
|
|
139
|
+
| Q17 | 安全基线 | §3 的 5 条 |
|
|
140
|
+
| Q18 | 仓库发版 | 单包;publish.yml 不改;tag 发版 |
|
|
141
|
+
| Q19 | 首批收录 | ✏️ 修订:dsh-skins + dsh-web-search(不含 skillhub) |
|
|
142
|
+
| Q20–24 | GUI 细节 | 3 视图 / esbuild+React / 自动头像 / CLI 薄封装 / 设置页三件事 |
|
|
143
|
+
|
|
144
|
+
### 9.1 可自定义 Registry v1 追加决策(2026-09-04 grilling + 评审)
|
|
145
|
+
|
|
146
|
+
| # | 决策 | 结论 |
|
|
147
|
+
|---|------|------|
|
|
148
|
+
| Q25 | 覆盖模型 | 单一 registry 地址**整体覆盖**默认清单;不做运行时多源合并、不做逐条 UI 编辑器 |
|
|
149
|
+
| Q26 | 新增插件 | 下载默认 registry.json → 自行编辑副本 → 填地址应用;副本为独立快照不同步官方 |
|
|
150
|
+
| Q27 | schema | 严格 v1:未知字段/非法 ID/超限/重复拒绝整份清单;2 MiB / 1,000 条上限;>200 条提示性能 |
|
|
151
|
+
| Q28 | 地址类型 | HTTPS URL(外网);HTTP 仅 loopback(本机管理员信任边界,不做 DNS rebinding 防护声明);本地普通文件(fd 级安全读取) |
|
|
152
|
+
| Q29 | 失败语义 | 自定义源失败只回退该源自身缓存,绝不伪装成官方清单;无数据返回空清单 + 不可用状态 |
|
|
153
|
+
| Q30 | 缓存 | host/cli 双 namespace、CacheFile v2 原子写、candidate 不 prune、commitActiveSource 先 metadata 后 prune、失败降级 warning |
|
|
154
|
+
| Q31 | live | registry 地址 live 生效;仅首次部署新 Host 代码需一次用户确认的重启 |
|
|
155
|
+
| Q32 | 性能 | 服务端分页:GUI withLatest 最多 50/页,Agent/CLI metadata-only 最多 80;latest probe 并发 ≤8 + TTL cache + 全局 deadline |
|
|
156
|
+
| Q33 | 诊断 | 用户主动触发的 probe(npm/GitHub/homepage/icon),统计 + 稳定排序 + 100 条截断;不改配置不写缓存 |
|
|
157
|
+
| Q34 | API 防护 | 除 ping 外全部 POST 要求 JSON + host 等价同源 guard;typed 错误 400/413/415/422/500 |
|
|
158
|
+
| Q35 | integrity | npm 精确版本 dist integrity 对照 pnpm lockfile v9,fail closed + best-effort 快照回滚(Q12 的落地实现) |
|
|
159
|
+
| Q36 | namespace | Agent tools 与 Host GUI 共用 host namespace 及 active config;仅独立 CLI 用 cli namespace(Q48-A 修正) |
|
|
160
|
+
| Q37 | CLI | registry/search/outdated 不可用 exit 1 并输出配置/实际生效地址;agent 输出不泄露本地路径 |
|
|
161
|
+
|
|
162
|
+
## 10. 实现参考(本地镜像)
|
|
163
|
+
|
|
164
|
+
- **skillhub 完整源码**:`~/.research-skillhub/all`(工作区内)。重点借鉴:`src/install.ts`(zip 原子写入、防穿越)、`src/plugin-market.ts`(install-plan、pinned SHA、spawn dsh CLI、dangerouslyAllowAllBuilds 重试)、`src/installed-plugins.js`(卸载前 live-disable)、`src/live-plugin.js`、`src/restart.ts`(重启路径)、`src/client.js`(GUI 模式范本)、`src/self-update.ts`。
|
|
165
|
+
- **dshmarketplace 源码**:`~/research-dshmarketplace/`。借鉴:registry 校验两段式(无密钥校验 + 受信写入)、HMAC 常量时间比对(若将来需要)、收录启发式(topic + 最少 commits + marker 文件,备将来自动发现)。
|
|
166
|
+
|
|
167
|
+
## 11. 已知事实约束(本机)
|
|
168
|
+
|
|
169
|
+
- profile 根:`$DSH_HOME/profiles/web`(默认 `~/.dsh/profiles/web`);已装插件 = 其 `package.json` dependencies + `dsh.profile.bundles`。
|
|
170
|
+
- 新装插件需**重启 dsh web** 才加载;HMR 仅在 `pnpm run dev:web` watcher 存活时有效。
|
|
171
|
+
- 禁止创建监听 3080 的进程;`dsh-web.service` 为 shim,重启走其转发路径。
|
|
172
|
+
- 插件包协议要点:`type: module`、`main` host 入口、`exports["./client"]` 指向打包产物、`dsh.client.platform: "web"`、`dsh.bundle.patch: ./cordis.patch.yml`(`- insert: - id: dsh-m; name: dsh-m`)。
|