Introduction

The design philosophy of DeepSeek Harness (DSH) is to treat everything as a plugin. During actual development or debugging, if you need to enable/disable a plugin or mount/unmount a new bundle, you usually have to restart the dsh web process, which interrupts the current workflow.

dsh-hotswap is a Web plugin hot-swap manager maintained by HongzhongL. It solves this problem by allowing you to enable, disable, or restart Cordis plugins at runtime without restarting dsh web, and by automatically syncing bundle configuration in the profile.

Core Features

1. Runtime Hot Enable/Disable

The plugin implements hot-swap by invoking the Loader’s entry.update({ disabled: true/false }) API.
* Hot disable: After calling this API, the plugin is unloaded immediately, and resources such as services, tools, and listeners are reclaimed right away.
* Hot enable: After calling this API, the plugin is re-imported and started immediately, including plugins that were disabled at startup.

2. Hot Restart and Bundle Synchronization

  • Hot restart: The plugin supports unloading and reloading, and does its best to clear the Node ESM module cache in order to attempt loading new code from disk (this process is best-effort).
  • Automatic Bundle synchronization (hot mount): The plugin watches the dsh.profile.bundles configuration in the profile’s package.json. When configuration entries are added or removed, it automatically performs hot mounting or unmounting via the Include root group, without requiring a manual restart.

3. Persistence and Configuration Management

  • Persistence: Each time a plugin’s state is toggled, the plugin writes disabled: true into the profile’s cordis.patch.yml file and maintains an automatic block named # === dsh-hotswap managed block ===. This ensures that the on/off state remains in effect after restarting dsh web.
  • External disable recognition: The plugin can recognize manually written disabled: true lines in cordis.patch.yml. When you enable a plugin in the UI, it removes that configuration line at the same time to avoid state inconsistency.

4. Safety Guardrails

To prevent system crashes caused by accidental operations, the plugin has built-in safety mechanisms:
* Protection list: Critical entries such as webserver, connection, api-gateway, modules, typert*, web*, and hmr, as well as the plugin itself, cannot be disabled.
* Expression control: Entries controlled by !!js expressions, or entries whose parent group is disabled, cannot be toggled.
* One-click recovery: Provides a “Restore All” function to re-enable all plugins disabled by the manager.

Installation and Configuration

Install

Install the plugin using DSH’s CLI tool:

dsh plugin --profile web add dsh-hotswap
# 安装完成后,需要重启 dsh web 才能生效
dsh web

Configuration (optional)

The plugin supports override configuration through the profile’s cordis.patch.yml:

- id: dsh-hotswap
  config:
    profile: web              # 持久化目标 profile(默认从 Loader baseUrl 推导)
    protected: [some-id]      # 追加不可停用的条目 id

Usage

UI Operations

After installation, go to DSH Web’s Settings → Plugins → “Plugin Management” tab. You can see a list of all currently mounted Cordis plugins. The list supports search and filtering, and displays each plugin’s status light and badge.

On the right side of each plugin entry, there are toggle and restart buttons. Click them to perform hot enable/disable or hot restart operations.

Modifying Configuration Files

Modify the dsh.profile.bundles configuration in the profile’s package.json. After saving, dsh-hotswap automatically detects the change and performs hot mounting or unmounting of the corresponding bundle.

Restoring Critical Plugins

If you accidentally disable a critical plugin and the UI becomes unusable, edit the persisted file shown in the UI (cordis.patch.yml), manually delete the automatic block for dsh-hotswap, and then restart dsh web to recover.

Notes and Limitations

Security Risks

This plugin exposes same-origin HTTP endpoints (/_dsh/hotswap/*) and does not add additional authentication.
* Local-only safety: As long as the Web service is bound to 127.0.0.1, only local machine processes can call it, which is relatively safe.
* LAN risk: If the webserver host is set to 0.0.0.0 and exposed to a local network, any device on the LAN can control your plugins (and thereby drive agents). Never expose it to untrusted networks.
* Origin validation: Origin validation (isSameOrigin) only blocks cross-site requests with an Origin header; local programs without an Origin header (such as curl) are allowed through. This means you should not share this machine with untrusted processes.

Compatibility

  • This plugin was developed and tested with DSH 0.1.0-rc.6.
  • Hot restart and code reloading rely on internal Cordis Loader APIs (entry._dispose / entry.refresh / loader.internal), which are not public contracts. After upgrading DSH, these APIs may change; confirm compatibility before upgrading.

Known Limitations

  • Client UI latency: After disabling a plugin, client UI injected by it into already open pages (such as settings page tabs) only disappears after refreshing the page.
  • ESM cache: The “code reload” part of hot restart is best-effort; the Node ESM module cache cannot be invalidated reliably, so in most cases it only unloads and re-applies, and may not read the new code from disk.
  • Headless mode: A headless profile has no webServer; this plugin only serves the Web UI and cannot work in Headless mode.
  • Persistence scope: Runtime enable/disable only affects the current process; persistence only covers toggles handled by this manager. Configuration lines manually written outside the managed block are not modified (unless they are removed when you click “Enable”).