dsh-preview-market 0.1.1 → 0.1.3
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 +11 -0
- package/README.md +25 -6
- package/README.zh.md +16 -5
- package/VERIFY.md +44 -7
- package/catalog/README.md +49 -0
- package/catalog/plugins/439436269-ctrl__dsh-preview-blender.json +24 -0
- package/catalog/plugins/439436269-ctrl__dsh-preview-media.json +72 -0
- package/catalog/plugins/439436269-ctrl__dsh-preview-stl.json +22 -0
- package/catalog.json +123 -0
- package/lib/catalog.js +77 -61
- package/lib/client.js +67 -7
- package/package.json +6 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.3
|
|
4
|
+
|
|
5
|
+
- Catalog entries now live in `catalog/plugins/<owner>__<repo>.json` — one file per plugin, so third parties can submit a PR without editing market code.
|
|
6
|
+
- The Host loads, validates and merges every file at startup; duplicate names and filename/repository mismatches fail fast.
|
|
7
|
+
- `catalog.json` remains the generated machine-readable snapshot; a test keeps it in sync.
|
|
8
|
+
|
|
9
|
+
## 0.1.2
|
|
10
|
+
|
|
11
|
+
- Add a top-level **Settings → Preview market** section, next to dsh-market, with Discover / Installed tabs.
|
|
12
|
+
- Keep the Settings → Plugins tab for discoverability; both render the same panel.
|
|
13
|
+
|
|
3
14
|
## 0.1.1
|
|
4
15
|
|
|
5
16
|
- Enable/disable installed preview plugins from the market when dsh-market is present (`/dsh-market/toggle`), with the current state read from `/dsh-market/installed`.
|
package/README.md
CHANGED
|
@@ -1,25 +1,31 @@
|
|
|
1
1
|
# dsh-preview-market
|
|
2
2
|
|
|
3
|
-
A **vertical preview market** for DeepSeek Harness.
|
|
3
|
+
A **vertical preview market** for DeepSeek Harness. A top-level settings section (and a Settings → Plugins tab) lists the preview plugins that exist for DSH, shows which ones the active profile already has, and hands installs/updates to [dsh-market](https://github.com/dsh-market/dsh-market) or the official `dsh plugin` command.
|
|
4
4
|
|
|
5
5
|
It is not a general plugin market, and it does not implement previews itself: every preview plugin stays an independent Loader entry with its own repository, version and settings. The market only provides the catalog, the installed view and the entry points.
|
|
6
6
|
|
|
7
|
+

|
|
8
|
+
|
|
7
9
|
## Install
|
|
8
10
|
|
|
9
11
|
```sh
|
|
10
12
|
dsh plugin --profile <profile> add dsh-preview-market
|
|
11
13
|
```
|
|
12
14
|
|
|
13
|
-
Open **Settings →
|
|
15
|
+
Open **Settings → Preview market** (the same panel is also under **Settings → Plugins**).
|
|
16
|
+
|
|
17
|
+
Upgrading from `dsh-media-preview` / `dsh-blend-preview` / `dsh-stl-preview`? See [MIGRATION.md](MIGRATION.md).
|
|
14
18
|
|
|
15
19
|
## What it does
|
|
16
20
|
|
|
17
21
|
- **Catalog** — first-party preview plugins with their formats, host requirements and versions.
|
|
18
|
-
- **Installed view** — reads the active profile's `package.json
|
|
22
|
+
- **Installed view** — reads the active profile's `package.json`, matching catalog names by default and honouring a package's `dsh.preview` manifest when present; never imports child plugin code.
|
|
19
23
|
- **Install / update** — delegates to `dsh-market` when it is present. Without it, the card shows the exact `dsh plugin --profile <profile> add <package>@<version>` command to copy.
|
|
20
24
|
- **Independent plugins** — media, Blender and STL remain separate packages; this page has no renderer and does not merge their code.
|
|
21
25
|
|
|
22
|
-
## Catalog (0.1.
|
|
26
|
+
## Catalog (0.1.3)
|
|
27
|
+
|
|
28
|
+
Every plugin is **one file** under [`catalog/plugins/`](catalog/plugins/), named `<owner>__<repo>.json`. A third-party submission adds exactly one file plus the regenerated `catalog.json` snapshot — no market code change. The Host loads, validates and merges all files at startup; the format and PR steps are in [`catalog/README.md`](catalog/README.md).
|
|
23
29
|
|
|
24
30
|
| Package | Formats | Host requirement |
|
|
25
31
|
|---|---|---|
|
|
@@ -33,17 +39,30 @@ Settings → Plugins → Preview market (namespace `preview-market`):
|
|
|
33
39
|
|
|
34
40
|
| Key | Default | Meaning |
|
|
35
41
|
|---|---|---|
|
|
36
|
-
| `enabled` | `true` | Register the routes and the
|
|
42
|
+
| `enabled` | `true` | Register the routes, the top-level section and the Settings → Plugins tab. |
|
|
37
43
|
| `routeRoot` | `/api/preview-market` | Authenticated route root; must stay under `/api`. |
|
|
38
44
|
| `profileDir` | `""` | Profile to inspect. Empty uses the Host `profileContext`, then `$DSH_HOME/profiles/desktop`. |
|
|
39
45
|
| `debug` | `false` | Reserved for request diagnostics. |
|
|
40
46
|
|
|
47
|
+
## Examples
|
|
48
|
+
|
|
49
|
+
- [`examples/profile-overrides.yml`](examples/profile-overrides.yml) — a safe starting point for per-profile overrides (media chunk size, Blender path, STL unit scale).
|
|
50
|
+
- [`catalog.json`](catalog.json) — machine-readable snapshot of the shipped catalog, enforced by a unit test.
|
|
51
|
+
|
|
41
52
|
## Development
|
|
42
53
|
|
|
43
54
|
```sh
|
|
44
55
|
node --test test/*.test.js
|
|
45
56
|
```
|
|
46
57
|
|
|
58
|
+
`catalog.json` is a machine-readable snapshot of the shipped catalog; regenerate it with `npm run catalog:write` and keep it in sync (a test enforces this).
|
|
59
|
+
|
|
60
|
+
Settings-section end-to-end (requires a running host with the plugin installed):
|
|
61
|
+
|
|
62
|
+
```sh
|
|
63
|
+
node scripts/e2e-section.mjs --base http://127.0.0.1:<port> --token <token>
|
|
64
|
+
```
|
|
65
|
+
|
|
47
66
|
Settings-tab end-to-end (requires a running host with the plugin installed):
|
|
48
67
|
|
|
49
68
|
```sh
|
|
@@ -66,4 +85,4 @@ The client bundle is `lib/client.js` (classic `__ModuleLoader__.load` factory, n
|
|
|
66
85
|
|
|
67
86
|
## Status
|
|
68
87
|
|
|
69
|
-
`0.1.
|
|
88
|
+
`0.1.3` — top-level Settings → Preview market section with Discover / Installed tabs, plus the Settings → Plugins tab. The catalog is one file per plugin under `catalog/plugins/`, so third-party entries are a one-file PR. Enable/disable goes through dsh-market. One-click install requires the package in the connected dsh-market registry; otherwise use the copyable command. Configuration stays in each child plugin's own Settings → Plugins page.
|
package/README.zh.md
CHANGED
|
@@ -4,22 +4,28 @@
|
|
|
4
4
|
|
|
5
5
|
它不是通用插件市场,也不自己实现预览:每个预览插件仍是独立的 Loader 条目,有自己的仓库、版本和设置;市场只提供目录、已安装视图和入口。
|
|
6
6
|
|
|
7
|
+

|
|
8
|
+
|
|
7
9
|
## 安装
|
|
8
10
|
|
|
9
11
|
```sh
|
|
10
12
|
dsh plugin --profile <profile> add dsh-preview-market
|
|
11
13
|
```
|
|
12
14
|
|
|
13
|
-
打开 **设置 →
|
|
15
|
+
打开 **设置 → 预览市场**(同一个面板也在 **设置 → 插件** 下)。
|
|
16
|
+
|
|
17
|
+
从 `dsh-media-preview` / `dsh-blend-preview` / `dsh-stl-preview` 升级?见 [MIGRATION.md](MIGRATION.md)。
|
|
14
18
|
|
|
15
19
|
## 功能
|
|
16
20
|
|
|
17
21
|
- **目录** — 第一方预览插件及其格式、宿主依赖、版本。
|
|
18
|
-
- **已安装** — 读当前 profile 的 `package.json
|
|
22
|
+
- **已安装** — 读当前 profile 的 `package.json`,默认按目录名匹配;包内声明 `dsh.preview` 清单时也认。不 import 子插件代码。
|
|
19
23
|
- **安装/更新** — 检测到 dsh-market 时委托给它;没有时显示可复制的 `dsh plugin --profile <profile> add <包>@<版本>` 命令。
|
|
20
24
|
- **独立插件** — media、Blender、STL 仍是独立包;本页不注册渲染器,也不合并它们的代码。
|
|
21
25
|
|
|
22
|
-
## 目录(0.1.
|
|
26
|
+
## 目录(0.1.3)
|
|
27
|
+
|
|
28
|
+
每个插件是 [`catalog/plugins/`](catalog/plugins/) 下的**一个文件**,命名为 `<owner>__<repo>.json`。三方收录只需新增一个文件 + 重新生成 `catalog.json`,不用改市场代码;Host 启动时读取、校验并合并全部文件。字段与 PR 步骤见 [`catalog/README.md`](catalog/README.md)。
|
|
23
29
|
|
|
24
30
|
| 包 | 格式 | 宿主依赖 |
|
|
25
31
|
|---|---|---|
|
|
@@ -29,7 +35,7 @@ dsh plugin --profile <profile> add dsh-preview-market
|
|
|
29
35
|
|
|
30
36
|
## 配置
|
|
31
37
|
|
|
32
|
-
设置 →
|
|
38
|
+
设置 → 预览市场(命名空间 `preview-market`):
|
|
33
39
|
|
|
34
40
|
| 键 | 默认 | 含义 |
|
|
35
41
|
|---|---|---|
|
|
@@ -38,6 +44,11 @@ dsh plugin --profile <profile> add dsh-preview-market
|
|
|
38
44
|
| `profileDir` | `""` | 要检查的 profile;空则用 Host `profileContext`,再退到 `$DSH_HOME/profiles/desktop`。 |
|
|
39
45
|
| `debug` | `false` | 预留的请求诊断。 |
|
|
40
46
|
|
|
47
|
+
## 示例
|
|
48
|
+
|
|
49
|
+
- [`examples/profile-overrides.yml`](examples/profile-overrides.yml):按 profile 覆盖媒体分块、Blender 路径、STL 单位。
|
|
50
|
+
- [`catalog.json`](catalog.json):目录的机器可读快照,单测会检查它与代码一致。
|
|
51
|
+
|
|
41
52
|
## 开发
|
|
42
53
|
|
|
43
54
|
```sh
|
|
@@ -48,4 +59,4 @@ node --test test/*.test.js
|
|
|
48
59
|
|
|
49
60
|
## 状态
|
|
50
61
|
|
|
51
|
-
`0.1.
|
|
62
|
+
`0.1.3` — 顶层「设置 → 预览市场」+ 发现/已安装两个 tab,同时保留「设置 → 插件」里的入口。目录改为 `catalog/plugins/` 下一插件一文件,三方收录只需一个文件 PR。启用/停用走 dsh-market;一键安装要求对应包已进入所连接 dsh-market 的 registry,否则用可复制命令。配置仍在各子插件自己的 设置 → 插件 页面。
|
package/VERIFY.md
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
# Verification record — dsh-preview-market 0.1.
|
|
1
|
+
# Verification record — dsh-preview-market 0.1.3
|
|
2
2
|
|
|
3
3
|
## Unit tests (2026-10-23)
|
|
4
4
|
|
|
5
|
-
`node --test test/*.test.js` → **
|
|
5
|
+
`node --test test/*.test.js` → **12 pass, 0 fail**.
|
|
6
6
|
|
|
7
7
|
| File | Covers |
|
|
8
8
|
|---|---|
|
|
9
9
|
| `test/config.test.js` | defaults, `/api` route fence, route normalization, boolean normalization |
|
|
10
|
-
| `test/catalog.test.js` |
|
|
10
|
+
| `test/catalog.test.js` | one file per entry, required fields, filename/repository match, duplicates, payload shape |
|
|
11
|
+
| `test/catalog-file.test.js` | `catalog.json` snapshot matches the files |
|
|
11
12
|
| `test/installed.test.js` | profile `package.json` + `node_modules` inventory, missing profile, `profileContext` resolution |
|
|
12
|
-
| `test/client.test.js` | bundle registers
|
|
13
|
+
| `test/client.test.js` | bundle registers the `settings.section` and `settings.plugins.tab` entries |
|
|
13
14
|
|
|
14
15
|
## Host / bundle smoke (2026-10-23, preview-test profile)
|
|
15
16
|
|
|
@@ -18,6 +19,21 @@
|
|
|
18
19
|
- The Web boot graph (`__DSH_BOOT__`) contains `dsh-preview-market` and injects `__DSH_PREVIEW_MARKET_CONFIG__`.
|
|
19
20
|
- The combo bundle URL returned **200** (16,213 B) and contains `settings.plugins.tab` + `dsh-preview-market`.
|
|
20
21
|
|
|
22
|
+
## One-file catalog (2026-10-23)
|
|
23
|
+
|
|
24
|
+
- Moved the three entries from `lib/catalog.js` into `catalog/plugins/<owner>__<repo>.json`; the Host loads and validates every file at startup.
|
|
25
|
+
- Added a temporary `catalog/plugins/example__dsh-preview-example.json`; `CATALOG` went from 3 to 4 entries without any code change, then was removed.
|
|
26
|
+
- Unit tests (12 pass) validate every file, the filename/repository match, duplicate names, required fields, and the `catalog.json` snapshot.
|
|
27
|
+
- `catalog/README.md` + `.github/PULL_REQUEST_TEMPLATE.md` document the one-file PR.
|
|
28
|
+
|
|
29
|
+
## Top-level section e2e (2026-10-23, preview-test)
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
node scripts/e2e-section.mjs --base http://127.0.0.1:59010 --token <token>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Result: **PASS** — the Settings nav contains `预览市场` immediately after `插件市场`; opening it shows the `发现` / `已安装` tabs and the three catalog cards (`dsh-preview-media`, `dsh-preview-blender`, `dsh-preview-stl`). No page errors. Screenshot: `docs/preview-market-section.png`.
|
|
36
|
+
|
|
21
37
|
## Settings tab e2e (2026-10-23, preview-test)
|
|
22
38
|
|
|
23
39
|
Installed `dsh-preview-market@0.1.0` plus `dsh-preview-media@0.1.4`, `dsh-preview-blender@0.1.0`, `dsh-preview-stl@0.1.0` into `preview-test`, started the Web host, and ran:
|
|
@@ -48,8 +64,29 @@ node scripts/e2e-toggle.mjs --base http://127.0.0.1:59006 --token <token>
|
|
|
48
64
|
|
|
49
65
|
Result: **PASS** — the STL card showed `停用`; clicking it wrote `dsh-preview-stl` into `/dsh-market/installed`'s `disabled` list and showed `已切换,刷新页面后生效`; clicking `启用` removed it again. The media card's `配置` showed `在 设置 → 插件 → dsh-preview-media 配置。` No page errors; screenshot: `%TEMP%\dsh-preview-market-toggle.png`.
|
|
50
66
|
|
|
51
|
-
##
|
|
67
|
+
## npm artifact install (2026-10-23, preview-test)
|
|
68
|
+
|
|
69
|
+
Replaced the local tarball with the published `dsh-preview-market@0.1.1` from npm (`dsh plugin --profile preview-test add dsh-preview-market@0.1.1`), then ran the settings e2e against that install:
|
|
70
|
+
|
|
71
|
+
```sh
|
|
72
|
+
node scripts/e2e-settings.mjs --base http://127.0.0.1:59007 --token <token>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Result: **PASS** — tab and all three installed cards rendered from the npm artifact. `package.json` dependency is `0.1.1`, `node_modules/dsh-preview-market/package.json` reports `0.1.1`.
|
|
76
|
+
|
|
77
|
+
## One-click install e2e (fixture registry, 2026-10-23)
|
|
78
|
+
|
|
79
|
+
To exercise the real install route without waiting for the production catalog, a local registry fixture was served on `127.0.0.1:59008`:
|
|
52
80
|
|
|
53
|
-
|
|
81
|
+
```json
|
|
82
|
+
{"plugins":[{"name":"dsh-preview-stl","url":"https://github.com/439436269-ctrl/dsh-preview-stl","npm":"dsh-preview-stl","category":["ui"]}]}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
The host was started with `DSHM_REGISTRY_URL=http://127.0.0.1:59008/plugins.json`, `dsh-preview-stl` was removed from `preview-test`, and the market's STL card was clicked. Result: **PASS** — dshmarket installed `dsh-preview-stl@0.1.0`; `/dsh-market/installed` contained it, the notice said `已安装: dsh-preview-stl`, and the card switched to `已是最新` with `停用`/`配置`. No page errors. Screenshot: `%TEMP%\market-oneclick.png`.
|
|
86
|
+
|
|
87
|
+
This proves the install route itself; the production catalog still needs the entries scheduled for 2026-10-24.
|
|
88
|
+
|
|
89
|
+
## Not yet verified live
|
|
54
90
|
|
|
55
|
-
|
|
91
|
+
- Production one-click install through the real dsh-market catalog (the new entries are scheduled for 2026-10-24).
|
|
92
|
+
- Desktop installation (the desktop profile is Electron-managed).
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Preview catalog
|
|
2
|
+
|
|
3
|
+
One JSON file per plugin. A third-party submission adds **exactly one file** here and opens a PR; nobody edits the market's code.
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
catalog/plugins/<owner>__<repo>.json
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
The filename must match the repository URL: `https://github.com/<owner>/<repo>` → `<owner>__<repo>.json`. The Host validates the filename, the required fields, duplicate names and the repository host at startup.
|
|
10
|
+
|
|
11
|
+
## Entry shape
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"name": "dsh-preview-example",
|
|
16
|
+
"npm": "dsh-preview-example",
|
|
17
|
+
"capability": "example",
|
|
18
|
+
"kind": "three",
|
|
19
|
+
"repo": "https://github.com/example/dsh-preview-example",
|
|
20
|
+
"version": "0.1.0",
|
|
21
|
+
"minDsh": "0.2.0-rc.2",
|
|
22
|
+
"requires": [],
|
|
23
|
+
"extensions": ["example"],
|
|
24
|
+
"formats": { "model": ["example"] },
|
|
25
|
+
"description": {
|
|
26
|
+
"zh": "一句话说明这个预览插件做什么。",
|
|
27
|
+
"en": "One sentence describing what this preview plugin does."
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Required: `name`, `npm`, `capability`, `kind`, `repo`, `version`, `extensions`, `formats`, `description.zh`, `description.en`.
|
|
33
|
+
|
|
34
|
+
Optional: `minDsh`, `requires` (defaults to `[]`).
|
|
35
|
+
|
|
36
|
+
- `kind` is currently `media` or `three`; `three` entries get the shared WebGL viewport.
|
|
37
|
+
- `extensions` drives the document-preview registration in the child plugin; the catalog only displays it.
|
|
38
|
+
- `formats` groups extensions for the card, e.g. `{ "video": [...], "audio": [...] }`.
|
|
39
|
+
|
|
40
|
+
## Submit a plugin
|
|
41
|
+
|
|
42
|
+
1. Add `catalog/plugins/<owner>__<repo>.json` with the shape above.
|
|
43
|
+
2. Run `npm test` (it validates every file and the `catalog.json` snapshot).
|
|
44
|
+
3. Run `npm run catalog:write` to regenerate the root `catalog.json` snapshot.
|
|
45
|
+
4. Open a PR that adds **one plugin file plus the regenerated snapshot**.
|
|
46
|
+
|
|
47
|
+
The plugin itself stays an independent DSH package with its own `dsh.bundle` and repository. Being in this catalog does **not** make one-click install work by itself: the package also has to be present in the connected dsh-market registry; otherwise the market shows the copyable `dsh plugin add` command.
|
|
48
|
+
|
|
49
|
+
Do not add a plugin to this catalog if it is only a copy of an existing package under another name. The catalog is for distinct preview capabilities.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dsh-preview-blender",
|
|
3
|
+
"npm": "dsh-preview-blender",
|
|
4
|
+
"capability": "blender",
|
|
5
|
+
"kind": "three",
|
|
6
|
+
"repo": "https://github.com/439436269-ctrl/dsh-preview-blender",
|
|
7
|
+
"version": "0.1.0",
|
|
8
|
+
"minDsh": "0.2.0-rc.2",
|
|
9
|
+
"requires": [
|
|
10
|
+
"blender"
|
|
11
|
+
],
|
|
12
|
+
"extensions": [
|
|
13
|
+
"blend"
|
|
14
|
+
],
|
|
15
|
+
"formats": {
|
|
16
|
+
"model": [
|
|
17
|
+
"blend"
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
"description": {
|
|
21
|
+
"zh": "Blender 场景:headless 导出缓存 GLB,右侧栏 WebGL 视口 + 对象/三角面/mm 包围盒/材质统计。",
|
|
22
|
+
"en": "Blender scenes: a cached headless GLB export rendered in a WebGL viewport, with object, triangle, mm-bounds and material statistics."
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dsh-preview-media",
|
|
3
|
+
"npm": "dsh-preview-media",
|
|
4
|
+
"capability": "media",
|
|
5
|
+
"kind": "media",
|
|
6
|
+
"repo": "https://github.com/439436269-ctrl/dsh-preview-media",
|
|
7
|
+
"version": "0.1.4",
|
|
8
|
+
"minDsh": "0.2.0-rc.2",
|
|
9
|
+
"requires": [],
|
|
10
|
+
"extensions": [
|
|
11
|
+
"mp4",
|
|
12
|
+
"m4v",
|
|
13
|
+
"mov",
|
|
14
|
+
"webm",
|
|
15
|
+
"ogv",
|
|
16
|
+
"ogg",
|
|
17
|
+
"mkv",
|
|
18
|
+
"avi",
|
|
19
|
+
"wmv",
|
|
20
|
+
"flv",
|
|
21
|
+
"3gp",
|
|
22
|
+
"ts",
|
|
23
|
+
"m2ts",
|
|
24
|
+
"mts",
|
|
25
|
+
"mp3",
|
|
26
|
+
"wav",
|
|
27
|
+
"flac",
|
|
28
|
+
"m4a",
|
|
29
|
+
"aac",
|
|
30
|
+
"oga",
|
|
31
|
+
"opus",
|
|
32
|
+
"weba",
|
|
33
|
+
"wma",
|
|
34
|
+
"aiff",
|
|
35
|
+
"aif"
|
|
36
|
+
],
|
|
37
|
+
"formats": {
|
|
38
|
+
"video": [
|
|
39
|
+
"mp4",
|
|
40
|
+
"m4v",
|
|
41
|
+
"mov",
|
|
42
|
+
"webm",
|
|
43
|
+
"ogv",
|
|
44
|
+
"ogg",
|
|
45
|
+
"mkv",
|
|
46
|
+
"avi",
|
|
47
|
+
"wmv",
|
|
48
|
+
"flv",
|
|
49
|
+
"3gp",
|
|
50
|
+
"ts",
|
|
51
|
+
"m2ts",
|
|
52
|
+
"mts"
|
|
53
|
+
],
|
|
54
|
+
"audio": [
|
|
55
|
+
"mp3",
|
|
56
|
+
"wav",
|
|
57
|
+
"flac",
|
|
58
|
+
"m4a",
|
|
59
|
+
"aac",
|
|
60
|
+
"oga",
|
|
61
|
+
"opus",
|
|
62
|
+
"weba",
|
|
63
|
+
"wma",
|
|
64
|
+
"aiff",
|
|
65
|
+
"aif"
|
|
66
|
+
]
|
|
67
|
+
},
|
|
68
|
+
"description": {
|
|
69
|
+
"zh": "视频与音频:右侧栏原生播放器,HTTP Range 流式读取,桌面端可拖动进度。",
|
|
70
|
+
"en": "Video and audio in the right-Sidebar document preview, streamed with HTTP Range and seekable in the desktop app."
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dsh-preview-stl",
|
|
3
|
+
"npm": "dsh-preview-stl",
|
|
4
|
+
"capability": "stl",
|
|
5
|
+
"kind": "three",
|
|
6
|
+
"repo": "https://github.com/439436269-ctrl/dsh-preview-stl",
|
|
7
|
+
"version": "0.1.0",
|
|
8
|
+
"minDsh": "0.2.0-rc.2",
|
|
9
|
+
"requires": [],
|
|
10
|
+
"extensions": [
|
|
11
|
+
"stl"
|
|
12
|
+
],
|
|
13
|
+
"formats": {
|
|
14
|
+
"model": [
|
|
15
|
+
"stl"
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
"description": {
|
|
19
|
+
"zh": "STL 网格:浏览器解析二进制/ASCII,右侧栏 WebGL 视口 + 尺寸/体积/表面积/水密统计。",
|
|
20
|
+
"en": "STL meshes: binary/ASCII parsed in the browser, with a WebGL viewport and size, volume, surface-area and watertightness statistics."
|
|
21
|
+
}
|
|
22
|
+
}
|
package/catalog.json
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": 1,
|
|
3
|
+
"plugins": [
|
|
4
|
+
{
|
|
5
|
+
"name": "dsh-preview-blender",
|
|
6
|
+
"npm": "dsh-preview-blender",
|
|
7
|
+
"capability": "blender",
|
|
8
|
+
"kind": "three",
|
|
9
|
+
"repo": "https://github.com/439436269-ctrl/dsh-preview-blender",
|
|
10
|
+
"version": "0.1.0",
|
|
11
|
+
"minDsh": "0.2.0-rc.2",
|
|
12
|
+
"requires": [
|
|
13
|
+
"blender"
|
|
14
|
+
],
|
|
15
|
+
"extensions": [
|
|
16
|
+
"blend"
|
|
17
|
+
],
|
|
18
|
+
"formats": {
|
|
19
|
+
"model": [
|
|
20
|
+
"blend"
|
|
21
|
+
]
|
|
22
|
+
},
|
|
23
|
+
"description": {
|
|
24
|
+
"zh": "Blender 场景:headless 导出缓存 GLB,右侧栏 WebGL 视口 + 对象/三角面/mm 包围盒/材质统计。",
|
|
25
|
+
"en": "Blender scenes: a cached headless GLB export rendered in a WebGL viewport, with object, triangle, mm-bounds and material statistics."
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"name": "dsh-preview-media",
|
|
30
|
+
"npm": "dsh-preview-media",
|
|
31
|
+
"capability": "media",
|
|
32
|
+
"kind": "media",
|
|
33
|
+
"repo": "https://github.com/439436269-ctrl/dsh-preview-media",
|
|
34
|
+
"version": "0.1.4",
|
|
35
|
+
"minDsh": "0.2.0-rc.2",
|
|
36
|
+
"requires": [],
|
|
37
|
+
"extensions": [
|
|
38
|
+
"mp4",
|
|
39
|
+
"m4v",
|
|
40
|
+
"mov",
|
|
41
|
+
"webm",
|
|
42
|
+
"ogv",
|
|
43
|
+
"ogg",
|
|
44
|
+
"mkv",
|
|
45
|
+
"avi",
|
|
46
|
+
"wmv",
|
|
47
|
+
"flv",
|
|
48
|
+
"3gp",
|
|
49
|
+
"ts",
|
|
50
|
+
"m2ts",
|
|
51
|
+
"mts",
|
|
52
|
+
"mp3",
|
|
53
|
+
"wav",
|
|
54
|
+
"flac",
|
|
55
|
+
"m4a",
|
|
56
|
+
"aac",
|
|
57
|
+
"oga",
|
|
58
|
+
"opus",
|
|
59
|
+
"weba",
|
|
60
|
+
"wma",
|
|
61
|
+
"aiff",
|
|
62
|
+
"aif"
|
|
63
|
+
],
|
|
64
|
+
"formats": {
|
|
65
|
+
"video": [
|
|
66
|
+
"mp4",
|
|
67
|
+
"m4v",
|
|
68
|
+
"mov",
|
|
69
|
+
"webm",
|
|
70
|
+
"ogv",
|
|
71
|
+
"ogg",
|
|
72
|
+
"mkv",
|
|
73
|
+
"avi",
|
|
74
|
+
"wmv",
|
|
75
|
+
"flv",
|
|
76
|
+
"3gp",
|
|
77
|
+
"ts",
|
|
78
|
+
"m2ts",
|
|
79
|
+
"mts"
|
|
80
|
+
],
|
|
81
|
+
"audio": [
|
|
82
|
+
"mp3",
|
|
83
|
+
"wav",
|
|
84
|
+
"flac",
|
|
85
|
+
"m4a",
|
|
86
|
+
"aac",
|
|
87
|
+
"oga",
|
|
88
|
+
"opus",
|
|
89
|
+
"weba",
|
|
90
|
+
"wma",
|
|
91
|
+
"aiff",
|
|
92
|
+
"aif"
|
|
93
|
+
]
|
|
94
|
+
},
|
|
95
|
+
"description": {
|
|
96
|
+
"zh": "视频与音频:右侧栏原生播放器,HTTP Range 流式读取,桌面端可拖动进度。",
|
|
97
|
+
"en": "Video and audio in the right-Sidebar document preview, streamed with HTTP Range and seekable in the desktop app."
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"name": "dsh-preview-stl",
|
|
102
|
+
"npm": "dsh-preview-stl",
|
|
103
|
+
"capability": "stl",
|
|
104
|
+
"kind": "three",
|
|
105
|
+
"repo": "https://github.com/439436269-ctrl/dsh-preview-stl",
|
|
106
|
+
"version": "0.1.0",
|
|
107
|
+
"minDsh": "0.2.0-rc.2",
|
|
108
|
+
"requires": [],
|
|
109
|
+
"extensions": [
|
|
110
|
+
"stl"
|
|
111
|
+
],
|
|
112
|
+
"formats": {
|
|
113
|
+
"model": [
|
|
114
|
+
"stl"
|
|
115
|
+
]
|
|
116
|
+
},
|
|
117
|
+
"description": {
|
|
118
|
+
"zh": "STL 网格:浏览器解析二进制/ASCII,右侧栏 WebGL 视口 + 尺寸/体积/表面积/水密统计。",
|
|
119
|
+
"en": "STL meshes: binary/ASCII parsed in the browser, with a WebGL viewport and size, volume, surface-area and watertightness statistics."
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
]
|
|
123
|
+
}
|
package/lib/catalog.js
CHANGED
|
@@ -1,75 +1,91 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The vertical preview catalog shipped with this release.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* same fields; `dsh.preview` in the installed package is used to enrich the
|
|
8
|
-
* installed view when present.
|
|
4
|
+
* One JSON file per plugin lives in `catalog/plugins/`; a third-party
|
|
5
|
+
* submission adds exactly one file and opens a PR. The Host reads and validates
|
|
6
|
+
* every file at startup, so adding an entry never requires touching this module.
|
|
9
7
|
*
|
|
10
8
|
* @module dsh-preview-market/catalog
|
|
11
9
|
*/
|
|
10
|
+
import { readdirSync, readFileSync } from "node:fs";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
import { fileURLToPath } from "node:url";
|
|
12
13
|
|
|
13
14
|
/** Catalog schema version. */
|
|
14
15
|
export const CATALOG_SCHEMA = 1;
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
zh: "视频与音频:右侧栏原生播放器,HTTP Range 流式读取,桌面端可拖动进度。",
|
|
37
|
-
en: "Video and audio in the right-Sidebar document preview, streamed with HTTP Range and seekable in the desktop app."
|
|
38
|
-
}
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
name: "dsh-preview-blender",
|
|
42
|
-
npm: "dsh-preview-blender",
|
|
43
|
-
capability: "blender",
|
|
44
|
-
kind: "three",
|
|
45
|
-
repo: "https://github.com/439436269-ctrl/dsh-preview-blender",
|
|
46
|
-
version: "0.1.0",
|
|
47
|
-
minDsh: "0.2.0-rc.2",
|
|
48
|
-
requires: ["blender"],
|
|
49
|
-
extensions: ["blend"],
|
|
50
|
-
formats: { model: ["blend"] },
|
|
51
|
-
description: {
|
|
52
|
-
zh: "Blender 场景:headless 导出缓存 GLB,右侧栏 WebGL 视口 + 对象/三角面/mm 包围盒/材质统计。",
|
|
53
|
-
en: "Blender scenes: a cached headless GLB export rendered in a WebGL viewport, with object, triangle, mm-bounds and material statistics."
|
|
54
|
-
}
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
name: "dsh-preview-stl",
|
|
58
|
-
npm: "dsh-preview-stl",
|
|
59
|
-
capability: "stl",
|
|
60
|
-
kind: "three",
|
|
61
|
-
repo: "https://github.com/439436269-ctrl/dsh-preview-stl",
|
|
62
|
-
version: "0.1.0",
|
|
63
|
-
minDsh: "0.2.0-rc.2",
|
|
64
|
-
requires: [],
|
|
65
|
-
extensions: ["stl"],
|
|
66
|
-
formats: { model: ["stl"] },
|
|
67
|
-
description: {
|
|
68
|
-
zh: "STL 网格:浏览器解析二进制/ASCII,右侧栏 WebGL 视口 + 尺寸/体积/表面积/水密统计。",
|
|
69
|
-
en: "STL meshes: binary/ASCII parsed in the browser, with a WebGL viewport and size, volume, surface-area and watertightness statistics."
|
|
70
|
-
}
|
|
17
|
+
const PLUGIN_DIR = fileURLToPath(new URL("../catalog/plugins/", import.meta.url));
|
|
18
|
+
const REQUIRED = [
|
|
19
|
+
"name",
|
|
20
|
+
"npm",
|
|
21
|
+
"capability",
|
|
22
|
+
"kind",
|
|
23
|
+
"repo",
|
|
24
|
+
"version",
|
|
25
|
+
"extensions",
|
|
26
|
+
"formats",
|
|
27
|
+
"description"
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
/** Derive `<owner>__<repo>` from a GitHub repository URL. */
|
|
31
|
+
function repoTuple(url) {
|
|
32
|
+
let parsed;
|
|
33
|
+
try {
|
|
34
|
+
parsed = new URL(url);
|
|
35
|
+
} catch {
|
|
36
|
+
throw new Error(`invalid repo URL: ${url}`);
|
|
71
37
|
}
|
|
72
|
-
|
|
38
|
+
if (parsed.hostname !== "github.com") throw new Error(`repo must be a github.com URL: ${url}`);
|
|
39
|
+
const parts = parsed.pathname.split("/").filter(Boolean);
|
|
40
|
+
if (parts.length < 2) throw new Error(`repo must point at a repository: ${url}`);
|
|
41
|
+
const owner = parts[0];
|
|
42
|
+
const repo = parts[1].replace(/\.git$/, "");
|
|
43
|
+
return { owner, repo };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function loadCatalog() {
|
|
47
|
+
const files = readdirSync(PLUGIN_DIR)
|
|
48
|
+
.filter((file) => file.endsWith(".json"))
|
|
49
|
+
.sort();
|
|
50
|
+
if (files.length === 0) throw new Error("catalog/plugins has no entries");
|
|
51
|
+
|
|
52
|
+
const seen = new Set();
|
|
53
|
+
return Object.freeze(
|
|
54
|
+
files.map((file) => {
|
|
55
|
+
let entry;
|
|
56
|
+
try {
|
|
57
|
+
entry = JSON.parse(readFileSync(join(PLUGIN_DIR, file), "utf8"));
|
|
58
|
+
} catch (error) {
|
|
59
|
+
throw new Error(`catalog/plugins/${file}: invalid JSON (${error.message})`);
|
|
60
|
+
}
|
|
61
|
+
for (const key of REQUIRED) {
|
|
62
|
+
if (entry[key] === undefined) throw new Error(`catalog/plugins/${file}: missing ${key}`);
|
|
63
|
+
}
|
|
64
|
+
if (!Array.isArray(entry.extensions) || entry.extensions.length === 0) {
|
|
65
|
+
throw new Error(`catalog/plugins/${file}: extensions must be a non-empty array`);
|
|
66
|
+
}
|
|
67
|
+
if (typeof entry.formats !== "object" || entry.formats === null) {
|
|
68
|
+
throw new Error(`catalog/plugins/${file}: formats must be an object`);
|
|
69
|
+
}
|
|
70
|
+
if (typeof entry.description?.zh !== "string" || typeof entry.description?.en !== "string") {
|
|
71
|
+
throw new Error(`catalog/plugins/${file}: description.zh/en must be strings`);
|
|
72
|
+
}
|
|
73
|
+
if (seen.has(entry.name)) throw new Error(`duplicate catalog name: ${entry.name}`);
|
|
74
|
+
seen.add(entry.name);
|
|
75
|
+
entry.requires = Array.isArray(entry.requires) ? entry.requires : [];
|
|
76
|
+
|
|
77
|
+
const { owner, repo } = repoTuple(entry.repo);
|
|
78
|
+
const stem = file.slice(0, -".json".length);
|
|
79
|
+
if (stem !== `${owner}__${repo}`) {
|
|
80
|
+
throw new Error(`catalog/plugins/${file}: filename must be ${owner}__${repo}.json`);
|
|
81
|
+
}
|
|
82
|
+
return Object.freeze(entry);
|
|
83
|
+
})
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** The catalog, loaded from one file per plugin. */
|
|
88
|
+
export const CATALOG = loadCatalog();
|
|
73
89
|
|
|
74
90
|
/** The catalog payload sent to the browser. */
|
|
75
91
|
export function catalogPayload() {
|
package/lib/client.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* dsh-preview-market browser half.
|
|
3
3
|
*
|
|
4
|
-
* Registers
|
|
4
|
+
* Registers a top-level Settings → Preview market section and keeps the
|
|
5
|
+
* Settings → Plugins tab. Both render the same panel: the Host catalog plus the
|
|
5
6
|
* active profile inventory, then either delegates installs/updates to
|
|
6
7
|
* dsh-market's same-origin API or shows the official `dsh plugin add` command.
|
|
7
8
|
* It never imports a preview plugin's client bundle; those stay independent
|
|
@@ -14,8 +15,9 @@ window.__ModuleLoader__.load({
|
|
|
14
15
|
var exports = module.exports;
|
|
15
16
|
const React = require("react");
|
|
16
17
|
|
|
17
|
-
/** Locale namespace and
|
|
18
|
+
/** Locale namespace, section id and Settings → Plugins tab id. */
|
|
18
19
|
const NS = "previewMarket";
|
|
20
|
+
const SECTION_ID = "preview-market";
|
|
19
21
|
const TAB_ID = "dsh-preview-market";
|
|
20
22
|
const DEFAULT_ROUTE_ROOT = "/api/preview-market";
|
|
21
23
|
|
|
@@ -53,7 +55,10 @@ window.__ModuleLoader__.load({
|
|
|
53
55
|
manageHint: "到 设置 → 插件 启用/停用。",
|
|
54
56
|
toggled: "已切换。",
|
|
55
57
|
toggleRefresh: "已切换,刷新页面后生效。",
|
|
56
|
-
toggleFailed: "切换失败"
|
|
58
|
+
toggleFailed: "切换失败",
|
|
59
|
+
tabDiscover: "发现",
|
|
60
|
+
tabInstalled: "已安装",
|
|
61
|
+
installedEmpty: "还没有安装本市场的预览插件。"
|
|
57
62
|
};
|
|
58
63
|
|
|
59
64
|
const en = {
|
|
@@ -90,7 +95,10 @@ window.__ModuleLoader__.load({
|
|
|
90
95
|
manageHint: "Use Settings → Plugins to enable or disable it.",
|
|
91
96
|
toggled: "Toggled.",
|
|
92
97
|
toggleRefresh: "Toggled; refresh the page to apply.",
|
|
93
|
-
toggleFailed: "Toggle failed"
|
|
98
|
+
toggleFailed: "Toggle failed",
|
|
99
|
+
tabDiscover: "Discover",
|
|
100
|
+
tabInstalled: "Installed",
|
|
101
|
+
installedEmpty: "No preview plugins from this market are installed yet."
|
|
94
102
|
};
|
|
95
103
|
|
|
96
104
|
/** Route root published by the Host at boot. */
|
|
@@ -205,6 +213,7 @@ window.__ModuleLoader__.load({
|
|
|
205
213
|
});
|
|
206
214
|
const [notice, setNotice] = React.useState("");
|
|
207
215
|
const [busy, setBusy] = React.useState("");
|
|
216
|
+
const [tab, setTab] = React.useState("discover");
|
|
208
217
|
|
|
209
218
|
const load = React.useCallback(async () => {
|
|
210
219
|
setState((previous) => ({ ...previous, loading: true, error: "" }));
|
|
@@ -252,6 +261,8 @@ window.__ModuleLoader__.load({
|
|
|
252
261
|
}, [load]);
|
|
253
262
|
|
|
254
263
|
const installedByName = new Map(state.installed.map((entry) => [entry.name, entry]));
|
|
264
|
+
const installedCards = state.catalog.filter((item) => installedByName.has(item.name));
|
|
265
|
+
const visible = tab === "installed" ? installedCards : state.catalog;
|
|
255
266
|
|
|
256
267
|
const install = React.useCallback(async (item) => {
|
|
257
268
|
setBusy(item.name);
|
|
@@ -334,6 +345,36 @@ window.__ModuleLoader__.load({
|
|
|
334
345
|
)
|
|
335
346
|
)
|
|
336
347
|
),
|
|
348
|
+
React.createElement(
|
|
349
|
+
"div",
|
|
350
|
+
{ className: "dsh-pm-tabs", role: "tablist" },
|
|
351
|
+
React.createElement(
|
|
352
|
+
"button",
|
|
353
|
+
{
|
|
354
|
+
type: "button",
|
|
355
|
+
role: "tab",
|
|
356
|
+
className: "dsh-pm-tab",
|
|
357
|
+
"data-active": tab === "discover",
|
|
358
|
+
"aria-selected": tab === "discover",
|
|
359
|
+
onClick: () => setTab("discover")
|
|
360
|
+
},
|
|
361
|
+
t("tabDiscover"),
|
|
362
|
+
React.createElement("span", { className: "dsh-pm-count" }, state.catalog.length)
|
|
363
|
+
),
|
|
364
|
+
React.createElement(
|
|
365
|
+
"button",
|
|
366
|
+
{
|
|
367
|
+
type: "button",
|
|
368
|
+
role: "tab",
|
|
369
|
+
className: "dsh-pm-tab",
|
|
370
|
+
"data-active": tab === "installed",
|
|
371
|
+
"aria-selected": tab === "installed",
|
|
372
|
+
onClick: () => setTab("installed")
|
|
373
|
+
},
|
|
374
|
+
t("tabInstalled"),
|
|
375
|
+
React.createElement("span", { className: "dsh-pm-count" }, installedCards.length)
|
|
376
|
+
)
|
|
377
|
+
),
|
|
337
378
|
state.loading
|
|
338
379
|
? React.createElement("p", { className: "dsh-pm-empty" }, t("loading"))
|
|
339
380
|
: state.error !== ""
|
|
@@ -343,12 +384,12 @@ window.__ModuleLoader__.load({
|
|
|
343
384
|
React.createElement("p", null, `${t("failed")}: ${state.error}`),
|
|
344
385
|
React.createElement("button", { type: "button", className: "dsh-pm-button", onClick: () => void load() }, t("retry"))
|
|
345
386
|
)
|
|
346
|
-
:
|
|
347
|
-
? React.createElement("p", { className: "dsh-pm-empty" }, t("empty"))
|
|
387
|
+
: visible.length === 0
|
|
388
|
+
? React.createElement("p", { className: "dsh-pm-empty" }, tab === "installed" ? t("installedEmpty") : t("empty"))
|
|
348
389
|
: React.createElement(
|
|
349
390
|
"div",
|
|
350
391
|
{ className: "dsh-pm-grid" },
|
|
351
|
-
|
|
392
|
+
visible.map((item) =>
|
|
352
393
|
React.createElement(Card, {
|
|
353
394
|
key: item.name,
|
|
354
395
|
item,
|
|
@@ -385,6 +426,10 @@ window.__ModuleLoader__.load({
|
|
|
385
426
|
"[data-preview-market] .dsh-pm-status{display:flex;gap:6px;flex-wrap:wrap}",
|
|
386
427
|
"[data-preview-market] .dsh-pm-pill{border-radius:999px;padding:3px 9px;font-size:11px;background:var(--dsw-alias-interactive-bg-hover,rgba(0,0,0,.06))}",
|
|
387
428
|
"[data-preview-market] .dsh-pm-pill[data-tone=ok]{color:#1f7a4d;background:rgba(46,160,92,.14)}",
|
|
429
|
+
"[data-preview-market] .dsh-pm-tabs{display:flex;gap:2px;border-bottom:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.1))}",
|
|
430
|
+
"[data-preview-market] .dsh-pm-tab{appearance:none;border:0;border-bottom:2px solid transparent;background:none;color:inherit;font:inherit;font-size:12px;padding:7px 10px;cursor:pointer;opacity:.62;display:inline-flex;align-items:center;gap:6px}",
|
|
431
|
+
"[data-preview-market] .dsh-pm-tab[data-active=true]{opacity:1;font-weight:650;border-bottom-color:var(--dsw-alias-label-accent,#2c6ef2)}",
|
|
432
|
+
"[data-preview-market] .dsh-pm-count{font-size:10.5px;border-radius:999px;padding:1px 6px;background:rgba(0,0,0,.06)}",
|
|
388
433
|
"[data-preview-market] .dsh-pm-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:12px}",
|
|
389
434
|
"[data-preview-market] .dsh-pm-card{border:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.1));border-radius:12px;padding:14px;display:flex;flex-direction:column;gap:9px;background:var(--dsw-alias-bg-layer-2,rgba(0,0,0,.02))}",
|
|
390
435
|
"[data-preview-market] .dsh-pm-card-head{display:flex;justify-content:space-between;gap:8px;align-items:center}",
|
|
@@ -418,6 +463,21 @@ window.__ModuleLoader__.load({
|
|
|
418
463
|
installStyle();
|
|
419
464
|
const t = ctx.locale.bind(NS);
|
|
420
465
|
ctx.effect(() => ctx.locale.register(NS, { zh, en }), "preview-market: dictionaries");
|
|
466
|
+
// Top-level Settings section, next to dsh-market's "Plugin market" row.
|
|
467
|
+
ctx.slots.inject("settings.section", () =>
|
|
468
|
+
ctx.slots.register(
|
|
469
|
+
{
|
|
470
|
+
name: "settings.section",
|
|
471
|
+
id: SECTION_ID,
|
|
472
|
+
order: 41,
|
|
473
|
+
label: () => t("nav"),
|
|
474
|
+
locale: NS,
|
|
475
|
+
inject: () => ({ t })
|
|
476
|
+
},
|
|
477
|
+
() => React.createElement(MarketPanel, { t })
|
|
478
|
+
)
|
|
479
|
+
);
|
|
480
|
+
// Keep the tab under Settings → Plugins for discoverability.
|
|
421
481
|
ctx.slots.inject("settings.plugins.tab", () =>
|
|
422
482
|
ctx.slots.register(
|
|
423
483
|
{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-preview-market",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Vertical preview market for DeepSeek Harness: discover, install and configure preview plugins (media, Blender, STL, ...) from one panel.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -21,6 +21,9 @@
|
|
|
21
21
|
},
|
|
22
22
|
"files": [
|
|
23
23
|
"lib/**/*.js",
|
|
24
|
+
"catalog.json",
|
|
25
|
+
"catalog/**/*.json",
|
|
26
|
+
"catalog/README.md",
|
|
24
27
|
"cordis.patch.yml",
|
|
25
28
|
"README.md",
|
|
26
29
|
"README.zh.md",
|
|
@@ -66,7 +69,9 @@
|
|
|
66
69
|
},
|
|
67
70
|
"scripts": {
|
|
68
71
|
"test": "node --test test/*.test.js",
|
|
72
|
+
"catalog:write": "node scripts/write-catalog.mjs",
|
|
69
73
|
"e2e": "node scripts/e2e-settings.mjs",
|
|
74
|
+
"e2e:section": "node scripts/e2e-section.mjs",
|
|
70
75
|
"e2e:fallback": "node scripts/e2e-fallback.mjs",
|
|
71
76
|
"e2e:toggle": "node scripts/e2e-toggle.mjs"
|
|
72
77
|
}
|