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.

Updater Npm — DSH Plugin for DeepSeek Harness
DeepSeek Harness Plugin Hub
ProfilesPluginsCategoriesNewsDocsSign inManage Profiles
ProfilesPluginsCategoriesNewsDocsSign in
← Plugins

dsh-updater-npm

Updater Npm

DSH updater + official docs sync plugin for DeepSeek Harness: one-click npm update of @deepseek-ai/dsh with real-time progress, an idle-based timeout so slow networks are not killed, a staged swap that keeps a rollback point (cleanable from the card), inc

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

npx -y @deepseek-ai/dsh plugin --profile web add dsh-updater-npm@1.13.4
READMECompatibilityVersions

Compatibility and provenance

Updater Npm is published as dsh-updater-npm and currently resolves to version 1.13.4. 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.13.4stable
9/18/2026
1.13.3stable
9/18/2026
1.13.2stable
9/18/2026
Show 19 more versionsCollapse versions
1.13.1stable
9/18/2026
1.13.0stable
9/18/2026
1.11.0stable
9/11/2026
1.10.0stable
9/11/2026
1.9.0stable
8/25/2026
1.8.1stable
8/24/2026
1.8.0stable
8/24/2026
1.7.1stable
8/21/2026
1.7.0stable
8/20/2026
1.6.0stable
8/20/2026
1.5.0stable
8/19/2026
1.4.4stable
8/19/2026
1.4.3stable
8/19/2026
1.4.2stable
8/19/2026
1.4.1stable
8/19/2026
1.4.0stable
8/19/2026
1.3.0stable
8/19/2026
1.2.0stable
8/19/2026

Related plugins

Loading related plugins…

Latest
1.13.4
DSH
*
HMR
Process restart
Tree shaking
Safe tree shaking not declared
Unpacked size
285.5 kB
Files
7
Surface
web
License
MIT
Source
npm
GitHub
★ 5
Weekly downloads
908
Security scan
✓ v1.13.4 scan passed
Last push
9/18/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.1.0stable
8/19/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-updater-npm

English | 中文

DSH updater + official docs sync plugin for DeepSeek Harness (dsh).

Two cards in Settings:

  • DSH Update (npm) — checks the latest @deepseek-ai/dsh on npm and updates it in one click, with live progress and a "Restart DSH" button that performs the staged swap.
  • DSH Docs (official) — incrementally syncs deepseek-ai/deepseek-harness docs/ to $DSH_HOME/docs-sync/ (skips unchanged files by GitHub blob sha) with a progress bar, and registers the dsh_docs_search / dsh_docs_read model tools.

The DSH Update and DSH Docs cards in Settings

Install · Usage · Run modes · Upgrade safety net · Routes · License

Install

# from npm (recommended)
dsh plugin --profile web add dsh-updater-npm

# or from GitHub
dsh plugin --profile web add github:SiriusWJ/dsh-updater-npm

Restart dsh web afterwards; the "DSH Update" and "DSH Docs" cards appear in Settings.

i18n: the UI and every host message support English / Chinese and follow the system language automatically (or the manual choice in Settings → General → Language). The dsh_docs_search / dsh_docs_read tool descriptions and outputs follow it too.

Usage

DSH Update

  • Checks every 30 minutes (the page refreshes the cached result every 60 s).
  • A red dot (🔴) appears next to "DSH Update" in the Settings sidebar when a new version exists.
  • "Update via npm" runs npm install -g @deepseek-ai/dsh@latest with live progress (bar + the last few lines of npm output). There is deliberately no scrolling log panel — the full npm output is written to $DSH_HOME/plugin-data/dsh-updater-npm/last-run.log when the operation ends, so the card stays quiet and the log is still there when you need it.
  • When the update finishes, a "Restart DSH" button appears: it exits the current process with the original command line and relaunches it (PowerShell on Windows, /bin/sh on macOS/Linux). The same button appears after source-tree updates and deployment repairs. No new activation URL is needed — the browser re-authenticates by itself and no new window pops up.
  • Once a swap succeeded (i.e. the new version is actually running) the card shows the rollback point's disk usage and a "Remove rollback point" button. The previous deployment is kept as <sibling of install dir>/dsh.old-<timestamp> (222 MB in a real case). Safety rule, enforced on the host: only rollback points whose version differs from the running version are listed and deleted — the live deployment is never touched.
  • Version comparison is semver-style: a local version newer than the remote one (e.g. rc.7 vs rc.6) is not reported as an update.

Timeout policy and run log (since v1.12)

Older versions used a blunt 10-minute hard timeout for npm installs. On a slow link a staged install was measured downloading 247 tarballs (231 of the 239 @deepseek-ai sub-packages of a 222 MB tree) in 9 min 25 s and was then killed, reporting just staging install failed: npm — not a hang, not a broken network, simply a hard timeout.

The watchdog is now two-threshold, and configurable through $DSH_HOME/plugin-data/dsh-updater-npm/config.json:

{
  "docsEnabled": false,
  "npmIdleMinutes": 10,
  "npmTimeoutMinutes": 60
}
KeyDefaultMeaning
npmIdleMinutes10minutes of zero activity before it is declared stuck and terminated (slow but moving ⇒ never killed)
npmTimeoutMinutes60absolute wall-clock ceiling, to stop a truly unbounded hang

What counts as activity (corrected in v1.12.1): watching the child's stdout alone is not enough — npm prints almost nothing when it is not attached to a TTY (one measured 5-minute install produced not a single stdout line while npm's own debug log recorded 525 requests, and the watchdog killed it). Three signals are now combined, and the maximum wins:

  1. --loglevel=http — npm logs every request/stage to stdout (measured: 1111 lines instead of 0);
  2. --logs-dir — npm's full debug log is written to plugin-data/dsh-updater-npm/npm-logs/;
  3. filesystem activity — npm's debug log may only be flushed at exit on Windows (in a measured 14-second install it sat at 0 bytes for 12 of them), so the staging directory and its node_modules/ are watched as well: extraction keeps writing files there.

Only when all three are idle is the install treated as stuck; during a silent phase a [heartbeat] … line is appended every minute (into last-run.log).

  • On a watchdog kill the log carries [watchdog] … and [exit] … lines, and the error states whether it was an idle timeout or the total limit, with the elapsed time — no more opaque : npm.
  • The same policy covers staged installs, non-Windows in-place npm install -g, and source-tree pnpm/npm install; msiexec /qn is silent by nature and gets a 10-minute idle window.
  • /dsh-updater-npm/progress returns progress only (no log payload).

Plugin self-version and self-update gate

  • The card shows this plugin's own version and compares it with the latest dsh-updater-npm on npm (GET https://registry.npmjs.org/dsh-updater-npm/latest, cached for 10 minutes).
  • If the plugin itself is outdated, the card says so and shows a copyable command (dsh plugin --profile <your profile> add dsh-updater-npm@<latest>). The "Update via npm" button is disabled, and /update is refused server-side with the same message.
  • Reason: updating DSH is performed by the currently running plugin code, and an outdated plugin's upgrade path may itself be unsafe (1.9.0, for example, staged without -g on Windows and lost every dependency after the swap).
  • Offline pass-through: nothing is blocked unless a newer plugin version is positively known, so air-gapped or offline setups are not locked out.
  • Source-tree mode (git pull) is not gated, only hinted.

DSH Docs

  • Sync switch (off by default): the "DSH Docs" card has an "Auto-sync official docs" toggle. While it is off, nothing is synced and the dsh_docs_search / dsh_docs_read tools are not loaded. When on, the plugin syncs on first start (~217 files: English + Chinese .zh.md) and then every 24 hours, and registers the tools. The switch state lives in $DSH_HOME/plugin-data/dsh-updater-npm/config.json.
  • "Sync official docs" triggers a manual sync (the switch must be on) with a progress bar (downloaded / total plus the current file) and phases (list → download → rebuild index).
  • Search and read from the docs section, or straight from a conversation with the model tools:
    • dsh_docs_search — search the local official docs index (Chinese queries prefer Chinese docs)
    • dsh_docs_read — read one document (section focus, 80 KB truncation, path-traversal guarded)

Docs live in $DSH_HOME/docs-sync/, the index in $DSH_HOME/docs-sync/.index.json.

Run modes

Windows without PowerShell 7: DSH's shell tools need pwsh. When pwsh is missing the card shows a hint and an "Install PowerShell 7" button (tries winget install Microsoft.PowerShell, falls back to the official win-x64 MSI with live progress; restart DSH to apply).

The plugin detects the run mode and behaves honestly:

ModeDetected byHow it updatesNotes
npm-globalargv[1] is <install>/lib/bin.jsWindows: staged update (new version into a separate staging dir → "Restart DSH" atomically swaps it in, rolls back on failure). Non-Windows: in-place npm install -g, then "Restart DSH"The Windows update target is the running instance itself (native deps included), where an in-place install hits EBUSY and leaves a half-installed tree. The staged flow never touches the live deployment; the old directory is renamed to dsh.old-* as a rollback point; the restart script validates the staged package before doing anything; a broken deployment is reported and can be repaired with one click
source (source tree)argv[1] contains bin.ts / tsx / apps/Source-tree update: git fetch → git pull --ff-only → dependency install (pnpm/npm)Running from a source tree (pnpm dsh web) means npm -g does not affect the running instance. The card shows branch / local and remote commit / commits behind, with a one-click update; uncommitted changes or a missing git disable the button with a clear message

Multi-copy protection: an environment may contain several dsh copies (global dirs of several Node installations, DSH profiles, …). The plugin only ever updates the currently running one, preferring the npm that belongs to the running instance's own Node install; /check lists the other copies it detected, and an npm run that succeeds while the running copy's version does not change is reported as a failure instead of a false success. Copies are de-duplicated by realpath, so junctions/symlinks pointing at the running instance (e.g. dependency mirrors under $DSH_HOME/profiles/node_modules) are not mistaken for separate copies.

Version-drift troubleshooting: if an update reports success but a restart brings back the old version, you are running from a source tree while npm updated the global install only. Start dsh in npm-global mode (e.g. a shortcut pointing at D:\tools\node22\dsh.cmd web) and the update applies.

Upgrade safety net

Each item below was added after a real 0.1.2-rc.1 → 0.1.5-rc.1 cross-version upgrade went wrong, and has been effective since v1.10.0.

  1. Staged installs must pass -g (layout consistency). npm install --prefix <staging> without -g produces a hoisted tree, while an npm-global deployment is nested (@deepseek-ai/dsh/node_modules/…, self-contained). The swap only moves the package directory, so a hoisted staging tree means losing every dependency of the new deployment. The command now always passes -g, and before writing the pending-swap marker the plugin verifies that a nested live tree has a nested staging tree and that the staged lib/bin.js actually runs under the instance's own node — any failure aborts without touching the deployment.
  2. Validation precedes the kill. The restart script validates the staged package (existence + layout) before stopping the current process; on failure it exit 1s, leaving the old process running rather than half-killed.
  3. The old deployment is kept as a rollback point. After a swap the previous directory is renamed to dsh.old-<timestamp> (never deleted immediately) and the result is recorded. Once the new version looks stable, the card's "Remove rollback point" button frees the space.
  4. Rename retries. A just-terminated process may briefly hold directory handles, so the rename is retried up to 5 times, 3 seconds apart.
  5. Automatic pre-upgrade backup. When a version will actually change, settings.yaml, .credentials.yaml, .agent-presets/ and every profile's package.json / cordis*.yml / pnpm-lock.yaml are snapshotted to $DSH_HOME/upgrade-backups/dsh-<from>-to-<to>-<timestamp>/; session logs (up to 256 MB) are copied too, because sessions migrate to a format that cannot be read back by older versions. The newest 5 snapshots are kept.
  6. No activation URL is required after a restart. Since DSH 0.1.5 the web auth cookie is signed for one activation, so a restart invalidates it — but the browser re-authenticates on its own. (Up to v1.12.2 the restart script scraped the new ?token= URL, wrote activation-url.txt and opened a browser window; that whole path was removed in v1.12.3 as it was not needed.)
  7. Leftover detection and one-click cleanup. /check reports unreferenced staging-* / repair-* directories (one unfinished update left 222 MB behind) and npm's interrupted-install leftovers (65 MB in a real case); the card offers "Clean leftovers", and staging directories older than 6 hours are reclaimed automatically at startup.

Routes

  • GET /dsh-updater-npm/check — update check (10-minute cache; includes the cross-version notice, last restart result, pending swap, leftovers and rollback points)
  • POST /dsh-updater-npm/update — run the npm update (same-origin only; backs up first, then stages)
  • POST /dsh-updater-npm/restart — restart this DSH instance (same-origin only; atomically swaps a pending staged package into place, Windows/macOS/Linux)
  • POST /dsh-updater-npm/cleanup — remove leftover staging dirs and npm install leftovers (same-origin only)
  • POST /dsh-updater-npm/cleanup-rollback — remove rollback points whose version differs from the running one (same-origin only)
  • GET /dsh-updater-npm/progress — live update/sync progress (polled)
  • GET /dsh-updater-npm/docs/status — docs sync status
  • POST /dsh-updater-npm/docs/sync — trigger a docs sync (same-origin only)
  • GET /dsh-updater-npm/docs/search?q=&lang=&limit= — search the local docs index
  • GET /dsh-updater-npm/docs/read?path=&section= — read one document

Changelog

v1.13.4

An audit of how the plugin behaves on DSH deployments other than the one it was developed on turned up seven defects. All seven are fixed, and each was reproduced and verified against a real deployment.

  • The Settings nav red dot never refreshed. The two-argument form locale.register(ns, dicts) treats each key of the second argument as a locale id and validates it against dsh-client-locale's LOCALE_ID_PATTERN (/^[A-Za-z]{2,8}(-[A-Za-z0-9]{1,8})*$/u). The plugin passed a synthetic "~nav…" key, which fails that check, so register() threw before publish() bumped the revision — and the surrounding catch swallowed the error. The shell recomputes the nav rows only when the slot version or the locale revision changes, so the red dot never appeared or disappeared. It now uses the three-argument form with a unique namespace.
  • locateInstall()'s fallback was dead code. It derived the install directory from an agent preset path ending in /agent-presets/<id>/agent.cordis.yml. That layout no longer exists: shipped presets live at <dsh>/node_modules/@deepseek-ai/dsh-agent-presets/presets/<id>/ and user presets at <DSH_HOME>/.agent-presets/<id>/. Neither contains /agent-presets/, so the suffix test was always false and update / repair / restart / the docs tools had no recovery path whenever argv[1] is not bin.js. It now resolves @deepseek-ai/dsh/package.json and realpaths it. The anchor is the profile directory, not import.meta.url: with a link: or junction install Node rewrites the module URL to the package's real path, where no node_modules exists.
  • buildRestartScript() took a platform argument but joined paths with the host's path.join. Production only ever passed process.platform, which hid the mismatch — but a POSIX script generated on Windows came out fully backslashed (a leading / became \), and the script then aborted with staging incomplete and skipped the swap entirely. It now selects posix.join / win32.join from the argument.
  • The 60-second cap on staged-package verification had no effect. verifyStagedBinary() passed the number 60000 as runInstallCmd's third argument, but that parameter has since become a limits object; (60000).idleMs is undefined, so the call silently fell back to the 5-minute / 60-minute defaults and a half-broken staged package could stall this step for an hour.

Verification: the local smoke suite gained assertions for platform path joining, registry parsing, the locale-bump contract and the locateInstall fallback. test/smoke.mjs still reports 57 passed / 1 failed — the same pre-existing EPERM failure it shows on the untouched upstream commit. The POSIX restart + swap flow was executed for real under Git Bash sh (swap, rollback point, staging cleanup, relaunch of the new deployment), which is also what exposed the path.join defect above.

v1.13.3

  • Docs only — no code changes.
  • Added a screenshot of both Settings cards to the README, taken from the running v1.13.2 build: it shows the current card layout (no run-log panel, no activation-URL line) and the plugin's own version row. The stale screenshot (which still showed the removed run-log panel) was dropped in v1.13.1; its replacement is docs/dsh-update-card-1.13.png. The version in the file name is deliberate — GitHub's raw CDN keeps serving the old bytes for a while when a file is overwritten.

v1.13.2

  • Docs only — no code changes.
  • Fixed the npm page showing the Chinese README. npm picks the package readme with glob('{README,README.*}') and takes the first markdown-ish hit; README.zh.md matches that pattern and sorts before README.md (the check regex is unanchored, so a trailing .zh.md counts as markdown), so the Chinese file won. The Chinese README is therefore named README_zh.md (underscore), which the glob cannot match — npm now publishes the English README.md. A note in both files records why the underscore must stay.

v1.13.1

  • Docs only — no code changes, runtime behaviour is identical to v1.13.0.
  • The README is now bilingual with English as the default (README.md) plus a Chinese translation (README_zh.md), cross-linked at the top; the Chinese file is shipped in the npm package.
  • Several sections had drifted from the code and were corrected: the stale card screenshot (it still showed the run-log panel that was removed in v1.12.3) was dropped; the timeout section no longer mentions a log panel or /progress?since=; the safety net no longer describes activation-URL scraping (the browser re-authenticates by itself); the route list gained cleanup-rollback; the rollback point is now described as the card's button; and the restart-launcher fix (node bootstrap) became safety-net item 9.

v1.13.0

  • Added: after a successful swap (new version running) the card shows the rollback point's disk usage and a "Remove rollback point" button (POST /dsh-updater-npm/cleanup-rollback). The safety rule is enforced on the host: only <leaf>.old-<timestamp> directories whose version differs from the running version are listed and removed, so the live deployment is never affected (hard assertions in the smoke tests).
  • Polished: the card's explanatory prose is gone — updNote / docsNote / pluginOutdatedBody were removed entirely and the remaining strings were compressed to a single line (srcDirty, pwshMissingHint, deployBrokenWarn, npmMismatch, stagingWasteFound, repairRunning, docs*Hint, …), leaving state and actions only.
  • Tests: 58 (new: rollback scanning, only non-current versions removed, live deployment untouched, same-origin guard on the cleanup route).

v1.12.3

Subtracting, on user feedback:

  • Removed: the restart script's whole "scrape the new activation URL + open the browser" logic (both the Windows and the POSIX branch), plus the up-to-2-minute polling tail it needed.
  • Removed: the scrolling run-log panel — the full npm output now goes to plugin-data/dsh-updater-npm/last-run.log when an operation ends ([watchdog] / [exit] lines included) and the card keeps only the progress bar and the last few lines. /progress no longer carries log / limits.
  • Kept: --loglevel=http (it is the watchdog's real heartbeat, not decoration), the three-signal activity probe, and the idle/hard timeout pair.
  • Tests: the script assertions now check that no token is scraped and no browser is opened, plus a last-run.log assertion (56 total).

v1.12.2

Fixes the broken chain "the built-in restart does nothing, and after an external restart you are still on the old version": the staged install had actually succeeded (verbose exit 0 / info ok), but the restart step failed silently, so the swap never happened.

  • Root cause (reproduced): launchRestartScript used spawn('powershell.exe', […], { detached: true }). On Windows that is DETACHED_PROCESS: the console program exits immediately with exit=0 without executing a single line of the script, while spawn reports no error. A/B test: the same script run through a detached node bootstrap executes fine.
  • Fix (critical): launch a detached node bootstrap that runs the platform script as an ordinary child; the bootstrap writes node bootstrap started <token> into restart.log.
  • Fix (critical): restartNow now waits for that token (up to 5 s) before handing over the staged package. If it never appears, it returns a clear error and keeps pending-swap.json and the staging directory — the old code deleted the marker here, so the 222 MB staged tree was later swept as "leftover garbage" and the user could neither upgrade nor recover it.
  • Added: /check returns pendingSwap, and the card shows "staged, waiting to be swapped" while keeping the "Restart DSH" button, so an external restart can still be completed with one click; a marker whose staging directory is gone is cleaned up automatically.
  • Tests: 3 new (54 total) — the launcher is really executed, waitForBootstrap does not report false positives, and launcher + swap script perform a real directory swap on a fake deployment. The old code necessarily fails these, which is exactly why it slipped past the previous 36 tests.

Earlier releases

  • v1.12.1 — fixed the false kill introduced by 1.12.0: npm is silent on stdout without a TTY, so the stdout-only idle watchdog killed a working install at exactly 5m00s. Added --loglevel=http --progress=false, --logs-dir and a three-signal activity probe; default npmIdleMinutes 5 → 10. Measured end-to-end: 520 packages in 1m, 222.6 MB / 25474 files, exit code 0 (the cold-cache run of the same command never finished in 9m25s).
  • v1.12.0 — the blunt 10-minute hard timeout became idle timeout + wall-clock ceiling, configurable via npmIdleMinutes / npmTimeoutMinutes; the watchdog and the run log were introduced (log panel removed again in 1.12.3); the source-tree dependency install reuses the same watchdog.
  • v1.11.0 — the card shows the plugin's own version and gates "Update via npm" while the plugin itself is outdated (/update refuses too; offline pass-through).
  • v1.10.0 — the upgrade safety net above, after the real 0.1.2-rc.1 → 0.1.5-rc.1 upgrade: -g + layout/executability validation, validate-before-kill, rollback point, rename retries, pre-upgrade backups, output redirection, leftover cleanup, breaking-change notices.

Full Chinese changelog with every measurement: README_zh.md.

License

MIT

.<name>-<hash>
  • Cross-version breaking-change notice. Jumping across a known breaking range (currently 0.1.5: V3 session format, persona text → prefix/suffix, plugin API and slot changes) shows a notice with a release-notes link.
  • The restart launcher really launches (v1.12.2). spawn('powershell.exe', …, { detached: true }) on Windows equals DETACHED_PROCESS: the script does not run a single line while spawn still reports exit=0 — a silent false success that left the swap undone. The launcher now starts a detached node bootstrap which runs the platform script as an ordinary child and writes node bootstrap started <token> into restart.log; the plugin only hands over the staged package after that token shows up (≤ 5 s), and otherwise keeps pending-swap.json and the staged tree and reports a clear error.
  • Upgrade backups left credential copies readable. The snapshot copies .credentials.yaml and the whole sessions/ tree. The backup directory was created with the default umask (commonly 0755 on POSIX), so other local accounts could read the credential copy. The backup root and the new backup directory are now 0700.
  • The registry was hard-coded to registry.npmjs.org. With a mirror or an internal registry, the plugin queried npmjs while npm itself installed from the mirror — slow at best, and behind a firewall it reported "registry unreachable" for an update that would have worked. It now resolves env → ./.npmrc → ~/.npmrc → default, skipping any value that is not an http(s) URL.
  • resolveProfileName() mis-detected shared installs. When the plugin lives only in the shared profiles/node_modules (hoisted, or some pnpm layouts), every per-profile probe returns false and the function discarded an argv-derived profile in favour of the hard-coded 'web', so the printed self-update command could name the wrong profile. It now checks the shared location too.