DeepSeek Harness Plugin Hub

Publish and manage complete Harness Profiles. Discover Plugins for your next setup.

Explore

PluginsPresetsDocsNews

Community

Publish a pluginContactReport an issue

Resources

Plugin Hub on GitHubDeepSeek HarnessSystem statusPrivacy notice
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

Independent and unofficial. Not affiliated with, authorized by, or endorsed by DeepSeek.

Update Checker — DSH Plugin for DeepSeek Harness
DeepSeek Harness Plugin Hub
ProfilesPluginsCategoriesNewsDocsSign inManage Profiles
ProfilesPluginsCategoriesNewsDocsSign in
← Plugins

dsh-update-checker

Update Checker

Auto-check DeepSeek Harness and third-party plugin updates, notify in the Web GUI, one-click update with backup/rollback and restart watchdog.

The plugin will be installed here. Keep web if you are unsure.

npx -y @deepseek-ai/dsh plugin --profile web add dsh-update-checker@1.5.0
READMECompatibilityVersions

Compatibility and provenance

Update Checker is published as dsh-update-checker and currently resolves to version 1.5.0. The Hub verifies its manifest and preserves the exact installation source for reproducible installs.

DSH compatibility
*
Runtime surfaces
web
Release source
npm
Registry updated
9/20/2026

Versions

1.5.0stable
9/17/2026
1.4.23stable
9/16/2026
1.4.22stable
9/9/2026
Show 35 more versionsCollapse versions
1.4.21stable
9/4/2026
1.4.20stable
9/3/2026
1.4.19stable
9/1/2026
1.4.18stable
9/1/2026
1.4.16stable
8/25/2026
1.4.15stable
8/22/2026
1.4.14stable
8/21/2026
1.4.13stable
8/21/2026
1.4.12stable
8/21/2026
1.4.11stable
8/21/2026
1.4.10stable
8/21/2026
1.4.9stable
8/20/2026
1.4.8stable
8/19/2026
1.4.7stable
8/19/2026
1.4.6stable
8/19/2026
1.4.5stable
8/19/2026
1.4.4stable
8/19/2026
1.4.3stable
8/18/2026

Related plugins

Loading related plugins…

Latest
1.5.0
DSH
*
HMR
Process restart
Tree shaking
Safe tree shaking not declared
Unpacked size
440.3 kB
Files
44
Surface
web
License
MIT
Source
npm
GitHub
★ 17
Weekly downloads
1,417
Security scan
✓ v1.5.0 scan passed
Last push
9/17/2026
View source ↗Project homepage ↗
README badge

Click the badge to copy Markdown for your README.

Do you maintain this Plugin?Claim benefit · Priority security scan

Verify the GitHub repository declared in package.json to manage this listing. After you claim it, Hub will prioritize a security scan of the current version and publish the result when it passes.

Claim this Plugin →
Report an issue
1.4.1stable
8/18/2026
1.4.0stable
8/17/2026
1.3.2stable
8/15/2026
1.3.1stable
8/15/2026
1.3.0stable
8/15/2026
1.2.3stable
8/15/2026
1.2.2stable
8/15/2026
1.2.1stable
8/15/2026
1.2.0stable
8/15/2026
1.1.2stable
8/15/2026
1.1.1stable
8/15/2026
1.1.0stable
8/15/2026
1.0.4stable
8/15/2026
1.0.3stable
8/15/2026
1.0.2stable
8/15/2026
1.0.1stable
8/15/2026
1.0.0stable
8/15/2026

Related plugins

More verified plugins in developer-tools.

Web App@deepseek-ai/dsh-web-appThe dsh browser-surface bundle: the web patch layer over dsh-base plus the runtime glue plugin (frontend dist serving, web-surface prompt, bash runtime variables, URL line)Sdk Minimal@deepseek-ai/dsh-sdk-minimalThe standalone minimal SDK profile bundle: JSON-RPC, one DeepSeek adapter, persistent shell, and JSONL sessionsSdk App@deepseek-ai/dsh-sdk-appThe dsh SDK profile bundle: stdio JSON-RPC serving and process lifecycle over dsh-baseSubagent Codex@deepseek-ai/dsh-subagent-codexOne-shot Codex subagent provider over the official app-server protocol

README

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

  • v1.5.0 — syncProfilesToDeploy links instead of copying (fixes the crash that followed a main-program update):

    • Root cause: the function's name and its junctionSkipped log field promised linking, but the write path never created a link — it called cp(src, dst, { recursive: true, force: true }). Entries already present and resolving to the same real path were skipped (228 of 236 on a real host), while packages not yet present in the profile — the 8 new ones a 0.1.6-alpha.1 update brings — were copied as real directories into $DSH_HOME/profiles/node_modules/@deepseek-ai/.
    • Why that is fatal: dsh's healProfilesModuleFallback/ensureSymlink only takes over symbolic links or dsh-managed module proxies. A real directory makes it throw dsh: <path> exists and is not a symlink or dsh-managed module proxy; remove it so dsh can manage the installation fallback during composeProfile — before the web server binds — so the next launch dies outright, while the update itself reported success (main-profile-sync total:236 junctionSkipped:228 failed:[]).
    • Fix: the write path is now mkdir + symlink(src, dst, process.platform === "win32" ? "junction" : "dir"), so the profile keeps pointing at the single deployed copy — exactly what healProfilesModuleFallback expects.
    • Self-healing: a destination that exists but is not the deploy copy is reclaimed safely — a symbolic link (including a dangling one) is rebuilt, and a real directory is replaced only after its package.json name matches the deploy package. Anything else is left untouched and reported as a failure (refusing to replace) instead of being overwritten, which also closes a second, previously unreported hazard: fs.cp(..., { force: true }) does not reject a same-named directory from another source — it overwrites that package's files and leaves the rest behind, silently gutting it.
    • Regression test: scripts/integration-sync-profiles.test.mjs extracts syncProfilesToDeploy from the real worker source (so the test cannot drift from the implementation) and covers six scenarios — a new package becomes a link, a leftover real copy is reclaimed, a same-named foreign directory is never deleted, a dangling link is rebuilt, non-dsh packages are ignored, and an unreadable deploy tree exits safely. The suite fails 4/6 against the 1.4.23 worker and passes 6/6 against this one.

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

  • The post-install health check now proves a new dsh process is serving: it used to accept any answer on the port — GET / → 200 swept assets, while 401/403/407 were declared success outright — so a build that died in composeProfile (no server at all) was still reported as a successful update. The host now hands its own instanceId to the worker, which reads the id back from this plugin's own routes (update-progress.json, then status.json; both answer without a browser session): a different id means the updated build really came up, the same id means the instance from before the restart is still the one answering and the update is reported as failed. When the probe cannot decide — this plugin not composed, a route not answering yet, or an older host that passed no id — the previous behaviour is kept rather than failing a healthy update.
  • The prerelease gate is channel-aware, instead of asking whether a stable version exists: the old test was isPrerelease(target) && !allowPrerelease && hasStable, and hasStable meant "npm holds some non-prerelease version". Every published @deepseek-ai/dsh is an rc/alpha, so hasStable was always false and the gate never fired: an allowPrerelease: false deployment was promoted rc → alpha anyway. The gate now compares release channels (alpha/beta/rc/stable) — a same-channel upgrade stays allowed, a cross-channel promotion is refused with E_PRERELEASE and a message naming the allowPrerelease setting, and missing data fails open.
  • State, backups and logs follow DSH_HOME: the home was derived only from where this package happens to sit, so an install outside a …/profiles/node_modules tree wrote its state next to the program files. A layout that really is a Harness home still wins (which keeps DSH_UC_PROFILE_NODE_MODULES overrides and the test suite's isolation working); anything else falls back to DSH_HOME, then ~/.dsh.
  • Recovery for machines already hit by this bug: move (do not delete) the real directories under $DSH_HOME/profiles/node_modules/@deepseek-ai/; the next dsh launch rebuilds them as junctions automatically.
  • v1.4.23 — Live main-program progress, stale-update recovery, safe plugin replacement (issues #17 #18 #20 #21 #25, PRs #23 #24):

    • Real progress during the dependency-tree check (#18 + the "6% → 64%" report): the download phase used to sit at 4–6% for the whole npm install --dry-run (minutes) and then jump straight to 64%. Every phase now runs a monotonic creep ticker that rewrites the progress record once per second (phaseCreepPercent, exported and unit-tested), and real npm/tarball counts only push the floor forward. The milestones were rescaled (download 10→55, stop 58, install 62→78, verify 84→87, sync-decl 88, restart 92→95, health 96, restart-pending 97–98, done 100) so no phase teleports. The 30-second service start and the restart watch also stream progress while they block.
    • Restart is observed instead of reported as failure (#18): after install + integrity + declaration sync succeed, a failed restart no longer ends the update. The worker enters restart-pending, keeps streaming progress, re-probes the port and re-spawns the launcher for up to DSH_UC_RESTART_WINDOW_MS (default 150000 ms), and only then fails with E_RESTART — with installed, restartPending: true and text stating the install itself succeeded. A later port appearing becomes a normal success.
    • Progress counters fixed (#18): the install phase no longer divides npm's http-line counter by a hardcoded 587; the total now comes from the real lockfile (countLockPackages, null when unknown) and done is clamped to it, so done > total cannot be displayed. The banner also states that closing the page does not interrupt the update.
    • An auth-gated frontend is no longer mistaken for a broken service (#18, real-world): the health check required GET / to return 200, so on a host whose / answers 401/403 (a password/token-gated UI) every successful install ended as E_RESTART: update installed <version> but restart/health failed: GET / -> 401, while the crash-recovery started the service right after — the user was told the update failed when it had actually succeeded. Health classification is now a pure exported helper (classifyHealthStatus): 200 → full dist/asset verification; 401/403/407 → the service is up but the frontend is auth-gated, so the update succeeds and the asset sweep is skipped (recorded as main-update-health-auth-gated); timeouts, 5xx and other 4xx still fail. The E_RESTART text now quotes both the launcher error and the health problems.
    • Stale progress/state reconciliation (#25): writeProgress no longer let the cached record overwrite the at timestamp — it froze at the first write, which is exactly why a killed update could look "fresh" or a live one look stale. Progress records now carry the owning workerPid/hostPid; isStaleProgress treats a record as stale when its owner process is gone (or, without pids, after 10 minutes without an update), and at startup / on read the host rewrites it to running:false, phase:error, code:E_INTERRUPTED and releases the update lock. A stale lock no longer blocks a new update for 10 minutes: locks older than the 2-minute spawn grace are dropped when no live worker owns them.
    • A crashed worker can no longer leave running:true (#25): uncaughtException/unhandledRejection and a fatal main() rejection write an error progress record and release the lock; previously the process simply died. startService/taskkill spawns got error handlers (a POSIX ENOENT or a batch-file EINVAL used to become an unhandled error event that killed the worker mid-update), and a failed launch fails fast instead of waiting 30 seconds.
    • Plugin replacement is now stage-then-swap (#21): backupAndReplace copies the new content into .dsh-uc-staging-* next to the target, renames the old directory to .dsh-uc-trash-*, renames the staged tree into place, and only then best-effort deletes the trash. Deleting a directory that contains a native module currently mapped by the running host used to raise EPERM after the delete-then-copy had already removed everything, leaving the package gutted (a locked .node file and nothing else, package.json included) and breaking the host. Any failure before the swap now leaves the installed package untouched, and a locked trash directory is simply swept on the next update. The two "stop reminding" buttons also stopped writing each other's flag.
    • Transient request failures no longer reload the page (#20): the client's 1.5-second status probe treated any single failed fetch (LLM streaming, tool work, a proxy hiccup) as "the service restarted" and called location.reload() unconditionally, refreshing the page mid-conversation. Reloading is now driven by a server instanceId: the page reloads only when the reported instance actually changes, at most once per instance (sessionStorage guard), so transient failures are ignored entirely.
    • Locale-service race fixed (#22/#23): the client half waits for the locale service (ctx.inject(["slots", "locale"])) before registering dictionaries and slot bindings, instead of reading ctx.get("locale") at apply time and silently binding fallbackT() (the Chinese dictionary) on an English UI.
    • POSIX core updates fail fast (#24): the main-framework /update route returns 501 E_PLATFORM_UNSUPPORTED immediately on Linux/macOS — before lock creation, backup or the Windows-only PowerShell spawn — instead of hanging at 8% with a stuck banner. Full POSIX support remains open (upstream PR #19).
  • v1.4.22 — Node version-manager shim resolution (issue #17):

    • resolveNodeExe() resolves a version-manager shim (mise/asdf/nvm) to the real Node binary by running node -p process.execPath through it, and getNpmCli() no longer falls back to a path that cannot exist — it throws ENPMCLI naming DSH_UC_NODE_EXE instead of producing MODULE_NOT_FOUND at npm time.