# dsh-webui-market-plugin

> Move the awesome-dsh-plugin.com plugin directory into the dsh Web settings page: browse, search, and FIFO queue for one-click install/uninstall/update, with whitelist and trial installation verification, cross-profile sync support, and hot-mount without restart.

## Metadata

- Author: [@Sanqi-normal](https://github.com/Sanqi-normal)
- Repo: <https://github.com/Sanqi-normal/dsh-webui-market-plugin.git>
- GitHub: [Sanqi-normal/dsh-webui-market-plugin](https://github.com/Sanqi-normal/dsh-webui-market-plugin)
- Stars: 94
- Language: JavaScript
- License: [MIT](https://spdx.org/licenses/MIT.html)
- Topics: `agent-harness`, `deepseek`, `dsh-plugin`, `plugin-market`, `ui`, `web`
- Forks: 3
- Open Issues: 2
- Last push: 2026-08-18T04:43:03.000Z
- Added: 2026-08-14T00:00:00.000Z

## Install

```bash
dsh plugin --profile web add github:Sanqi-normal/dsh-webui-market-plugin
```

## Wiki

## One-Sentence Pitch
Brings the awesome-dsh-plugin.com plugin directory into a visual plugin market within the dsh Web settings page: Open "Settings → Plugins → Plugin Market" to browse, search, and install/uninstall/update community plugins with one click, and sync web-installed plugins to desktop and other profiles.

## Core Features
- Browse and search the community plugin directory from awesome-dsh-plugin.com (including categories, star count, submission date, Chinese/English descriptions), sorted by "Most Popular / Latest"
- One-click install, update, uninstall, executed serially in FIFO queue; real-time display of "Queued / Validating / Running / Complete / Failed / Stopped / Timeout" status and pnpm logs
- Two-layer security gate before installation: source whitelist (only accepts github: sources from the curated directory) + trial installation verification (web profile actually starts once in a temporary environment)
- One-click cross-profile sync: copy-installed plugins from web to other initialized profiles like desktop, adding only without deleting
- Disable / Enable: keeps dependency files, only toggles activation status; disabled state persists after restart
- One-click update all + single plugin update: github source compares lockfile commit with HEAD, npm source compares dist-tag.latest
- Local plugin inventory: lists all dependency-managed plugins (including those installed outside the market), marks in-directory / out-of-directory, source type, disabled status
- After successful installation, simple plugins can hot-mount to the current running combination, usable without restarting the Web service

## Technical Implementation
- **Language**: TypeScript (compiled output is ESM JS, source builds to `lib/host.js` + `lib/client.js`)
- **Key Dependencies**: `@deepseek-ai/cordis` (host framework, peerDependency); `@deepseek-ai/dsh-client-runtime` and `@deepseek-ai/dsh-client-ui-slots` (browser-side registration of settings page tab); `react` ^18.2.0 (panel UI)
- **Architecture Pattern**: Cordis dual-form plugin — host half registers `/api/dsh-market` HTTP route on `webServer` service via `apply(ctx)`, browser half is declared to be loaded by frontend ModuleLoader via `exports["./client"]` + `dsh.client.platform: "web"`, registers to `settings.plugins.tab` slot; install/update/uninstall uses `node:child_process` to invoke `dsh plugin` subprocess, write operations require same-origin POST
- **Entry Files**: Host entry `lib/host.js` (exports `name: 'dsh-market-plugin'`, `inject: ['webServer']`, `apply`); Client entry `lib/client.js` (exports `inject: ['slots','sessions','workspaces']`, `apply`, registers to `settings.plugins.tab` slot)

## Use Cases
Users who use dsh web or desktop daily and want to browse and install community plugins through a GUI without manually typing `dsh plugin add` commands; people who need to sync plugins between web and desktop and other profiles; and operational users who want visual control over each plugin's status (disabled / enabled / installed / has update) and can one-click ask DSH to troubleshoot when failures occur.

## Prerequisites and Compatibility

| Dependency | Minimum Version | Notes |
|---|---|---|
| Node.js | ^22.19.0 or >=24.0.0 | Required by `package.json:37-39` `engines.node`; uses `AbortSignal.timeout` and other newer APIs |
| DSH Host | No specific version declared | `peerDependencies` only writes `*`; host must expose `webServer` service (host half `inject: ['webServer']`), `slots` / `sessions` / `workspaces` (browser half `inject`) and `settings.plugins.tab` slot |
| pnpm | ≥11 recommended | Installation uses host's built-in pnpm; pnpm 11 defaults to 24h `minimumReleaseAge` and `ERR_PNPM_IGNORED_BUILDS` interception, market can automatically add to whitelist and retry |
| Platform | macOS / Windows / Linux | Cross-platform; Windows separately handles `.cmd/.bat` shim, `shell:true` startup and `taskkill /T /F` to kill process tree (`lib/host.js:101-112, 300-309`) |
| Native Modules | None | Only uses Node.js built-in modules (`node:fs` / `node:child_process` / `node:os` / `node:path` / `node:url` / `AbortSignal.timeout`) |

## Installation
```bash
dsh plugin --profile web add github:Sanqi-normal/dsh-webui-market-plugin
```

## Configuration
This plugin does not require writing configuration in cordis patch; all user-facing toggles are in the panel "Install Settings" and "Cross Profile Sync".

| Configuration | Type | Description | Default |
|---|---|---|---|
| Auto-sync to other profiles (Install Settings) | Panel Toggle | When enabled, automatically syncs plugins to all initialized profiles on this machine during installation; when disabled, only installs to the profile selected during installation | Enabled |
| Skip security check (web profile installation) | Panel Checkbox | Skips source whitelist + trial installation verification simultaneously, may install non-curated sources or break web startup, at your own risk | Disabled |
| Skip source whitelist check (non-web profile installation) | Panel Checkbox | Only skips whitelist (still takes pre-install snapshot), may install non-curated sources | Disabled |
| Install to Profile | Panel Dropdown | Target profile selectable in installation confirmation dialog (default web); when auto-sync is enabled, selected target will be auto-installed to other profiles | web |
| dsh CLI path (fill when auto-detection fails) | Panel Input | When auto-detection fails, manually fill in `apps/cli/lib/bin.js` under dsh repository root, or set `DSH_BIN` environment variable and restart web; remembers last input | Empty |

Environment variables (set in host process environment):

| Environment Variable | Description | Default |
|---|---|---|
| `DSH_MARKET_OP_TIMEOUT_MS` | Hard timeout for individual install/update/uninstall task (ms), automatically terminates pnpm subprocess after timeout | 120000 |
| `DSH_MARKET_FETCH_TIMEOUT_MS` | Timeout for single pnpm network fetch (ms) | 30000 |
| `DSH_MARKET_FETCH_RETRIES` | Retry count when pnpm fetch fails | 1 |
| `DSH_MARKET_FETCH_RETRY_MINTIMEOUT_MS` / `MAXTIMEOUT_MS` | Lower / upper bound for pnpm retry interval (ms) | 1000 / 10000 |
| `DSH_BIN` | Explicitly specify dsh CLI entry file path (for source startup scenario) | Not set |
| `DSH_HOME` | DSH data root directory read by host / plugin | `~/.dsh` |

## FAQ
**Q: What's the relationship between this plugin and awesome-dsh-plugin.com?**

A: The list comes directly from awesome-dsh-plugin.com's plugins.json API (`lib/host.js:973, 1069-1077`), automatically returns Chinese/English descriptions based on system language; falls back to built-in offline snapshot `data/catalog-snapshot.json` when initial fetch fails. Local installation only accepts github: sources from the curated directory by default; sources outside the directory are rejected by the whitelist.

**Q: Do I need to restart the Web service after installation?**

A: Simple plugins (where `cordis.patch.yml` only has `- id:` / `name:` insertion lines) attempt hot-mount to the current running combination and auto-refresh the page to take effect (`lib/host.js:1152-1176`); if the patch is complex or the environment doesn't support it, the market falls back to "effective after next Web restart", won't auto-restart the host.

**Q: How to resolve pnpm's "Blocked build scripts" during installation?**

A: pnpm ≥11 intercepts build scripts not allowlisted in allowBuilds by default. The market automatically adds the intercepted package name to the profile's `pnpm-workspace.yaml` `allowBuilds` and retries once when the task fails (`lib/host.js:442-468, 685-695`); if that dependency truly doesn't need to execute build scripts, write the corresponding entry as `false` (explicitly reject) and it won't be automatically re-added.

**Q: Will trial installation verification modify my real profile?**

A: No. Trial installation verification reconstructs the combination in a temporary directory (`mkdtempSync(tmpdir() + 'dsh-mkts-probe-')`) using the web profile template, installs the candidate plugin with the same dsh CLI, then actually starts once with `--port 0`; it's only considered installable if the `dsh web:` ready line appears (`lib/host.js:823-893`). The real profile is never written to during the entire process; the temporary directory is cleaned up after verification regardless of success or failure.

**Q: Why do some plugins fail to install (rejected)?**

A: By default, only curated directory-listed `github:` sources can pass the whitelist; registry/link sources are not restricted by this but still go through whitelist + pre-install snapshot; trial installation startup failure also rejects and returns the real startup error (`lib/host.js:601-617`). If you确实需要安装目录外或试装失败的插件，可勾选「跳过安全检查」（风险自负）。

**Q: How do I sync plugins installed on web to desktop?**

A: The "Cross Profile Sync" section at the top of the panel lists all initialized profiles on this machine (e.g., `desktop`); clicking "Sync to xxx" will copy-installed plugins that are installed in web but missing in the target profile (`lib/host.js:1492-1506`). Sync only adds, does not delete or downgrade any existing content in the target profile. Restart the corresponding application after installation for changes to take effect. Sync carries `syncFrom` validation: only proceeds when the target source is indeed a dependency installed in the source profile, so plugins installed on web but not in the curated directory (like aegis) can also be synced.

**Q: What's the difference between disabling a plugin and uninstalling?**

A: Disabling keeps dependencies and disk files, only removes the plugin from `dsh.profile.bundles` and writes `dsh.market.disabled`; it stays disabled after restart (`lib/host.js:1284-1318`). Uninstalling deletes both dependencies and bundle. Note: manually executing `dsh plugin add/remove/update` on the command line triggers reconcile which briefly restores disabled items; the next market operation or restart will disable it again.

**Q: How to handle install/update failures?**

A: Failed entries have an "Ask DSH" button; clicking it opens a new conversation with the operation target, status, environment information (DSH_HOME / node / dsh detection results) and complete error log as the prompt, sent to AI for direct troubleshooting (`lib/client.js:165, 740`). Network errors (ETIMEDOUT / ECONNRESET, etc.) the market automatically retries once (`lib/host.js:700-707`); persistent failures prompt to check proxy or mirror.

**Q: Will one-click update all update all plugins?**

A: No. One-click update only reinstalls plugins with `updateAvailable=true` (`lib/host.js:1820-1840`): github source compares lockfile commit with GitHub HEAD, npm source compares `dist-tags.latest` with installed version, considering pnpm 11's 24h `minimumReleaseAge`; local link/file links don't participate in detection. Detection failure silently falls back to "no updates", won't block the list.

## Difficulty Level
Beginner — No configuration needed after installation to use directly; only need to fill in `apps/cli/lib/bin.js` path in the panel or set `DSH_BIN` if auto-detection of dsh CLI fails, zero-config in the vast majority of cases.

## Known Issues and Limitations
- Most plugins require restarting the Web service after installation to take effect; only simple plugins with patch being pure `- id:` / `name:` insertion lines will hot-mount and auto-refresh the page (`lib/host.js:1152-1176, 1201-1217`)
- Trial installation verification only executes for web profile: non-web profiles (like desktop) have their combinations defined by the corresponding desktop shell, which the market cannot replicate in a temporary environment; their installation is guarded by "source whitelist + pre-install snapshot", no startup validation (`README.md:66`, `lib/host.js:599-617`)
- Manually executing `dsh plugin add/remove/update` on the command line triggers reconcile which briefly restores disabled items; requires restart or next market operation to disable again (`README.md:75`)
- Single task defaults to 120 second timeout, can be increased via `DSH_MARKET_OP_TIMEOUT_MS` in host environment (e.g., 300000); pnpm subprocess runs in CI mode fixed to avoid silent hang without TTY (`lib/host.js:32, 52-58, 656`)
- pnpm 11's 24h `minimumReleaseAge` and `ERR_PNPM_IGNORED_BUILDS` interception automatically fixes and retries once; if build scripts were temporarily approved in the trial installation environment, that approval only applies to the trial directory, not written to real profile (`lib/host.js:676-695, 866-878`)
- Cross-profile sync adds only, never deletes or downgrades; if the target profile already has the same dependency installed (even a different version), sync skips it (`lib/host.js:1492-1506`)
- Write operations (install / uninstall / update / disable / enable / kill / clear) only accept same-origin POST (Origin header matches Host), cross-origin requests return 403 (`lib/host.js:221-230, 1822-1825, 1843-1845, 1878-1881, 1885-1887, 1900-1903, 1921-1924`)

---

This document is auto-generated by [deepseek-plugin.org](https://deepseek-plugin.org). HTML page: [dsh-webui-market-plugin](https://deepseek-plugin.org/plugins/Sanqi-normal/dsh-webui-market-plugin)
Wiki generated by AI (model: `MiniMax-M2.5`)
