dsh-plugin-runcat-inventory (Runcat Plugin Overview / 逃咪-插件总览)
中文 | English
Version: v1.3.2 · Changelog: CHANGELOG.en.md (中文)
A better DSH plugin list: table view, status filters, enable/disable switches (hot-applied), uninstall, update reminders, config viewer and copy, automatic zh/en UI switching.
Entry point: Settings → Runcat Plugin Overview (in the Settings left navigation; shown as 逃咪-插件总览 in Chinese).
Screenshot
Runcat Plugin Overview (English UI)
Features
| Capability | Description |
|---|
| Table view | 4 columns with fixed ratios: Name 36% / Status 15% / Source 21% / Actions 28% (name takes the largest share) |
| Entry point | Registered directly in Settings → Runcat Plugin Overview (left navigation, right after "Plugins") |
| Languages | Built-in Simplified Chinese / English; the UI follows the DSH environment (Settings → General → Language, or the browser language); the plugin's own description switches too |
| Runtime status | Enabled/Disabled + Cordis status (Mounted / Waiting for deps / Loading / Mount failed / Not mounted / Unloading) |
| Description / Version | Read from each package's package.json; the full description is shown in the expanded row (click "Details") |
| Source | Only this plugin shows its repository home page (https://github.com/runcat-tommy/dsh-plugin-runcat-inventory); others show the install method (local link / local path / GitHub / npm / built-in) |
| Details expansion | The "Details" button appears when a plugin has a description or a config; the expanded row shows the full description + config JSON, with one-click copy |
| Enable / Disable | Edits the profile's cordis.patch.yml (user override layer), hot-applied via HMR — no restart needed |
| Uninstall | "Uninstall" button in the Actions column with a confirm dialog; removes the dependency and bundle layer from the profile, effective after restarting the Web UI; cannot uninstall itself or built-in packages; uninstalled rows are marked "Uninstalled" in the list (dimmed, actions disabled) to avoid repeat operations |
| Update reminders | Checks the npm registry for the latest version (batched scan: 4 per batch, 200ms gap, 1h cache); when the plugin itself has a new version, a prominent card appears at the top of the panel; other plugins show vX → vY highlighting in the version column + an inline "Update" button + a top banner; the update pins the target version into the command (add <name>@<latest>) and re-checks the installed version afterwards |
| Update results | Progress and results render inside the row (the confirm dialog closes on confirm and never blocks the UI): success → "applied" or "restart DSH to use it"; failure → "Update failed" plus Reason (error code / command / exit code / stderr); after a successful update the plugin asks DSH's own HMR to hot-apply, so no restart is needed when it can be applied |
| Batch & restart | Two buttons in the top banner: Update all (sequential, per-row progress, summary) and Restart DSH (CLI hosts restart directly and the page waits for it; on Desktop the shell owns the host, so it explains that a manual reopen is required) |
| Update boundaries | Local link dependencies (link: / file: / workspace:) are not updatable (clicking Update refuses explicitly: installing the npm release would drop the development link); a local version already ≥ npm latest reports "already up to date" instead of failing; VERSION_MISMATCH now means only "genuinely older than the target" (npm source not synced yet — retry later) |
| Search & filter | Keyword (combined search over name / id / description / source / version) + status filter |
| Sorting | Config order (default) / Name ↑ / Name ↓ |
| Width | No sticky columns; ←/→ arrow keys scroll horizontally; the Source column hides on narrow screens |
Structure
dsh-plugin-runcat-inventory/ # local folder name after git clone (same as the repo)
├── package.json # dsh.bundle.patch + dsh.client declarations
├── cordis.patch.yml # patch layer: inserts this plugin entry into the root entry list
├── lib/
│ ├── index.js # Host half: loader inventory + /runcat-api routes + patch file editing
│ └── client.js # Browser half: hand-written ModuleLoader bundle, table UI
├── test/
│ └── mock-test.mjs # host-half unit tests (node test/mock-test.mjs, 5 cases)
├── assets/
│ ├── preview-zh.png # Chinese-UI screenshot
│ └── preview-en.png # English-UI screenshot
├── CHANGELOG.md # changelog (Chinese)
├── CHANGELOG.en.md # changelog (English)
├── README.md # Chinese docs
└── README.en.md # English docs (this file)
Prerequisites
| Dependency | Required? | Notes |
|---|
| Node.js | ✅ Required | DSH itself is a Node program; install Node.js (suggest 20+ or the latest LTS; no strict minimum) |
| DSH CLI | ✅ Required | npm i -g @deepseek-ai/dsh |
| pnpm | ✅ Required | dsh plugin forwards to pnpm; without it you get pnpm not found on PATH; install with npm i -g pnpm |
| Git | ⚠️ Depends on method | Needed for Method B (GitHub source) or Method C (local development); not needed for Method A (npm) |
| Network | ⚠️ Depends on environment | Method A needs access to the npm registry; Methods B/C need access to GitHub — if direct connections fail, configure a git proxy, e.g. git config --global http.https://github.com.proxy http://127.0.0.1:7897 |
This plugin itself has zero dependencies: the host half only uses Node built-ins (plus lazily resolving js-yaml from the profile), and the browser half is a hand-written ModuleLoader bundle. Nothing extra to install.
Installation
Installs into the web profile (replace web with your profile name if different).
Method A: npm install (simplest, recommended)
dsh plugin --profile web add dsh-plugin-runcat-inventory
Pulls directly from the npm registry; the package is published at
https://www.npmjs.com/package/dsh-plugin-runcat-inventory
(if your npm/pnpm is configured with a mirror, wait for the mirror to sync).
Method B: install directly from GitHub
dsh plugin --profile web add github:runcat-tommy/dsh-plugin-runcat-inventory
pnpm pulls the repo directly from GitHub; this plugin has no build scripts, so no allowBuilds is needed.
Method C: local folder (for development/debugging)
git clone https://github.com/runcat-tommy/dsh-plugin-runcat-inventory.git
cd dsh-plugin-runcat-inventory
dsh plugin --profile web add .
dsh plugin add . links this folder into the profile via link: — dev-friendly: code changes take effect after restarting the Web UI, no reinstall needed.
Verify
dsh --profile web --dump-config should end with an entry whose id is runcat-inventory and name is dsh-plugin-runcat-inventory.
Then restart the Web UI and open Settings → Runcat Plugin Overview (in the left navigation; 逃咪-插件总览 in Chinese).
How it works
- Data: the host half iterates
ctx.loader.entries() (same as the official inventory); fiber status maps from FiberState; description/version are read from each package's package.json; source is derived from the profile's package.json dependency declarations.
- Enable/Disable: writes
{id, name, disabled: true} patches into ~/.dsh/profiles/web/cordis.patch.yml (to disable) or removes them (to enable). DSH watches this file via HMR (watchUserPatches) and hot-applies changes to the loader — plugins toggle instantly without a restart.
- Communication: the browser half fetches same-origin
/runcat-api routes; routes carry a loopback trust check (CSRF protection).
- Lazy js-yaml resolution: when installed via
link:, the plugin's real path is the workspace (no node_modules there), so at runtime js-yaml is resolved anchored at the profile directory.
Uninstall
dsh plugin --profile web remove dsh-plugin-runcat-inventory
Known limitations
- If
cordis.patch.yml contains !!js expressions, the enable/disable switch reports a failure (the file is never corrupted; it just cannot be auto-edited).
- The disable patch is matched and removed exactly as
{id, name, disabled: true} (three keys); conflicts with hand-written content are resolved by the "exactly three keys" rule.
Changelog
Full history in CHANGELOG.en.md (中文).
- v1.3.2 (2026-10-19): the enable/disable result moved from the bottom of the panel to directly under that plugin's row (full width, room for long text), worded "Enabled: X (applying live — click Refresh at the top right to confirm)"; the notice stays readable for at least 5 seconds and is retired only once the state really flips.
- v1.3.1 (2026-10-19): fixed "clicking Enable/Disable does nothing" — the host could not resolve js-yaml (
YAML_UNAVAILABLE), so the patch file was never written. Enable/disable is now plain text editing (append/remove a marked - id/name/disabled: true item, everything else preserved byte for byte), with no YAML parser dependency at all.
- v1.3.0 (2026-10-19): UX rework — the confirm dialog for update/uninstall closes as soon as you confirm, and progress/results move into the row ("restart DSH to use it" or "applied" on success; "Update failed" plus an expandable Reason with error code, command, exit code and stderr tail on failure); the top banner gains "Update all" and "Restart DSH"; successful updates are hot-applied through DSH's own HMR, so no restart is needed when it can be applied (on Desktop the Electron shell owns the host, so the plugin explains that a manual reopen is required instead of pretending).
- v1.2.3 (2026-10-19): fixed three measured defects on Desktop 0.2.1-rc.2 (unrelated to version compatibility) — ① update/uninstall always failed because
dsh is not on the host process's PATH: added CLI resolution (RUNCAT_DSH_CLI / host exe + asar cli.js / PATH / known install locations) and a DSH_CLI_NOT_FOUND code; ② enable/disable failed wholesale when the patch layer contains !!js: a !!js type plus placeholder round-trip now writes the original code back unchanged; ③ writes no longer drop the user's comments.
- v1.2.2 (2026-10-16): fixed two measured defects — ① the update command now pins the target version (
add <name>@<latest>), so "pnpm no-op exits 0 → the self-check calls it a failure" is gone; local link dependencies (link/file/workspace) are explicitly refused; "already up to date" and "update failed" are separate messages, and the response carries from_version → to_version. ② host peer declarations completed (locale + runtime + ui-settings), so the market reads compatible instead of unknown.
- v1.2.1 (2026-10-16): declared the host peer range — but the declared
@deepseek-ai/dsh-client-runtime is not in the Desktop host inventory, so the market still read (fixed in v1.2.2).