houlain
dsh-workspace-studio
DeepSeek Harness plugin: workspace file browser + code viewer + session change diff + per-hunk partial revert (Trae-style). Windows verified only; Linux/macOS untested — use with caution.
- Stars
- 0
- Language
- TypeScript
- Created
- Aug 16, 2026
- Updated
- Aug 16, 2026
Introduction
dsh-workspace-studio
⚠️ Platform status: Windows verified only. This plugin has been tested on Windows (PowerShell). It has NOT been verified on Linux or macOS — path handling, shell behavior, and sandbox interactions may differ on those platforms. Use with caution on non-Windows systems.
A DeepSeek Harness (dsh) plugin that turns the Web UI into a lightweight coding workspace with Trae-style partial revert:
- Workspace file browser — collapsible file tree; build-artifact noise filtered; folders containing changed files are auto-expanded with count badges; modified files are marked with a dot.
- Code viewer — click any file to view its content with line numbers.
- Change review (git-style diff) — every
write/editthe agent makes is tracked with full before/after snapshots and rendered as line-level diff hunks, with live SSE updates. - Per-hunk partial revert / accept — revert one change block at a time (like Trae), or mark it as accepted; resolved changes stop being shown and stop being marked. Conflict protection rejects reverts when the region was modified afterwards.
⚠️ Important notes
- Windows-only (verified). Linux/macOS are unverified — use at your own risk on those platforms.
- Change tracking is per session — a session only sees its own changes (by design).
- Only
write/edittool calls are tracked. Direct file edits made outside those tools (e.g. in your own editor) are not recorded.
Install
From GitHub (recommended)
dsh plugin --profile web add github:houlain/dsh-workspace-studio
Then restart dsh web and open a new session.
Manually (no pnpm required)
-
Copy the package into the profile's
node_modules:$src = "<your-clone-path>\dsh-workspace-studio" $dst = "$env:USERPROFILE\.dsh\profiles\web\node_modules\dsh-workspace-studio" Copy-Item -Recurse -Force $src $dst -
Register it in the profile's
package.json:{ "dependencies": { "dsh-workspace-studio": "0.1.0" }, "dsh": { "profile": { "bundles": ["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-web-app", "dsh-workspace-studio"] } } } -
Restart
dsh web.
The package ships pre-built (
lib/), so no build step is needed for installation. The installed copy must be a copy, not a symlink into a directory you keep editing — rebuild and re-copy after updating.
Usage
- Open a session in the Web UI and switch to the 「Studio」 tab (next to Chat).
- The left pane shows the workspace file tree:
- Folders are collapsible (
▸/▾); folders containing pending changes show a count badge and auto-expand. - Files modified by the agent carry a ● marker.
- Folders are collapsible (
- Click a file to view its content (top-right) and its change panel (bottom-right).
- Each change operation shows one or more change blocks (hunks) with two actions:
- 「撤回此块」(Revert this block) — undoes only that block; other blocks stay. A confirm dialog appears, then the file is rewritten on disk.
- 「认可」(Accept) — keeps the change; the block stops being shown/marked and can no longer be reverted.
- 「撤回全部修改」(Revert all) restores the file to its state before this session's first recorded change (files created in this session are deleted).
- 「清空」(Clear) removes this session's change records (does not touch file contents).
- The Studio tab label shows a badge with the number of files that still have pending changes; it and all markers update in real time via SSE when the agent edits files.
Revert safety rules
- A hunk can only be reverted if its exact lines are still present in the file. If a later change modified that region, the revert is rejected with a hint (conflict protection).
- A hunk that was reverted or accepted cannot be acted on again.
- Reverting a hunk of an old operation works even when later operations shifted line numbers elsewhere.
Architecture
One package, two halves (dsh.bundle + dsh.client manifests), mounted as a single loader entry:
dsh-workspace-studio/
├── src/
│ ├── core/ # Pure logic, zero deps, fully unit-tested
│ │ ├── diff.ts # LCS line diff → hunks with context
│ │ ├── ledger.ts # before/after snapshot ledger + persistence
│ │ ├── hunkRevert.ts # per-hunk reverse apply + conflict detection
│ │ └── fileTree.ts # tree builder with ignore rules
│ ├── host/ # Node half: tools/result listener, HTTP/SSE routes, ctx.fs
│ ├── client/ # Browser half: Studio view (React, no external deps)
│ └── shared/ # Payload types shared by both halves
├── lib/ # Pre-built bundles (lib/index.js host, lib/client.js browser)
└── tests/ # 67 tests (node:test, no test framework dependency)
HTTP routes (same-origin, all under /ws-studio/*)
| Route | Method | Purpose |
|---|---|---|
/ws-studio/tree?root= | GET | Workspace file tree |
/ws-studio/file?path= | GET | File content (size-capped) |
/ws-studio/ops?session= | GET | Change operations with hunks (pending only in the file list) |
/ws-studio/revert?session= | POST | Revert one hunk, or the whole file (no op/hunk) |
/ws-studio/accept?session= | POST | Accept one hunk |
/ws-studio/clear?session= | POST | Clear the session's change records |
/ws-studio/context?session= | GET | Session working directory |
/ws-studio/events | GET (SSE) | Live change notifications |
Data & persistence
- Change snapshots persist to
<profile-dir>/ws-studio-state.json(e.g.~/.dsh/profiles/web/ws-studio-state.json), debounced, atomic write, flushed on exit. - Per-file capacity guards: max 100 operations per file, 120 KB per snapshot (oversized operations are recorded without content — visible but not revertible).
Sandbox awareness
- Revert writes go through the harness filesystem service (
ctx.fs) with a session-level sandbox policy (workspace-write+ the session's workspace root), so writes outside the session workspace are rejected by the harness sandbox itself. - File tree and reads also go through
ctx.fswhen available (fallback:node:fs).
Security & privacy
- No telemetry, no analytics, no external network calls. All routes are same-origin; the plugin never contacts any third-party server.
- The plugin does not read or store credentials, API keys, environment secrets, or OS/user metadata.
- The only data stored on disk is the change ledger (file paths + file contents that were edited during a session) plus UI state.
- Sandbox policies of the harness still apply to revert writes.
Configuration
The file tree ignores common noise by default (.git, node_modules, dist, build, lockfiles, coverage, etc.). The ignore list lives in src/core/fileTree.ts (DEFAULT_TREE_OPTIONS) — rebuild if you want to customize it.
Development
Requirements: Node.js ≥ 22.6 (tests run via Node's native TypeScript type-stripping — no build needed for tests), npm.
npm install # dev dependency: esbuild
npm run build # bundles lib/index.js (host) + lib/client.js (browser)
npm test # 67 tests via node --test
Notes for contributors:
- The browser half uses
React.createElement(no JSX) and a tiny localreactstub undernode_modules/reactso tests can assert the rendered element tree without a DOM. Do not delete the stub; a realnpm install reactwould replace it. - Code must stay erasable-syntax TypeScript (no enums, no parameter properties) so Node's type-stripping can run the tests directly.
- Relative imports use explicit
.tsextensions (NodeNext).
Known limitations
- Platform: verified on Windows only; Linux/macOS untested — use with caution.
- Change tracking is per-session and covers only
write/edittool calls. - Diff is line-based LCS; hunk display is simplified (no intra-line character diff).
- Reverting a middle hunk of an old operation requires the region's lines to still be intact; overlapping later edits reject the revert.
- Whole-file revert restores the state before the session's first recorded operation on that file.
- Very large files (> 2 MB) are refused by the viewer; oversized change snapshots (> 120 KB) are not revertible.
License
MIT © 2026 houlain