dsh-session-cleaner-cli 🐳🧹

August 14, 2026 Β· View on GitHub

δΈ­ζ–‡

license node test topic

An offline CLI that deep-cleans DeepSeek Harness (DSH) workspace sessions: list by workspace, delete with a trash bin, restore, prune ghost entries β€” keeping the workspace registry and projection cache in sync. Cross-platform (Windows / macOS / Linux), zero dependencies.


Why

DSH's session persistence is append-only by design β€” the GUI only offers archive (hide; data stays on disk) and exposes no delete at all (the SessionPersistence service has create/append/load/inspect/list, but no delete). Test conversations and abandoned chats pile up forever.

This tool deletes sessions at both layers β€” the workspace registry (storages/workspace.json) and the log directories (sessions/<scope>/<id>/) β€” so you can freely delete any conversation in any workspace.

Quick start

# 1. Stop the GUI first (the tool refuses to delete while the server is running)
#    Windows: run stop-dsh.cmd in the deepseek-harness repo root
#    macOS / Linux: press Ctrl+C in the terminal running `dsh web`, or kill the process

# 2. Interactive: pick a workspace β†’ select rows (1,3 / 2-5 / all) β†’ type DELETE to confirm
node dsh-session-cleaner.mjs

# 3. Restart the GUI (the sidebar reflects the new state after restart)

CLI mode:

node dsh-session-cleaner.mjs list                  # read-only listing of workspaces and sessions
node dsh-session-cleaner.mjs delete <id> [id...]   # delete specific sessions (--yes skips the prompt)
node dsh-session-cleaner.mjs restore <batch-ts>    # restore a previous deletion
node dsh-session-cleaner.mjs trash list            # inspect the trash bin
node dsh-session-cleaner.mjs prune-ghosts          # strip registry ids whose data dirs are gone

Install / Uninstall

Zero dependencies; Node.js β‰₯ 18:

# Option 1: run directly from GitHub via npx (no clone needed)
npx github:ChenChen913/dsh-session-cleaner-cli list

# Option 2: clone
git clone https://github.com/ChenChen913/dsh-session-cleaner-cli.git
cd dsh-session-cleaner-cli
node dsh-session-cleaner.mjs

Uninstall = delete the repository/script; if you no longer need recoverable data, also clear ~/.dsh/trash and ~/.dsh/storages/backups.

Commands

CommandWhat it does
(no args)Interactive: pick a workspace β†’ select sessions to delete
listList all workspaces and sessions (read-only; safe while the server runs)
list -w <title-or-path>Show one workspace only
delete <id> [id...]Delete sessions (moves to trash by default; still requires typing DELETE)
restore <batch-ts>Restore a deletion batch (see trash list)
trash list / trash emptyInspect / empty the trash bin
prune-ghostsStrip registry ids whose session dirs are gone

Global flags: --home <dir> (defaults to $DSH_HOME or ~/.dsh), --pid-file <path> (extra dsh.pid location for the liveness check), --dry-run, --purge (wipe immediately, no trash), --yes, --force (skip the running-server guard).

How it works

DSH's default JSONL backend on disk:

~/.dsh/
  sessions/<encoded-workspace-path>/<session-id>/session.jsonl.zstd   ← session log
  storages/workspace.json                                            ← workspace registry + archive set
  storages/session_projcache.json                                    ← title/stats projection cache

Deleting a session is a four-step transaction:

  1. Backup: both registry files are copied to storages/backups/<timestamp>/
  2. Move to trash: log dir β†’ .dsh/trash/<timestamp>/<id>/ (--purge deletes directly)
  3. Sync registry: remove the id from sessionIds and archivedSessionIds in workspace.json, stamp updatedAt
  4. Clean cache: remove the session_projcache.json entry (rebuilt by the harness when the session is next opened)

restore is the exact inverse: move the dir back, re-attach the id to its workspace, and restore the archived flag.

One key safety fact: the DSH workspace entity's sessionIds getter filters by the live header index (packages/workspace/workspace/src/entity.ts), so even if a deleted id lingers in the registry, it is invisible after restart and pruned on the next registry write β€” the tool and the harness converge by design.

Safety design

  • Running-server guard: delete/restore/prune refuse to run while 127.0.0.1:3080 is listening or a dsh.pid process is alive. The process check uses a cross-platform signal-0 probe β€” no platform commands
  • Home validation: mutating commands verify that --home actually looks like a DSH_HOME (sessions/ or storages/ present), so a mistyped path errors out instead of creating junk directories
  • Mutex lock: mutating commands hold .dsh-session-cleaner.lock (records the pid) so two instances can never overwrite each other's registry writes; stale locks from dead holders are taken over automatically
  • Trash by default: delete = move, not wipe; restore brings data back, and trash empty clears it for good
  • Automatic backups: both registry JSONs are backed up before every write
  • Confirmation prompt: interactive and CLI flows both require typing DELETE (opt out with --yes)
  • Ghost self-healing: registry ids pointing at missing data dirs are shown as "ghosts"; prune-ghosts strips them in one pass

Cross-platform support

PlatformDefault DSH_HOMEHow to stop the GUIStatus
WindowsC:\Users\<you>\.dshstop-dsh.cmd (or end the process in Task Manager)Development environment; CI-covered
macOS~/.dshCtrl+C in the terminal running dsh webCI-covered
Linux~/.dshCtrl+C in the terminal running dsh webCI-covered
  • The tool has zero platform dependencies: pure Node.js standard library, no native modules, no external commands
  • Liveness detection = port probe + signal-0 process probe (replaced the earlier Windows-only tasklist approach)
  • Session-dir scanning does not depend on how workspace paths are encoded (works with both the Windows `--C-Users-...--$ \text{encoding} \text{and} \text{Unix} \text{encodings})
  • \text{CI} (\text{GitHub} \text{Actions}) \text{matrix}: \text{ubuntu} / \text{macos} / \text{windows} \times \text{Node} 18 / 20 / 24

\text{Configuration}

\text{Item}\text{Description}
$DSH_HOMEenv var /--home`harness data directory; defaults to ~/.dsh
--pid-file <path>extra dsh.pid location for the liveness check (non-standard installs)
--purgedelete without trash
--dry-runpreview only
--forceskip the running-server guard (only when the GUI is confirmed stopped)

Permissions & data

  • Reads/writes DSH_HOME only (~/.dsh): never touches workspace project files or harness code
  • No network requests: the only network operation is a localhost port-3080 liveness probe
  • No credentials: settings.yaml, .anonymous-user-id, etc. are never read or written
  • Attachments untouched: images live in content-addressed shared storage (attachments/v1) and do not belong to a single session

Compatibility

  • Verified against deepseek-harness mainline 47f943859bef60e4160492346772ded9b24f765a (2026-08-13); storage formats workspace.json unit v2 and session_projcache.json unit v3 (the tool keeps unit blocks untouched and only edits fields)
  • Developed and tested on Windows 11 + Node 24; CI covers ubuntu / macos / windows Γ— Node 18 / 20 / 24
  • Handles BOM-prefixed registry JSON; needs no compression tools (titles come from the projection cache, not from parsing zstd logs)

Troubleshooting

  • Garbled Chinese output: run in Windows Terminal, or run chcp 65001 first in legacy cmd
  • "server is running" refusal: stop the GUI first (Windows: stop-dsh.cmd; macOS/Linux: stop dsh web); use --force only when no server is up
  • "does not look like a DSH_HOME": --home points at the wrong directory β€” check the path or the DSH_HOME env var
  • "another dsh-session-cleaner process": a second cleaner instance is running; after confirming none is, remove ~/.dsh/.dsh-session-cleaner.lock
  • Titles missing after restore: expected β€” the projection-cache entry is removed at delete time and rebuilt by the harness when the session is next opened
  • Deleted a parent session: subagent sessions are not in workspace accounting; they appear under "Ungrouped" β€” clean those up too

Development

npm test   # 13 end-to-end tests: list/delete/restore/purge/prune/interactive flow/running-server refusal/unknown id/lock/pid-file/home validation/incomplete batches

Tests drive the real CLI as a subprocess against scratch DSH_HOME fixtures and assert both filesystem and registry outcomes; CI lives in .github/workflows/test.yml.

Ecosystem

  • Listed on the GitHub dsh-plugin topic
  • Tracked by the awesome-dsh-plugins radar (topic auto-discovery, 8h scans)
  • Curated list: awesome-deepseek-harness
  • Related project: fountunt/dsh-session-cleaner β€” a plugin that deletes sessions inside the running web runtime (GUI delete button + /api-ext/session.delete). Complementary to this tool (offline CLI + trash/restore/ghost pruning): use the former for one-click in-GUI deletion, this one for bulk cleanup with recovery and ghost-accounting repair

License & security

MIT Β© 2026 ChenChen913. This tool handles no credentials; report security concerns via GitHub Issues.