DeepSeek Harness Plugin Hub

Publish and manage complete Harness Profiles. Discover Plugins for your next setup.

Explore

PluginsPresetsDocsNews

Community

Publish a pluginContactReport an issue

Resources

Plugin Hub on GitHubDeepSeek HarnessSystem statusPrivacy notice
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

Independent and unofficial. Not affiliated with, authorized by, or endorsed by DeepSeek.

Session Deleter — DSH Plugin for DeepSeek Harness
← Plugins
S

dsh-session-deleter

Session Deleter

Delete stored DSH sessions and subagents from the web UI: a recycle bin by default, permanent deletion only on explicit confirmation.

The plugin will be installed here. Keep web if you are unsure.

npx -y @deepseek-ai/dsh plugin --profile web add github:ghgjkbf/dsh-session-deleter#6dc214b20fdb1eb703f0aa513d60b34e8871888c
READMECompatibilityVersions

Compatibility and provenance

Session Deleter is published as dsh-session-deleter and currently resolves to version 0.2.0. The Hub verifies its manifest and preserves the exact installation source for reproducible installs.

DSH compatibility
*
Runtime surfaces
web
Release source
github
Registry updated
10/8/2026

Versions

0.2.0stable
10/8/2026

Related plugins

Loading related plugins…

Latest
0.2.0
DSH
*
HMR
Process restart
Tree shaking
Safe tree shaking not declared
Unpacked size
Unavailable
Files
Unavailable
Surface
web
License
MIT
Source
github
GitHub
★ 0
Weekly downloads
0
Last push
10/8/2026
View source ↗
README badge

Click the badge to copy Markdown for your README.

Do you maintain this Plugin?Claim benefit · Priority security scan

Verify the GitHub repository declared in package.json to manage this listing. After you claim it, Hub will prioritize a security scan of the current version and publish the result when it passes.

Claim this Plugin →
Report an issue
DeepSeek Harness Plugin Hub
ProfilesPluginsCategoriesNewsDocsSign inManage Profiles
ProfilesPluginsCategoriesNewsDocsSign in

Related plugins

More verified plugins in memory-context.

Hindsight Coding Agents@vectorize-io/hindsight-coding-agentsReflect-only Hindsight long-term memory for coding agents (harness-pluggable: opencode, …), with automatic background ingestion (no setup CLI).Memsearch Dsh@zilliz/memsearch-dshMemSearch plugin for DeepSeek Harness: shared markdown memory across agents, with capture, pre-step context injection, memory-recall skill, and a skill-candidate review panel.Memory@furongjun1999/dsh-memoryLingshu (Lingshu·líng shū) DeepSeek Harness plugin: a complete brain—long-term memory/knowledge flywheel/self-awareness/recursive reflection integrated with DSH, with conversations automatically distilled into the md_cg cognitive graph (md documents)Archive Manager@michengai/dsh-archive-manager归档、恢复、收藏和永久删除会话,并诊断损坏的会话日志。 · Archive, restore, favorite, and permanently delete sessions, and diagnose damaged session logs.

README

dsh-session-deleter

Delete what the harness gives no API for deleting: a whole stored Session — and a Session's contents — from the DSH web UI. Deletion is a move to a private recycle bin; bytes leave the disk only on an explicit, separately confirmed permanent delete.

Release history: CHANGELOG.md.

Why this exists

@deepseek-ai/dsh-session-persistence-jsonl offers create/open/flush/ stat/list and nothing else, so the UI can archive a Session but never remove one. The sidebar keeps its row until the next Workspace write prunes the id, the subagent/catalog is append-only so a child cannot be dropped by appending, and no client-side service exposes a delete. This plugin adds the missing operation without touching the harness.

What it does

Three operations, reachable from the UI:

  • Delete a whole Session — moves the Session's entire directory (every log generation) into the recycle bin. Reversible.
  • Restore — moves a held directory back to its original path. It refuses to overwrite an occupied path rather than guessing.
  • Delete permanently — the only irreversible step, and the only one that reclaims disk space. Requires a second, explicit click (or confirm: true).

Where it appears in the UI

SurfaceSlotPosition
Sidebar foot, beside Settingssidebar.footer.actionorder: 20 — always visible, no hover needed
Session picker dialogshell.overlayopened by the footer entry
A Session's "..." menusidebar.workspaces.session.menu.itemorder: 500, after the shipped pin/rename/fork/archive rows
Confirmation dialogshell.overlayframe-wide floating layer
Management pagesettings.sectionorder: 50 in Settings
Management page (same body)shell.overlayorder: 5 — the in-plugin manage overlay, see below

The sidebar-foot entry is the primary door and it does not depend on hover: DSH only draws a Session row's "..." trigger while the pointer is over a non-current row, so a reader who never hovers sees no sign the plugin exists. The picker it opens lists every deletable session itself, and a running or current session is shown but not deletable.

The management page renders in two places from one component. The shell owns the Settings panel and exposes no client service that opens it: layout.selectPanel(id) only addresses a main panel registered in the sidebar.panellist slot (whose shipped occupants are plugins and dsh-market), and selecting an unregistered key throws. So the in-plugin entries that promise "manage" — the picker's 「管理回收站」 and the dialog's 「打开管理页」 — open the manage overlay, which renders the same body. A best-effort selectPanel("settings") is still attempted first, purely as a courtesy for a build where that key does exist.

Both dialogs are dry runs first: the plan shows the directory, the size, the log generations, what else is affected, and what residue stays behind — before anything moves.

Design commitments

Reversible by default. A first request never removes bytes. rename into the recycle bin is atomic on one filesystem and is the whole of the destructive work.

Nothing the backend cannot read afterwards. Rewrites re-emit one checksummed Zstandard frame per durable batch. The .jsonl.zstd artifact is a concatenation of independently decodable frames, not one stream — so a single recompressed stream would decode to the right bytes yet stop matching the backend's structural scanner on the next append.

Multi-generation aware. Session directories legitimately hold a v3 log, a v4 log, or both. Nothing here hardcodes a filename.

Refuses what it cannot safely do. A running Session's log is open for writing, so it is refused rather than deleted under its writer. The Session issuing the request cannot delete itself. A Session id is a path segment, so traversal-shaped ids are rejected before reaching the filesystem.

Host routes

Served on the harness web server under /session-deleter:

MethodPathPurpose
GET/healthRoots in effect and the current Session id
GET/inventoryEvery stored Session, with bytes, generations, titles
GET/plan?sessionId=…Dry run: consequences, residue, blockers
POST/delete{sessionId, force?} → move into the recycle bin
GET/trashHeld entries, orphan detection, size
POST/restore{id} → move back
POST/purge{id, confirm: true} → remove bytes
GET/ledger?limit=Append-only operation log
GET/messages?sessionId=…Surface messages with live/shadowed status
POST/messages/shadow{sessionId, seq} → tombstone one message (line A)
POST/messages/unshadow{sessionId, tombstoneSeq} → undo one shadow
POST/messages/truncate{sessionId, throughSeq} → drop the tail (line B)
POST/messages/untruncate{sessionId, backupPath} → restore the backup

Shadow vs truncate: what each one really does

  • Shadow is append-only and fully reversible. A developer/message tombstone replaces one surface node in the model-visible fold — the same mechanism the shipped compaction flow uses. The transcript keeps showing the original row (by the surface's own documented contract), and the tombstone derives to no LLM message. Deleting a message from the model's context is what this does; deleting it from the screen requires truncation.
  • Truncate removes events from the artifact by rebuilding it from the surviving frame-aligned prefix. It takes the transcript rows with it and keeps a .bak- backup for a byte-exact restore. It is the only message operation that touches existing bytes.

Configuration

Optional, supplied as the bundle row's config:

- insert:
    - id: session-deleter
      name: 'dsh-session-deleter'
      config:
        sessionRoot: 'D:/somewhere/sessions'
        trashRoot: 'D:/somewhere/trash'
        protectCurrentSession: true
        refuseLiveSessions: true

Defaults: sessionRoot = <DSH_HOME|~/.dsh>/sessions, trashRoot = <home>/session-trash/sessions.

State on disk

  • <home>/session-trash/sessions/ — held directories, one per deletion, plus manifest.json.
  • <home>/session-trash/ledger.jsonl — one append-only line per operation phase. A torn trailing line (a crash mid-append) is dropped on read rather than treated as corruption.

Verification

Each check runs real filesystem and HTTP work against a sandbox copy of a real session tree — no mocks of the plugin's own logic.

node tools/verify-host.mjs "$DSH_HOME/sessions"
node tools/verify-http.mjs
node tools/verify-client.mjs
node tools/check-locale.mjs     # static: t() keys vs both dictionaries
node tools/verify-frames.mjs <log> [<log> …]
node tools/verify-manage.mjs   # needs a browser + the gate cookie, see below
node tools/verify-ui.mjs       # same
node tools/verify-footer.mjs   # same

verify-host covers inventory/title parsing, the full hold → restore → purge cycle, refusal paths (occupied path, purged entry, unknown entry), atomic replacement backups, ledger durability, byte-exact frame round trips, and traversal-shaped id rejection. verify-http mounts the plugin through a webServer stub matching the shipped contract and drives all eight routes over real HTTP. verify-client executes the browser bundle in a VM against a stub module loader and asserts every slot registration. check-locale proves every t("…") call resolves in both dictionaries (a missing key renders as the literal key text) and that no key is shadowed by a duplicate. verify-manage, verify-ui, and verify-footer drive the real GUI in Chrome and prove the surfaces render, not merely register: verify-manage opens the picker from the sidebar foot, clicks 「管理回收站」, and asserts the management view's rendered counts equal what the routes return — an empty-but-mounted panel cannot pass.

Nothing machine-specific is committed. tools/harness.mjs discovers the browser and puppeteer-core at run time, so the suites work on another machine; each value has an override:

VariablePurpose
DSH_URLGUI origin under test (default http://127.0.0.1:3080)
DSH_COOKIE_NAME / DSH_COOKIE_VALUEThe GUI gate cookie; overrides in-memory minting in the browser suites
DSH_HOMEHarness home whose credential file the cookie is minted from
DSH_CHROMEChrome/Chromium binary
DSH_PUPPETEER_COREpuppeteer-core entry module
DSH_SHOTS_DIRWhere screenshots land
DSH_SESSIONS_DIRSource tree verify-http copies its fixture sessions from
DSH_LAUNCHER / DSH_PLUGIN_DIRUsed by tools/restart-and-verify.ps1

The gate cookie is a bearer credential and is never written to this repository. When DSH_COOKIE_NAME/DSH_COOKIE_VALUE are absent, cookieForBaseUrl() in tools/harness.mjs mints one in memory from this Harness home's own .credentials.yaml (client-connection/browser-session), signing it exactly as dsh-client-connection does — payload {version, authority, issuedAt, expiresAt} in milliseconds, HMAC-SHA256 over the base64url body with the decoded 32-byte secret, and the name dsh-auth-<base64url sha256(authority)>. Nothing is printed or persisted. The environment variables still win when set, so a run against a remote host needs no local credential file.

Uninstalling

Remove the bundle row and the package. Held directories stay in the recycle bin and can be restored by hand — the manifest records each entry's original path.