deepseek-harness
deepseek-ai
DeepSeek Harness: Everything is a Plugin.
nmbzth/dsh_update_check
dsh插件/dsh plugin. *CN: 1. dsh启动时自动检查更新,并提示风险性改动内容。由于dsh预览版的更新常具破坏性,为避免兼容性错误,不提供更新安装功能...... *EN: 1. Perform an immediate update check upon dsh startup. Automatic update installation is not provided to avoid compatibility issues.
PROJECT TOPICS
INSTALL REFERENCE
dsh plugin --profile web add github:nmbzth/dsh_update_check
该命令指向仓库当前默认分支;尚无绑定当前 commit 的完整验证结果。
PROJECT README
dsh_update_check is a DSH plugin that automatically compares the official upstream DeepSeek Harness repository and prompts you when an update is available.
connection/reset); the DSH check and the plugin's own check are separate switches.releases/latest API → releases list → tags API in order, with a 10 s timeout; tags with a dsh-v* prefix parse correctly (semver-style comparison, including rc/beta prereleases).package.json version with the repo's plugin/package.json (informational: the DSH update itself is always manual).$DSH_HOME/update-check.json.breaking change, 破坏性更新, 破坏…兼容, etc.) → yellow warning "breaking update";incompatible, migration, removed, deprecated, 不兼容, 迁移, 移除, etc.) → yellow warning "possibly breaking update", with the complete matched item shown for you to judge.locale service and follows the active language live (banner, settings page and nav label); it falls back to the built-in Chinese dictionary when the locale service is unavailable.The plugin is distributed as the npm package dsh-update-check (plugin/ directory) and is mounted into the host composition, loading automatically when DSH starts:
Install the package: copy the plugin/ directory into your profile's node_modules (Windows default: C:\Users\<you>\.dsh\profiles\<profile>\node_modules\dsh-update-check\, containing package.json + lib/);
Mount it: edit that profile's cordis.patch.yml and append:
- insert:
- id: upd-check
name: 'dsh-update-check'
Restart DSH: it takes effect without any manual loading and stays resident (no reinstall needed after DSH updates).
Note: the Host exposes
GET /upd-check/api/checkthrough the hostwebServer(the Host declaresinject: ['webServer']as a hard dependency so routes register after the service is ready). The browser client bundle (ModuleLoader format) is auto-bundled by dsh's client-modules viaexports["./client"]+ thedsh.clientfield inpackage.json; it mounts theshell.overlaybanner and registers the dedicated "Check for updates" page (settings.section, same level as General / Models / Plugins).
| Side | Responsibility |
|---|---|
Host — supervisor (plugin/lib/index.js) |
Process-level infrastructure: three-level network fallback, settings persistence, HTTP routes, and the hot-swap / self-update engine. |
Host — implementation (plugin/lib/impl.js) |
Hot-swappable detection logic: local DSH version detection (module resolution → npm global fallback, reporting the channel it used), release-notes parsing, section classification, graded breaking-change signals, version comparison. Bound to the supervisor by the API_VERSION / IMPL_CONTRACT contract. |
Client (plugin/lib/client.js) |
shell.overlay top banner + the dedicated Settings page (settings.section); shows update reminders, breaking-risk details with matched keyword snippets, network errors, and the hot-update button. |
| Communication | webServer HTTP routes (/upd-check/api/check, /upd-check/api/settings, /upd-check/api/self-update) + same-origin fetch |
Three-level network fallback:
web.fetch (when a fetch provider is mounted);subprocess running node - (script fed via stdin) with the standard fetch (auto-follows redirects);github.com at 127.0.0.1 with a self-signed cert) → the script resolves real IPs via dns.resolve4, connects directly with servername/Host headers, manually follows redirects, and retries IP by IP.The plugin can update itself from its own GitHub releases, without a DSH restart for most changes.
Layering and boundaries
| File | Role | Takes effect |
|---|---|---|
lib/impl.js |
Detection/parsing implementation (hot-swappable) | immediately — re-imported with a new ?v=<version> and swapped atomically |
lib/client.js |
Browser UI bundle | immediately — dsh-client-hmr serves the new rev and the page reloads the bundle in place |
lib/index.js |
Supervisor: services, settings, network, routes | on the next DSH start (restartRequired in the response) |
package.json |
Version marker | immediately (version display) |
The supervisor is deliberately not self-modifying at runtime: it is the code that performs the update, so replacing it live would mean pulling the rug out from under the running process. Changes to it are written to disk and reported as restartRequired.
Update flow (POST /upd-check/api/self-update, manual only)
releases/latest (falls back to contents/plugin/package.json when no release exists);lib/client.js, lib/impl.js, lib/index.js, package.json) from that tag through the contents API;lib/.stage/ — package.json shape, client.js parsed with node --check, impl.js actually import()-ed and contract-checked, index.js checked for its key markers;lib/.bak/<old-version>_<timestamp>/;rename;impl.js/client.js from the backup and keep serving with the previous engine still in memory;$DSH_HOME/update-check-history.json (successes and failures; last 20).Any failure before or during step 6 leaves the disk untouched; a failure at step 7 rolls back. The response reports from/to, hot, clientReloaded, restartRequired, the per-file changed flags, and the backup path.
Endpoints
| Method | Route | Purpose |
|---|---|---|
GET |
/upd-check/api/self-update |
Installed version, live engine version/contract, hot-file set, restart scope, recent history |
POST |
/upd-check/api/self-update |
{"action":"update"} performs the update; {"action":"update","force":true} updates even when versions are equal (content is still diffed); {"action":"reload"} re-imports the implementation from disk without any download |
Releasing (the content source)
pwsh -NoProfile -File scripts/release.ps1 -Final
Runs both contract suites as a gate, extracts the version's CHANGELOG section as the release notes, commits, pushes, and creates the tag plus the GitHub Release (all idempotent).
Release policy: every version gets a tag — tags are what the self-update uses to fetch content — but only the final version of a series gets a GitHub Release. Publishing a Release for every intermediate version just confuses people. So run scripts/release.ps1 (tag only) while a series is in progress, and add -Final once for the finished version. The plugin's self-update consumes releases/latest, i.e. exactly that final release.
On this machine
github.comgit transport is unavailable (connect timeout / SSL verification failure), so the push goes through the Git Data API (scripts/push-via-api.ps1); local and remote refs therefore stay content-identical but SHA-divergent, which is expected.
| Item | Status | Notes |
|---|---|---|
| Windows / macOS / Linux | ✅ | Shell fallback chain (cmd.exe → sh); node resolution tries node → node.exe; no hard-coded paths |
| DSH installed via npm globally | ✅ | Local version read via npm ls -g @deepseek-ai/dsh / npm root -g |
| pnpm / bun / git clone installs | ✅ | Local version is resolved through Node's module system (require.resolve('@deepseek-ai/dsh/package.json'), ~6 ms, no shell), so non-npm layouts are covered; npm ls -g remains the fallback and the settings page shows which channel answered |
| hosts hijacking (Steamcommunity302 etc.) | ✅ | Built-in DNS direct-connect bypass |
| Deployments without a fetch provider | ✅ | Node direct-connect fallback |
| GitHub anonymous API rate limit | ⚠️ | 60 req/h/IP; one auto-check per page load plus on-demand manual checks are usually enough |
| DSH version adaptation | ⚠️ | Slot names (shell.overlay, settings.section) verified against 0.1.0-rc.x; if the slot tree changes in future versions the UI simply won't mount (no crash), and Host checks keep working |
| Breaking-change detection | ✅ | Semver detection is deterministic; release-note keywords are graded (strong → breaking; weak → yellow warning with the complete matched item) |
| Settings storage | ✅ | $DSH_HOME/update-check.json (atomic write; invalid content falls back to defaults); the three switches survive restarts |
| Plugin hot update | ✅ | lib/impl.js + lib/client.js apply without a DSH restart; lib/index.js needs the next start (restartRequired); every attempt is validated first, backed up, and rolled back on failure |
| Plugin hot update, no releases yet | ⚠️ | The update source is releases/latest; with no Release at all it falls back to contents/plugin/package.json on the default branch (development channel). Intermediate versions get a tag only — see the release policy above |
| Plugin hot update, offline | ⚠️ | Needs GitHub reachability (same three-level fallback as the check); nothing is written when the download fails |
| Static plugin | ✅ | Auto-loads with DSH; no reinstall after DSH restart/update; Host has no harness, uses same-origin webServer HTTP (localhost only) |
C:\Windows\System32\drivers\etc\hosts for hijack lines mapping github.com / api.github.com → 127.0.0.1 (common with Steamcommunity302 and similar tools); delete those lines (admin rights) or rely on the built-in DNS bypass, then click Retry.node_modules/dsh-update-check exists, the cordis.patch.yml line is present, and restart DSH; check GET /upd-check/api/check returns JSON.restartRequired: the release also changed lib/index.js (the supervisor). The new file is already on disk; it takes effect on the next DSH start. GET /upd-check/api/self-update shows the live engine version.impl-contract-mismatch, remote-client-syntax, http-404) and the attempt is recorded in $DSH_HOME/update-check-history.json; the backup of the previous version is under plugin/lib/.bak/.latest) is published.rate-limit) and shows a dedicated message instead of "cannot reach GitHub"; plugin self-update uses a different repository and keeps working. Retry after the window resets (/rate_limit reports the reset time).plugin/ directory = the npm package dsh-update-check (lib/index.js supervisor + lib/impl.js hot-swappable implementation + lib/client.js browser bundle).node scripts/check-src.js — syntax and source-contract checks (102 assertions; also run by CI);node scripts/check-runtime.mjs — runtime contract checks: loads the real host half with a stub ctx in a temp sandbox and drives its real HTTP handlers, covering detection payloads, settings, engine contract, and the whole hot-update path including zero-damage rollback and both version-detection channels (62 assertions; also run by CI).node scripts/verify-real-selfupdate.mjs [package-dir] — opt-in, needs network: copies a package into a temp dir, downgrades it to 0.0.1 with content drift, and performs a real self-update from the published GitHub Release, then asserts the files, the live engine version and the backup. Never touches the source directory; prints SKIPPED and exits 0 when GitHub is unreachable.plugin/package.json + write the CHANGELOG section, then pwsh -NoProfile -File scripts/release.ps1 (tag only) while iterating, and ... -Final once for the finished version.IMPL_CONTRACT in lib/index.js and API_VERSION in lib/impl.js; CI compares them.MIT © nmbzth
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: 无有效分类标签。