Bundle
dsh-undo
Durable multi-level context undo/redo for DeepSeek Harness, with per-user-message WebUI actions.
- Source
- LingLambda
- stars
- 4 stars
- License
- MIT
- Updated
- Updated 3 days ago
Readme
# dsh-undo
English | [中文](README.zh.md)
> [!WARNING]
> **Forward-looking preview: this release is not usable with any currently published DeepSeek Harness version.** It depends on unreleased Harness support for durable `surface/rewind` / `surface/restore` events and the `conversation.chat.user-actions` WebUI slot. Installing it today will make `/undo` fail closed with an upgrade message. Publish this package only to preview and coordinate the future integration; do not present it as production-ready until the matching Harness release exists. look for <https://github.com/deepseek-ai/deepseek-harness/discussions/467/>
Durable, multi-level undo/redo for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (`dsh`). It rewinds model context by real user turn and restores workspace files changed by tools in that turn.
The commands are handled locally and are never sent to the model:
- **`/undo`** rewinds the latest visible real user message and every surface message after it.
- **`/undo <user-seq>`** rewinds from a specific visible user message, including all later turns.
- **`/redo`** restores the latest active rewind. Repeated undo and redo operations use LIFO order.
The WebUI client contributes an undo action to finalized real-user message bubbles. The action invokes `/undo <user-seq>`; the Host validates that the addressed message is still a legal rewind target.
## How It Works
Harness sessions remain append-only. Undo appends a dedicated `surface/rewind` control event for the exact current surface suffix; redo appends `surface/restore` for the newest active rewind. The original message nodes, message IDs, tool-call correlations, and log events are retained. Session replay reconstructs the same visible surface and redo stack after restart.
Before and after each top-level tool execution, the plugin records a workspace tree using an isolated hidden Git directory under `~/.dsh/dsh-undo/snapshots/`. It does not create commits, switch branches, or modify the repository's own Git index. Undo restores only files touched by tools in the selected user turns; redo restores the pre-undo tree. Patch and redo metadata are stored per session so file redo can survive a Host restart.
Workspace tracking includes tracked files and untracked files up to 2 MiB. Files ignored by the repository and larger untracked files are left untouched. A small two-phase journal reconciles interrupted file operations against the durable active-rewind stack after restart. If the session has no Git workspace, context undo/redo still works and the command reports that file restoration is unavailable.
Background jobs returned by top-level tools are associated with their user turn. Undo requests termination for jobs started in the removed turns. Redo restores context and files but cannot restart terminated processes.
## Requirements
This plugin requires a Harness version that supports:
- Durable `surface/rewind` and `surface/restore` session events.
- The `conversation.chat.user-actions` client slot for the WebUI action.
Older Harness releases fail closed: `/undo` reports that a compatible Harness upgrade is required instead of writing replacement assistant messages or copying transcript events.
## Limits
- File restoration is limited to the detected Git workspace. It never restores files outside that root.
- Network requests, database writes, remote API calls, already-exited processes, and other external effects cannot be undone.
- Background jobs started through nested tool dispatches or child agents may not be associated with the root user turn.
- Undo signals recorded top-level background jobs but does not wait indefinitely for process exit.
- New ordinary surface output invalidates active redo history according to Harness surface semantics.
## Install
The package is a [dsh bundle](https://deepseek-harness.github.io/deepseek-harness/develop/basic/publish/). `package.json` points `dsh.bundle` to `cordis.patch.yml`, which activates the Host plugin, and exposes a WebUI Client bundle.
From npm:
```sh
dsh plugin --profile demo add dsh-undo
```
From git (the `prepare` script builds `lib/` during installation; authorize the build in the profile's `pnpm-workspace.yaml` first):
```sh
dsh plugin --profile demo add github:LingLambda/dsh-undo#<sha>
```
For local development against a Harness checkout, load the Host source with an overlay:
```sh
pnpm dsh web --patch ./cordis.patch.yml --patch /absolute/path/to/dsh-undo/overlay.yml
```
```yaml
- insert:
- id: undo
name: /absolute/path/to/dsh-undo/src/index.ts
```
## Usage
```text
/undo
/undo 42
/redo
```
Use `/undo` for the latest user turn, the action on an older user bubble to rewind from that point, and `/redo` to restore the most recent rewind.
## Develop
```sh
corepack yarn install
corepack yarn typecheck
corepack yarn test
corepack yarn build
```
## License
MIT
Install
dsh plugin --profile web add github:LingLambda/dsh-undo
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-undo from the hub
- This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.