Install
Inside DeepSeek Harness, with dsh-market
dsh plugin --profile web add dshmarket
Or from the command line
dsh plugin --profile web add github:NattoCB/dsh-plugin-sidebar-views
Installing runs third-party code with your own permissions — it can read your files, use your credentials and reach the network. Review the source first, and pin a commit (github:owner/repo#sha) when you can.
README
Language / 语言:English | 中文
A DeepSeek Harness client-side plugin that upgrades the sidebar session list: a Workspaces / Recent sessions switcher above the list — Workspaces is the native grouping; Recent flattens every session into one recency-sorted list with relative timestamps, running-state dots, and the owning workspace as a tag. A pinned-sessions group stays on top in both views. Since 0.3.0 the Recent view splits into Workspace / External groups — automation traffic is collapsed by default with a live count. Plain DOM throughout — no React, no portals, no slot takeover. Install into the
webprofile and restart.
✨ Features
- 🔀 Two-view switcher: two tabs above the list — Workspaces (the native grouping) and Recent sessions (every session in one recency-sorted flat list, with relative timestamps, running/completed/pending state dots, and the owning workspace as a tag).
- 📌 Pinned sessions group: stays above the list in both views, with a live count, collapse memory, and dimmed rows for sessions that no longer exist.
- 🗂️ Workspace / external groups: the Recent view splits into Workspace (sessions attached to a regular workspace, expanded by default) on top and External (workspace-less headless sessions plus
Automation-*workspace sessions — i.e. automation traffic) below, collapsed by default with a live count. Automation runs do join a real workspace, matched by workspace title or directory basename prefix (Automation-). Collapse state persists in localStorage (dsx2-groups); searching always expands both groups; collapsed groups skip row rendering entirely, so thousands of automation history rows never build DOM. - ⋯ Per-row menu: every row (pinned and flat) gets a "⋯" menu: pin/unpin the session and copy its session id.
- 🔎 Title filter: a filter box in the Recent view for instant title matching.
- 📁 Open in Finder: the native workspace "…" menu gains an open-in-Finder item, using the workspace cwd carried by the menu's fiber payload and activated through the stock
workspaces.openPathservice — zero host-side code. - 🧩 Plain DOM, zero framework: no React rendering, no portals, no slot takeover. The switcher is planted as the first child of the native sidebar list container; a CSS class hides the native list in Recent mode; a keep-alive interval survives native re-renders; a
ResizeObserverhides the widget entirely when the sidebar rail collapses. - ⚡ Large-list performance: DocumentFragment batch inserts,
content-visibilityso off-screen groups skip layout/paint, and a 400 ms throttle on data refreshes (direct interactions — tab switch, collapse, search — stay unthrottled). Expanding 2400+ rows measures in milliseconds. - 🔁 Legacy migration: when the older
dsh-plugin-pin-sessionplugin is still installed, its pin list is merged once at startup viaGET /pin-session/pins(id-deduplicated, stays oldest-first), and every pin/unpin is dual-written to itsPOST /pin-session/pin|unpinduring the transition. Both calls are silent no-ops once the legacy plugin is gone.
Quick Start
Prerequisites
- DeepSeek Harness installed (
dsh webruns). - Client bundles join the boot graph only at process start — restart
dsh webafter installing.
Install (into the web profile)
One command:
dsh plugin --profile web add github:NattoCB/dsh-plugin-sidebar-views
Manual install: in the profile's package.json, add the package to dependencies and the plugin name to dsh.profile.bundles, then run pnpm install inside the profile directory and restart dsh web.
Run
After the restart the switcher appears above the sidebar list — zero configuration. View, pin, and collapse state all live in browser localStorage and survive refreshes.
Storage & migration
Pins and group state live in browser localStorage — pins follow the browser profile, not the DSH host:
| localStorage key | Contents |
|---|---|
dsx2-pins |
Pin list (oldest-first [{ id, title?, pinnedAt }]) |
dsx2-pins-collapsed |
Collapse state of the pinned group |
dsx2-groups |
Collapse state of the workspace/external groups (external collapsed by default) |
Migration semantics toward the legacy dsh-plugin-pin-session: see 🔁 above — one-shot merge plus transition dual-writes, both silently fault-tolerant.
Uninstalling safely
Remove the plugin from both dependencies and dsh.profile.bundles in the profile package.json, then restart DSH. Deleting the package from node_modules while leaving the bundles entry in place makes the boot graph request a client.js that no longer exists — the module loader treats that as fatal and the whole web GUI fails to mount.
Development
npm test # node --test: package contract + pin merge logic
client/client.js is a window.__ModuleLoader__.load({ id, factory }) bundle in the same shape as DSH's own client bundles. The pin-merge logic is exported as exports._mergePins so tests exercise the real code, not a copy.
Comments
Comments live in GitHub Discussions. Sign in with GitHub to post or react.