dsh-plugin-edit-regenerate
DSH plugin: edit a user message in conversation history and regenerate from the revised prompt in a forked session.
- Stars
- 1
- Language
- JavaScript
- Created
- Aug 18, 2026
- Updated
- Aug 18, 2026
Introduction
dsh-plugin-edit-regenerate
English · 简体中文
A DSH (DeepSeek Harness) plugin that lets you edit a user message in conversation history: click the "✎ Edit" button under a user bubble, confirm the revision, and the system drops everything after that message and regenerates from the revised prompt.
Demo
The screenshot below demonstrates the core edit-and-regenerate flow: the ✎ 编辑 button on a user bubble (kept alongside the stock ⧉ 复制), and the revised prompt regenerating the reply.
Behavior
- Non-first message: forks a new child session at the end of the previous turn (
sessions.fork+ prompt + open); the original session is left untouched. - First message: creates a fresh blank session in the same workspace and regenerates with the revised text as the opening prompt.
- Messages with attachments are resent as plain text after revision (attachments are not kept; the UI warns about this).
- The user bubble keeps its original copy action: a
⧉ 复制button now sits right next to✎ 编辑, so both actions coexist on every user message (the plugin's renderer shadows the stock one, so it re-implements copy instead of dropping it). - Session storage is an append-only log and cannot be truncated in place; forking is the platform-native "edit and regenerate".
Architecture
A single DSH plugin package that declares both halves:
dsh.bundle.patch→cordis.patch.yml, assembled into the profile as a bundle;dsh.client→ browser half (./client), injected intowindow.__DSH_BOOT__bydsh-client-modules;main→ host half entrylib/index.js.
Host (lib/index.js + lib/typert.host.js)
EditRegenerateService extends TypertRemoteService registers the Cordis service editRegenerate, exposed to the client through the ./typert manifest via @deepseek-ai/dsh-typert-loader:
resolve(sessionId, seq)— reads the session event log, locates the user message, and computes the precedingturn/endas the fork boundary; for the first message it resolves the owning workspace.
Browser (lib/client.js)
- Mounts
TYPERT_REMOTEand installsremote.editRegenerateinto the runtime; - takes over the
conversation.chat.nodeslot'suserkey renderer atpriority: -1(the stockuserrenderer is shadowed; other keys such assteeringare unaffected), rendering an editable user bubble that keeps the copy action (⧉ 复制next to✎ 编辑) so no stock functionality is lost.
Install (persistent)
The plugin is installed per profile — pick the profile that matches how you run DSH:
| Version | Profile | Windows | macOS | Linux |
|---|---|---|---|---|
| DSH Desktop app (Electron) | desktop | C:\Users\<user>\.dsh\profiles\desktop | /Users/<user>/.dsh/profiles/desktop | /home/<user>/.dsh/profiles/desktop |
Official launcher / CLI (dsh web) | web | C:\Users\<user>\.dsh\profiles\web | /Users/<user>/.dsh/profiles/web | /home/<user>/.dsh/profiles/web |
# DSH Desktop app
dsh plugin --profile desktop add file:./dsh-plugin-edit-regenerate
# Official launcher / CLI
dsh plugin --profile web add file:./dsh-plugin-edit-regenerate
Or manually: append dsh-plugin-edit-regenerate to dsh.profile.bundles and add "dsh-plugin-edit-regenerate": "file:<absolute path>" to dependencies in that profile's package.json (e.g. C:\Users\<user>\.dsh\profiles\desktop\package.json on Windows, or ~/.dsh/profiles/desktop/package.json on macOS/Linux), then run pnpm install in the profile directory.
Restart DSH for the changes to take effect. The two profiles are independent — installing into one does not affect the other.
Troubleshooting
A forked conversation fails to reload after restarting DSH (SessionFormatUnsupportedError: ... unknown to this harness and not marked ignorable)
A fork copies the parent session's event log verbatim. If the parent contains events written by other plugins that this harness build does not recognize and that are not marked ignorable in their envelope — e.g. the session/distill-review-request event written by @loserfox/distill before its #5 fix — the forked log refuses to load after a restart (the parent session itself is affected the same way). The plugin releases that wrote those events have since stopped writing them, but logs that already contain them need a one-time migration: mark the offending events ignorable: true.
Run the bundled repair script (stop DSH first):
node scripts/repair-session-logs.mjs
It discovers every session.jsonl.zstd under $DSH_HOME/sessions (default ~/.dsh/sessions), marks the legacy events ignorable while preserving the rest of the log byte-for-byte, and backs each file up to <file>.bak. Pass explicit log paths for a targeted run, or --dry-run for a preview of what would change.
License
MIT