dsh-update-checker
English | 中文
A permanent Cordis plugin for the DeepSeek Harness Web GUI that auto-checks for new DeepSeek Harness releases and installed third-party plugin updates (the former standalone dsh-plugin-checker was merged in v1.1.0), asks the user, and one-click updates with success/failure feedback.
Features
- Full update lifecycle — check, backup, update, rollback, and restart, all in one plugin.
- Main program check — compares the installed
@deepseek-ai/dsh against the npm latest (full packument, stable-first, semver-aware). A pre-release target is installed only when it belongs to the channel the deployment already follows — a cross-channel promotion (rc → alpha) is refused with E_PRERELEASE unless you enable the allowPrerelease setting, so the checker never promotes the harness into an unintended pre-release channel.
- Third-party plugin check — scans installed non-official plugins (layout-agnostic, incl. pnpm-hoisted
node_modules), cross-compares each against npm + GitHub (target = higher version); local tools with no publish source go to ignored. When a plugin name has multiple copies, the one in the composition-owning profile's node_modules wins (the rest are listed as copies), and each plugin can be excluded from prompts (excludedPlugins, re-enableable in the settings page).
- Working GitHub channel — dedicated HTTPS client for GitHub domains (tolerates self-signed local proxies; the npm registry still uses strict TLS), with redirects, size caps and timeouts; codeload tarballs are validated before install.
- In-GUI banner — locale-aware (zh/en follows the DSH UI language), states update / up-to-date / failure, with a suppression flag and a change brief (vX→vY + risk level + release notes when available).
- One-click update with safety — main program: dry-run guard (abort if the plan contains
remove) → snapshot backup (version manifests + a main-snapshot copy of the @deepseek-ai tree for offline rollback) → layout-adaptive install (in-place or -g) → post-install check installed==latest; plugins: temp-dir install + copy, dependency version reconciliation, auto --allow-scripts for native deps on npm ≥ 12. Updates (and rollbacks) persist to the profile package.json + lockfile (pnpm install --lockfile-only / npm install --package-lock-only), so a later install never silently reverts the plugin — no more "same plugin keeps asking for the same update" loops.
- Real rollback — main program via
POST /rollback, plugins via POST /plugin-rollback; GET /backups.json lists both.
- Restart with watchdog — launcher derived from the current process argv, kill by PID + port, recovery confirmed by port listening, an HTTP 200 probe (
GET /restart-status.json) and a new instance id read back from this plugin's own routes, so "something answers on the port" is no longer mistaken for "the updated build came up".
- Write-route security — all write routes require
{ "confirm": true } and a loopback source (127.0.0.1/::1), so LAN clients can't trigger update/restart/rollback.
- Zero-config portability — profile dir / composition file / deploy root are derived from the plugin's own install location, while state, backups and logs honour
DSH_HOME (then ~/.dsh); works on any machine without editing code.
Host & Client
- Host (
lib/index.js) — HTTP routes: status.json (check), suppress, update (with dry preview), rollback, backups.json, restart, restart-status.json, plugins.json, plugin-update, plugin-rollback, plugin-exclude.
- Client (
lib/client.js) — renders two banners in the root shell.overlay slot: a core banner (main-program update state) and a plugin banner (updatable plugins with single / update-all buttons). Both check on page load, then every 6 hours; the settings page ("检查更新") adds rollback buttons.
Install & mount
The package is a profile bundle (its manifest declares dsh.bundle.patch).
# 1) put the package into $DSH_HOME/profiles/node_modules/ so the profile can resolve it.
# ⚠️ Never run `npm install` directly inside $DSH_HOME/profiles — it has no
# package.json and npm would prune the whole node_modules (data loss).
# Safe option A — install in a temp dir, then copy only this package:
npm i dsh-update-checker --prefix <temp-dir> --no-save
cp -r <temp-dir>/node_modules/dsh-update-checker $DSH_HOME/profiles/node_modules/
# Safe option B — copy the package directory manually (git clone or tarball).
# 2) add the row to $DSH_HOME/profiles/web/cordis.patch.yml
# $DSH_HOME/profiles/web/cordis.patch.yml
- insert:
- id: dsh-update-checker
name: 'dsh-update-checker'
Then let patch HMR apply it (or restart dsh web) and reload the page.
Step-by-step guide with troubleshooting (中文): docs/INSTALL.md.
Configuration & portability
All paths are auto-detected at runtime — nothing is hardcoded:
- Plugin / profile dir — derived from the plugin's own install location (
import.meta.url).
$DSH_HOME — the parent of the profiles root (state, backups, restart log live there).
- Composition file — defaults to
$DSH_HOME/profiles/web/cordis.patch.yml.
- Deployment root — junction
realpath first, then DSH_DEPLOY_ROOT, then process.cwd(), then the npm global prefix (parent of npm root -g's output; v1.4.9+ covers npm -g installs).
- systemd /
npm -g escape hatch: if auto-detection ever misses your setup, set DSH_DEPLOY_ROOT to the directory that contains node_modules/@deepseek-ai/dsh (e.g. <npm prefix>/lib on Linux).
- Node / npm executables —
resolveNodeExe() finds the real Node: DSH_UC_NODE_EXE override → npm_node_execpath → process.execPath when it is Node → common install dirs → PATH. This is what makes DSH Desktop (Electron, where process.execPath is electron.exe) able to run npm for plugin updates. If your Desktop build bundles Node elsewhere, set DSH_UC_NODE_EXE to it. If your Node is managed by mise / asdf / nvm and your PATH only exposes the version-manager shim (e.g. ~/.local/share/mise/shims/node), the shim directory has no npm beside it; v1.4.22+ resolves the real binary by running node -p process.execPath through the shim. If that still fails (or you want to skip the lookup), set DSH_UC_NODE_EXE to the real binary, e.g. mise which node / asdf which node.
- Restart launcher — self-adapting: probes common launcher names under the deployment root; the web port is read from the running
webServer.port.
- Tuning env vars —
DSH_UC_UPDATE_PORT sets the port the update worker stops/starts/probes (default 3080), and DSH_UC_RESTART_WINDOW_MS sets how long the worker keeps observing a slow first start before giving up (default 150000; the progress record streams the whole time).
Platform & install-layout support
- Detection (checks) — layout-agnostic, works on any machine.
- One-click update & restart — tuned for the layout they were developed on:
- Windows only — the restart flow spawns PowerShell.
- Main-program update adapts: in-place
npm install when the deploy root has a package.json, npm install -g otherwise; both run the dry-run guard and re-read the installed version afterwards.
- Plugin updates — temp-dir install + copy, npm 11/12+ compatible.
- Other platforms/layouts: banners and version checks still work. On Linux/macOS the main-framework update route now refuses immediately with
501 E_PLATFORM_UNSUPPORTED (install/restart there still need code adaptation) instead of hanging at 8% and leaving a stuck banner; plugin updates and rollback work. Full POSIX support is the natural next step.
Notes
- Host code changes require a service restart (the loader caches imported modules); client changes are picked up by HMR and apply on the next page refresh.
- Update/rollback/restart/suppress/settings routes are guarded by
{ "confirm": true } and a loopback-source check (127.0.0.1/::1).
- Before
npm install, a backup (deployment package.json + package-lock.json + both @deepseek-ai version manifests + backup-meta.json + a main-snapshot copy of the @deepseek-ai framework tree) is written to $DSH_HOME/dsh-update-checker-backups/<timestamp>/; both main-program and plugin rollback routes are provided, and main-program rollback restores from the main-snapshot when present instead of re-installing from the registry.
Changelog
Development
lib/index.js — Host half: plain ESM, Node built-ins only, no build step; pure helpers exported as named ESM exports for unit testing.
lib/client.js — Client half: plain JS (window.__ModuleLoader__), requires only react, no build step.
- Tests:
npm test (Node ≥ 20 built-in test runner, no third-party deps).
scripts/restart-service.ps1 — manual restart helper (run with -ExecutionPolicy Bypass).
License
MIT