dsh-shelfry 0.0.0-stage → 0.4.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.
Files changed (124) hide show
  1. package/LICENSE +27 -0
  2. package/README.md +121 -2
  3. package/README.zh.md +112 -0
  4. package/UPDATE-API-V1.md +207 -0
  5. package/assets/logo.svg +10 -0
  6. package/client/client.js +18329 -0
  7. package/cordis.patch.yml +4 -0
  8. package/lib/accelerate.js +194 -0
  9. package/lib/agents.js +67 -0
  10. package/lib/backup.js +629 -0
  11. package/lib/body-progress.js +173 -0
  12. package/lib/catalog-local-match.js +160 -0
  13. package/lib/catalog-npm.js +151 -0
  14. package/lib/changelog.js +460 -0
  15. package/lib/channels.js +64 -0
  16. package/lib/check.js +1491 -0
  17. package/lib/compatibility.js +243 -0
  18. package/lib/diagnostics.js +49 -0
  19. package/lib/discovery-compatibility.js +437 -0
  20. package/lib/drain-journal.js +133 -0
  21. package/lib/drain.js +917 -0
  22. package/lib/dsh-cli.js +1377 -0
  23. package/lib/dsh-install.js +259 -0
  24. package/lib/entry-identity.js +85 -0
  25. package/lib/gist.js +349 -0
  26. package/lib/groups.js +108 -0
  27. package/lib/home-paths.js +29 -0
  28. package/lib/host-recovery.js +159 -0
  29. package/lib/hot.js +835 -0
  30. package/lib/http.js +252 -0
  31. package/lib/index.js +390 -0
  32. package/lib/install.js +1146 -0
  33. package/lib/lifecycle.js +37 -0
  34. package/lib/log-redaction.js +24 -0
  35. package/lib/log.js +202 -0
  36. package/lib/ndjson.js +154 -0
  37. package/lib/net.js +174 -0
  38. package/lib/official-desktop.js +574 -0
  39. package/lib/order.js +284 -0
  40. package/lib/patch.js +746 -0
  41. package/lib/pending-rows.js +141 -0
  42. package/lib/pending-updates.js +318 -0
  43. package/lib/pnpm-compat.js +862 -0
  44. package/lib/presets.js +282 -0
  45. package/lib/probe-context.js +20 -0
  46. package/lib/profile.js +1889 -0
  47. package/lib/recovery.js +1059 -0
  48. package/lib/region-probe.js +93 -0
  49. package/lib/regions.js +282 -0
  50. package/lib/registry.js +299 -0
  51. package/lib/release-candidates.js +101 -0
  52. package/lib/restart.js +688 -0
  53. package/lib/routes.js +7788 -0
  54. package/lib/settings.js +164 -0
  55. package/lib/shelfry-catalog.js +177 -0
  56. package/lib/snapshot.js +500 -0
  57. package/lib/source-migration.js +164 -0
  58. package/lib/sources.js +1005 -0
  59. package/lib/store.js +163 -0
  60. package/lib/themes.js +314 -0
  61. package/lib/trial.js +125 -0
  62. package/lib/types/accelerate.d.ts +85 -0
  63. package/lib/types/agents.d.ts +52 -0
  64. package/lib/types/backup.d.ts +148 -0
  65. package/lib/types/body-progress.d.ts +94 -0
  66. package/lib/types/catalog-local-match.d.ts +39 -0
  67. package/lib/types/catalog-npm.d.ts +62 -0
  68. package/lib/types/changelog.d.ts +131 -0
  69. package/lib/types/channels.d.ts +56 -0
  70. package/lib/types/check.d.ts +353 -0
  71. package/lib/types/compatibility.d.ts +83 -0
  72. package/lib/types/diagnostics.d.ts +29 -0
  73. package/lib/types/discovery-compatibility.d.ts +142 -0
  74. package/lib/types/drain-journal.d.ts +25 -0
  75. package/lib/types/drain.d.ts +279 -0
  76. package/lib/types/dsh-cli.d.ts +469 -0
  77. package/lib/types/dsh-install.d.ts +106 -0
  78. package/lib/types/entry-identity.d.ts +68 -0
  79. package/lib/types/gist.d.ts +52 -0
  80. package/lib/types/groups.d.ts +34 -0
  81. package/lib/types/home-paths.d.ts +13 -0
  82. package/lib/types/host-recovery.d.ts +94 -0
  83. package/lib/types/hot.d.ts +389 -0
  84. package/lib/types/http.d.ts +114 -0
  85. package/lib/types/index.d.ts +52 -0
  86. package/lib/types/install.d.ts +463 -0
  87. package/lib/types/lifecycle.d.ts +14 -0
  88. package/lib/types/log-redaction.d.ts +2 -0
  89. package/lib/types/log.d.ts +43 -0
  90. package/lib/types/ndjson.d.ts +52 -0
  91. package/lib/types/net.d.ts +92 -0
  92. package/lib/types/official-desktop.d.ts +52 -0
  93. package/lib/types/order.d.ts +100 -0
  94. package/lib/types/patch.d.ts +190 -0
  95. package/lib/types/pending-rows.d.ts +81 -0
  96. package/lib/types/pending-updates.d.ts +146 -0
  97. package/lib/types/pnpm-compat.d.ts +93 -0
  98. package/lib/types/presets.d.ts +94 -0
  99. package/lib/types/probe-context.d.ts +14 -0
  100. package/lib/types/profile.d.ts +531 -0
  101. package/lib/types/recovery.d.ts +342 -0
  102. package/lib/types/region-probe.d.ts +50 -0
  103. package/lib/types/regions.d.ts +134 -0
  104. package/lib/types/registry.d.ts +148 -0
  105. package/lib/types/release-candidates.d.ts +26 -0
  106. package/lib/types/restart.d.ts +279 -0
  107. package/lib/types/routes.d.ts +130 -0
  108. package/lib/types/settings.d.ts +112 -0
  109. package/lib/types/shelfry-catalog.d.ts +48 -0
  110. package/lib/types/snapshot.d.ts +93 -0
  111. package/lib/types/source-migration.d.ts +100 -0
  112. package/lib/types/sources.d.ts +391 -0
  113. package/lib/types/store.d.ts +47 -0
  114. package/lib/types/themes.d.ts +46 -0
  115. package/lib/types/trial.d.ts +61 -0
  116. package/lib/types/update-api-v1.d.ts +83 -0
  117. package/lib/types/updates.d.ts +252 -0
  118. package/lib/types/verify.d.ts +277 -0
  119. package/lib/update-api-v1.js +273 -0
  120. package/lib/updates.js +927 -0
  121. package/lib/verify.js +904 -0
  122. package/locale/en.json +3 -0
  123. package/locale/zh.json +6 -0
  124. package/package.json +112 -4
package/LICENSE ADDED
@@ -0,0 +1,27 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 fkysly and dsh-market contributors
4
+ Copyright (c) 2026 dsh-shelfry contributors
5
+
6
+ This project is a modified derivative of dsh-market
7
+ (https://github.com/dsh-market/dsh-market), with its catalog source
8
+ replaced by shelfry. The original MIT notice above is retained as the
9
+ license requires.
10
+
11
+ Permission is hereby granted, free of charge, to any person obtaining a copy
12
+ of this software and associated documentation files (the "Software"), to deal
13
+ in the Software without restriction, including without limitation the rights
14
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
+ copies of the Software, and to permit persons to whom the Software is
16
+ furnished to do so, subject to the following conditions:
17
+
18
+ The above copyright notice and this permission notice shall be included in all
19
+ copies or substantial portions of the Software.
20
+
21
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,122 @@
1
- # Temporary Holding Version
1
+ <p align="center">
2
+ <img src="assets/logo.svg" width="96" alt="dsh-shelfry logo">
3
+ </p>
2
4
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
5
+ # dsh-shelfry
6
+
7
+ English | [中文](README.zh.md)
8
+
9
+ A plugin market for DeepSeek Harness, built by modifying
10
+ [dsh-market](https://github.com/dsh-market/dsh-market) and pointing its catalog
11
+ at **shelfry**. On dsh 0.2.1+ it is a tab on the **Plugins** page next to
12
+ **Installed**; older hosts reach it from Settings → **Shelfry Market**.
13
+ Browse, search, one-click install.
14
+
15
+ This package is **not published to npm**. Install it from the repository.
16
+
17
+ ## Install
18
+
19
+ ```sh
20
+ dsh plugin --profile web add github:shelfry/dsh-shelfry
21
+ ```
22
+
23
+ Then restart `dsh web`. For a profile other than `web`, replace the name:
24
+
25
+ ```sh
26
+ dsh plugin --profile <profile> add github:shelfry/dsh-shelfry
27
+ ```
28
+
29
+ Installing from a git source makes pnpm ask before running build scripts. The
30
+ `client/client.js` bundle is committed, so the market itself needs no build
31
+ step; a prebuilt tarball can be attached to a release if you prefer that route.
32
+
33
+ On a machine with DSH Desktop, `dsh plugin --profile web` installs into
34
+ `profiles/web`, **not** the profile the desktop app uses. Install through the
35
+ app's **Settings → Plugins** instead.
36
+
37
+ ## Catalog
38
+
39
+ The plugin list comes from shelfry, fetched live:
40
+
41
+ ```
42
+ https://shelfry.app/data/market-top.json
43
+ ```
44
+
45
+ That file has its own shape (`entries[]` with `i`, `n`, `d`, `s`, `sc`, `t`,
46
+ `vr`, `g`, `cmd`), which is mapped onto the market's internal `Registry` in
47
+ [`src/shelfry-catalog.ts`](src/shelfry-catalog.ts). Both download regions read
48
+ the same URL — shelfry publishes one JSON, so there is no mirror to fall back to
49
+ and the market does not pretend there is.
50
+
51
+ To point it somewhere else, set `DSHM_REGISTRY_URL` in the environment dsh runs
52
+ in. Overrides replace the source list rather than heading it.
53
+
54
+ ## Configuration
55
+
56
+ All settings live under `config:` in the profile's `cordis.patch.yml` — the
57
+ loader passes only that sub-object to a plugin, so a top-level key is silently
58
+ ignored:
59
+
60
+ ```yaml
61
+ - id: dsh-shelfry
62
+ name: 'dsh-shelfry'
63
+ config:
64
+ allowRestart: false # hide the restart button (systemd/pm2/launchd)
65
+ buildEnv:
66
+ CC: /usr/bin/gcc-11
67
+ CXX: /usr/bin/g++-11
68
+ ```
69
+
70
+ - `allowRestart` — one-click restart is hidden automatically when this process
71
+ is systemd's own service process; pm2 and launchd are not detected, so those
72
+ deployments set this by hand.
73
+ - `buildEnv` — environment for the processes the market spawns (installs,
74
+ compiles, git). `PATH` and `CI` stay managed by the market.
75
+ - `DSHM_GITHUB_PROXY` — operator-owned GitHub acceleration prefix; disables the
76
+ matching field in the UI when set.
77
+
78
+ Most of the rest is edited in the UI: download region, GitHub acceleration,
79
+ release channel, entries (sidebar / Settings / Plugins tab), build environment,
80
+ favorites, groups and per-plugin notes.
81
+
82
+ ## What you get
83
+
84
+ Browse and search the whole shelfry catalog with category filters, star counts
85
+ and bilingual descriptions that follow your UI language; screenshots and
86
+ comments per card; favorites; groups that switch as a unit; themes that apply
87
+ without a restart; one-click install with live progress; backup and restore
88
+ (local JSON, WebDAV, or a private GitHub Gist); per-plugin update checks with a
89
+ "What changed" link; resilient GitHub routes for the China download region;
90
+ uninstall; hot enable/disable through `cordis.patch.yml`; a one-click restart
91
+ when a change cannot hot-load; an "Adjust plugins" recovery page for a boot that
92
+ did not come back; a sanitized log export; a settings card that manages the
93
+ market itself; and a diagnostics page for load order and conflicts.
94
+
95
+ Install order: a repo-verified npm package first, then a prebuilt GitHub Release
96
+ tarball, then the full repository source. Build scripts stay blocked by default
97
+ (pnpm ≥10); allowing one is an explicit per-package choice.
98
+
99
+ ## Development
100
+
101
+ ```sh
102
+ npm install
103
+ npm run typecheck # host, client, tests
104
+ npm test # vitest, 3000+ specs
105
+ npm run build # lib/ + client/client.js
106
+ ```
107
+
108
+ `client/client.js` is a committed artifact: rebuild it and commit the result
109
+ with the source change. `scripts/preflight.mjs` (run by `prepack`) checks that
110
+ the loader id in that file matches `package.json`, that
111
+ `cordis.patch.yml` inserts by the same name, and that the declared icon ships.
112
+
113
+ The browser bundle registers itself as `window.__ModuleLoader__.load({ id })`,
114
+ where the id must equal the package name — a mismatch loads no UI at all.
115
+
116
+ See [TESTING.md](TESTING.md) for code conventions and [SECURITY.md](SECURITY.md)
117
+ for the security boundary.
118
+
119
+ ## License
120
+
121
+ MIT. This is a derivative of dsh-market; the original copyright notice is
122
+ retained in [LICENSE](LICENSE).
package/README.zh.md ADDED
@@ -0,0 +1,112 @@
1
+ <p align="center">
2
+ <img src="assets/logo.svg" width="96" alt="dsh-shelfry logo">
3
+ </p>
4
+
5
+ # dsh-shelfry
6
+
7
+ [English](README.md) | 中文
8
+
9
+ 装在 DeepSeek Harness 里的插件市场。它基于
10
+ [dsh-market](https://github.com/dsh-market/dsh-market) 改造,目录数据换成
11
+ **shelfry**。dsh 0.2.1 起它是 **插件** 页上紧挨着 **已安装** 的一个页签;
12
+ 更早的宿主从设置 → **Shelfry 市场** 进入。逛一逛,点一下,装好。
13
+
14
+ 本包**没有发布到 npm**,从仓库安装。
15
+
16
+ ## 安装
17
+
18
+ ```sh
19
+ dsh plugin --profile web add github:shelfry/dsh-shelfry
20
+ ```
21
+
22
+ 装完重启 `dsh web`。profile 不是 `web` 的话换个名字:
23
+
24
+ ```sh
25
+ dsh plugin --profile <profile> add github:shelfry/dsh-shelfry
26
+ ```
27
+
28
+ 从 git 源安装时,pnpm 会先问是否允许运行构建脚本。`client/client.js` 已经
29
+ 随仓库提交,所以市场本身不需要构建;也可以把预构建的 tarball 挂到 release
30
+ 上走那条路。
31
+
32
+ 装了 DSH 桌面端的机器上,`dsh plugin --profile web` 装进的是
33
+ `profiles/web`,**不是**桌面端在用的那个 profile。这种情况请用应用里的
34
+ **设置 → 插件** 安装。
35
+
36
+ ## 目录数据
37
+
38
+ 插件列表实时取自 shelfry:
39
+
40
+ ```
41
+ https://shelfry.app/data/market-top.json
42
+ ```
43
+
44
+ 这份文件有自己的结构(`entries[]`,字段 `i`、`n`、`d`、`s`、`sc`、`t`、
45
+ `vr`、`g`、`cmd`),由 [`src/shelfry-catalog.ts`](src/shelfry-catalog.ts)
46
+ 映射成市场内部的 `Registry`。两个下载地区读同一个地址——shelfry 只公开这一份
47
+ JSON,没有镜像可以退,市场也不做「换一个镜像」的假动作。
48
+
49
+ 想指到别处,在 dsh 运行的环境里设 `DSHM_REGISTRY_URL`。这个覆盖是**替换**
50
+ 来源列表,而不是加在队首。
51
+
52
+ ## 配置
53
+
54
+ 所有设置都在 profile 的 `cordis.patch.yml` 的 `config:` 下面——加载器只把
55
+ 这个子对象传给插件,写在顶层的键会被静默忽略:
56
+
57
+ ```yaml
58
+ - id: dsh-shelfry
59
+ name: 'dsh-shelfry'
60
+ config:
61
+ allowRestart: false # 隐藏重启按钮(systemd / pm2 / launchd)
62
+ buildEnv:
63
+ CC: /usr/bin/gcc-11
64
+ CXX: /usr/bin/g++-11
65
+ ```
66
+
67
+ - `allowRestart` —— 本进程是 systemd 的服务主进程时,重启按钮会自动隐藏;
68
+ pm2 和 launchd 检测不到,这些部署要手动设这一项。
69
+ - `buildEnv` —— 市场拉起的每个进程(安装、编译、git)的环境变量。`PATH` 和
70
+ `CI` 由市场自己管理,不能覆盖。
71
+ - `DSHM_GITHUB_PROXY` —— 运营方持有的 GitHub 加速前缀;设了它,界面里的对应
72
+ 输入框会变成只读。
73
+
74
+ 其余大部分在界面里改:下载地区、GitHub 加速、更新通道、入口(侧栏 / 设置 /
75
+ 插件页签)、构建环境、收藏、分组,以及每个插件的一行备注。
76
+
77
+ ## 它有什么
78
+
79
+ 浏览和搜索整个 shelfry 目录,带分类筛选、星标数和跟随界面语言的简介;每张卡片
80
+ 有截图和讨论区;收藏;可以整体开关的分组;装完即生效的主题;一键安装与实时
81
+ 进度;备份与恢复(本地 JSON、WebDAV、私有 GitHub Gist);逐插件检查更新并附
82
+ 「更新内容」;中国大陆地区的 GitHub 线路降级;卸载;通过 `cordis.patch.yml`
83
+ 热启用/停用;不能热加载时的一键重启;启动失败后的「调整插件」恢复页;脱敏的
84
+ 日志导出;管理市场自身的设置卡片;以及查看加载顺序与冲突的诊断页。
85
+
86
+ 安装顺序:仓库校验过的 npm 包优先,其次是作者预构建的 GitHub Release
87
+ tarball,最后才是整仓库源码。构建脚本默认被拦住(pnpm ≥10),放行需要你针对
88
+ 单个包明确同意。
89
+
90
+ ## 开发
91
+
92
+ ```sh
93
+ npm install
94
+ npm run typecheck # 宿主、客户端、测试三份
95
+ npm test # vitest,3000+ 用例
96
+ npm run build # lib/ 与 client/client.js
97
+ ```
98
+
99
+ `client/client.js` 是提交进仓库的产物:改了源码要重新构建并一起提交。
100
+ `scripts/preflight.mjs`(由 `prepack` 触发)会检查这个文件里的 loader id 与
101
+ `package.json` 一致、`cordis.patch.yml` 按同一个名字插入,以及声明的图标有没有
102
+ 打进去。
103
+
104
+ 浏览器产物以 `window.__ModuleLoader__.load({ id })` 注册自己,id 必须等于包名
105
+ ——不一致就一个界面都加载不出来。
106
+
107
+ 代码规范见 [TESTING.md](TESTING.md),安全边界见 [SECURITY.md](SECURITY.md)。
108
+
109
+ ## 许可
110
+
111
+ MIT。本项目是 dsh-market 的衍生修改版,原始版权声明保留在
112
+ [LICENSE](LICENSE)。
@@ -0,0 +1,207 @@
1
+ # Public plugin update API v1
2
+
3
+ > **Status: beta.** The shape described here may still change between
4
+ > releases. `GET /dsh-shelfry/api/v1/capabilities` reports
5
+ > `"stability": "beta"` while that is true, and `"stable"` once it stops
6
+ > moving — read that field rather than assuming from the `v1` in the path.
7
+ >
8
+ > Nothing here is going away; what is not yet promised is that field names
9
+ > and response shapes will survive untouched. If you ship against it now,
10
+ > say so in an issue: a shape somebody depends on is a much stronger reason
11
+ > not to move it, and it is how this reaches `stable`.
12
+
13
+
14
+ `dshmarket` exposes a small, versioned, same-origin JSON API for plugin-owned
15
+ update surfaces. It lets a plugin show its own update button without spawning a
16
+ package manager, copying the Market installation algorithm, or binding to the
17
+ Market UI's private response fields.
18
+
19
+ All responses carry:
20
+
21
+ ```json
22
+ { "schema": "dsh-shelfry/update-api/v1" }
23
+ ```
24
+
25
+ Clients must discover the API before enabling mutation controls:
26
+
27
+ ```http
28
+ GET /dsh-shelfry/api/v1/capabilities
29
+ ```
30
+
31
+ The response names the Market version, profile, runtime (`web` or `desktop`),
32
+ supported features, restart owner and endpoint paths. A client must hide its
33
+ restart button when `restart.supported` is false. Desktop and supervised hosts
34
+ normally delegate restart to their owning shell or operator.
35
+
36
+ ## Count what can be updated
37
+
38
+ ```http
39
+ GET /dsh-shelfry/api/v1/updates/summary
40
+ ```
41
+
42
+ ```json
43
+ {
44
+ "schema": "dsh-shelfry/update-api/v1",
45
+ "checked": 12,
46
+ "updatable": 3,
47
+ "packages": [
48
+ { "name": "dsh-mcp-connector", "source": "npm", "installedVersion": "1.1.0", "latestVersion": "1.2.0" }
49
+ ]
50
+ }
51
+ ```
52
+
53
+ `checked` is the denominator — how many installed plugins the answer looked
54
+ at. Read it, or a badge cannot tell "nothing to update" from "nothing was
55
+ looked at". The two are different answers and only one of them means the
56
+ profile is up to date.
57
+
58
+ `packages` carries the same objects the single-package endpoint below
59
+ returns, and lists only plugins that can be updated. A badge needs
60
+ `updatable`; a panel needs the rows; neither should have to filter the whole
61
+ profile itself.
62
+
63
+ `GET /dsh-shelfry/api/v1/capabilities` reports this endpoint at
64
+ `endpoints.updatesSummary` and sets `features.updatesSummary`. Check that
65
+ rather than probing for the path.
66
+
67
+ ## Check one installed package
68
+
69
+ ```http
70
+ GET /dsh-shelfry/api/v1/updates?name=dsh-mcp-connector&force=1
71
+ ```
72
+
73
+ The response includes the installed version, target version, source kind and
74
+ whether the target is a forward update. Omitting `force=1` allows the Market's
75
+ short update-check cache.
76
+
77
+ ## Start and observe an update
78
+
79
+ Mutation requests require the same-origin protection used by the Market UI.
80
+
81
+ Every endpoint here — reads included — also sits behind DSH's own browser
82
+ login, on any host that has one (`dsh web` from 0.1.2-alpha.2 on): a request
83
+ without the host's session cookie is answered `401`, and one from an untrusted
84
+ origin `403`, exactly as DSH answers for its own API (#603). A plugin UI running
85
+ in the DSH page sends that cookie with every same-origin `fetch`, so it needs no
86
+ change. A script or tool calling these endpoints from outside the browser is the
87
+ anonymous client this refuses; there is no separate token for it.
88
+
89
+ ```http
90
+ POST /dsh-shelfry/api/v1/updates
91
+ Content-Type: application/json
92
+
93
+ { "packageName": "dsh-mcp-connector" }
94
+ ```
95
+
96
+ An accepted request returns HTTP `202` immediately with an `operationId`.
97
+ Passing `"force": true` opts this one operation out of the registry release-age
98
+ wait; clients should offer it only after the normal operation reports
99
+ `RELEASE_TOO_FRESH` or `VERSION_UNCHANGED`.
100
+
101
+ Poll the operation by id:
102
+
103
+ ```http
104
+ GET /dsh-shelfry/api/v1/operations?operationId=<id>
105
+ ```
106
+
107
+ States are `queued`, `running`, `succeeded`, `failed`, `cancelled` and
108
+ `rolled-back`. Running operations include structured package progress when
109
+ pnpm provides it. Terminal operations include:
110
+
111
+ - the before and actually installed versions;
112
+ - `refreshRequired` and `restartRequired` outcomes;
113
+ - a stable failure code, bounded user-facing message and retryability;
114
+ - whether a compatibility rollback is currently available.
115
+
116
+ For npm updates, Market verifies the package version that pnpm actually placed
117
+ on disk before reporting success. This prevents pnpm's release-age policy or a
118
+ lagging registry mirror from silently turning `@latest` into an older or
119
+ unexpected build. A mismatch is restored from the pre-update recovery point
120
+ and reported as one of these stable failures:
121
+
122
+ - `DOWNGRADE_DETECTED`: the resolved version is older than the version present
123
+ before the operation; not retryable without a new target.
124
+ - `RESOLVED_VERSION_MISMATCH`: the resolved version is BELOW the registry
125
+ target checked immediately before installation; retryable after registry or
126
+ mirror convergence. A version above that target is accepted — `latest` can
127
+ move forward while the install is still running.
128
+
129
+ Provider clients should still compare `beforeVersion`, the target they showed
130
+ to the user, and `installedVersion` before offering restart. That independent
131
+ check protects clients connected to another compatible provider implementation.
132
+
133
+ Up to 50 operation records live in the current Host process. A boot id is
134
+ embedded in every operation id, so a client never mistakes a stale browser
135
+ record for a task belonging to the replacement process.
136
+
137
+ ## Roll back
138
+
139
+ ```http
140
+ POST /dsh-shelfry/api/v1/rollback
141
+ Content-Type: application/json
142
+
143
+ { "operationId": "<id>" }
144
+ ```
145
+
146
+ Rollback is intentionally capability- and operation-scoped. It is available
147
+ only when the Market's compatibility verification retained a recovery point;
148
+ a later mutation may supersede it. The normalized result is written back to
149
+ the same operation record.
150
+
151
+ ## Restart
152
+
153
+ ```http
154
+ POST /dsh-shelfry/api/v1/restart
155
+ Content-Type: application/json
156
+
157
+ {}
158
+ ```
159
+
160
+ This preserves the Market's stricter restart guard: direct loopback,
161
+ same-origin, no forwarding headers, no package mutation in progress, and a Host
162
+ whose lifecycle is not owned by Desktop or a supervisor. Clients must feature
163
+ detect it; they must not invent an alternative process-control path.
164
+
165
+ ## Rendering the market's panel elsewhere (client-side)
166
+
167
+ A host shell that wants the market inside its own container — rather than in
168
+ the settings page — reads the client service this package publishes:
169
+
170
+ ```ts
171
+ const market = ctx.reflect.get('market')
172
+ const element = market.render({ preferredSubsectionId: 'installed' })
173
+ ```
174
+
175
+ `render()` returns the market's own panel wrapped in its error boundary, as a
176
+ React element. Same page, same React instance: this package's client bundle
177
+ resolves react through the host's module table, so the element mounts
178
+ anywhere in that tree.
179
+
180
+ | member | |
181
+ |---|---|
182
+ | `version` | `1` |
183
+ | `render(props?)` | the panel element; `preferredSubsectionId` is optional |
184
+ | `setSettingsVisible(visible)` | register or retract the market's own `settings.section` entry |
185
+ | `settingsVisible()` | whether that entry is registered right now |
186
+
187
+ The user's own entry switches (#1015) are ANDed with this control: a host's
188
+ `setSettingsVisible(true)` cannot override an entry the user turned off, and
189
+ the user cannot turn on an entry the host hides. `settingsVisible()` reports
190
+ the resulting registration, not the host's last request.
191
+
192
+ `ctx.provide(name, value)` and `ctx.reflect.provide(name, value)` are the
193
+ same call — cordis's `Service.provide` delegates to the reflect layer — so
194
+ either idiom reaches this service.
195
+
196
+ What `render()` is **not**: a way to rearrange the market. It hands over the
197
+ whole panel, chrome included. Cutting the market into host-fillable regions
198
+ is a different design, and one host asking is not yet evidence that it fits
199
+ anyone else.
200
+
201
+ ## Compatibility policy
202
+
203
+ - New optional response fields may be added within v1.
204
+ - Existing v1 fields and meanings are not repurposed.
205
+ - A breaking change uses a new path and schema version.
206
+ - When discovery is unavailable, plugin UIs should fall back to opening the
207
+ Market rather than calling legacy `/dsh-shelfry/*` mutation routes directly.
@@ -0,0 +1,10 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128" role="img" aria-labelledby="t">
2
+ <title id="t">插件箱子</title>
3
+ <!-- 品牌标记:一只箱子,提手 + 朱红箱盖 + 深色箱体。 -->
4
+ <rect width="128" height="128" rx="28" fill="#f6f2ea"/>
5
+ <g>
6
+ <rect x="50.4" y="9.6" width="27.2" height="20.8" rx="10.4" fill="#2b2620"/>
7
+ <rect x="8.8" y="30.4" width="110.4" height="19.2" rx="8" fill="#c0392b"/>
8
+ <rect x="16" y="51.2" width="96" height="59.2" rx="9.6" fill="#2b2620"/>
9
+ </g>
10
+ </svg>