dsh-workspace-relink
English | 中文
Workspace routing migration for DeepSeek Harness. Move a project folder, then repoint its workspace at the new location — the conversations that lived in the old folder keep working, without a single byte of session history being rewritten.
The problem it solves
A DSH workspace is one registry record pointing at one directory, and a stored
session is grouped into a workspace by the canonical form of cwd recorded in
its immutable header. Move the files and both halves break at once:
- the workspace reports
missing-dir; - the conversations it lists cannot resolve their working directory, so every tool call fails until the directory is back.
There is no relocation API — the header is append-only storage — so the only honest fix is to make the old directory spelling resolve again while the workspace record moves to the new canonical path. That is exactly what a directory route (a Windows directory junction) does, and it is why this plugin is about routing, not about editing history.
What it does
D:\A\B\C ──► moved by you to ──► D:\E\F\A\B\C
│ │
└── becomes a junction ───────────────┘
(workspace record now lives here)
- You move the files yourself (this plugin never moves or deletes your data).
工作区路由迁徙(Plugins → the plugin's page) plans the move: it checks the new directory, says whether the old path is free, and lists what it will do.- On apply it creates the junction at the old path, creates (or reuses) the workspace at the new canonical path, transfers each session's ownership through the registry's own attach/detach validation, and retires the old registration once nothing is left in it.
The same page can move a single conversation into another workspace, and manages the junctions it created (inspect them, remove them).
Requirements and limits
- The old and new directories must be reachable from the same machine; a junction is a local filesystem object.
- Junction creation needs no elevation on Windows (
fs.symlink(..., 'junction')). - A leftover old directory (copy instead of move) blocks the plan until you let
the plugin rename it aside as
<name>.moved-<timestamp>; nothing is deleted. - Removing a junction is allowed only for routes this plugin recorded, and only while the path still is a junction. Conversations that resolved their working directory through it go back to reporting a missing directory.
- A conversation whose recorded directory is a different existing directory cannot be re-homed into a workspace it does not resolve to — DSH refuses that ownership transfer, and so does this plugin, instead of silently detaching it.
- Sessions whose logs carry no
cwdare reported as untransferable rather than guessed at.
The page
Plugins → 工作区路由迁徙.
- Every workspace with its path, status badge, session count, and expandable session list.
- Per workspace:
修改位置→ new path,浏览…,预览计划,执行迁徙, with blockers and warnings spelled out before anything is written. - Per session: move it to another workspace.
- Recorded routes with target liveness and a remove button.
Agent tools
Available to the model unless agentTools is false:
| Tool | Purpose |
|---|---|
workspace_relink_status |
Workspaces, paths, status, session counts, recorded routes. includeSessions: true also returns each session's id, title, recorded cwd, cwdState and live flag |
workspace_relink_plan |
Dry run for repointing one workspace |
workspace_relink_apply |
Execute it (confirmed: true required) |
workspace_relink_move_session |
Move one conversation into another workspace |
workspace_relink_route_remove |
Remove one recorded route |
Every tool answers with a one-line human summary plus the full JSON payload as a
second text block, so the model can read plan.blockers[].code, workspace ids and
session titles instead of guessing from prose.
Configuration
| Key | Default | Meaning |
|---|---|---|
agentTools |
true |
Expose the tools above to the model; the page always works |
allowSessionRoutes |
true |
Allow creating a route when moving a conversation whose directory is gone |
Bookkeeping
Routes this plugin created are recorded in
<DSH_HOME>/workspace-relink/routes.json (absolute paths, kind, ids, timestamp).
It is an index over the filesystem, never the authority: a hand-made symlink is
never touched, and a recorded route whose link is gone is simply reported.
Self-test
node scripts/selftest.mjs
The harness exercises the engine against a stand-in registry that reproduces
DSH's membership canon (realpath(header.cwd) equality, plus the missing-cwd
wildcard): broken state, plan, apply, route reuse, refusal cases, leftover
directory displacement, single-session adoption, and route removal. It writes
nothing outside a temporary directory.
License
MIT © dsh-workspace-relink contributors
No comments yet. Be the first to write one.