dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
随手做的一个dsh归档架,可以查看,还原,彻底清除已归档的会话,纯大肥鱼手工打造
An Archive Shelf for the DeepSeek Harness Web GUI.
Harness sessions can be archived, but the product ships no way back: the sidebar menu only hides them, and there is no unarchive control and no way to delete a session's logs. This plugin adds one settings page that lists every archived session and supplies the missing actions: restore, queue a deletion (which you can cancel again), and — where the host supports it — release a session and delete it immediately.
English | 中文
Settings → Archive Shelf (below Agent presets):
session/disposed), and it hands the new archive set to the product's workspace state.
Both are needed before the sidebar can show the row again. The one exception is
restoring the last archived session, which leaves no anchor to sync with — the
notice then says to refresh instead of pretending it worked;dsh start deletes it.
A queued deletion is always cancellable, and cancelling does nothing else;agents.release(id) (see below):
unloads the session's live runtime so it can be deleted at once, with no restart;Queueing deletes nothing right away; it records your intent:
.archive-shelf/pending.json under the harness home (beside the
session root) and survives restarts;dsh start (a sweep a few seconds in); reading or
refreshing the shelf never deletes anything, so queueing and deleting stay separate
acts. An entry that is still resident or running at that moment waits for the start
after that;Once a session has been loaded in the host process there is no public way to unload
it — that is the current shape of DSH (the agents service has no release-by-id
method, and the one dispose handle that could do it is discarded by its creator).
So the plugin detects the capability:
agents.release(id), the list route reports canRelease: true
and rows grow a Release button: release → no longer resident → deletable, no
restart at any point;That host-side capability is not in upstream DSH today. To get it you either patch
your own DSH (edit packages/core/agent in a source checkout, or pnpm patch an npm
install) or wait for it to be accepted upstream.
The patch ships with this repository: patches/host-release.patch — it touches only
packages/core/agent (retain each agent handle's disposal capability and expose
release(id)), plus a 161-line spec.
cd /path/to/deepseek-harness
git apply /path/to/dsh-plugin-archive-shelf/patches/host-release.patch
pnpm exec tsc -b packages/core/agent && pnpm --filter @deepseek-ai/dsh-agent exec tsdown
# restart dsh: loaded rows in the shelf now carry a Release button
git pull may refuse to merge it. On a
conflict, run git checkout -- packages/core/agent and apply it again; either way the
change needs a rebuild and a restart.lib/ files, so
the equivalent change goes through pnpm patch @deepseek-ai/dsh-agent — same semantics,
different landing site.web profile. Developed and verified against 0.1.5-rc.2.^22.19 || >=24 (whatever the harness itself requires).One command — the dependency and the mount happen together, and re-running it is safe:
dsh plugin --profile web add github:JIUYUE-SEP/dsh-plugin-archive-shelf
Then restart dsh (Ctrl+C, then dsh web again) and reload the page. A static client
plugin ships with the page's boot graph, so a plain refresh does not reliably pick it up
(browser cache and scan timing both interfere); a restart always does.
Why that is enough: this package declares dsh.bundle.patch in its own package.json and
ships a cordis.patch.yml layer. After pnpm finishes, dsh plugin add reconciles that
layer into the profile's dsh.profile.bundles, so you never edit
~/.dsh/profiles/web/cordis.patch.yml by hand.
# Append to ~/.dsh/profiles/web/cordis.patch.yml, then restart
- insert:
- id: archive-shelf
name: dsh-plugin-archive-shelf
git clone https://github.com/JIUYUE-SEP/dsh-plugin-archive-shelf.git
dsh plugin --profile web add ./dsh-plugin-archive-shelf # mounts itself the same way
dsh plugin --profile web remove dsh-plugin-archive-shelf # also drops it from dsh.profile.bundles
If you added the - insert: block from the fold-out above by hand, delete that too.
The patch ships with this repository: patches/host-release.patch — it touches only
packages/core/agent (retain each agent handle's disposal capability and expose
release(id)), plus a 161-line spec.
cd /path/to/deepseek-harness
git apply /path/to/dsh-plugin-archive-shelf/patches/host-release.patch
pnpm exec tsc -b packages/core/agent && pnpm --filter @deepseek-ai/dsh-agent exec tsdown
# restart dsh: loaded rows in the shelf now carry a Release button
git pull may refuse to merge it. On a
conflict, run git checkout -- packages/core/agent and apply it again; either way the
change needs a rebuild and a restart.lib/ files, so
the equivalent change goes through pnpm patch @deepseek-ai/dsh-agent — same semantics,
different landing site.web profile. Developed and verified against 0.1.5-rc.2.^22.19 || >=24 (whatever the harness itself requires).# 1. install the plugin into your web profile
dsh plugin --profile web add github:JIUYUE-SEP/dsh-plugin-archive-shelf
# 2. mount it — append to ~/.dsh/profiles/web/cordis.patch.yml
- insert:
- id: archive-shelf
name: dsh-plugin-archive-shelf
Then restart dsh and reload the page. A static client plugin is delivered
with the page boot graph, so a plain refresh is not a reliable way to pick up a
new or updated plugin; a restart always is.
git clone https://github.com/JIUYUE-SEP/dsh-plugin-archive-shelf.git
dsh plugin --profile web add ./dsh-plugin-archive-shelf
# same cordis.patch.yml row as above, then restart
dsh plugin --profile web remove dsh-plugin-archive-shelf
# then delete the `- insert:` row you added to cordis.patch.yml
This plugin fills gaps the product explicitly does not offer (archiving is one-way, there is
no session-deletion entry point, and no API unloads a session), so it necessarily touches
things that were never promised: the workspace registry's private setState, the session
log's on-disk layout, and the agents.release(id) capability the optional host patch adds.
After upgrading DSH, spend one minute on this:
cd /path/to/dsh-plugin-archive-shelf && npm test # both suites: client contract/rendering + host behaviour
setState check);Failures are meant to be loud: when a private API is gone, a path no longer matches, or the
session-list snapshot cannot be read, the plugin refuses and says why instead of guessing. If
something does break, open an issue with the message the shelf showed plus your npm test output.
No build step: both halves are plain JavaScript and shipped as-is.
lib/index.js (host) — a Cordis plugin injecting workspaceRegistry,
sessionPersistence and webServer. It registers one same-origin JSON route
(POST /archive-shelf/api) and implements seven operations: list,
unarchive, delete, forget, queue, unqueue, release. Deleting uses
node:fs directly — the host plugin is ordinary Node code, so it needs no
sandbox escalation. The queue is this plugin's own state, written to
<harness home>/.archive-shelf/pending.json through a temporary file plus a
rename, so a half-written queue can never be read back.lib/client.js (browser) — written directly in the client module loader's
factory form (window.__ModuleLoader__.load({ id, factory })), because the
harness's own client bundler preset lives inside its repository and is not
published. It registers one settings.section, so the page appears in the
settings card's left tab bar and needs no change to the product.The route authenticates itself: POST + content-type: application/json + the
x-archive-shelf-client: 1 marker header is a non-simple cross-origin request,
so a foreign page hits a CORS preflight this server never answers, and an
Origin/Host match is checked on top. That protects against cross-site
requests, not against other processes on the same machine — those can already
read and delete session files directly.
setState. If a harness upgrade changes that internals shape
the plugin fails loudly instead of silently doing nothing.npm test # zero dependencies; two suites: contract/rendering + host behaviour
test/plugin.test.mjs imports the host half as an ESM module, evaluates the browser
half the way the client loader does, and renders rows through a minimal React
stand-in, asserting badges, button visibility and disabled reasons, failure copy, and
the exact request each button sends;test/host.test.mjs drives the real apply() through fake Cordis contexts and real
loopback HTTP servers, deleting and writing for real inside temp directories: path
escape, an oversized body, running/resident refusals, queueing, cancelling, honouring
the queue across a restart, the three release outcomes, and a service-less
composition. Every one of them is a runnable regression assertion; npm test prints the exact totals.Two invariants worth knowing before you edit:
registration.id === manifest.name) — the loader looks the factory up by
that name. The test fails if they drift.node: builtins
only; every other capability arrives through injected services. That is what
lets the package live outside the harness repository and still load.MIT — see LICENSE.