Skip to content
dsh.fish
Bundle

dsh-delete

DSH-DELETE: recoverable conversation deletion for DeepSeek Harness — a session menu item and /delete-conversation command that queue deletions, hide sessions immediately, and move logs to a recoverable trash on restart

Source
Hyna-hla
stars
1 stars
License
MIT
Updated
Updated yesterday

Readme

# DSH-DELETE

**English** | [中文](README.zh.md)

Recoverable conversation deletion for DeepSeek Harness: adds a **Delete conversation** item to the session row `…` menu and registers the `/delete-conversation` human command. After confirmation the target Session enters a deletion queue and is immediately hidden from the list through the Workspace persisted archive projection; on the next DSH startup the plugin validates the Session's full lifecycle before the Web Workspace builds its session index, then atomically moves its log directory into a recoverable trash.

> Derived from [omdsh-dev/dsh-essential](https://github.com/omdsh-dev/dsh-essential) (MIT, Copyright (c) 2026 ExDragine). This repository renames the package / Remote IDs / UI class names to `dsh-delete` and adds a `stateDir` default (`~/.dsh/conversation-trash`) so marketplace one-click installs need no manual config.

## Why deletion is two-phase

DSH's Session persistence is append-only and the public services expose no delete method; an active Agent's destroy handle belongs to its creator only. The plugin cannot safely move logs out from under an active writer. Deletion therefore happens in two phases: the running process only writes a durable request and hides the row immediately; the next startup completes the log move before any session recovery. This boundary avoids log rebuilds, partial writes, and lifecycle races.

## Install

### Option 1: DSH plugin marketplace (recommended)

This repository ships built artifacts (`lib/`), so marketplace one-click install needs no build and no config:

1. DSH Web GUI → Settings → DSH plugin marketplace
2. Search `DSH-DELETE`, click **Install**
3. Restart DSH

### Option 2: official bundle install

```sh
node /path/to/DSH/apps/cli/lib/bin.js plugin --profile web add /path/to/DSH-DELETE
```

Restart DSH afterwards. The bundle mounts `dsh-delete` and makes the Web Workspace wait for the `conversationDeletion` service to finish startup recovery before building the Session index.

### Option 3: write cordis.patch.yml directly

```yaml
- insert:
    - id: dsh-delete
      name: dsh-delete
      config:
        stateDir: /absolute/path/to/conversation-trash
- id: workspace
  inject: [conversationDeletion]
```

`stateDir` must be absolute and outside Session artifact directories; it defaults to `~/.dsh/conversation-trash`.

## Usage

- Open the target session's `…` menu in the session list and choose **Delete conversation**. Confirmation is an in-page card (title "Confirm deleting this conversation?", actions "Cancel / Delete conversation") — no native browser dialogs.
- A confirmed request archives the Session immediately, hiding it across all session groups (the row disappearing is the success feedback).
- If the request was written but the archive call failed, the card reports "queued but cannot hide yet" instead of misreporting a failed deletion.
- Human command: `/delete-conversation CONFIRM` (deletes the current conversation); `/delete-conversation <session-id> CONFIRM` (deletes another conversation by Session id).

After confirming, restart DSH; logs are moved to `<stateDir>/trash/<session-lifecycle-key>/`. `deletion.json` inside records the original directory.

## Recovery

Stop DSH, delete the `deletion.json` inside the recovery directory, then move that directory back to `originalDirectory`. Do not recover while DSH is running.

## Config

| Field | Type | Default | Description |
|---|---|---|---|
| `stateDir` | string | `~/.dsh/conversation-trash` | Directory holding pending requests and the recoverable trash; must be absolute and outside Session artifact directories |
| `commandName` | string | `delete-conversation` | Optional human-command alias (no leading `/`); the menu always uses the stable `/delete-conversation` |

## Safety and recovery semantics

- The command requires the literal `CONFIRM`; nothing is written without it.
- Requests bind `sessionId`, `createdAt`, and `cwd`; a reused id will not delete a new Session lifecycle.
- The move re-validates the persisted list, backend location, and full inspect results.
- The product operation uses same-filesystem directory `rename`, never `unlink` of Session logs; post-move crashes are recoverable.
- Validation/move failures keep the pending request and record an error; the original log stays untouched.
- **Per-Session JSONL backends only**: SQLite has no independent artifact location, and the plugin refuses it explicitly.
- **Not permanent erasure**: logs go to a recoverable trash; retention and final cleanup are deployment-administrator policy.

## Building from source

Requires Node `^22.19.0 || >=24.0.0` (tsdown needs `Promise.withResolvers`). On Windows keep the Node 22+ used for building first in PATH:

```sh
pnpm install
pnpm add -D -w unrun   # optional peer of tsdown; must be explicit when autoInstallPeers=false
pnpm run build
pnpm run verify:self-contained
pnpm run typecheck
pnpm test
```

## License

MIT. Original copyright belongs to [dsh-essential](https://github.com/omdsh-dev/dsh-essential) (Copyright (c) 2026 ExDragine); see [LICENSE](LICENSE).

Install

dsh plugin --profile web add github:Hyna-hla/DSH-DELETE

Profile: web

  • 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.
Source