dsh-session-plus
中文 | English
 
Session completion for DeepSeek Harness: sidebar archive directory, restore to the original workspace slot, delete, and branch conversation.
Stock DSH can already archive a session, but it has no UI to list, unarchive, or delete. I built this plugin to fill those operations. Everything goes through public slots and the workspace domain. It does not patch @deepseek-ai packages, and it does not inject DOM into the native View options menu.
Open Archive next to Settings at the bottom of the sidebar.
<p align="center"> <img src="docs/archive-button.png" alt="Sidebar footer: Archive above Settings" width="240" /> </p>
Known failure (read this first)
This is not a one-version regression. I reproduced it across multiple builds of this plugin, and other community archive plugins hit the same class of bug. The root cause is DSH session persistence: tool / result events must carry source.kind = tool and a callId. Archiving while a tool call is still in flight (the host will clear() / unbind) can write an illegal event. A log that is already corrupt cannot be repaired by this plugin — delete it.
What I actually tested:
| Scene | Result |
|---|---|
| Scene 1: archive after the turn has finished, then restore | Does not fail. Survives a restart. |
| Scene 2: archive mid-answer on a long write with no tools, then restore | Does not fail. The answer can finish. Survives a restart. |
| Scene 3: archive while a tool call is in progress, then restore | Always fails. |
| Delete | I have not found remaining bugs. |
| Branch conversation (Edit and branch) | I did not hit a bug on the paths I tried. |
After Scene 3, the client commonly shows:
历史加载失败:conversation Context 9:tool-call received more than one start Match(internal)After a server restart:
history unavailable
SessionPersistenceCorruptionError: ... message must have tool source(internal)So: do not archive while a tool is still running. Wait for the turn to finish, or stop it first. A blank “New session” cannot be archived anyway. The plugin tries to wait until idle (including runningCalls / partial, up to about 30 seconds) before archive; on timeout it tells you to wait or stop. That does not cover every timing. If the log is already broken, restore is useless — just delete that session.
Install
npm (stable, official recommendation). Please take 0.1.1 — the npm 0.1.0 was only a name-hold, not this codebase.
dsh plugin --profile web add dsh-session-plusAlready on 0.1.0:
dsh plugin --profile web update dsh-session-plusOr follow GitHub (latest commit; this package ships prebuilt lib/, so git install does not need allowBuilds):
dsh plugin --profile web add github:SZMY-haruhi/dsh-session-plusPin a commit:
dsh plugin --profile web add github:SZMY-haruhi/dsh-session-plus#<commit>Remove:
dsh plugin --profile web remove dsh-session-plus> dsh.bundle · prebuilt lib/ · git install does not need allowBuilds
Features
- Archive directory: the official
archivedSessionIdsset, not a shadow list I invented - Restore: drop the id from that set; workspace
sessionIdsaccounting is kept on archive, so the session returns to its original slot - Delete: centered confirm (red delete), detach workspace accounting, remove the session log (including the
.zstdsibling and the session directory); do not unarchive after rm, so the card cannot ghost back into the list - If the deleted session is the current one:
sessions.clear()to a blank New session — notconnectWorkspace(that felt like “return to workspace”) - Blank New session: no archive, no delete
- Branch conversation: Y-fork-with-arrows icon beside your message (not the official git-branch dots) → nearby popover to edit the prompt, optional new title, empty falls back to official
increaseTitle(1)(2)→sessions.forkthen send; the old session stays - One entry, one operation surface; I am not building a settings-page session OS (export, pause, compaction, AI rename)
Restore / Delete in the archive directory:
<p align="center"> <img src="docs/delete.gif" alt="Archive directory: delete a session from the list" width="720" /> </p>
Edit and branch beside your message: nearby popover to change the prompt, optional new title, original conversation stays.
<p align="center"> <img src="docs/branch-edit.png" alt="Edit-and-branch popover: title optional, defaults to (1) (2)" width="480" /> </p>
<p align="center"> <img src="docs/edit-and-branch.gif" alt="Open Edit and branch from a user message" width="720" /> </p>
Behavior
| Action | Path | Result |
|---|---|---|
| Archive | official workspaces.archiveSession | hidden from grouping; accounting kept |
| Restore | write workspace-domain archivedSessionIds | back in the original workspace slot |
| Delete | detach + delete persistence file | irreversible |
| Branch conversation | fork + prompt | new session = prefix + edited prompt + new answer |
Out of scope
- No file patches on
@deepseek-aipackages - No override of official plugin rows (the patch is insert-only)
- No injection into the native View options menu
- No repair of already-corrupt session logs (that belongs to host persistence)
Develop from source
pnpm install
pnpm build
dsh plugin --profile web add .pnpm pack builds the tarball I would send to npm. Install this cut with dsh plugin --profile web add ./dsh-session-plus-0.1.1.tgz.
Changelog
0.1.1 · 2026-08-18
Publish this GitHub cut to npm. The npm 0.1.0 was only a name-hold and cannot be overwritten, so this is 0.1.1.
0.1.0 · 2026-08-18 · first release
This cut was GitHub main at the time. The npm 0.1.0 with the same number is only the earlier name-hold stub; they are not the same code.
This is the first working cut of “session completion.” This version ships:
- Sidebar footer Archive (
sidebar.footer.action, same geometry as official Settings) - Overlay archive directory: list, restore, delete
- Archive via official
workspaces.archiveSession(writesarchivedSessionIdsonly; workspace slot kept) - Restore returns the session to its original workspace slot
- Delete: centered confirm, detach accounting, remove jsonl /
.zstd/ session directory; current session clears to a blank New session - Blank drafts refuse archive / delete
- Wait until idle before archive or delete; do not
cancel()the in-flight turn - Edit and branch on user messages: nearby popover, optional title,
sessions.fork+prompt - Public Harness APIs only — no
@deepseek-aipatches, no View-options DOM injection
See “Known failure” above. Scene 3 is a host log constraint, not a regression unique to this cut.
Voice input
Official DSH has no speech-to-text. The voice plugins I tried were fiddly to set up and awkward in use, so I wrote otoink — cross-window dictation with a built-in engine.
Acknowledgements
I read these MIT repositories as design references. Ideas only; I did not copy their code. Copyright remains with their authors:
- cokiscarazo-rgb/dsh-session-management
- Moeblack/dsh-message-edit
- cindyguyuehu123/dsh-webchatlike (interaction model; this plugin does not patch core packages)
- dylan121322/dsh-session-unarchive (restore-to-original-slot idea)
I do not treat repositories without a LICENSE as copyable source. Public contracts are listed in NOTICE.
Official contracts come from DeepSeek Harness / Cordis.
License
[MIT](LICENSE) · Copyright (c) 2026 SZMY-haruhi
---
Author
<a href="https://tonkatsu258.vercel.app/index.html"> <img src="docs/avatar.png" width="96" height="96" alt="tonkatsu258" /> </a>
Thanks for the star ❤️ tonkatsu258 · personal site