dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
Electron desktop shell for the DeepSeek Harness Web GUI; first run auto-installs a portable runtime (Node + pinned deepseek-harness), with prebuilt packs, CN mirrors and zh/en UI. DeepSeek Harness 桌面版外壳:首启自动装配运行环境,支持预构建运行包与国内镜像,界面中英双语。
English | 中文
An Electron shell that turns the DeepSeek Harness Web GUI into a real Windows desktop app: double-click an icon and the GUI opens in its own window while the checkout's dsh web service starts in the background. This directory is the out-of-repo shell — it never modifies the deepseek-harness checkout (the only optional, separately distributed change is the start-at-login row in share/, see Optional checkout patch).
Current version: 0.4.2 (Windows x64; NSIS installer + portable exe under release/). UI language: English / 中文 (follows the OS by default, switchable from the tray). Installed builds update themselves from GitHub Releases (see App updates).
tar.exe cannot create symlinks the engine falls back to a built-in zip reader, pack aliases are rebuilt as junctions, and git-less source zips get a ref-derived build commit. A machine-installed old Node.js cannot hijack the build (portable Node is pinned first on PATH)..sha256 + size + PE sanity), then upgrade in place silently and relaunch. Portable builds get the verified file instead, since they cannot replace their own exe.--hidden in the background after sign-in; the tray checkbox and the GUI's Settings → General row share one setting.port: 0 lets the OS pick a free port; never collides with other dsh web instances.contextIsolation + sandbox, no nodeIntegration; external http(s) links open in the system browser; navigation is locked to the GUI origin.desktop.log + crashes.log and shown in an error dialog (0.2.1+); a failing window icon falls back to the exe icon so the taskbar never shows a blank button (0.2.6+).smoke / e2e / probe / provision:selftest / update:selftest / update:probe (see Automated checks).The harness GUI is not a static page — only the dsh web process serves it (injecting window.__DSH_BOOT__ and owning /api and RPC). The shell therefore:
Resolves resources — reads settings.json/environment for the checkout and node.exe and validates the checkout (apps/cli/src/bin.ts, node_modules/tsx). No checkout at all → opens the setup wizard (autoProvision, default on) or the legacy directory picker (autoProvision: false).
Starts the backend in the checkout directory (hidden window, PATH pinned to the resolved Node dir so a machine-wide old Node cannot interfere):
node --import tsx/esm apps/cli/src/bin.ts web --no-open --port <port> [extraArgs…]
Same launch path as pnpm dsh web; --no-open keeps the CLI from opening a browser; --port 0 asks the OS for a free port.
Waits for readiness — parses dsh web: http://127.0.0.1:<port>/?token=... from stdout (90 s timeout, recent log tail on failure).
Loads the GUI — the main window loads the authenticated URL; the preload exposes window.__dshDesktopShell (get/setAutoStart) so the GUI registers the "Start at login" row only inside the shell; the wizard window uses a separate window.__dshProvision bridge.
Lifecycle — closing the window hides to the tray (service keeps running); real quit (tray → Quit or Ctrl+Q) terminates the backend process tree with taskkill /T /F. Session data is persisted per event, so quitting is safe. An unexpected backend exit offers "Restart service / Quit" (tray balloon when the window is hidden).
When no usable checkout is found (no settings.json repoPath, no DSH_DESKTOP_REPO, no sibling deepseek-harness folder), the shell opens the runtime setup wizard and provisions:
| Step | Content | Size |
|---|---|---|
| Node.js | portable Node (official dist or npmmirror mirror) | ≈35 MB |
| deepseek-harness | pinned tag source zip (GitHub or proxy) | ≈20–150 MB |
| pnpm + deps | pnpm installed into the portable Node, then pnpm install | ≈1.4 GB download |
| Build | pnpm run build (web client + packages, ~3–10 min) | — |
On success the shell writes settings.json (repoPath/nodePath pointing at the provisioned runtime) and boots the GUI. The wizard offers:
Artifacts live under the user-data directory (survive app upgrades/uninstalls):
%APPDATA%\DeepSeek Harness Desktop\
├─ settings.json runtime config
├─ runtime.manifest.json (optional) manifest override
└─ runtime\
├─ node\… portable Node.js
├─ harness\<ref>\ checkout (deps installed + built)
├─ provisioned.json provisioning record
├─ .downloads\ downloaded zips (reusable, deletable)
└─ .cache\ npm / pnpm caches
Roughly 3 GB disk and 10–40 minutes depending on the network. Notes:
dsh-v0.1.2-alpha.5) and does not contain the local optional patch — tray start-at-login always works regardless;settings.json livesapp.asar: settings always live at %APPDATA%\DeepSeek Harness Desktop\settings.json.%APPDATA%\DeepSeek Harness Desktop\settings.json.| Field | Default | Meaning |
|---|---|---|
repoPath | "" (auto) | deepseek-harness checkout path; empty → try DSH_DESKTOP_REPO, sibling ../deepseek-harness, then wizard/picker |
nodePath | null (auto) | absolute node.exe; detection order: DSH_DESKTOP_NODE → Program Files nodejs → sibling of Electron → PATH node |
port | 0 | 0 = free port each boot; a fixed port (e.g. 3080) must be free |
closeToTray | true | closing the window keeps the app in the tray |
autoStart | true | start at login (tray + GUI General row share this field) |
extraArgs | [] | extra arguments passed to dsh web (e.g. ["--patch","xxx.yml"]) |
autoProvision | true | first-run auto-install wizard when no checkout exists; false restores the legacy picker |
mirrorMode | "auto" | provisioning source: auto / cn / direct (switchable in the wizard) |
language | "auto" | UI language: auto (OS) / zh / en (0.3.0+; also switchable from the tray) |
dshRef | null | override the deepseek-harness ref (default from manifest) |
nodeMirrorBase / registryMirror / githubProxies | null | advanced mirror overrides (npmmirror + built-in proxies by default) |
checkUpdates | true | silent release check on startup (tray checkbox mirrors it) |
skipVersion | "" | version the user chose to skip (e.g. 0.4.1) |
updateIncludePrerelease | false | also consider pre-releases |
updateMirror | "" | optional prefix for GitHub download URLs (e.g. https://ghfast.top); empty = direct, then built-in accelerators |
updateRepo | "" (built-in) | owner/name of the release repository, for forks |
Changes to port/extraArgs/repoPath apply after tray → Restart service.
runtime.manifest.json)The default manifest ships inside the app; placing a runtime.manifest.json next to settings.json merges over it (top-level and dsh/node/pnpm nodes). Commonly edited fields: dsh.ref/dsh.url/dsh.sha256, node.version/node.url/node.sha256, pnpm.version, registry/registryMirror, optional pack.url/pack.sha256 (prebuilt runtime pack channel).
Dev testing: start with
DSH_DESKTOP_FORCE_PROVISION=1to open the wizard even when a checkout exists.
Constraint: the harness engines accept ^22.19.0 || >=24.0.0 only (20/23 are rejected). The portable Node is independent of any system Node/nvm.
node.version, node.url, node.sha256 from the SHASUMS file on nodejs.org/npmmirror);%APPDATA%\DeepSeek Harness Desktop\runtime\node — the engine reuses any existing Node that passes the version gate, so removal forces a re-download;npm run pack:runtime -- --node-version 24.8.0 and switch pack.url;settings.json nodePath or DSH_DESKTOP_NODE at any node.exe, then Restart service (provisioning always uses its own portable Node — use "Choose an existing checkout…" to run your own).The shell updates itself from this repository's GitHub Releases; the harness runtime is versioned separately and is still installed/updated by the setup wizard (the wizard offers a shortcut whenever an app upgrade pins a newer dsh ref — see runtimeOutdated in the update window footer).
How it works (updater.js, pure Node + --selftest):
GET /repos/<repo>/releases/latest (or /releases when pre-releases are enabled), semver comparison including pre-release identifiers against app.getVersion().DeepSeek-Harness-Desktop-Setup-<version>.exe into %APPDATA%\DeepSeek Harness Desktop\updates, resumable (Range) and mirror-aware: updateMirror prefix → direct GitHub → built-in accelerators (mirrorMode: cn tries the accelerators first).digest, else the published .sha256 sidecar; then size and PE-header checks. Any mismatch deletes the file.Setup-<version>.exe --updated /S --force-run: electron-builder's NSIS installer skips its pages, upgrades the registry-recorded install directory in place, and relaunches the app.Where it surfaces:
| Entry point | Behavior |
|---|---|
| Startup (8 s after launch) | silent check; a newer version shows a dialog — Update now / Later / Skip this version |
Autostart (--hidden) | tray balloon only, never a modal dialog |
| Tray → Check for updates… | opens the update window (version, release notes, progress, options) |
| Tray → ⬆ Update available | appears while an update is pending |
| App menu → Check for updates… | same window |
Notes and limits:
DSH_DESKTOP_FORCE_UPDATE_INSTALL=1 forces the real hand-off for testing).updateMirror (e.g. https://ghfast.top) or switch mirrorMode to cn.Prerequisites: Windows 10/11, Node.js ≥ 22.19, and a sibling deepseek-harness checkout that has run pnpm install && pnpm run build.
cd <repo>\dsh-desktop-app
npm install # installs Electron (~200 MB, needs network)
npm run smoke # optional headless boot check
npm run e2e # optional real-window regression
npm run probe # optional UI probe of the autostart row
powershell -ExecutionPolicy Bypass -File scripts\make-icon.ps1
powershell -ExecutionPolicy Bypass -File scripts\create-shortcuts.ps1
Then launch the DeepSeek Harness shortcut. If the checkout is not the sibling folder, write settings.json or set DSH_DESKTOP_REPO.
| Action | Effect |
|---|---|
| Double-click icon | start (or focus) the app, start dsh web, open the GUI |
| Window close button | hide to tray by default (service keeps running) |
| Click tray icon | open the main window |
| Tray → Open in system browser | open the current GUI URL in the default browser |
| Tray → Restart service | restart the backend (re-reads settings.json) |
| Tray → Check for updates… | open the update window (version check + release notes) |
| Tray → Language | switch UI language immediately |
| Tray → Quit (stop service) | kill the backend process tree and exit |
| Ctrl+R / F12 / Ctrl+Q | reload / devtools / quit |
Logs: main process + dsh web output go to %USERPROFILE%\.dsh-desktop-logs\desktop.log (2 MB cap); tray → Open log folder.
| Command | Verifies |
|---|---|
npm run smoke | headless: boot the real service → parse URL → HTTP probe → exit |
npm run e2e | real window: GUI page loads → auto-exit |
npm run probe | real window DOM: opens Settings → General, asserts the "Start at login" row + bridge (DSH_PROBE_TOGGLE=1 toggles twice) |
npm run provision:selftest | engine offline self-test (no network/Electron) |
npm run update:selftest | updater offline drill: semver, release parsing, asset picking, download/resume/verify against a local fixture server |
npm run update:probe | real window: loads update.html through the preload bridge, runs one live release check, fails on renderer console errors |
probeexpects the optional checkout patch + rebuilt web client; without it the row does not exist and probe exits 1 by design.
DSH_DESKTOP_REPO, DSH_DESKTOP_NODE, DSH_DESKTOP_FORCE_PROVISION=1, DSH_PROVISION_FILELOG=1, DSH_FORCE_NODE_UNZIP=1, DSH_PACK_DEBUG=1, DSH_DESKTOP_SKIP_UPDATE_CHECK=1 (never touch the update server), DSH_DESKTOP_FORCE_UPDATE_INSTALL=1 (let a dev run hand the installer to Windows), ELECTRON_MIRROR/ELECTRON_BUILDER_BINARIES_MIRROR.
To show a "Start at login" switch inside the GUI (Settings → General), the checkout needs a small feature in packages/client/ui-settings-general (row component + controller + bridge contract + tests; registered only when window.__dshDesktopShell exists — plain browsers are untouched). The checkout contains no OS login logic; the shell owns it.
git apply <repo>\dsh-desktop-app\share\dsh-settings-autostart-row.patch
pnpm run build:lib:client
pnpm run build:web
Without the patch everything works; only that row is missing (the tray toggle is equivalent). Want to upstream it? See share/PR-INSTRUCTIONS.md.
npm run dist # NSIS installer + portable exe (win x64)
npm run dist:cn # same, downloads Electron/tools via npmmirror
npm run dist:dir # only release/win-unpacked
Outputs (installer flow: welcome → license → per-user/all-users → folder → options → done; silent /S keeps both options on; uninstall removes program, shortcuts and the autostart entry but keeps %APPDATA% data):
DeepSeek-Harness-Desktop-Setup-<version>.exe — assisted installer;DeepSeek-Harness-Desktop-Portable-<version>.exe — portable single exe;win-unpacked/ — unpacked layout.Version comes from package.json; artifacts use ${version}. Build scripts pass --publish never (electron-builder would otherwise demand a GH_TOKEN and try to publish implicitly on tag pushes); the build workflow runs both engine self-tests, packages every push, attaches a .sha256 checksum next to each exe on tag builds, and publishes the GitHub Release for v* tags — that release is what the in-app updater consumes.
Releasing an update: bump package.json version → commit → git tag vX.Y.Z && git push origin vX.Y.Z → wait for the workflow → verify the release lists DeepSeek-Harness-Desktop-Setup-X.Y.Z.exe (+ .sha256, .blockmap, portable). Installed apps then see the new version within one startup check.
On a release machine with a built checkout:
npm run pack:runtime # options: --repo <path> --ref <tag> --node-version <v> --out <dir>
Produces dsh-runtime-<ref>-win-x64.zip (portable Node + full checkout with deps and built frontend, no .git) plus a .sha256 file. Publish both, then enable the channel via the manifest override:
{ "pack": { "url": "<zip download url>", "sha256": "<from .sha256>" } }
Users then only download → verify → extract (minutes), no pnpm/build on their machine. Remove the entry to fall back to the online source build. Notes: the archive is large (≈500 MB+ deflate; 7-Zip compresses faster/smaller), one pack per ref, and it ships the official sources (no share/ patch). node_modules symlinks are recorded as an alias manifest in pack.json and rebuilt as junctions after extraction — no admin required.
npm run dist; first run auto-provisions (needs network, 10–40 min).node_modules/, release/, settings.json) and have them run setup.ps1 -RepoPath <checkout>.--hidden). End all DeepSeek Harness Desktop processes, uninstall the old version, then run the new one.Node.js v20.x … globSync): fixed since 0.2.5 (portable Node pinned on PATH) — upgrade.Can't create … / tar errors: machines without symlink privileges — fixed since 0.2.3 (built-in zip fallback); upgrade.%USERPROFILE%\.dsh-desktop-logs\desktop.log.dsh web (browser GUI) uses the same ~/.dsh.%APPDATA%\DeepSeek Harness Desktop\runtime if blocked.%APPDATA%\DeepSeek Harness Desktop (settings + runtime, ≈3 GB). Uninstall first, then delete the folder for a full cleanup.updateMirror prefix or mirrorMode: cn; "no published releases yet" means the tag's Release has not been built (see Packaging).%APPDATA%\DeepSeek Harness Desktop\updates and the next Download update resumes it.--force-run only applies to a silent install. If SmartScreen blocked the installer, run the Setup manually once; settings and data are untouched (they live in %APPDATA%).| Version | Highlights |
|---|---|
| 0.1.x | Shell basics: standalone window, tray, start-at-login, first-run checkout picker, smoke/e2e/probe |
| 0.2.0 | First-run automatic runtime provisioning (wizard, mirrors, resume) |
| 0.2.1 | Fixed packaged settings silently writing into app.asar; crash logging + error dialogs |
| 0.2.2 | Prebuilt runtime pack channel; node_modules alias manifest + junction rebuild |
| 0.2.3 | Built-in zip fallback (zip64, symlink placeholders); git-less source builds |
| 0.2.4 | pnpm global install pinned with --prefix |
| 0.2.5 | Portable Node pinned on PATH for provisioning and backend children |
| 0.2.6 | Window icon fallback to exe icon (blank taskbar fix) |
| 0.3.0 | i18n (zh/en UI + docs), language switch in tray, GitHub CI + Release, MIT |
| 0.4.0 | Self-update from GitHub Releases: startup check with skip-version, update window (notes/progress/options), resumable verified download, silent in-place NSIS upgrade; CI --publish never fix + .sha256 assets |
| 0.4.1 | Probe the direct GitHub host before downloading (accelerators straight away on networks that block github.com); richer Release body shown in the update window |
| 0.4.2 | Interrupted transfers now retry the source list automatically, resuming from the partial file (up to 4 attempts) with a "resuming" notice in the update window — the fix for CN networks that cut ~110 MB downloads |
MIT © 2026 DeepSeek Harness Desktop contributors. Third-party components keep their own licenses.