dsh-plugin-sidebar

September 1, 2026 ยท View on GitHub

dsh-plugin-sidebar: workspace/session browsing on the left, file & Git panel on the right

๐Ÿ—‚๏ธ A left & right sidebar for DeepSeek Harness
Left ยท workspace/session browsing โ€” Right ยท file + Git panels

Highlights ยท Install ยท Development ยท Architecture ยท License ยท ไธญๆ–‡


๐ŸŒ ็ฎ€ไฝ“ไธญๆ–‡: ่ง README.md ยท English in this file

dsh-plugin-sidebar

Make DeepSeek Harness session management feel like an IDE.

Browse every session by workspace on the left (status dots, groups, search, one-click actions); browse files and review Git changes in-place on the right (commit, switch branches). Install and go โ€” styling follows the DSH theme and adapts to light/dark.

โœจ Highlights

  • Grouped by workspace: collapsible group headers (folder icon + title + count + chevron), active session highlighted
  • Session status at a glance: running (green pulse) / waiting (amber) / done / idle โ€” status lane + title chip
  • Hover quick actions: rename (inline) / fork / archive / move to folder
  • Top search: local title/cwd/workspace match merged with remote content search (250 ms debounce), Esc to dismiss
  • Group-hover actions: new session here / rename workspace / delete workspace
  • Rail mode: sidebar collapses to an icon column; search/new auto-expand
  • Session-header toggle (next to the session log download); toggle state is remembered per session โ€” a session you opened the panel in stays open after switching away and back
  • File explorer: lazy directory tree (expand to load children), name search, content search (file/line/text), directory git-status aggregation badges (highest priority D>M>A>R>U of changed files underneath)
  • File preview tab (CodeMirror editing): a File preview tab after the main region's Conversation / Trajectory tabs; clicking a file in the right sidebar auto-switches there. Text files render with CodeMirror 6 โ€” syntax highlighting (language auto-picked by extension) + editable + save back to disk (โ— unsaved marker + save button, head pinned so it's always visible); binary/large files show a notice
  • Git panel: status split into Staged / Changes (--porcelain=v1 -z NUL parsing), colored diff, commit box, branch switch
  • Bulk actions (VSCode Source Control style, on section-header hover): Stage all(+) / Unstage all(โˆ’) / Discard all(undo); per-file row hover: diff(file) + stage(+)/unstage(โˆ’) + discard(undo)
  • Commit history (VSCode Source Control style): timeline dots + connector line, one-line-truncated message; expand to reveal author ยท date + that commit's changed-file list (M/A/D colored letters), files lazy-loaded on demand

Right sidebar file explorer + file preview tab

File preview: editing README in CodeMirror (syntax highlighting + save)

Right Git panel + VSCode-style commit history

๐Ÿ”€ Move session to folder

  • Copy semantics (fork): the source session stays; a new session is created in the target workspace inheriting all completed history, auto-opened after creation
  • Uses the official agents.create(seed + meta.cwd) path; the new session is an agent (lifecycle owned by the agent registry, not removed when the plugin stops)
  • Target-workspace picker: createPortal to body + position: fixed anchored, escaping list overflow clipping, flips upward near the viewport bottom

๐ŸŒ Polished for Chinese users

  • Full Chinese UI + English, follows the DSH locale automatically
  • Uses only DSH theme tokens (--dsw-alias-* / --ds-*), adapting to light/dark

๐Ÿ“ฆ Install

Install from GitHub or a local path. First confirm your dsh version, then pick the plugin version that matches it per the Version Compatibility table below:

# From GitHub (recommended; pin the version to match your dsh)
# Note: pnpm's GitHub version-lock syntax uses `#tag`; the old `@0.3.2` form is mis-parsed by pnpm as the nonexistent repo null/0.3.2
dsh plugin --profile web add github:webkong/dsh-plugin-sidebar#v0.3.2

# Or install the latest main branch
dsh plugin --profile web add github:webkong/dsh-plugin-sidebar#main

# Or from a local path (development)
dsh plugin --profile web add /path/to/dsh-plugin-sidebar

After restarting dsh web, the left sidebar takes over sidebar.workspaces, the right sidebar takes over the details column, and a panel toggle appears in the session header.

โš ๏ธ How it takes effect: install / restart; Host changes require a dsh web restart, while Client changes (lib/client.js) only need a page refresh.

๐Ÿ’ก Install recommendation:

  • dsh โ‰ฅ 0.1.2 (incl. 0.1.2-alpha.3): use 0.3.2 โ€” it adapts the dsh 0.1.2 client service migration and lazy resolution;
  • dsh 0.1.1-rc.x: use 0.3.2 or 0.3.1;
  • older dsh: fall back to โ‰ค 0.2.x (but on dsh โ‰ฅ 0.1.2 the older client never loads).

๐Ÿ”– Version Compatibility

Quick reference: your dsh version โ†’ recommended plugin version

Your dsh versionCompatible plugin versionsRecommendation
dsh โ‰ฅ 0.1.2 (incl. 0.1.2-alpha.3)0.3.1 or newerRecommended 0.3.2: adapts the dsh 0.1.2 uiWorkspace service migration + lazy resolution
dsh 0.1.1-rc.x0.3.0 โ€“ 0.3.2Either; 0.3.0 verified on 0.1.1-rc.2
dsh โ‰ค 0.1.1-rc.xโ‰ค 0.2.xOlder; on dsh โ‰ฅ 0.1.2 the client never loads (waits for the removed dsh-client-runtime)

Detailed: plugin version โ†’ compatible dsh versions

Plugin versionCompatible dsh versionsNotes
0.3.2dsh โ‰ฅ 0.1.1-rc.2Left-panel hierarchy styling: the status dot left of a session title is indented rightward to emphasize the folder โ†’ session parent-child level; the session title font size is reduced from 13px to 12px
0.3.1dsh โ‰ฅ 0.1.1-rc.2 (verified on 0.1.1-rc.2, 0.1.2-alpha.1, 0.1.2-alpha.3)Adapted to the dsh 0.1.2 client service migration: startSession / pickDirectory now go through the uiWorkspace service (formerly on workspaces), and layout/sessions/workspaces/uiWorkspace/timer are lazy-resolved at call time (services activate asynchronously; no longer cached at apply time). Fixes "right-panel toggle no response" and "left add-folder no response"
0.3.0dsh โ‰ฅ 0.1.1-rc.2 (verified on 0.1.1-rc.2, 0.1.2-alpha.1)Removed dsh-client-runtime from the client inject list (removed in dsh 0.1.2); not adapted to the 0.1.2 uiWorkspace migration, so some clicks may be unresponsive on 0.1.2-alpha.3
โ‰ค 0.2.xdsh โ‰ค 0.1.1-rc.xOlder; on dsh โ‰ฅ 0.1.2 the client never loads while waiting for the removed dsh-client-runtime
โ‰ค 0.2.xโ‰ค 0.1.1-rc.xOn dsh โ‰ฅ 0.1.2 older clients never load while waiting for the removed dsh-client-runtime

๐Ÿ”ง Development

npm install          # esbuild / typescript (dev only)
npm run build        # esbuild src/ โ†’ lib/ (Host ESM + Client __ModuleLoader__ bundle)
npm run typecheck    # tsc --noEmit strict
npm test             # node --test pure-function unit tests (42 cases)
npm run check        # typecheck + bundle syntax checks + unit tests

Structure (TypeScript-modular)

Source is organized TypeScript-modular (modeled on the official UI plugins); build output lives in lib/:

dsh-plugin-sidebar/
โ”œโ”€โ”€ package.json              # dsh.bundle / dsh.client declarations, scripts
โ”œโ”€โ”€ cordis.patch.yml          # bundle patch: mounts the dsp-sidebar row
โ”œโ”€โ”€ build.mjs                 # esbuild build (Host ESM + Client __ModuleLoader__ bundle)
โ”œโ”€โ”€ tsconfig.json             # strict typecheck (node + DOM/React)
โ”œโ”€โ”€ lib/                      # build output (gitignored)
โ”‚   โ”œโ”€โ”€ index.js              # Host single-file ESM bundle
โ”‚   โ””โ”€โ”€ client.js             # Client __ModuleLoader__ bundle
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ host/                 # Host source (Node env)
โ”‚   โ”‚   โ”œโ”€โ”€ index.ts          # entry: name/inject/apply + webServer route registration
โ”‚   โ”‚   โ”œโ”€โ”€ session.ts        # session copy (move to folder): readSession โ†’ cut โ†’ agents.create(seed+meta.cwd)
โ”‚   โ”‚   โ”œโ”€โ”€ git.ts            # git ops: runGit + porcelain/NUL/log parsing
โ”‚   โ”‚   โ”œโ”€โ”€ fs.ts             # fs ops: listDir / readText (512 KB truncation)
โ”‚   โ”‚   โ”œโ”€โ”€ search.ts         # search: name recursion + content line matching
โ”‚   โ”‚   โ””โ”€โ”€ http.ts           # JSON responses / loopback check / body / escaping
โ”‚   โ””โ”€โ”€ client/               # Client source (DOM + React env)
โ”‚       โ”œโ”€โ”€ index.ts          # apply entry: inject styles / register dictionaries / register slots
โ”‚       โ”œโ”€โ”€ api.ts            # /dsp-sidebar/api fetch wrapper
โ”‚       โ”œโ”€โ”€ i18n.ts           # zh/en dictionary (NS + key types)
โ”‚       โ”œโ”€โ”€ types.ts          # contracts: session/workspace data plane + Host API + git wire shapes
โ”‚       โ”œโ”€โ”€ util.ts           # shared helpers: relative time / basename / status derivation
โ”‚       โ”œโ”€โ”€ icons.tsx         # icons (lucide-style stroke + right-panel filled glyph)
โ”‚       โ”œโ”€โ”€ previewStore.ts   # file-preview shared store (sessionId-scoped, useSyncExternalStore)
โ”‚       โ”œโ”€โ”€ preview/          # main-region "File preview" view
โ”‚       โ”‚   โ””โ”€โ”€ PreviewView.tsx  # conversation.view occupant: subscribes to previewStore
โ”‚       โ”œโ”€โ”€ styles/           # CSS split by component domain + aggregate injection
โ”‚       โ”‚   โ”œโ”€โ”€ left.css      # left sidebar styles
โ”‚       โ”‚   โ”œโ”€โ”€ right.css     # right sidebar styles
โ”‚       โ”‚   โ”œโ”€โ”€ preview.css   # main-region preview tab styles (global dsw tokens)
โ”‚       โ”‚   โ””โ”€โ”€ index.ts      # injectStyles (idempotent single style tag)
โ”‚       โ”œโ”€โ”€ left/             # left sidebar (aligned with official WorkspaceBrowser + rows/)
โ”‚       โ”‚   โ”œโ”€โ”€ derive.ts     # data derivation: grouping / search merge
โ”‚       โ”‚   โ”œโ”€โ”€ rows.tsx      # row components: SessionCard / SearchRow / GroupSection (incl. move portal)
โ”‚       โ”‚   โ””โ”€โ”€ WorkspaceBrowser.tsx  # main component: header + search + list + rail
โ”‚       โ””โ”€โ”€ right/            # right sidebar (aligned with official RightSidebar + SourceControl + FileExplorer)
โ”‚           โ”œโ”€โ”€ derive.ts     # git status classification (badge / staged / unstaged / untracked / dirBadge)
โ”‚           โ”œโ”€โ”€ FilesPanel.tsx   # file browser (lazy tree + search + preview + git badges)
โ”‚           โ”œโ”€โ”€ GitPanel.tsx     # git panel (status / stage / diff / commit / timeline history / branch)
โ”‚           โ””โ”€โ”€ RightPanel.tsx   # panel shell (activity bar + tab switch) + header toggle
โ””โ”€โ”€ test/                     # pure-function unit tests (node --test)

๐Ÿ“ก Communication contract

The Host exposes an HTTP API via a webServer prefix route /dsp-sidebar/api (loopback only, POST, method name as the last path segment); the Client calls it with browser fetch:

MethodDescription
fs.listlist dir ({path})
fs.readread text (512 KB truncation; binary returns kind:'binary')
fs.searchsearch ({mode: 'name'|'content', path, query})
fs.gitStatusdir git-status map (path โ†’ XY, for file badges)
git.statusgit status ({cwd})
git.diffdiff ({cwd, path?, staged?})
git.stage / git.unstagestage / unstage ({cwd, path?})
git.discarddiscard changes ({cwd, path})
git.commitcommit ({cwd, message})
git.logcommit history ({cwd, count?})
git.logFileschanged files of one commit ({cwd, hash}, name-status parsed)
git.branchesbranch list ({cwd})
git.checkoutcheckout branch ({cwd, branch})
session.copyTocopy session to target workspace ({srcId, targetPath}) โ†’ returns {sessionId}

๐Ÿ— Architecture

  • Host (src/host/): registers the /dsp-sidebar/api prefix route via webServer. File ops go through the mounted fs service (resolve โ†’ listDir/stat/readText/readBytes, respecting sandbox & observation policy); git ops go through the mounted shell service (resolve + run, git -C <cwd> + porcelain/NUL parsing โ€” the same execution path as the official bash tool)
  • Client (src/client/): calls the Host via fetch('/dsp-sidebar/api/...'); registers slots (sidebar.workspaces / details / conversation.session.header.utilities / conversation.view); session copy uses Host services like sessionQuery / workspaceRegistry / agents (lazy resolution โ€” these activate asynchronously, so ctx.get at call time rather than cached at apply)

๐Ÿ“„ License

MIT