DSH Plugins Marketplace

DSH Plugins

Plugins

/

dsh-session-migration

A

dsh-session-migration

Manifest valid

DeepSeek Harness session migration panel: move a session (log, header cwd, workspace membership) into another workspace from a button in the session header.

UI (client)hasBundlePatch

DSH Session Migration

A button in the DeepSeek Harness session header that moves a whole session — log, header.cwd, and workspace membership — into another working directory, with session browsing, one-click backup export, and a workspace health check.

English | 中文

icon

Why a tool is needed

A DSH session's workspace membership is decided by three things:

#WhereWhat
①~/.dsh/sessions/<projectKey(cwd)>/<sessionId>/session.v4.jsonl.zstdthe directory name encodes the working directory
②the header in frame 1 of the logthe cwd is stored again inside the log
③~/.dsh/storages/workspace.json → workspace.sessionIdsdecides which workspace lists it

Moving the folder by hand trips one of three real crash modes:

  • A — two copies of one sessionId (copy instead of move): the start-up scan conflicts and the session list scrambles.
  • B — a registry entry pointing at data that is gone: the whole workspace refuses to open, and directoryPickerController goes unavailable with it.
  • C — editing workspace.json while DSH runs: the in-memory registry overwrites it on exit, so changes are half-applied.

This plugin performs the flow behind one button, and uses only DSH's own services and (byte-exact) storage conventions: move, never copy; rewrite only frame 1; write the registry only through the live workspaceRegistry Service.

Features

  • Migrate a session to an existing workspace or any browsed directory: preflight first, then execute, with an automatic backup, byte-level verification, automatic rollback, and copy-paste rollback commands.
  • Optionally move the source working-directory files into the target (top-level entries; a name clash is a refusal; the old directory stays as an empty directory so other sessions keep working).
  • Session list: id, working directory, log size, frame count, last write, current membership, and problem badges.
  • Health check: dangling references, duplicate ids, header/directory mismatch, empty logs, missing workspace directories, unregistered sessions. Dangling references can be removed safely through the live registry — no shutdown needed.
  • Export a backup: copy the session directory to a destination of your choice, with a migration-export.json manifest, without touching the registry.

Install

Local directory (best for self-hosting):

plugin_manager install_bundle  target = C:\path\to\dsh-session-migration

From GitHub:

plugin_manager install_bundle  target = git+https://github.com/Alvin070911/dsh-session-migration.git

Or add the row to a profile's cordis.patch.yml yourself:

- insert:
    - id: session-migration
      name: dsh-session-migration

The browser half is picked up automatically from the dsh.client declaration. If the button does not appear, reload the page once — a freshly installed client bundle needs the page to walk the module graph again.

Usage

  1. Open any session; an icon button (two panels, one arrow) appears in the header utilities.
  2. Pick the session to migrate in the left column. The session currently in use cannot migrate itself — its log is open, so the plugin refuses.
  3. Pick a target workspace, or switch to "custom path" and type/browse any directory.
  4. Read the preflight: project-key change, target session directory, whether the workspace will be created, and the file-move entry count and clashes.
  5. Click “Start migration”, then “Confirm migration”.
  6. The result lists each step: backup → data move → header rewrite → verification → file move → workspace membership.

About “restart required”

The workspace step reports pending-restart by design, not as a failure:

The live workspace registry is a start-up snapshot indexed from session headers; a plugin cannot refresh it in place, and writing workspace.json by hand while DSH runs is crash mode C.

So the membership write goes into a queue (~/.dsh/plugin-data/dsh-session-migration/pending.json) and is applied on the next DSH start, with the outcome logged. Nothing to do manually: restart once and the session appears under its new workspace. The “Pending” tab can retry it sooner.

Safety model

InvariantHow
Move, never copyan existing target session directory is a refusal; the target log size is verified after the move
No dangling registry referencesthe registry is written only through workspaceRegistry, and only after the data is in place
Only frame 1 changesdecompress frame 1, set cwd, recompress frame 1, concatenate the untouched tail
Verifiable integritycompare everything after frame 1; a growing frame count (chat continues) is not a failure
Idempotenta repeated move to the same target is a same-target no-op, never a second copy
Rollbackany failure moves data back, restores the .bak, removes a created workspace, and prints copy-paste rollback commands
No self-migrationliveness comes from the agents Service; a live session is refused

Why "decompress, edit, recompress" is wrong

zlib.zstdDecompressSync(log) returns only the first frame — normally the ~200-byte header. That looks like “the whole log is one line”, and code that concludes the session is empty or corrupt can delete real history. This plugin therefore walks RFC 8878 frame/block headers for exact frame boundaries (falling back to a magic-byte scan), counts frames in chunks without loading an 18 MB log into memory, and replaces frame 1 only.

Health checks

codeseveritymeaningauto-fix
dangling-referenceerrorthe registry names a session that is not on disk✅ one click
duplicate-sessionerrorthe same sessionId exists under several project keys❌ keep the newer one, back up the other
cwd-mismatcherrorheader.cwd disagrees with the project directory❌ manual
id-mismatcherrordirectory name ≠ header.id❌ manual
empty-log / missing-logerrorzero bytes, or no log at all❌ manual
missing-workspace-dirwarnthe workspace directory is gone❌ report only
orphan-sessionwarnno workspace accounts for the session (invisible in the UI)❌ report only

“Small log” is not dirty data: an empty session's header is about 300 bytes and is perfectly valid.

Configuration

The row's config in cordis.patch.yml (defaults shown):

- id: session-migration
  name: dsh-session-migration
  config:
    backupBeforeMove: true        # full copy of the session directory before touching it
    keepBackups: 10               # how many automatic backups to retain
    tryImmediateAttach: true      # try to write membership immediately (usually blocked by the index snapshot)
    pendingApplyDelayMs: 2500     # how long after start to apply the queue
    dshHome: ''                   # defaults to $DSH_HOME, then ~/.dsh
    sessionsRoot: ''              # defaults to <dshHome>/sessions

Data this plugin owns:

<dshHome>/plugin-data/dsh-session-migration/
  pending.json                 deferred membership writes
  backups/<stamp>-<sessionId>/ pre-migration backups
  exports/<stamp>-<sessionId>/ manual exports

Manual rollback

Every migration prints its own rollback commands; typically (with DSH fully exited):

Remove-Item -Recurse -Force "<targetDir>"
Copy-Item -Recurse "<backup>" "<targetDir>"

session.v4.jsonl.zstd.bak inside the session directory is the pre-rewrite log; DSH never treats it as a real generation. To undo the membership too, delete the matching entry from pending.json.

Development

node --check index.js client.js lib/*.js
node --test      # 31 cases: projectKey, frame walking, header rewrite, move & rollback, client contract

Layout:

index.js        Host entry: mounts /dsh-session-migration/api, applies the membership queue after start
lib/paths.js    projectKey / encodeSegment / DSH home / path canonicalization (mirrors DSH)
lib/frames.js   zstd frame walking, header read, frame-1 replacement, tail comparison
lib/scan.js     session scan, raw registry read, doctor rules
lib/engine.js   plan / move / verify / rollback / file move / export / pending queue / HTTP dispatch
client.js       browser half: header button + shell.overlay dialog

Only Node built-ins are imported, so the package can be published and installed on its own.

Known limits

  • The open session cannot migrate itself (its log is held open). That is a guard, not a bug.
  • Only frame 1 of a v4 log is rewritten; let DSH finish any cross-version format migration first.
  • Moving a whole workspace directory is out of scope: a workspace path is fixed by realpath at registration, so relocating it makes the old workspace missing-dir. The plugin moves contents and keeps the source directory.
  • Exporting a session that is being written can capture a torn tail; DSH discards a torn tail when reading, and the source is untouched.

Publishing

gh repo create dsh-session-migration --public --source . --remote origin --push

Then anyone can install it directly:

plugin_manager install_bundle  target = git+https://github.com/Alvin070911/dsh-session-migration.git

License

MIT. Storage format, projectKey rules, and workspace semantics follow the DSH version you run (dsh-session-persistence-jsonl, dsh-workspace).

Comments

Loading…

Similar plugins

dsh-session-mover

by baisama-cloud

Move a session to another workspace by dragging it onto the target workspace header in the sidebar: the session is cloned with full history into the target workspace and the original is archived.

Tools & CapabilitiesTerminal & ClientsSessions & MessagesManifest valid

★ 2

MIT

JavaScript

Aug 22, 2026

dsh plugin --profile web add dsh-session-mover

by ame-code

Move a DeepSeek Harness workspace (folder tree, nested workspaces, sessions) to a new location from the sidebar — with rename, rollback and undo.

Development & InfrastructureSessions & MessagesManifest valid

★ 1

MIT

JavaScript

Nov 10, 2026

dsh plugin --profile web add @reed-io/dsh-workspace-move

by FurryBear2025

Drag a session onto another workspace in the DSH sidebar and it really moves: the session-log header cwd is rewritten and the log directory is re-homed under the target project, with a progress bar wh

UI & ExperienceSessions & MessagesManifest valid

★ 2

MIT

JavaScript

Oct 13, 2026

dsh plugin --profile web add dsh-session-drag-move

by ailiasdesu

DSH session migration plugin: drag-and-drop sessions between workspaces in the Web UI settings panel (auto backup/rollback, official workspaceRegistry sync)

Terminal & ClientsManifest valid

★ 0

BSD-3-Clause

JavaScript

Aug 28, 2026

dsh plugin --profile web add @dsh-external/dsh-session-manager

by yvban

DSH plugin: move sessions between workspaces safely — frame-level zstd header rewrite, byte-level verification, full-directory backup, live membership update

Manifest valid

★ 0

MIT

JavaScript

Oct 14, 2026

dsh plugin --profile web add dsh-session-mover

by mienfong

Move, archive, restore, portable backup/export and import sessions across workspaces in the DeepSeek Harness web UI.

Sessions & MessagesManifest valid

★ 8

↓ 351/wk

MIT

JavaScript

Oct 4, 2026

dsh plugin --profile web add dsh-session-mgr