dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
按官方状态给 DSH 侧栏会话行染色,配色取自福音战士:等你处理的会话为蓝色左轨,主视图打开的那条为红色左轨,已结束但未查看为紫色左轨,置顶行的标题为静态彩虹。左侧轨道按模式分档——暗档保留原色,亮档换成对浅底 ≥4.5:1 的压暗变体——分档读的是 DSH 自己的暗色标记;未读的紫色轨道两种模式共用。只读取官方 Client 服务,自身不持有状态、不轮询,也没有宿主侧代码。
English | 中文
Colors DSH sidebar Session rows by their official UI status, in an Evangelion-flavored palette. The plugin owns no state: it reads facts the Client already has, writes one data- attribute per row, and styles that attribute from a single injected stylesheet.
| Row state | Official fact it reads | Decoration |
|---|---|---|
| Pending interaction (approval / question / plan review) | uiSession.sessionStatus.pendingInteraction | blue full-height left rail + 1.6 s breathing. Two blues, one per mode, both from card C ("Newtype" cover): dark #AAC7EF, light #3F629C |
| Selected — the session open in the main view | sessions.list snapshot: retainedBy.mainView > 0 | red full-height left rail, static. Two reds, one per mode: dark keeps #FF3B30, light overrides it with the redder, deeper #E01B24 |
| Finished but not viewed | …sessionStatus.completionUnread | purple #7A4FD6 full-height left rail |
| Pinned | workspaces.list snapshot: pinnedSessionIds | the row title becomes a static six-color rainbow (background-clip: text); the row itself gets no rail. Two palettes, one per mode: dark keeps the original six, light uses a darker six solved to ≥4.5:1 against the light wall |
| Running / subagents running / idle / archived / blank | — | nothing drawn; the official spinner and archived dimming already say it |
The official priority is pending > running > subagents > completed. When a session has finished but its subagents are still running, the official row shows the ongoing spinner, so this plugin draws nothing and lets that spinner through instead of calling the row "finished".
The plugin's own priority is pending > selected > subagents (yields) > unread. A row that needs you outranks the row you happen to be looking at, and a selected row keeps its red rail while its subagents run — the official spinner is not hidden on selected rows, so both readings stay visible at once.
The design rule behind the palette: shape carries meaning, color and light carry style. The pin icon and the pinned-first ordering stay entirely official — only the pinned row's title text is re-colored, so the pin itself is never restyled or decorated.
The rainbow is mode-scoped, because the same mid-luminance stops do not survive both backgrounds: on the light theme's wall (measured luminance 0.405–0.658 under the pinned titles) the original six score only 1.15–3.63:1, while on the dark theme's wall they are fine. Dark therefore keeps the original six colours unchanged, and light uses six darker stops of the same hues in the same order, each clearing 4.5:1 against the darkest patch measured under the title. The split is read from DSH's own dark marker (body[data-ds-dark-theme], theme-presenter.ts), not from any theme-specific hook.
The pending rail is mode-scoped for the same reason. Its blue comes from card C (the "Newtype" cover reference), which carries two blues: #3F629C (slate blue — 5.84:1 on the light wall but only 2.82:1 on the dark one) and #AAC7EF (pale blue — 9.94:1 on the dark wall but only 1.66:1 on the light one). Neither survives both, so each mode takes the one that reads on its own wall: light #3F629C, dark #AAC7EF. Both tiers share one @keyframes: the rail reads its colour through a custom property (--dsh-session-eva-status-pending), and the light rule overrides only that property, so the breathing period, easing and low point stay byte-for-byte identical and only the colour changes.
The selected rail is mode-scoped for the same reason. #FF3B30 keeps a high green channel (59) and scores only 3.39:1 on the light wall; light overrides the colour alone with the redder, deeper #E01B24 — hue rotated past pure red (HSL 357.3°), green cut from 59 to 27 — which clears 4.62:1. Dark is byte-for-byte unchanged. The override is one extra rule scoped by body:not([data-ds-dark-theme]) that sets background and nothing else, so the rail's geometry, stacking and lack of animation are untouched.
From the npm registry:
dsh plugin --profile <profile> add dsh-session-eva-status
Or straight from GitHub:
dsh plugin --profile <profile> add github:WhatCannotBeSaid/dsh-session-eva-status
Replace <profile> with the target profile name (for example web), then restart DSH: the client bundle is only refreshed when the module graph is recomposed, so a plain page refresh hits the old cache.
Working from a checkout instead? Point the CLI at the directory — the package also installs as a plain Profile dependency listed in that profile's package.json and dsh.bundles:
dsh plugin --profile <profile> add <path-to>/dsh-session-eva-status
The shipped cordis.patch.yml inserts the entry with these defaults; edit them there.
| Field | Default | Meaning |
|---|---|---|
hideOfficialDot | true | Hide the official status dot on pending and unread rows (their left rail replaces it) |
breatheMs | 1600 | Breathing period for the pending rail (ms, ≥ 200) |
colors | EVA palette | Override pending / pendingLight / selected / selectedLight / unread. pending and selected are the dark-mode values; pendingLight and selectedLight are the light-mode overrides |
A malformed config throws at load; nothing is silently skipped.
[data-row-key="session:<id>"] — rendered by @deepseek-ai/dsh-client-ui-workspace.ctx.uiSession.sessionStatus, the Client's own HostObservable<ReadonlyMap<SessionId, SessionStatus>> (running, pendingInteraction, completionUnread), plus ctx.sessions.list for two more official facts: the subagent catalog that decides the official "subagents running" state, and retainedBy.mainView > 0 — the same fact the official row's own selected flag is computed from. The pinned set comes from ctx.workspaces.list (pinnedSessionIds). No polling, no event sniffing, no host half.::before pseudo-element rail, and the row's own background is left completely alone — so official hover and selection feedback is untouched. The rail is deliberately not an inset box-shadow: an inset shadow is a band hugging the border's inner edge, so it follows the row's own border-radius all the way around and curls into a right-facing hook at each end — it reads as a bracket, not a rail. An absolutely positioned pseudo-element is not clipped by the row's radius, so the rail is one straight, square-ended bar spanning the full row height.data-eva-state attribute React does not manage, so re-renders cannot wipe it; a MutationObserver filtered to data-row-key re-reconciles when rows mount, unmount or change identity.Nothing here was copied wholesale. This list states exactly what each source contributed.
Code techniques borrowed
window.__ModuleLoader__.load({ id, factory }) envelope with named apply / inject, decorating Session rows through [data-row-key^="session:"], re-applying after React re-renders with a MutationObserver coalesced into one microtask, and pre-tagging the injected stylesheet (dataset.plugin / dataset.pluginCss) so a sibling plugin's hot reload cannot claim and delete it. Its 2-second polling, its own unread store and its title-gradient painting were deliberately not reused.dsh-ledger-cn (the local plugin package in C:\DSH\plugins\dsh-ledger-cn, unpublished) — the package layout this plugin follows: private: true, main: lib/index.js, the . / ./client export pair, a cordis.patch.yml that inserts its own Loader row, and the test style of loading the browser bundle behind a fake window.__ModuleLoader__ with a minimal DOM stub.@wxg-prc-cpg/browser-skill-dsh-plugin — the reference for an external package's dsh manifest: dsh.bundle.patch, dsh.client.platform, dsh.client.inject, and the files list.Contracts read from the official Harness (deepseek-ai/deepseek-harness)
packages/client/ui-workspace — the Session row DOM (data-row-key, the leading 16 px cell, title, time, pin), the row's own geometry (Rows.module.css: 32 px tall, border-radius: var(--dsw-radius-md)) and the SlotMap declaration of the row seats.packages/client/ui-session — ctx.uiSession.sessionStatus, the HostObservable<ReadonlyMap<SessionId, SessionStatus>> this plugin reads.packages/client/ui-primitives — StateDot, whose states define what the official row dot means.packages/client/ui-schedule — the worked example of occupying sidebar.session.row.leading and sidebar.session.row.hover (not used yet; kept for a planned hover readout).No code, stylesheet or copy from the official packages is bundled here: the plugin reads their rendered DOM and their public Client services only.
> :first-child on the row. In a pending or unread row that 16 px cell holds only the status dot (the sidebar.session.row.leading seat renders only while the row is idle), so nothing else is affected today — a future DSH that puts another occupant there would have it hidden too.background-clip: text), so it needs no extra DOM: nothing is inserted into the row, and uninstalling removes the attribute and the rule together.data-row-key, the plugin stops decorating rows and nothing else breaks.node --test test/client.test.mjs
MIT