dsh-plugin-marketplace 0.4.2 → 0.5.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/LICENSE +21 -21
- package/README.md +23 -108
- package/README.zh.md +21 -110
- package/VERIFICATION.md +7 -0
- package/client.js +36 -2
- package/index.js +150 -278
- package/locale/en.json +6 -6
- package/locale/zh.json +6 -6
- package/management.js +171 -0
- package/package.json +90 -85
- package/runtime.js +87 -82
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Scorp1o117
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Scorp1o117
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,108 +1,23 @@
|
|
|
1
|
-
# dsh-plugin-marketplace
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
A **plugin marketplace** inside the DeepSeek Harness Web UI: browse
|
|
25
|
-
[github.com/topics/dsh-plugin](https://github.com/topics/dsh-plugin) right
|
|
26
|
-
from the settings page — no terminal needed.
|
|
27
|
-
|
|
28
|
-
- **Search** the topic by keyword, **sort** by stars or last update
|
|
29
|
-
- **Plugin cards** with description, stars, language, and update date
|
|
30
|
-
- **Detail panel**: GitHub README summary, install command, repo/npm links
|
|
31
|
-
- **AI explain**: one click asks the configured default model what a plugin
|
|
32
|
-
roughly does, answered in the UI — no need to read the README yourself
|
|
33
|
-
- Powered by the public GitHub search API (CORS-enabled, no key needed;
|
|
34
|
-
unauthenticated rate limit 60 req/h)
|
|
35
|
-
- Zero client dependencies (React only), no build step — hand-written
|
|
36
|
-
ModuleLoader bundle
|
|
37
|
-
|
|
38
|
-
## Compatibility (v0.3.7)
|
|
39
|
-
|
|
40
|
-
Verified with DSH `0.1.7-rc.2` (Web) and `0.2.0-rc.2` (Desktop runtime) in isolated profiles. The Desktop app uses its own `desktop` profile. Other DSH prereleases remain unverified.
|
|
41
|
-
|
|
42
|
-
## Desktop install
|
|
43
|
-
|
|
44
|
-
Use the Desktop-installed `dsh` command (Application → Manage dsh Command), or the app’s Plugins page. Then install into the Desktop profile:
|
|
45
|
-
|
|
46
|
-
```powershell
|
|
47
|
-
dsh plugin --profile desktop add dsh-plugin-marketplace@0.3.7
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
Restart the Desktop app to load the client bundle. Desktop keeps its profile under `$DSH_HOME/profiles/desktop`.
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
## Install
|
|
54
|
-
|
|
55
|
-
As a profile bundle (recommended):
|
|
56
|
-
|
|
57
|
-
```
|
|
58
|
-
dsh plugin --profile web add dsh-plugin-marketplace
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
or via the package's `dsh.bundle.patch` layer — add `dsh-plugin-marketplace`
|
|
62
|
-
to `dsh.profile.bundles` in `$DSH_HOME/profiles/web/package.json`.
|
|
63
|
-
|
|
64
|
-
Manual mount in `$DSH_HOME/profiles/web/cordis.patch.yml`:
|
|
65
|
-
|
|
66
|
-
```yaml
|
|
67
|
-
- insert:
|
|
68
|
-
- id: plugin-marketplace
|
|
69
|
-
name: 'dsh-plugin-marketplace'
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
> **Upgrading from ≤ 0.2.2?** If you previously mounted the plugin manually,
|
|
73
|
-
> **remove that row from `cordis.patch.yml`** before switching to the bundle
|
|
74
|
-
> install — the bundle layer already inserts the entry, and two entries with
|
|
75
|
-
> the same id abort boot with `duplicate loader entry id: plugin-marketplace`.
|
|
76
|
-
> The two ways are alternatives, not both.
|
|
77
|
-
|
|
78
|
-
Then restart `dsh web` (new client plugins require a process restart to be
|
|
79
|
-
scanned into the browser roster) and open **Settings → Plugin Marketplace**.
|
|
80
|
-
|
|
81
|
-
Version 0.3.7 uses DSH's `configForms` client service and Profile patch
|
|
82
|
-
settings. Use an older plugin release with older DSH hosts.
|
|
83
|
-
Note: when dsh web is opened from a non-loopback origin (a LAN IP, say), DSH
|
|
84
|
-
keeps settings writes process-local, so install / AI-explain requests never
|
|
85
|
-
reach the host.
|
|
86
|
-
|
|
87
|
-
## How it works
|
|
88
|
-
|
|
89
|
-
| Layer | File | Role |
|
|
90
|
-
|---|---|---|
|
|
91
|
-
| host shell | `index.js` | settings-backed install + AI-explain flows; `dsh.bundle.patch` makes the package a proper profile bundle |
|
|
92
|
-
| browser half | `client.js` | registers the `settings.section` "marketplace" tab; fetches GitHub search API; renders cards + detail; "AI explain" button |
|
|
93
|
-
| manifest | `package.json` | `dsh.bundle: { patch: "./cordis.patch.yml" }` + `dsh.client: { platform: "web" }` + `exports["./client"]` — discovered by `dsh-client-modules` |
|
|
94
|
-
|
|
95
|
-
The browser half needs no `dsh.client.inject` packages: it only uses `react`
|
|
96
|
-
(provided by the web runtime) and the `slots` / `locale` client services.
|
|
97
|
-
|
|
98
|
-
## Notes
|
|
99
|
-
|
|
100
|
-
- The GitHub search API returns at most 1000 results; the topic currently has
|
|
101
|
-
280+ repos, so paging covers everything.
|
|
102
|
-
- READMEs are fetched per plugin on demand and truncated to ~1200 chars.
|
|
103
|
-
- If you see "rate-limited", wait an hour or run the web through a proxy that
|
|
104
|
-
adds a GitHub token.
|
|
105
|
-
|
|
106
|
-
## License
|
|
107
|
-
|
|
108
|
-
MIT
|
|
1
|
+
# dsh-plugin-marketplace
|
|
2
|
+
|
|
3
|
+
Browse GitHub's dsh-plugin topic and manage plugins in the active DSH Web or Desktop profile. Version 0.5.0 requires DSH 0.2.0-rc.2 or later 0.2.x.
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
dsh plugin --profile desktop add dsh-plugin-marketplace@0.5.0
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Use the Desktop-provided dsh command (Application → Manage dsh Command); use --profile web for Web. Restart DSH, then open **Plugins → Installed → dsh-plugin-marketplace**.
|
|
10
|
+
|
|
11
|
+
## Plugin management
|
|
12
|
+
|
|
13
|
+
The configuration page lists the active profile's direct dependencies and built-in bundles. Enter an npm package name (including scoped names) to install, update individual installed packages to latest, refresh the list, or uninstall with an inline confirmation. Updates explicitly resolve package@latest, including dependencies pinned to an older version. Built-in bundles are listed as managed by DSH and cannot be overwritten or removed here. Transitive libraries are not independent profile plugins.
|
|
14
|
+
|
|
15
|
+
Operations use the official CLI carried by the current Host. Desktop uses its bundled Electron CLI and package manager with its own profile; it does not invoke the global Web CLI or the Desktop Host entry as a CLI. Operations are serialized across the suite and marketplace. Results refresh the actual installed inventory; a failed batch reports its failure and any partial installed state. Restart DSH after package changes, including updating or uninstalling this marketplace itself.
|
|
16
|
+
|
|
17
|
+
Bundle registration/removal is reconciled by DSH. Legacy manual mounts and their configuration patches are removed structurally on uninstall. Unrelated YAML configuration and comments are preserved. Settings requests are acknowledged outside HMR and consumed once; pending work is cancelled on unload.
|
|
18
|
+
|
|
19
|
+
The GitHub browser retains explicit search, star/update sorting, README previews and AI explanations using the configured model. Package names inferred from repository names should be checked against the author's installation instructions; the management form also accepts an explicit npm name. Both Chinese and English follow the DSH language setting.
|
|
20
|
+
|
|
21
|
+
## Validation
|
|
22
|
+
|
|
23
|
+
npm test covers Desktop CLI routing, state writes, HMR, localization, pinned updates, uninstall cleanup, built-in protection, failed operations and serialization.
|
package/README.zh.md
CHANGED
|
@@ -1,110 +1,21 @@
|
|
|
1
|
-
# dsh-plugin-marketplace
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
在 DeepSeek Harness **Web UI 里内置的插件市场**:直接在设置页浏览
|
|
23
|
-
[github.com/topics/dsh-plugin](https://github.com/topics/dsh-plugin),无需打开终端。
|
|
24
|
-
|
|
25
|
-
- **搜索**:按关键词搜索主题下的插件,按 Star 或更新时间**排序**
|
|
26
|
-
- **插件卡片**:名称、简介、Star 数、语言、更新时间一目了然
|
|
27
|
-
- **详情面板**:GitHub README 摘要、安装命令、仓库 / npm 链接
|
|
28
|
-
- **AI 解释**:一键调用已配置的默认模型,用中文直接告诉你这个插件大概是干嘛的,不用自己啃 README
|
|
29
|
-
- 基于 GitHub 公开搜索 API(浏览器 CORS 直连,无需密钥;未认证限流 60 次/小时)
|
|
30
|
-
- 零客户端依赖(只用 React),无构建步骤 —— 手写 ModuleLoader bundle
|
|
31
|
-
|
|
32
|
-
## 兼容性(v0.3.7)
|
|
33
|
-
|
|
34
|
-
已在 DSH `0.1.7-rc.2`(Web)与 `0.2.0-rc.2`(桌面端运行时)的一次性 Profile 验证。桌面端使用独立的 `desktop` Profile;其他预发布版本暂未验证。
|
|
35
|
-
|
|
36
|
-
## 桌面端安装
|
|
37
|
-
|
|
38
|
-
在桌面端的“插件”页面安装,或使用桌面端“应用 → 管理 dsh 命令”注册的命令:
|
|
39
|
-
|
|
40
|
-
```powershell
|
|
41
|
-
dsh plugin --profile desktop add dsh-plugin-marketplace@0.3.7
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
重启桌面端以加载客户端插件。配置位于 `$DSH_HOME/profiles/desktop`。
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
## 安装
|
|
48
|
-
|
|
49
|
-
作为 profile bundle 安装(推荐):
|
|
50
|
-
|
|
51
|
-
```
|
|
52
|
-
dsh plugin --profile web add dsh-plugin-marketplace
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
或通过包的 `dsh.bundle.patch` 层:把 `dsh-plugin-marketplace` 加进
|
|
56
|
-
`$DSH_HOME/profiles/web/package.json` 的 `dsh.profile.bundles`。
|
|
57
|
-
|
|
58
|
-
手动挂载(`$DSH_HOME/profiles/web/cordis.patch.yml`):
|
|
59
|
-
|
|
60
|
-
```yaml
|
|
61
|
-
- insert:
|
|
62
|
-
- id: plugin-marketplace
|
|
63
|
-
name: 'dsh-plugin-marketplace'
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
> **从 ≤ 0.2.2 升级?** 如果你之前是手动挂载的,切到 bundle 安装前**先删掉
|
|
67
|
-
> `cordis.patch.yml` 里那一行**——bundle 层自己会插入条目,两行同 id 会让启动
|
|
68
|
-
> 直接报 `duplicate loader entry id: plugin-marketplace`。两种方式二选一,别同时用。
|
|
69
|
-
|
|
70
|
-
然后重启 `dsh web`(新客户端插件需要重启进程才会被扫描进浏览器清单),打开 **插件 → dsh-plugin-marketplace**。
|
|
71
|
-
|
|
72
|
-
DSH `0.1.0-rc.7` 起会公开全部已注册的 settings 命名空间,插件市场无需再修改官方文件。
|
|
73
|
-
因此从 `0.2.8` 起最低支持 DSH `0.1.0-rc.7`。仍使用 DSH `0.1.0-rc.6` 的用户
|
|
74
|
-
请锁定 `dsh-plugin-marketplace@0.2.6`;这是最后一个包含旧 settings 白名单兼容
|
|
75
|
-
补丁的版本。
|
|
76
|
-
|
|
77
|
-
DSH `0.1.2-rc.1` 移除了客户端的 `connection.api`(旧 settings RPC 入口),
|
|
78
|
-
`0.3.1` 起改用 `settingsScope` 自带的 `mutate` 写入(`0.1.2-rc.1` 之前的主机仍走
|
|
79
|
-
旧通道)。注意:非本机回环(如局域网 IP)访问 dsh web 时,DSH 的设置写入是
|
|
80
|
-
进程本地的,安装 / AI 解释请求不会到达宿主。
|
|
81
|
-
|
|
82
|
-
## 实现方式
|
|
83
|
-
|
|
84
|
-
| 层 | 文件 | 作用 |
|
|
85
|
-
|---|---|---|
|
|
86
|
-
| 服务端壳 | `index.js` | settings 通道的安装 + AI 解释流程;`dsh.bundle.patch` 让包成为标准 profile bundle |
|
|
87
|
-
| 浏览器端 | `client.js` | 注册 `settings.section` 的 "marketplace" 分区;调用 GitHub 搜索 API;渲染卡片 + 详情;"AI 解释"按钮 |
|
|
88
|
-
| 清单 | `package.json` | `dsh.bundle: { patch: "./cordis.patch.yml" }` + `dsh.client: { platform: "web" }` + `exports["./client"]` —— 被 `dsh-client-modules` 扫描发现 |
|
|
89
|
-
|
|
90
|
-
浏览器端不需要任何 `dsh.client.inject` 依赖包:只用 `react`(web 运行时自带)和 `slots` / `locale` 客户端服务。
|
|
91
|
-
|
|
92
|
-
## v0.3.3:写入改为校验而非假定
|
|
93
|
-
|
|
94
|
-
`writeField` 在走 settings scope 时只检查了 `snapshot.status === "ready"` 就返回成功。
|
|
95
|
-
但 scope 的契约是「完成写入与恢复读取后结算」,**被宿主以 `settings/conflict` 拒绝的
|
|
96
|
-
写入同样会 resolve**——而拒绝之后命名空间依然注册着,恢复读取也会把它重新渲染成
|
|
97
|
-
`ready`,所以这个检查恒真,被拒的写入会被报成成功。
|
|
98
|
-
|
|
99
|
-
现在改为比对 section 自身的值(`settings-not-applied`),调用方拿到的 `{ok:false}` 才
|
|
100
|
-
真的代表写入没生效。
|
|
101
|
-
|
|
102
|
-
## 备注
|
|
103
|
-
|
|
104
|
-
- GitHub 搜索 API 最多返回 1000 条;该主题目前有 280+ 仓库,翻页可以覆盖全部。
|
|
105
|
-
- README 按需按插件拉取,截断到约 1200 字符。
|
|
106
|
-
- 遇到 "rate-limited":等一小时,或让 web 走带 GitHub token 的代理。
|
|
107
|
-
|
|
108
|
-
## License
|
|
109
|
-
|
|
110
|
-
MIT
|
|
1
|
+
# dsh-plugin-marketplace
|
|
2
|
+
|
|
3
|
+
浏览 GitHub 的 dsh-plugin 插件,同时管理当前 DSH Web / Desktop Profile 的插件。0.5.0 需要 DSH 0.2.0-rc.2 或后续 0.2.x。
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
dsh plugin --profile desktop add dsh-plugin-marketplace@0.5.0
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
使用 Desktop 提供的 dsh 命令(应用 → 管理 dsh 命令);Web 改用 --profile web。重启后打开 **插件 → 已安装 → dsh-plugin-marketplace** 配置页。
|
|
10
|
+
|
|
11
|
+
## 插件管理
|
|
12
|
+
|
|
13
|
+
展示当前 Profile 的直接依赖与内置 bundle。输入 npm 包名(支持 @scope/name)即可安装;每个已安装插件可以更新到最新版或二次确认卸载,还可刷新列表。更新明确安装 package@latest,能跨过旧版本锁定。内置 bundle 标明由 DSH 自身管理,不能在此覆盖或卸载。间接依赖库不作为独立插件显示。
|
|
14
|
+
|
|
15
|
+
Desktop 使用当前宿主携带的 Electron CLI、包管理器与 Desktop Profile。套件和市场的操作按 Profile 串行执行;操作后重新读取真实安装状态,失败时展示错误与部分完成的状态。安装、更新、卸载后需要重启 DSH;市场自身更新或卸载也适用。
|
|
16
|
+
|
|
17
|
+
DSH 负责 bundle 的挂载与移除;卸载旧式插件时会结构化清理手动挂载及其配置补丁,保留其它 YAML 配置和注释。设置请求在 HMR 事务外消费,并在卸载插件后取消待处理工作。
|
|
18
|
+
|
|
19
|
+
保留关键词搜索、Star / 更新时间排序、README 预览和使用当前模型的 AI 解释。仓库名未必等于 npm 包名,请核对作者说明;也可直接在管理表单输入实际包名。中英文跟随 DSH。
|
|
20
|
+
|
|
21
|
+
运行 npm test 验证 Desktop 路径、HMR、版本更新、卸载清理、内置保护、失败行为与串行执行。
|
package/VERIFICATION.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# v0.5.0 validation — 2026-10-12
|
|
2
|
+
|
|
3
|
+
- Full npm test passed (25 tests), including pinned-version update arguments, structural YAML cleanup, failed operations, built-in protection, HMR and profile serialization.
|
|
4
|
+
- npm pack contents include management.js, runtime.js, client.js, locale metadata and bundle patch.
|
|
5
|
+
- Installed tarballs through the real Desktop bundled CLI in an isolated profile and started them using the installed Desktop 0.2.0-rc.2 runtime.
|
|
6
|
+
- Settings-channel refresh, invalid-package rejection, installation, update and uninstall of dsh-motion-ui all reached the expected real installed state.
|
|
7
|
+
- Browser showed the active Desktop inventory, explicit npm-name input, update/uninstall controls and protected built-in bundles.
|
package/client.js
CHANGED
|
@@ -83,6 +83,9 @@ window.__ModuleLoader__.load({
|
|
|
83
83
|
var NS = "marketplace";
|
|
84
84
|
var inject = ["slots", "locale", "configForms", "connection"];
|
|
85
85
|
var zh = {
|
|
86
|
+
manage: "插件管理", installed: "已安装插件", packageName: "npm 包名(支持 @scope/name)", refresh: "刷新列表",
|
|
87
|
+
updatePlugin: "更新到最新版", removePlugin: "卸载", confirmRemove: "确认卸载", builtin: "内置(随 DSH 更新)",
|
|
88
|
+
restartHint: "安装、更新或卸载后,请重启 DSH。操作针对当前 Profile。", operationOk: "操作完成", operationError: "操作失败", operationBusy: "正在处理…",
|
|
86
89
|
nav: "插件市场",
|
|
87
90
|
searchBtn: "搜索",
|
|
88
91
|
sortLabel: "排序方式",
|
|
@@ -117,6 +120,9 @@ window.__ModuleLoader__.load({
|
|
|
117
120
|
notExposed: "无法写入插件市场的设置通道:DSH 版本过旧(需 0.1.0-rc.7+)、宿主半端未挂载,或当前页面不是本机回环访问;请通过 127.0.0.1 打开 dsh web 后重试。"
|
|
118
121
|
};
|
|
119
122
|
var en = {
|
|
123
|
+
manage: "Plugin management", installed: "Installed plugins", packageName: "npm package name (supports @scope/name)", refresh: "Refresh list",
|
|
124
|
+
updatePlugin: "Update to latest", removePlugin: "Uninstall", confirmRemove: "Confirm uninstall", builtin: "Built-in (updated with DSH)",
|
|
125
|
+
restartHint: "Restart DSH after installing, updating or uninstalling. Operations target the current profile.", operationOk: "Operation completed", operationError: "Operation failed", operationBusy: "Working…",
|
|
120
126
|
nav: "Plugin Marketplace",
|
|
121
127
|
searchBtn: "Search",
|
|
122
128
|
sortLabel: "Sort plugins",
|
|
@@ -356,6 +362,33 @@ window.__ModuleLoader__.load({
|
|
|
356
362
|
);
|
|
357
363
|
}
|
|
358
364
|
|
|
365
|
+
function PluginManager(props) {
|
|
366
|
+
var t = props.t, channel = props.channel || {};
|
|
367
|
+
var [pkg, setPkg] = react.useState("");
|
|
368
|
+
var [confirm, setConfirm] = react.useState("");
|
|
369
|
+
var inventory = channel.inventory || {};
|
|
370
|
+
var busy = Boolean(channel.install && channel.install.ts) || channel.installState && channel.installState.status === "running";
|
|
371
|
+
var disabled = busy || !props.writable;
|
|
372
|
+
return h("section", { className: "__mp_manager", "aria-label": t("manage") },
|
|
373
|
+
h("h3", null, t("manage") + (inventory.profile ? " · " + inventory.profile : "")),
|
|
374
|
+
h("p", { className: "__mp_status" }, t("restartHint")),
|
|
375
|
+
h("form", { className: "__mp_toolbar", onSubmit: function (event) { event.preventDefault(); if (pkg.trim() && !disabled) props.onAction(pkg.trim(), "install"); } },
|
|
376
|
+
h("input", { className: "__mp_input", value: pkg, disabled: disabled, "aria-label": t("packageName"), placeholder: t("packageName"), onChange: function (event) { setPkg(event.target.value); } }),
|
|
377
|
+
h("button", { type: "submit", disabled: disabled || !pkg.trim() }, t("installBtn")),
|
|
378
|
+
h("button", { type: "button", disabled: disabled, onClick: function () { props.onAction("~refresh", "refresh"); } }, t("refresh"))),
|
|
379
|
+
h("h3", null, t("installed")),
|
|
380
|
+
h("ul", { style: { listStyle: "none", padding: 0 } }, (inventory.packages || []).map(function (row) {
|
|
381
|
+
return h("li", { key: row.name, style: { padding: "12px 0", borderBottom: "1px solid var(--dsw-alias-border-l2)", overflowWrap: "anywhere" } },
|
|
382
|
+
h("strong", null, row.name), " ", row.version || "—", " ",
|
|
383
|
+
row.managed ? h("span", { style: { display: "flex", gap: 8, flexWrap: "wrap", marginTop: 8 } },
|
|
384
|
+
h("button", { type: "button", disabled: disabled, onClick: function () { props.onAction(row.name, "update"); } }, t("updatePlugin")),
|
|
385
|
+
h("button", { type: "button", disabled: disabled, onClick: function () { if (confirm !== row.name) setConfirm(row.name); else { setConfirm(""); props.onAction(row.name, "remove"); } } }, t(confirm === row.name ? "confirmRemove" : "removePlugin")))
|
|
386
|
+
: h("span", null, t("builtin")));
|
|
387
|
+
})),
|
|
388
|
+
channel.installState && channel.installState.status !== "idle" ? h("p", { role: channel.installState.status === "error" ? "alert" : "status", className: "__mp_status" },
|
|
389
|
+
t(channel.installState.status === "running" ? "operationBusy" : channel.installState.status === "error" ? "operationError" : "operationOk") + ": " + (channel.installState.pkg || "") + (channel.installState.status === "error" ? " · " + channel.installState.message : "")) : null);
|
|
390
|
+
}
|
|
391
|
+
|
|
359
392
|
function MarketplaceSection(props) {
|
|
360
393
|
useLocale(props.locale);
|
|
361
394
|
var t = props.t;
|
|
@@ -403,9 +436,9 @@ window.__ModuleLoader__.load({
|
|
|
403
436
|
if (detail && detail.code === "settings-not-exposed") return { key: "notExposed" };
|
|
404
437
|
return { key: "", detail: String(detail && (detail.message || detail.code) || fallback) };
|
|
405
438
|
};
|
|
406
|
-
var onInstall = react.useCallback(function (pkg) {
|
|
439
|
+
var onInstall = react.useCallback(function (pkg, action) {
|
|
407
440
|
set(function (prev) { return Object.assign({}, prev, { installError: null }); });
|
|
408
|
-
writeField(scope, api, "install", { pkg: pkg, ts: Date.now() }).then(function (result) {
|
|
441
|
+
writeField(scope, api, "install", { pkg: pkg, action: action || "install", ts: Date.now() }).then(function (result) {
|
|
409
442
|
if (!result.ok) {
|
|
410
443
|
set(function (prev) { return Object.assign({}, prev, { installError: mutateError(result.error, "unknown") }); });
|
|
411
444
|
}
|
|
@@ -470,6 +503,7 @@ window.__ModuleLoader__.load({
|
|
|
470
503
|
};
|
|
471
504
|
var more = function () { load(s.q, s.sort, s.page + 1, true); };
|
|
472
505
|
return h("div", { className: "__mp_root dsh-flat" },
|
|
506
|
+
h(PluginManager, { channel: channel, t: t, onAction: onInstall, writable: installState && installState.writable }),
|
|
473
507
|
h("form", { className: "__mp_toolbar", onSubmit: submit },
|
|
474
508
|
h("input", { className: "__mp_input", type: "search", value: s.q, "aria-label": t("search"), placeholder: t("search"), onChange: function (e) { set(function (prev) { return Object.assign({}, prev, { q: e.target.value }); }); } }),
|
|
475
509
|
h("button", { type: "submit", className: "__mp_btnPrimary", disabled: s.loading }, t("searchBtn")),
|