dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
DSH 插件:侧栏工作区行四态灯(🟡 待交互 / 🔄 执行中 / 🟢 已完成 / ⏰ 仅定时)+ 会话「⋯」菜单 Mark as unread。纯客户端,外观复用宿主原生组件。
Adds Workspaces | Tags tabs to the sidebar, one status light per workspace, and tags for
sessions. Client-only plugin for DeepSeek Harness (dsh) —
no host-side behaviour. Bilingual (en / zh).
No settings to touch: the sidebar header simply gains Workspaces | Tags.
/), counts, status lights, search, view options,
double-click to rename, delete (inline two-step confirmation), drag to reorder.[Plugins] [Automation tasks] […] [refresh] — plugin panels on the left, refresh on the right,
icon-only with tooltips.| Light | Meaning | Priority |
|---|---|---|
| 🟡 | a session in this workspace is waiting for you (question / approval) | 1 (highest) |
| 🔄 | a session is running (animated) | 2 |
| 🟢 | a session finished and you haven't looked at it | 3 |
| ⏰ | only scheduled work remains | 4 (lowest) |
Priority mirrors the host's own rule, so this light never contradicts the dots you already see.
Roll-up in tree mode: a parent aggregates every descendant workspace — and it keeps working when the parent is collapsed (the judgement comes from the host's own grouping state, not from "the indentation currently visible").
test/test1 does not attach test.
Selecting a tag lists only the sessions explicitly tagged with it, and the number is its own usage;
an implicit level (no tag record) is empty. The status light still aggregates the subtree./-separated name
creates hierarchy; attachments are keyed by id and stay intact.⋯ menu).
Tagged rows keep it visible and carry a count.| Chord | Action |
|---|---|
| ⌘1 | sidebar-light.tabWorkspaces — switch to the Workspaces tab |
| ⌘2 | sidebar-light.tabTags — switch to the Tags tab |
| ⌘D | sidebar-light.markUnread — mark the current session unread |
| ⌘R | refresh the page (handled by this plugin, via a user override on the host's shortcut system) |
The plugin registers two ctx.shortcuts commands, neither with a default binding (defaults: {}):
parseShortcutDefinitions checks default-chord collisions per profile, and the host's
built-in page.refresh already owns ⌘R — declaring it here throws
Conflicting or reserved shortcut default.keybindings.json). For example:// ~/Library/Application Support/@deepseek-ai/dsh-desktop/keybindings.json
{
"schemaVersion": 2,
"profiles": {
"desktop:macos": {
"sidebar-light.markUnread": { "code": "KeyD", "modifiers": ["meta"] },
"sidebar-light.refresh": { "code": "KeyR", "modifiers": ["meta"] },
"sidebar-light.tabWorkspaces": { "code": "Digit1", "modifiers": ["meta"] },
"sidebar-light.tabTags": { "code": "Digit2", "modifiers": ["meta"] },
}
}
}
Why refresh is a plugin command instead of the built-in
page.refresh: the host's shortcut service captures ⌘R before page scripts (it registers earlier), and the built-inpage.refreshdoes nothing in the desktop app — hence "⌘R never worked". Registeringsidebar-light.refreshand binding ⌘R to it in the user overrides makes the host service dispatch to this command, and refresh finally works.Keybinding changes need a DSH restart (the desktop build has no file watcher).
How the target session is found: a shortcut has no menu context, so the plugin reads a semantic
attribute on the host's session row — [data-row-key^="session:"][aria-selected="true"] (not a CSS-module
hashed class name). With no selected session it returns blocked (no session selected).
⚠️ The command id is a user-visible contract (
keybindings.jsonis keyed by it); renaming it leaves existing bindings silently dormant.
Language: the plugin's strings (including the Tags view-options menu) follow DSH's language setting — the source of truth is the host's own
<html lang>, so switching DSH to Chinese switches the plugin immediately (no restart; a refresh is enough).
Each tab pill carries a tooltip: hovering shows its chord (e.g.
Tags (⌘2)). If you rebind it in Settings the hint follows (read from the host; falls back to the shipped chord).
dsh plugin --profile <your-profile> add \
https://github.com/luzonghao/dsh-sidebar-light/releases/latest/download/dsh-sidebar-light.tgz
A new bundle needs a DSH restart; after that, code changes only need a page refresh. Other sources (folder / npm / git), uninstall and the manual equivalent are in INSTALL.md.
The indicators are not hand-drawn copies of the host's styling — they are clones of the host's own
StateDot component inserted into the row. The search box, the menu and the header buttons likewise
reuse the host's own implementation (reading its class names / measuring its computed styles / using its
buttons directly), so a DSH upgrade carries the plugin along instead of breaking it.
The plugin does only three kinds of things to the host, all bounded:
document.body (Tags view, menu, refresh button) — never inside the host's
React subtrees;<html> attributes — those trigger a host layout recompute (once squeezing the main column
from 1402px to 546px; see index.md §63).node test/logic.test.mjs # 173 offline unit tests, no DSH needed
It also offers channels that do not need a console (the desktop app has none):
safety / probe / panel) to the clipboard;__dshSidebarLight.probe() // anchors / overlay / element rects
__dshSidebarLight.safety() // circuit-breaker state and captured errors
__dshSidebarLight.layoutSelfTest() // withdraws each plugin trace and measures the main column
__dshSidebarLight.surface('sidebarTab', false) // disable the Tags tab (effective after refresh)
useWorkspaces / sessionStatus), so collapsed workspace groups
still count toward the aggregate;localStorage (the active tab in sessionStorage) and do
not sync across machines;⋯ menu slot changes shape, the menu entry disappears silently (the lights are unaffected);| File | Contents |
|---|---|
| INSTALL.md | install / uninstall / verify / publish |
| index.md | design, decisions and the full revision history (post-mortems included) |
| LICENSE | MIT |
Third-party plugin, not affiliated with DeepSeek. Installing a third-party dsh plugin runs its code on
your machine with your own permissions — read the source first.