dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
A DeepSeek Harness plugin for Windows: writes a self-contained one-click launcher, and refuses to start a second instance when the target port already serves one. / 一个 Windows 专用的 DeepSeek Harness 插件:写入自包含的一键启动器;目标端口已有 Harness 实例时拒绝启动第二个。
English | 中文
Switch the generated launcher's language at any time — /launch --lang zh, /launch --lang en, or /launch --lang auto to follow the console.
A DeepSeek Harness plugin for Windows that writes a self-contained one-click
launcher — a .bat on your Desktop — and refuses to start a second Harness
instance when the port already serves one.
The launcher it writes does not import this plugin. Uninstall the plugin and the
.bat on your Desktop keeps working; it is a single file with everything it
needs already inside it.
A marketplace hot-mounts a plugin whose bundle patch is a plain insert, so this
one goes live the moment you click Install — and that is when the launcher
appears. It is created only when your Desktop has none: an existing launcher,
yours or an older one of ours, is left exactly as it is, because a plugin load
is not a decision by you. Replacing one stays an explicit action (/launch, or
the launcher_install tool). Set provisionOnLoad: false to have the plugin
load silently instead.
A launcher records the version of the plugin that wrote it. When a later build of this plugin loads and finds a launcher written by an earlier one, it rewrites the file with the current template — that is how a repaired message or a fixed code-page path reaches a Desktop instead of living only in the repository.
The rewrite is of that launcher: the port, workspace, runner, language, and
browser behaviour recorded inside it are carried over, so refreshing a template
can never move your setup. Changing settings stays an explicit /launch. Set
autoUpdate: false to keep the file frozen; the doctor still reports when it is
out of date.
Two things this deliberately does not touch: a launcher whose recorded version already matches, and one whose version cannot be read — a guess is how a hand edit gets lost.
The launcher also starts the newest harness on every run, because
npx @deepseek-ai/dsh resolves the published version each time rather than
pinning whatever was current when the file was written.
launcher_install resolves your Desktop the way Windows defines it (including a
OneDrive-redirected or localized Desktop folder), checks that the folder accepts
a new file, encodes the launcher for your console's code page, writes it
atomically, and then runs it once in dry-run mode to prove it parses and
reaches its own logic. A launcher that fails that self-test is rolled back, not
left on your Desktop.
The generated launcher then does the following every time it is double-clicked:
node runs and that the runner (npx or dsh) answers.Only the first case starts anything. There is no flag that starts a second instance.
dsh web mints a per-process launch token and prints an authenticated URL
carrying it; the server answers every unauthenticated request with 401 dsh web authentication required. So opening a bare http://127.0.0.1:3080 while an
instance is running shows a 401 page, not your session — and starting a second
instance fails on the bind anyway. A launcher therefore has exactly two honest
options when the port is busy, and this one takes the second: say which URL to
use, and start nothing.
The fingerprint is the 401 body itself, so "a Harness instance" is detected rather than assumed — a different program holding the port is reported as a different program, with its PID.
dsh plugin --profile web add dsh-launch-in-one-click
Or straight from the repository:
dsh plugin --profile web add github:233fxr-collab/dsh-launch-in-one-click
Remove the row from your profile to uninstall it. Existing launchers keep working — they are self-contained.
Three tools, plus a slash command.
| Tool | Effect |
|---|---|
launcher_doctor | Read-only. Reports Node, npx, the console code page, the resolved Desktop, whether it is writable, what holds the target port, which harness version npx has cached, and the state of any launcher already installed. Optionally runs an installed launcher in dry-run mode, or asks the registry for the published harness version. |
launcher_install | Writes the launcher (atomic, backed up, self-tested). |
launcher_uninstall | Deletes a launcher this plugin wrote, and the backups of it. Refuses a file it did not write unless force is set. |
/launch install with the deployment defaults
/launch doctor same report as launcher_doctor
/launch list every launcher this plugin put on the Desktop, with its settings
/launch --port 3111 start the harness on another port
/launch --lang zh write the launcher in Chinese (--lang en | --lang auto)
/launch --name "Work.bat" choose the file name
/launch --overwrite replace a file this plugin did not write
/launch --dry-run show what would be written
--language is the long form of --lang. Switching language rewrites the
launcher this plugin wrote, keeping a timestamped backup, and changes nothing
else about it: the port, the workspace, and the runner stay as they were.
| Flag | Effect |
|---|---|
--port N | start on another port |
--workdir DIR | use another workspace |
--no-open | do not open the browser |
--silent | start with no console window; the run goes to the log |
--dry-run | checks and a plan, no launch |
--help | usage |
%LOCALAPPDATA%\dsh-launch\launcher.log records what the launcher decided —
the environment check, the workspace, the port verdict, the command, and the
exit code — because the console window is gone the moment it closes. That is
also what --silent writes to, since it has no window at all. The log path is
printed on the way out of a failed run.
The launcher itself accepts --port N, --workdir DIR, --no-open,
--dry-run, and --help.
The launcher's exit code is its contract, so a shortcut wrapper or a scheduled task can branch on it without parsing localized text.
| Code | Meaning |
|---|---|
| 0 | the harness ran and exited cleanly, or a dry run printed its plan |
| 1 | node or the runner is missing |
| 2 | the port already serves a Harness instance — nothing was started |
| 3 | another program holds the port — nothing was started |
| 4 | an argument was invalid |
| 5 | the work directory is missing or cannot be entered |
| 9 | the port probe could not reach a verdict |
| 20 | the harness itself failed; its own exit code is printed above |
Optional, in the bundle's patch row:
- id: launch-in-one-click
name: dsh-launch-in-one-click
config:
defaultPort: 3080 # port a generated launcher targets
language: auto # auto | en | zh
runner: npx # npx | dsh
packageSpec: '@deepseek-ai/dsh' # what npx resolves
openBrowser: true # let `dsh web` open the browser
provisionOnLoad: true # create the launcher on load, if absent
autoUpdate: true # refresh a launcher written by an older build
⚠️ Adding a config: row here has a cost. A marketplace hot-mounts only a
plain id/name insert, so a bundle patch carrying configuration activates on
the next restart instead of immediately. That is why every default above lives
in code, not in this file: install with no patch row at all, and the launcher
still appears the moment you click Install.
%USERPROFILE%\Desktop. A source pointing
at a folder that does not exist is skipped rather than trusted.auto (the default) follows the console: a Chinese-capable
code page gets Chinese, an English one gets English with no warning, because
matching the console is the point rather than a fallback. An explicit
language: zh is honoured even on a console that cannot print it, by writing
the file in UTF-8 and switching the console to match.|, &, <, >, ^, %, (, ), or ". cmd.exe does
not know the pair is one character and starts a pipe, a redirect, or a
variable expansion. Every file is scanned for this before it is written.overwrite, replaced with a timestamped backup.force refreshes it.MoveFileEx fails with EPERM while an
indexer or antivirus holds the destination open, so the rename is retried with
backoff.npx versus npx.cmd — Node ships an extensionless POSIX shim beside
npx.cmd. PATH resolution tries PATHEXT candidates first, so the shim cmd
cannot run never wins.npm install --legacy-peer-deps # iconv-lite; the rest are peer dependencies
npm test
The suite is 90 tests. The interesting ones generate a launcher and run it with real cmd.exe against real listeners — a fake Harness server that answers the 401 fingerprint, an unrelated HTTP server, and a free port — then assert the exit codes. That is what caught the two defects unit tests could not: a file written with bare LF endings (cmd reads it as one enormous line) and a code page switch placed after the first multi-byte character.
test/plugin.test.js checks the manifest contract a plugin marketplace verifies,
including the peer range. That range is deliberately long:
>=0.0.1-rc.1 <0.2.0-0 || >=0.1.0-rc.1 <0.2.0-0 || >=0.1.1-rc.1 <0.2.0-0 ||
>=0.1.2-alpha.1 <0.2.0-0 || >=0.1.3-alpha.1 <0.2.0-0 || >=0.1.5-alpha.1 <0.2.0-0
node-semver only lets a prerelease satisfy a range when some comparator carries
that exact major.minor.patch tuple and a prerelease tag. A range that looks
generous — >=0.0.1-rc.1 <0.2.0, or even >=0.0.0-0 — therefore excludes every
published 0.1.x prerelease, and users hit an ERESOLVE they have to work
around by hand. The enumerated form admits each published line; a test asserts
that the tuple of the harness installed here is one of them.
When the harness packages resolve, the same file validates every tool schema
against the real defineTool compiler; otherwise it reports the skip.
npx (with Node) for the default runner, or an installed dsh command if you
set runner: dsh.MIT