dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)

English | 中文
System Prompt management for DSH (DeepSeek Harness). It adds a Prompt manager to the Web GUI's Settings: you can see the system prompt a session actually assembles on every turn, search it, write your own instructions into it, and roll back a bad edit — all without touching the global DSH install.
Every DSH turn is injected with a base system prompt assembled by @deepseek-ai/dsh-system-prompt.
Until now the only way to adjust it was to hand-edit files inside the global pnpm node_modules.
The cost of that:
This plugin moves that into the Settings page: the assembly is laid out section by section, the part you write is its own section pinned to the end, every other built-in section stays read-only, and changes come with history, diffs and exportable backups.
Settings gains a "Prompt settings" pane (id: prompt-setting) with six top-level tabs:
| Tab | What you can do |
|---|---|
| My Prompt | The only write surface: write your own system-level instructions (pick a layer → edit → save), plus a one-click "Restore default". This text is placed after every built-in section. The "View scope" selector is inside this panel, under its title (since g-071): it decides which layer a save lands in, and it is the only place the scope is changed (the panel also repeats the current target as a read-only line). Since g-084 a read-only two-line status summary sits under that target line: the latest key node's assembly / delivery verdicts and "this layer: N override(s) · M not in effect". It follows "View scope" (a global scope says so and borrows no session), "Details" opens Advanced pinned to that session, and it carries no switch and no per-entry reason. "Restore default" deletes only this layer's My Prompt entry and keeps the layer's other overrides. |
| My presets | Your catalogue of reusable texts: save a text as a preset (create / edit / delete), then apply it to a workspace (it is written into that workspace layer's reserved section) or cancel the application, which restores exactly what that workspace held before. Deleting an applied preset cancels its applications first: every affected workspace is restored to what it held before, and only then is the preset removed from the library (the confirmation names those workspaces). Tags (g-082): the library has its own tag set; a preset may carry 0–N tags and the list filters by one tag at a time. Tags are created, renamed and deleted under "Manage tags"; a deletion asks first and states how many presets lose the tag — the presets keep their other tags and only that tag goes. |
| Prompt overview | Read-only: the assembled section list (status marks / search / filters / copy), the full text, and a base ↔ effective diff — so you can see exactly what your change did. |
| Version history | The history list (fixed-height, internally scrolling, paged — 50 per page by default) and line-level version diffs. The log has its own scope selector (workspace dimension), independent of the "View scope" selector in My Prompt: the user layer's log is global and is never sliced by session. |
| Backup & restore | Export the configuration for download, and preview an import (review the change plan before anything is written). |
| Advanced | A read-only list of legacy overrides, two double-confirm buttons ("clear all overrides", "reset the whole layer"), the "Check for updates" switch (on by default; off means this plugin makes no network request at all), the "Update now" action (the host installs the version the banner named; you restart yourself — re-run dsh web after a command-line start, or quit and reopen DeepSeek Harness in the desktop app), and a full status area (mount state / build fingerprint / renderer self-check). The complete assembly-status block and its switch live here; since g-084 each clear states its scope in words — "reset the whole layer" clears the layer including My Prompt, while "clear all overrides" keeps it. |
All UI copy follows DSH's language setting: switch DSH to Chinese and this page turns Chinese, with no refresh or restart.
The tab bar itself. The six top-level tabs are plain text — no fill, no border, no equal-width columns. The selected one carries a short underline pressed against the faint rule under the bar, and the bar stays on one line, scrolling sideways when the panel is narrower than the labels (it never widens the page). 「My presets」shows its library size as
(N)— and shows no number until that size is really known, so a placeholder(0)can never appear. 「Advanced」shows a small red dot while a newer release is on offer; dismissing the update banner does not clear the dot, because the dot states a fact while the banner is only a notice.
When the settings page opens, the host (Node side) sends one GET to
https://api.github.com/repos/zangxx66/dsh-prompt-setting/releases/latest — a URL derived from this
package's package.json (repository.url), never hardcoded a second time. That is the plugin's
only outbound request, and it is switchable:
User-Agent: dsh-prompt-setting/<version>; a 5-second timeout; not repeated within six hours in the
same process;<DSH_HOME>/prompt-setting/preferences.json
records {"updateCheck": false}. Hand-editing that file — or deleting it to return to the default
(on) — works the same way;The version gets installed; the restart is still yours — and the page says how. The banner's
Update now button opens a second confirmation (which says so), and on confirm the host installs
that release's .tgz into the current profile through the official plugin manager. Afterwards the page
answers for the launch shape it is talking to: a command-line host says "vX.Y.Z is installed — restart
dsh web yourself", the official desktop app says "quit and reopen DeepSeek Harness" (a desktop user has
no terminal, so dsh web never appears there), and an undecidable shape falls back to copy both readers
can follow. Nothing here restarts anything.
https://github.com/zangxx66/dsh-prompt-setting/releases/download/<tag>/dsh-prompt-setting-<version>.tgz,
with <tag>/<version> taken from the same update check — so the version announced is the version
installed, and a cached check still costs zero outbound requests. Being an asset, it needs no pnpm
build-script approval;requestId at once and the page polls it (1.5–5 s, up to 16
minutes) with a cancel button. A failure names its category (asset missing 404 / build blocked /
network / pnpm missing / …) with a retry — never an automatic retry, never an automatic restart;link: install is refused: a profile that holds this package as a link:/local path is a
development working tree, so the button refuses and points at the manual route instead of overwriting
that link with a published version;npm pack asset, named exactly
dsh-prompt-setting-<version>.tgz, and this package must not add postinstall/install scripts
(a tarball carrying one is stopped by pnpm's build gate). See packages/dsh-prompt-setting/NOTES.md
§107.Prerequisites: DSH installed at >= 0.2.1-0 < 0.3.0-0 — every 0.2.1 prerelease (alpha, beta,
rc.N, and the synthetic -0 floor), the 0.2.1 release itself, and every later 0.2.x patch
(0.2.2, 0.2.9, …) are in range; the 0.1.x / 0.2.0 lines below 0.2.1 are out, and so is the whole
0.3.0 line and everything after it — the next minor has to be re-declared (tested) before it is admitted.
Node >= 22 is needed only to run the tests or to develop.
The registry is the primary way in (this package is published; npm latest is 0.2.2 — this repository is 0.2.5, and the two meet when it is published):
dsh plugin --profile <name> add dsh-prompt-setting
The Web GUI's profile is web. The other three routes — git/GitHub, a local checkout, a tarball — are the
development / offline / fallback ones. All four routes put this package into one DSH profile — the
same profile files, the same package manager, the same log — so pick by what you have at hand. Do not
hand-edit profile config files.
Current DSH carries a standalone Plugins page in the Web GUI sidebar. It is not under Settings — Settings → Built-in plugins is the read-only inventory, not an installer:
dsh plugin add, then Install:
dsh-prompt-setting (primary; pulls the latest version from npm);<absolute path to repo>/packages/dsh-prompt-setting (clone or download the repository first; a
relative path is refused, because the host's working directory means nothing to a browser);github:zangxx66/dsh-prompt-setting#path:/packages/dsh-prompt-setting (the #path: part is required
for this monorepo);dsh-prompt-setting-<version>.tgz, on disk or over http(s);A local path installs as a link: — the profile and your checkout become the same files. That is a
development working tree, and the plugin's own "Update now" button deliberately refuses to overwrite it
with a published version (see the "Update now" note above): update such an install with git pull.
If your DSH build has no Plugins entry in the sidebar, use the dsh command line below.
Paste the address into a session and say what to do with it — the agent installs it into the profile that session is running:
install
https://github.com/zangxx66/dsh-prompt-settinginto this profile
In Creator mode the agent has the plugin_manager tool and calls it directly:
plugin_manager(action: "install_bundle", target: "github:zangxx66/dsh-prompt-setting#path:/packages/dsh-prompt-setting", enabled: true)
#path: part is required: this repository is a monorepo and the plugin lives in a subdirectory.
Without it pnpm installs the synthetic 0.0.0 empty package rooted at the repository, and the plugin
never shows up;package.json and bundle selection, and
the installed Host code then runs in-process, outside the workspace sandbox — the tool therefore
requires danger-full-access, or a per-call approval. Read the spec before approving it.dsh command linedsh plugin --profile <name> <pnpm args…> runs pnpm inside that profile's directory and selects the
bundle the run added. The Web GUI's profile is web:
# from the registry (primary)
dsh plugin --profile web add dsh-prompt-setting
# straight from GitHub — development / fallback; no clone first; the #path: part is required for this monorepo
dsh plugin --profile web add 'github:zangxx66/dsh-prompt-setting#path:/packages/dsh-prompt-setting'
# a local checkout — development (absolute path; installed as link:)
dsh plugin --profile web add '<absolute path to repo>/packages/dsh-prompt-setting'
# a tarball built from the package directory — offline / fallback; same behaviour
cd packages/dsh-prompt-setting && pnpm pack
dsh plugin --profile web add '<absolute path to the .tgz>'
pnpm ≥10 does not run a git dependency's build scripts by default, so a git install fails the first
time and prints an exact package key (ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED); copy that key into the
profile's pnpm-workspace.yaml under allowBuilds and re-run add. That grant means "this package's
code may execute on your machine at install time", so grant it only to sources you trust and pin the
commit (…#<sha>). This package is zero-build: prepare only runs a release self-check — are all
declared entry points present, are they all inside the files allowlist, does every patch row resolve.
To avoid the grant entirely, pnpm pack a tarball and add that instead; behaviour is identical.
Open the DSH Web GUI → Settings: the "Prompt settings" pane should be there. To confirm the host
half is mounted, the page's "raw response" area shows the JSON returned by GET /prompt-setting/ping,
or run await (await fetch('/prompt-setting/ping')).json() in the page console.
A bare
curlagainst that route is rejected (401): it requires the browser's cookie authentication. That is expected behaviour and does not mean the route is missing. SeeNOTES.md§4.
Measured output, the full check table and the untested items are in
NOTES.md §96; the package-level summary — what it is, features
and install, bilingual — is in packages/dsh-prompt-setting/README.md.
PUT and the single-name DELETE return 403 write-locked (and touch not one byte
of the files when they refuse). Since g-074 import is the one exception: a backup is the whole
installation (every override of both layers, every registered workspace layer, the preset library, the
preferences), and restoring it must not be blocked by the write face. That exemption costs no check —
the document is validated at least as strictly as before, and a rejected import writes nothing
(CONTRACT §11.1, §11.7, §15.7).history.jsonl).standard sessions since 2026-09-30
21:32). It is not a hard switch over model behaviour.complete: true (the built-in minimal, and this machine's
"梁神模式") — the platform collapses the assembly into a single section, so this plugin's text cannot
enter the final prompt, and the Settings page raises a blocking notice; ② the plugin is not loaded at
all — a broken plugin never affects DSH startup, so the terminal is the only signal; run
node scripts/check-compat.mjs first.Prove it for this session (two paths plus a failure rule):
# Path 1 (hardest evidence): read this session's persisted final prompt
ls ~/.dsh/sessions # find your workspace dir (escaped; non-ASCII becomes ~XXXX~)
F=~/.dsh/sessions/<workspace-dir>/<session-id>/session.v4.jsonl.zstd # e.g. --Users-me-Documents-proj--
zstd -dc "$F" | jq -r 'select(.type=="system/message") | .data.message.content[0].text[-200:]'
matches host / page is stale / unknown; "stale" only means the page is old — refresh).agentPreset and freeze state first.packages/dsh-prompt-setting/ # the plugin package (publishable to npm on its own)
├── index.js # host half: routes + assembly listeners + the reserved section
├── client.js # client half: the four Settings tabs
├── core/ # pure-function kernels + the only module that touches the filesystem
├── cordis.patch.yml # bundle patch (one insert row mounting both halves)
├── scripts/ # check-compat.mjs (read-only diagnostic) + prepare.mjs (git-install gate)
├── CONTRACT.md # the frozen REST contract (the client is written against it)
├── NOTES.md # design trade-offs, measurements, untested items
└── test/ # eighteen test suites
assets/ # the hero image for this README
.dsh-graph/ # project board and event log (separate inner repo, not part of this one)
.worktrees/ # isolated worktrees for subagents (not part of this one)
cd packages/dsh-prompt-setting
# syntax
node --check index.js && node --check client.js && for f in core/*.js scripts/*.mjs; do node --check "$f"; done
node --test # eighteen suites; the integration suite runs against the real DSH package and must pass (not skip)
node scripts/check-compat.mjs # read-only compatibility self-check (no network, never throws, always exit 0)
node scripts/prepare.mjs # the prepare gate pnpm runs on a git install (exit 1 when it fails)
npm pack --dry-run # confirm the published artifact is clean (29 files, no test/, no .dsh-graph)
Latest run on this machine: node --test 740 tests, all passing, 0 skipped (31 of them in the
integration suite); npm pack --dry-run reports 29 files (measured 2026-10-09).
Worth knowing:
test/integration.test.mjs resolves the real @deepseek-ai/dsh-system-prompt and the real Cordis from
your local DSH install root, and verifies assembly semantics (waterfall order, complete freezing,
scope shadowing) in a real context — these conclusions are measured, not guessed — and the same
conclusions are written into CONTRACT.md and the snapshot's
experiments field.skips, so node --test stays green on a machine
without DSH; on a development machine you must see it pass, not skip — a skip means the evidence is missing.client.js runs inside a node:vm sandbox with require / React / fetch
all stubbed, so "primitives available / unavailable" and "probe ok / HTTP error / network error" are all
asserted offline.~/.dsh: the relevant suites point $DSH_HOME at a temp directory.When the plugin does not show up after a DSH upgrade and the terminal says nothing, run
node scripts/check-compat.mjs first — it prints the terminal signature of the four boot failure modes
and the rescue steps. How a code change takes effect, and the maintainer commands, are in the package
README's "For maintainers" section; the detailed measurements are in
NOTES.md §91.
ctx.systemPrompt.assemble({scope: agent}) and gets back the sections
(sections[{name,text}]) plus the full text.system-prompt/assemble waterfall
hook and replaces / hides / appends by section name — no change to DSH's core, none to the global install.apply it registers the reserved section
prompt-setting:custom-prompt (empty text, interpolate: false); your text lands on that section
through the override engine and is moved to the end of the final assembly by an outermost listener.
interpolate: false is not a style choice: once user text takes part in interpolation, a single
{{unknown-variable}} would make every later assembly throw.store.js, everything under core/ is plain data in,
plain data out; store.js is the only module that touches the filesystem, and it is not on the
assembly path. Listeners on the assembly path r