dsh-session-trash
Delete sessions from the DeepSeek Harness Web sidebar straight into a Trash settings page, then restore them or delete them permanently.
- Stars
- 0
- Language
- JavaScript
- Created
- Oct 16, 2026
- Updated
- Oct 16, 2026
Introduction
dsh-session-trash
Delete sessions from the sidebar into a Trash page in Settings, then restore them or delete them permanently.
A global DeepSeek Harness
plugin published as one npm package carrying both halves: a Host plugin mounted
by the bundle patch, and a browser half served from the same package's ./client
export.
Install
This package is a DeepSeek Harness bundle: dsh.bundle.patch is its Host
row, dsh.client is its browser half, and the package resolves both. Install it
into a profile with the harness's own Plugin Manager — point it at this
directory (or at the repository URL) and it records the bundle in the profile:
dshCLI, if the harness exposes the Plugin Manager surface:dsh plugin --profile <name> add <source>- or add it to the profile's dependencies and bundle list directly, then boot.
The profile's own cordis.patch.yml is applied after this bundle's layer, so
it is also where any config below is pinned.
What it adds
- A delete button at the end of every Session row in the sidebar, beside the shipped archive and pin buttons. One press deletes: the session goes straight to Trash with no confirmation step, because Trash is the undo.
- A Delete session row in the Session's
…menu, for keyboard users and anyone who never hovers a row. - A Trash page in Settings listing every deleted session, with Restore and Delete permanently per session and Empty Trash for the whole list. Permanently deleting a session drops its log and its derived projection cache; a live session cannot be trashed or purged. These two stay behind a confirmation, because they are the irreversible half.
The deleted row leaves an open browser immediately
Moving a log aside makes the session absent from the Host catalog on the next listing — but nothing schedules one. The browser's session store was filled by a pull that already happened, so a deleted row would otherwise stay on screen (the sidebar renders it as an ungrouped "stray") until the page was reloaded.
After the log actually moves, the Host therefore emits the declared Remote Event
api-session/removed, which Cordis relays to every connected client. That is the
same path the shipped Session controller uses for its own disposal
notifications (dsh-api-session-controller/lib/index.js), so the browser clears
the row through its ordinary list-mutation code — no client-side list surgery,
and no plugin knowledge of another package's internals. The route's response
reports announced: false if the relay was unavailable, so a deployment without
the event simply falls back to clearing on the next load.
How deletion works
The Harness ships no session-deletion API: SessionPersistence creates, opens,
lists, and flushes handles but never removes one, and the browser session
controller exposes no delete verb. What the store does publish is its
addressing rule — a session is visible exactly when its directory holds a
canonical generation log (session.jsonl, session.v<N>.jsonl, either with the
configured compression suffix).
So deleting a session appends .trashed to that one basename inside the
session's own directory. Nothing is copied and the log's bytes are untouched:
stat/list/open all report the session as absent, so the sidebar catalog,
search, title folding, and lineage traces treat it as gone without knowing this
plugin exists. Restoring removes the suffix again, which brings the title back
with the log, and permanently deleting removes the directory and the session's
projection-cache record.
The trash index is this plugin's own plain JSON document. A missing, empty, or hand-edited index is reconciled against the session root on every read, so a trashed session is never stranded by index damage.
Configuration
The row takes an optional config, set from the profile's own
cordis.patch.yml (the layer applied after this bundle's):
- id: session-trash
name: 'dsh-session-trash'
config:
# Defaults to $DSH_HOME/sessions, the session-persistence root.
sessionsRoot: /absolute/path/to/sessions
# Defaults to $DSH_HOME/storages/dsh-session-trash/index.json.
indexFile: /absolute/path/to/index.json
# Defaults to $DSH_HOME/storages/session_projcache/sessions.
projectionCacheDir: /absolute/path/to/session_projcache/sessions
Verification
Two dependency-free suites ship with the package and run against a scratch session root in the system temporary directory:
node verify.mjs # the store: trash, list, restore, purge, empty, recovery
node verify-route.mjs # the route: dispatch, validation, refusals, envelopes
verify.mjs asserts the property this design rests on — a trashed session is
invisible to a canonical-generation scan while its bytes are byte-for-byte
unchanged, and restoring brings back the identical file.
Upgrade stability
The Host half imports no Harness package; its one contribution is a
connection.fetch exact route on the authenticated /api channel, and the
store knowledge it relies on is the filename grammar above — a storage-format
constant rather than a module API, with v<N> left open-ended so a future
format generation is matched by the same scan. The browser half imports no
Harness Client package either: it uses the module-loader factory contract,
ctx.slots.inject/register, the slot's standard useSessions hook,
ctx.locale, and --dsw-alias-* theme tokens only.