Skip to content
dsh.fish
Bundle

dsh-session-surgeon

Repair DeepSeek Harness sessions that refuse to load (seq gap, torn zstd frames, lone surrogates).

Source
xiaoshenming
stars
5 stars
License
MIT
Updated
Updated 5 hours ago

Readme

# dsh-session-surgeon

Copy a session ID from the sidebar ⋯ menu, then paste it into a new chat so the new session can learn from the old one — the Codex-style “continue from this thread” move that stock DSH does not expose.

Also repairs DeepSeek Harness sessions that refuse to load — seq gap, torn zstd, lone surrogates, and events missing their message id. `inspect` also **warns** on dangling `tool/call` (no matching `tool/result` → next model request 400) but **will not invent** a fake result. 官方以后修加载器,也救不回已经坏掉的 `session.jsonl.zstd`。

> Compatible with `@deepseek-ai/dsh@0.1.2-rc.1` and 0.1.3-alpha format generations (`session.vN.jsonl.zstd`). Catalog, seq-range handling, and format version follow the *installed* runtime.

## Why copy the session ID

Stock DSH session ⋯ only has rename / fork / archive. There is no “copy ID”.

After this plugin:

1. Left sidebar, click ⋯ on a session → **复制会话 ID**
2. Open a new chat and paste something like:

   ```text
   Continue from session session-1e66cda9-a046-4893-8f4b-b817080acbea.
   Read that log if you need prior context.
   ```

   or, for an agent with tools:

   ```text
   session_inspect id=session-1e66cda9-a046-4893-8f4b-b817080acbea
   Then keep going from where that conversation left off.
   ```

The ID is the durable handle (with or without the `session-` prefix — same session). Fork duplicates a file; copying the ID lets a **new** session refer to the old one, the way people pass a Codex thread id around.

## Install

One command, same as other DSH plugins:

```bash
dsh plugin --profile web add "github:xiaoshenming/dsh-session-surgeon#main"
```

Restart `dsh web`. Then:

- Session ⋯ menu: **复制会话 ID** (the everyday action) / inspect / dry-run repair
- Sidebar **会话医生 / Session surgeon**: browse conversations, copy id, dry-run repair, apply repair, compact preview, export JSONL

Developers working in a checkout can still use `dsh plugin --profile web add link:"$(pwd)"`.

In an agent chat that has this checkout (or the installed plugin skills), **更新插件** is enough: scan official Discussions, absorb in-scope repair feedback, changelog, reply, push `main` via `px` (`127.0.0.1:7897`). See [skills/dsh-session-surgeon-update/SKILL.md](./skills/dsh-session-surgeon-update/SKILL.md).

## Also: repair unloadable sessions

Real crash families from official Discussions:

- [#317](https://github.com/deepseek-ai/deepseek-harness/discussions/317) stack overflow on huge history
- [#1497](https://github.com/deepseek-ai/deepseek-harness/discussions/1497) / [#1586](https://github.com/deepseek-ai/deepseek-harness/discussions/1586) `seq gap in committed region`
- [#436](https://github.com/deepseek-ai/deepseek-harness/discussions/436) lone UTF-16 surrogate → permanent HTTP 400
- [#674](https://github.com/deepseek-ai/deepseek-harness/discussions/674) leftover `.tmp` plaintext

Default repair is dry-run. `--apply` writes `.bak.<utc>` first, never invents missing seqs, and fills missing message ids without dropping events. If a crash-recovery closer collided with a still-live writer (#1586), repair drops those synthetic closers and keeps the live tail instead of truncating at the first gap. A packed chunk row that overlaps already-committed seqs but continues through the cursor (#5151) keeps the uncommitted suffix. Compact refuses an unloadable file — repair first, with all writers stopped. Alpha compressed `sourceEventSeqs` ranges (#5160) are native on 0.1.2-rc.1+ (surgeon does not rewrite). Older rc.2 still cannot fold them — repair expands inclusive pairs into dense integers; nothing is invented. A validated Alpha `model/selection` event is preserved and marked `ignorable: true` for rc.2; arbitrary unknown plugin events are never changed. Empty `tool_calls[].id` (#5182) is flagged `empty-tool-call-id`; repair will not invent an id. Sessions that refuse to load **after upgrading to 0.1.5** (#6151 / #6175 / #6189 / #6194 — extra `permission/preset` members, `subagent/descriptor` version 2, mismatched plugin-source `form`/`summary`, broken chunk provenance) are normalized losslessly against the released v0 inventory — verified against the real `sessionFormatV0ToV1` stage — when the installed runtime migrates v0 itself. Unknown types (`session/imported`, plugin messages) are reported only; the converter refuses them even when `ignorable` and repair never deletes events.

## CLI

No `dsh web` required after the plugin (or this repo) is on disk:

```bash
npx --yes github:xiaoshenming/dsh-session-surgeon scan
npx --yes github:xiaoshenming/dsh-session-surgeon inspect <session-id>
npx --yes github:xiaoshenming/dsh-session-surgeon repair <session-id>          # dry-run
npx --yes github:xiaoshenming/dsh-session-surgeon repair <session-id> --apply  # writes .bak.<utc> first
```

Or from a clone: `node bin/dsh-session-surgeon.mjs scan`.

Agent tools after install: `session_scan` / `session_inspect` / `session_repair` (`apply` defaults to false).

## Commands

| command | meaning |
|---|---|
| `scan [root]` | list sessions + header health + orphan `.tmp` |
| `inspect <id>` | decode every zstd frame, expand packed rows, report seq gaps / missing ids / dangling tool/call |
| `repair <id>` | default `--dry-run`; `--apply` rewrites after `.bak.<utc>` |
| `compact <id> --keep-last-turns N` | keep the last N complete turns, renumber seq from 0 |
| `export <id>` | JSONL dump; redacts secrets unless `--no-redact` |
| `index [root]` | session / parent / goal / health table |

`--format text` prints a human table. Exit 0 on success, 2 on usage error, 1 on not-found / refuse.

## What this is not

Not a marketplace, not a token heatmap, not a memory plugin, not a Codex task store.

DSH has **session id + optional same-session goal id**, not a Codex-style resumable task id. Copying the session ID is the closest everyday equivalent. See [docs/LEARNING-TASKS.md](./docs/LEARNING-TASKS.md).

## Docs

- [docs/PLAN.md](./docs/PLAN.md) — milestones, safety, release
- [docs/SESSION-FORMAT.md](./docs/SESSION-FORMAT.md) — zstd frames, header, packed rows, when the official loader refuses
- [docs/REPAIR-SPEC.md](./docs/REPAIR-SPEC.md) — repair steps aligned with the official loader
- [docs/LEARNING-TASKS.md](./docs/LEARNING-TASKS.md) — why there is no Codex task id
- [docs/IMPLEMENTATION-CONTRACT.md](./docs/IMPLEMENTATION-CONTRACT.md) — multi-agent implementation contract
- [CHANGELOG.md](./CHANGELOG.md) — user-facing changes

## Safety

- Default is read-only. Write paths require `--apply` and write `.bak.<utc>` first. Windows: fsync on the read-only backup handle used to abort with `EPERM` after the copy already succeeded; `--apply` now treats that as best-effort.
- Never commit raw files from `~/.dsh/sessions` (they contain user text and secrets).
- Do **not** put `@deepseek-ai/dsh-tools` in `dependencies`.
- Export redacts `sk-*`, PEM blocks, and home paths unless `--no-redact`.

## License

MIT

Install

dsh plugin --profile web add github:xiaoshenming/dsh-session-surgeon

Profile: web

  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source