DeepSeek Harness appearance toolkit. Independently tune opacity + frosted-glass blur across 8 surfaces (main background, sidebar, cards & panels, inputs & controls, settings, conversation frame, trajectory view, produced/highlights — 9 with dsh-better-sidebar). Use any image or video as wallpaper with a drag-to-pan, scroll-to-zoom position editor and 5 layout modes (Fit/Fill/Stretch/Tile/Center); videos loop muted, survive refresh, and capture a live frame for preview, color extraction and framing. Rotate a pool of images (shuffle/order, every refresh/daily/weekly). Also: PS-style color wheel, one-click wallpaper color extraction, 6 presets + saved profiles, day/night auto switch, and full theme export/import.
Install
# from npm (prebuilt)
dsh plugin --profile web add dsh-any-background
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:Tkingxiao/dsh-any-background
Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).
README
English | 中文
A DeepSeek Harness appearance plugin: custom theme color, background wallpaper (image / video / algorithmically generated), and fine-grained per-surface opacity & blur controls. Compatible with DSH 0.1.5-rc.2 through the whole 0.1.7 line below 0.2.0 (official-Sidebar UI such as the "Theme" card enables itself where the host exposes the Sidebar registry extension point, and is skipped silently where it does not).
Screenshots
Features
- PS-style Color Wheel — Pick hue on the ring, adjust saturation & lightness in the inscribed square. Generates 30+ CSS design tokens in real time.
- Precise HSL / RGB Input — Enter exact color values numerically with instant bidirectional sync to the wheel.
- Smart Color Extraction — One click derives a theme color from your wallpaper by sampling the visible region, quantizing, and filtering out gray / near-black / near-white pixels. Video wallpapers contribute via an auto-captured frame. Fully client-side.
- Eyedropper — Hover the wallpaper to preview a color and click to pick it as the theme color.
- Background Wallpaper — Upload any image as your wallpaper. Drag to pan and scroll to zoom inside a viewport-proportional editor (one finger to pan, two to pinch-zoom on touchscreens).
- Video Wallpaper — Use a video as a live wallpaper: muted looping playback that survives refreshes (file persistence + HTTP streaming with Range seek), with an auto-captured frame powering the preview, theme-color extraction, and the position editor.
- Position Editor — One shared editor for images and videos: drag to pan, scroll or pinch to zoom, one-click reset. Image and video placements are stored separately and never overwrite each other.
- Layout Modes — Fit / Fill / Stretch / Tile / Center for both images and videos; in Fit mode the editor-committed framing stays consistent across window resizes and cross-monitor moves.
- Generated Dynamic Backgrounds — Choose mesh gradient, Shader, or geometric patterns with adjustable spread, intensity, and seed locking.
- Per-surface Interface Opacity — Independent sliders for the main background, sidebar, cards & panels (including the dropdowns and menus around the dialog), the input & controls (composer box, Cordis panel), the settings panel, the conversation text frame, the trajectory view, the right sidebar (or bettersidebar), produced / highlighted content, and the header popovers (Agent Team panel, background-job list and the session-header dropdowns).
- Per-surface Interface Blur — Frosted-glass
backdrop-filterblur (0–60 px) per surface, including a real backdrop on the composer, the Cordis panel and popover surfaces via stable host selectors. - Produced / Highlights — Code blocks in conversation content (with their language banner), inline
codehighlight chips and produced chips share one opacity + blur slider. The opacity is the alpha of each surface's own background color (no second color stacked on top of the original), and the blur frosts that same layer so the wallpaper shows through the content. - Right sidebar / bettersidebar surface — One slider pair (
panelOpacity/blurs.panel), two identities: without dsh-better-sidebar it reads "右方侧边栏" (Right sidebar) and drives the official right Sidebar's surface tokens and frosted blur (works on 0.1.5-rc.2 through 0.1.7); with dsh-better-sidebar installed it reads "bettersidebar" and takes over that plugin's bottom workbench panel (the official sidebar keeps responding too). The row is always visible. - Header popovers — The session-header dropdowns get their own opacity + blur pair: the Agent Team panel, the background-job list, the open-in-app / session-log menus and the subagent lineage tree. On 0.1.7 the open-in-app picker moved to a portal and the session-row menu became a dynamic slot, so the plugin observes the stable
conversation.session.header*slot anchors and tags the open popover at runtime instead of relying on class shapes. - Sidebar "Theme" page (dual mode) — The same five pages (Color / Interface / Font / Background / Profiles) register into two surfaces: without dsh-better-sidebar, a "Theme" card is contributed to the official right Sidebar's guide page through its public extension points (
sidebarRightTabs+ thesidebar.right.pane.tabkeyed seat); with dsh-better-sidebar installed, the page registers in that plugin's sidebar instead and the official guide card withdraws itself, so the two never duplicate. Settings panel, official sidebar and better-sidebar all share one page implementation and one state store — a change in any of them shows up everywhere. The shell adapts to the panel width, and a narrow panel tightens padding and falls back to a single column. On a host without the right Sidebar the registration silently never happens. - Conversation View Cards — The message list is wrapped in a translucent card automatically, and the trajectory page gets whole-page opacity & blur controls, letting the wallpaper shine through the content.
- Theme Export / Import — One-click export to a self-contained
dsh-any-theme.json(config + wallpaper, video embedded as a data URL) and import to restore it anywhere. - Appearance Presets & Profiles — Six one-click presets (Default / Frosted glass / Minimal / Midnight / Cyber / Warm daylight) plus named profiles: save the current look and re-apply it anytime. A two-step confirm guards deletion.
- Wallpaper Rotation — Add images to a rotation pool (thumbnail picker included) and let the wallpaper change by shuffle or order on every refresh, daily, or weekly. Advancing copies the chosen image into the active wallpaper slot, so export/import and color extraction keep working unchanged.
- Day/Night Auto Switch — Assign a day profile and a night profile; the plugin switches automatically at fixed clock times or by following the OS dark mode.
- Custom Font — Upload a ttf / otf / woff / woff2 file (up to 100 MB) and apply it to the whole interface through
@font-face; toggle it off or remove it at any time. Fonts stream as raw bytes and persist in the plugin data dir; code blocks keep their monospace stack. - Per-part Text Outline — The same surface groups as the interface page (now ten, including the header popovers), each with its own
-webkit-text-stroke: width 0–4 px (0 = off) and a color of auto-contrast / gray / black / white / accent / custom. Code blocks, inlinecode, icons and the host'sbackground-clip: textshimmer chrome (the "深度求索中" turn-status line and the turn-process rows) are exempted automatically, so multi-color syntax never smears and gradient text is never flattened into a stroke-coloured blob. - Forced Interface Scheme — Force light or dark token palettes regardless of the accent color's lightness; in
Autoboth the surface and font directions follow the accent's lightness (dark pick → light fonts, light pick → dark fonts), falling back to the wallpaper's perceived brightness when no color is picked. - File-based Persistence — All settings are stored on the filesystem under
~/.dsh/.dsh-any-background-data/, notlocalStorage. - Bilingual — Full Chinese / English UI with automatic locale detection.
- Theme Watchdog — Re-asserts the custom theme if the host resets it.
Changelog (latest two releases)
v0.3.2 (Produced artifacts fully bound, 0.1.7-rc.2 loads again)
- The produced slider now covers every artifact 0.1.7 renders: the tool-details card (
[data-inspect],ToolDetails.module.css), the turn-event rows ([data-turn-trigger], including their hover fill), the diff block ([data-diff]), the changed-files card ([data-changed-files]— root, header button and the file-count tile each paint their own token) and inlinecodefrost were all driven by the host at full alpha with no binding on our side, so the "产出物/高亮内容" sliders did nothing to them. Each now re-emits its own host token throughcolor-mix(… var(--dsh-any-prod-pct))and joins the shared frost (inlinecodeexcepted under the compact markdown variant, where a frost on hint-sized text only smudges). The outline group lists the same surfaces, so their text no longer keeps inheriting the conversation-frame outline. - Code-card banners are themed again instead of a pale slab: 0.1.7 moved ReadBlock / DiffBlock / CodeBlock onto one shared CodeCard whose header fills from
--dsl-code-block-background→--dsw-alias-markdown-code-block, while--dsl-code-block-banner-background-colorexists only inside a markdown block. Our banner arm still read the old--dsw-alias-markdown-code-block-bannerfirst, which is why a read/diff header stayed an opaque near-white bar that ignored the slider. The arm now follows the host's own chain, and the pre-0.1.7 arm is guarded with:not([data-code-block-banner])so the two cannot both claim one element (verified live on an injected 0.1.7 card: at 20% the banner blends with the card, and where the host really does use the banner token — the diff header — the two colors stay distinct). - The dsh-better-sidebar workbench belongs to the produced slider now:
[data-dsh-bottom-panel]opens the artifact a conversation row points at, so it fades and frosts with the produced surfaces rather than with the panel row, which is now the host's own right Sidebar only. Its alpha cannot ride the in-place re-emit trick — every surface inside it (pane chrome, tab bar, cards) reads a layer token — so the produced slider writes four root variables that re-scope those tokens, the same way the panel row drives the native panel. Both settings pages' labels and icons follow that split. - The composer frost no longer leaves a stacking context behind at 0: the input rule was gated by a
dab-input-frostclass on<html>that is dropped when the blur slider returns to 0, so a composer that is not frosted is no longer isolated. Measured live:isolationgoesisolate → auto. The host's own card rule keepsposition: relativethere regardless (.uV2eYG_card), and the per-part frost patches position only while its blur is non-zero, so the remaining case where a frosted surface paints above another plugin's in-flow notice is the frost itself, not a leftover — that one needs the specific notice to be exempted by name. - The changed-files card answers to one slider now: its root paints from
--dsw-alias-bg-layer-1, which is precisely the token the interface "card" (option-panel) opacity re-emits globally onbody, so the producedcolor-mixwas multiplying the produced alpha onto the card alpha and one artifact card obeyed two sliders. The root now reads a produced-slider variable carrying the RAW token (--dsh-any-prod-layer-1, written byapplyProducedfrom the same source the panel row uses) — verified live: dropping the card alpha to 0.3 leaves the card untouched while the produced alpha still takes it to 0.2. - The hover preview window is bound: hovering a produced artifact opens
ui-primitives/HoverCard, which portals its card todocument.body— outside every in-tree re-scope and owned by no slider at all. It joins the produced group's frost, alpha and outline, anchored by the one stable marker that card has: the inline--dsh-hover-preview-fadeproperty it always sets. That marker is 0.1.7-only (the card carries no distinguishing attribute on 0.1.5 / 0.1.6), so older hosts simply leave it alone rather than being caught by a[class$="_card"]that would also match the composer. Two surfaces sit under that one attribute and they are faded from their own source: the plain card keeps the host's component literal--dsw-hovercard-bg: #2C2C2E(dark in both themes by the host's choice), while thepreviewvariant repaints from the theme surface--dsw-alias-bg-layer-1and so reads the produced slider's raw layer variable — mixing both on the literal turned a light themed preview dark (measured:rgb(44,44,46)over a light theme). - antd confirm dialogs are no longer claimed as the settings panel:
SETTINGS_PANEL_SELidentified the settings modal as "the onlyaria-modaldialog that labels itself witharia-labelledby", but the host's antdModal— the 「删除会话」 confirm among others — emits those same three attributes, so the dialog inherited the settings surface color, the settings blur, the whole--dsw-alias-bg-layer-*re-scope the panel row writes, and the settings outline group. The selector now additionally requires the hashedcss.panelclass thatui-settings-general/SettingsRoot.tsxputs on its own dialog element, which it does identically from0.1.5-rc.2through0.1.7-rc.1; antd rendersant-modal-*hyphenated names that can never contain it. Measured live on the host: the real settings dialog still matches the tightened selector, while a full antd modal subtree (container, close, header, body, footer, both buttons) scores 0 hits across everydsh-any*stylesheet — where it matched the loose selector before. Any residual offset of the confirm button is therefore outside this plugin in the current build. 0.1.7-rc.2loads again, and future 0.1.7 builds load with it: from rc.1 the host's peer check turns a missing release name into a plugin that never starts, and rc.2 was not in the list (issue #20). All seven@deepseek-ai/dsh-*peers,engines.dshanddsh.compatibility.dshnow end in|| 0.1.7-rc.2 || >=0.1.7-alpha.1 <0.2.0-alpha.0, so the whole 0.1.7 line — and any later 0.1.x — is admitted without another manifest edit. That umbrella has to be written exactly like that:>=0.1.7alone matches no prerelease build at all (semver only lets a prerelease compete with a comparator that carries the same[major,minor,patch]tuple), and the cap must be<0.2.0-alpha.0rather than<0.2.0for the same reason — the looser cap would let0.2.0-alpha.1in. Every verdict was replayed against the host's ownsemver(the 7.8.5 copy inside the rc.1 runtime) with the gate's{includePrerelease: true}, and nothing before that tail is left implicit: earlier lines (0.1.5-rc,0.1.6-alpha) stay enumerated build by build, because an umbrella over a line this plugin has not looked at would declare compatibility it has not checked. Loading is all the manifest decides, though — the adapter table is untouched, so an rc.2 host still resolves through the patch-line rule to the existing 0.1.7 folder (line, notexact), and the surface drift rc.2's own diff shows (menu fills moving to--dsw-menu-surface-fill, the single-file variant of the changed-files card) is a styling follow-up that needs a machine running rc.2 to measure against.
v0.3.1 (Isolated per-version adaptation: one folder per host release)
- Front-loaded release detection: resolving the host release and bucketing its channel now lives in
src/host-compat/(the Node half reads the release out of the very@deepseek-ai/dsh/package.jsonthe process was composed from —ctx.profileContext.installAnchor— falling back to the manifest beside the launcher'shomes/<ver>and then to the directory name; the verdict travels in thereadRPC payload), withsrc/client/host-compat/receiving it on the client, broadcasting changes, and re-cutting the static stylesheet the moment the verdict lands. Version logic that used to be spread acrosssrc/client/host.tsand its call sites is consolidated there; that module is gone. - One folder per release: under
src/client/host-compat/versions/, thev0-1-5-rc-2-3/v0-1-6-alpha-1-2/v0-1-7-alpha-1-2-rc-1/unknownfolders each describe that version's panel mechanics (which layer carries the promotion and the blur) and its header slot keys, andversions/registry.tsis the plugin's only release → code mapping. Base code only asks the adapter questions (who owns the guide surface, which slot selectors apply) and never compares version strings — supporting a new host means adding a folder and registering it, leaving base code untouched. - Release identity is named down to the channel: an adapter key is no longer a bare patch number like
0.1.5but "patch line + prerelease channel" —0.1.5-rc,0.1.6-alpha,0.1.7-alpha. Each folder's mechanics were checked tag by tag against a specific channel, so recording0.1.5-rc.3and a hypothetical0.1.5-beta.1under one key would let an unverified shape inherit a verified conclusion. Folders and adapter ids now name the exact tags behind them (v0-1-6-alpha-1-2reporting0.1.6-alpha.1/alpha.2), so how far a table reaches is readable without opening it — and where two builds on one line genuinely differ (leadingheader slot and the plugin-manager page only exist from0.1.6-alpha.2), the folder carries that prerelease gate itself. - Releases outside the verified table take the nearest adapter: the
SUPPORTED_RELEASEStable insrc/host-compat/channel.ts(0.1.5-rc.2/0.1.6-alpha.2/0.1.7-alpha.2/0.1.7-rc.1, oldest first — one row per build whose facts were checked, so one line may carry two) is matched by PATCH LINE first: a machine on0.1.6-alpha.4gets the0.1.6-alphaadapter even though verification stopped atalpha.2, because the number after the channel is only a build counter on that line — and0.1.6-beta.1or a future channel-less0.1.6count as the same line too. Only when no verified line covers the patch number does it clamp: newer than the newest → that newest adapter, older than the oldest → the oldest, strictly between two → the LOWER one, since an adapter may only claim what it was verified for. A clamped verdict logs one line saying the host is outside the verified range and which adapter is standing in, so a report against a new host build starts from that fact. Falling intounknown— where the DOM arbitrates — is left for the case where no release parses at all (a plain~/.dshinstall, for instance). 0.1.7-rc.1joins the verified range without an adapter change: diffed against0.1.7-alpha.2, every anchor this plugin matches is still emitted where it was, so the 0.1.7 folder only gained that build in its name (v0-1-7-alpha-1-2-rc-1) plus aSUPPORTED_RELEASESrow — which turns an rc.1 host's verdict fromlineintoexact. What did change is how the host reads the manifest: from rc.1 the profile composition checks each plugin's@deepseek-ai/dsh*peerDependenciesagainst the running release and disables its row before importing a single module when a declared range does not match, the only way past that being an exact-version exemption the plugin manager stores in the profile's owncompatibility.json.engines.dshremains declarative, so the peer list is what decides whether the plugin runs — hence|| 0.1.7-rc.1on all seven@deepseek-ai/dsh-*peers.- No
:has()dependency once the host is known: a resolved release emits its own targeted branches, ungated. That also fixes a latent problem: on an engine without:has()the previous gate dropped the panel promotion entirely on 0.1.5 / 0.1.6. An unresolvable release still falls intounknownand lets the DOM shape arbitrate (:has()dual arms) instead of guessing a version. - Header popover selectors spelled once: the top-bar surface list was duplicated three times inside
wallpaper.ts; it is now composed once and shared by the opacity rule and the outline rule (the latter deliberately keeps the bare tag without[role], with the reason documented in place). Slot keys come from the adapter, so theleadingslot unique to0.1.6-alpha.2no longer leaks into base code. - The plugin page's card list is framed:
Settings → Pluginsrenders each group's plugins in aulthat has no surface of its own, so with the settings surfaces faded the whole table floated straight on the wallpaper. Each group's list now gets what the composer capsule gets — a rounded frosted block on an::beforeunderlay, painted from the settings-interface opacity and frosted by the settings blur (the page is a sibling of the settings dialog on 0.1.7, so reading the dialog's own token re-scope would have left it on the homepage alpha). It is contributed only by the adapters whose release ships that page, so the selector never rides a host that cannot match it. - Fixed the wallpaper disappearing while the right Sidebar animates: the AppFrame's own translucent background was cleared with an inline
background: transparent, and the host'sstylerewrite during the sidebar open/close animation dropped it — the frame snapped back to an opaque layer, hiding the wallpaper and flattening every frost above it, because abackdrop-filterwith nothing behind it has nothing to blur. The clear is a class rule with!importantnow, which the host's style writes cannot reach (measured on the live frame:rgb(200,207,218)opaque →rgba(0,0,0,0)with the class, opaque again without it). - Fixed the chat card landing on a settings page at startup: while no conversation view is mounted (starting the host with the settings panel open, for instance), the marker-less chat-card fallback picked "the largest scrollable element" by geometry — so the settings page got card chrome plus a frost underlay (
<div class="dab-part-underlay">) spread over the whole window. The fallback can now only refine a conversation that already exists: with none of[data-chat-flow]/[data-conversation-scroll]/[data-composer-seat]/[data-conversation-composer-overlay]present in the center column it no longer guesses, and candidates inside the settings dialog are still rejected. - Fixed the covered area of the per-part frosted blur: the class rule for the hosting element was missing its leading dot (
dab-part-blur{isolation:isolate}), so that layer never created a stacking context and thez-index:-1frost underlay fell into the page-level one — its sampling region and its painted position both stopped matching the surface (measured live: the host element's computedisolationwasauto). With the dot restored, the frost stays inside its own surface. This defect predates v0.3.0. - Corrected several wrong assumptions about the host: the native right Sidebar and
ctx.sidebarRightTabsare not a new-host feature (0.1.5-rc.2already ships them), and dockkit itself predates 0.1.7 — only itshost/emptyattributes are 0.1.7 markers. - README: the Compatibility section gains a "Isolated per-version adaptation" entry and Known limitations names the layer where version-specific selectors live; the intro no longer implies the official-Sidebar UI exists only on newer hosts.
v0.3.0 (DSH 0.1.7 adaptation, compatible with 0.1.5-rc.2 ~ 0.1.7-alpha.1)
- 0.1.7 right Sidebar: the host reworked that panel — it is now a stationary frame whose docked children (
[data-dockkit-host="dock"]/[data-dockkit-empty]) carry the slide transform, and the panel no longer paints its own background. The plugin follows the new shape: the blur rides the sliding children so it travels with the sidebar instead of staying pinned, and the surface tokens are re-scoped where the panel actually renders. The previous unconditionalposition:fixedpromotion was removed — on 0.1.7 it detached the panel from the animated track. - 0.1.6 right Sidebar blur restored:
[data-dockkit-host]only exists from 0.1.7, so the child-based blur selector matched nothing on 0.1.6 (which slides the panel itself). A second,:has()-gated arm now frosts the panel wrapper there, and the pre-0.1.7 promotion is re-applied only where it is needed. - Gradient "shimmer" text is no longer flattened by the outline feature:
-webkit-text-strokeis inherited, so the conversation-frame rule reached thebackground-clip: textactivity chrome — the "深度求索中" turn-status line (0.1.5/0.1.6) and the turn-process/shimmer rows (0.1.7) turned into a flat stroke-coloured blob. They are now explicitly exempt, matched by[role="status"],[data-turn-process]and the TextShimmer marker. - New "Header popovers" surface: the Agent Team panel, background-job list, open-in-app / session-log menus and the subagent lineage tree get their own opacity + blur sliders, plus a matching outline group. Because these popovers are portalled to
<body>(severed from the header) and 0.1.7 moved open-in-app to a portal and made the session-row menu a dynamic slot, a runtime tagger watches the stableconversation.session.header*slot anchors and marks the open popover. The exempt confirm dialogs and session-row menu are pinned opaque with real color literals — no self-referencingvar()fallback, which is a CSS cycle that would render them fully transparent. - Host release detection: the client context exposes no host version (
window.__DSH_BOOT__.versionis a module-table tag, not a release), so the release plus a generation bucket is resolved on the Node half from the launcher's on-disk layout and handed to the client through thereadRPC payload. Feature gates use it; when it cannot be determined they fall back to capability probing rather than guessing. - Native support for the official right Sidebar: a "Theme" card is contributed to the official Sidebar's guide page through its public extension points (a page type in
ctx.sidebarRightTabsplus the keyedsidebar.right.pane.tabbody seat), opening the same five pages as the settings panel. Active without dsh-better-sidebar; when that plugin is present, its own "Theme" page takes over and the official guide card withdraws itself. Registration waits on the service at runtime — hosts without the Sidebar registry API skip it silently, so older hosts are unaffected. - The right-sidebar slider row follows the environment: the Interface page's panel group (
panelOpacity/blurs.panel) reads "右方侧边栏" (Right sidebar) without better-sidebar — driving the official right Sidebar's surface tokens and frosted blur on 0.1.5-rc.2 through 0.1.7 — and "bettersidebar" with it. The row is now always visible instead of hiding when better-sidebar is absent. - The better-sidebar presence probe no longer counts
[data-sidebar-right-panel]: on every host generation that is the official right Sidebar's stable marker (present whenever a session is open), so counting it pinned the "bettersidebar" verdict to true forever. - Compatibility declarations now cover
0.1.5-rc.2,0.1.5-rc.3,0.1.6-alpha.1,0.1.6-alpha.2and0.1.7-alpha.1; peerDependencies widened to span every generation of the client packages;@deepseek-ai/dsh-home-pathsstays at the lockfile-consistent^0.1.0-rc.6(build-time only — the host injects its own copy at runtime).
Installation
Method 1: npm install (Recommended)
# published on the npm registry
dsh plugin --profile web add dsh-any-background
# or straight from the GitHub repository
dsh plugin --profile web add github:Tkingxiao/dsh-any-background
Then launch:
dsh web
The plugin appears as a "Theme" section in Settings.
Method 2: npx (No Global Install)
npx @deepseek-ai/dsh plugin --profile web add dsh-any-background
npx @deepseek-ai/dsh web
Method 3: Local Build (Development)
The lib/ directory is committed, so installs need no build step. To rebuild after editing src/:
git clone https://github.com/Tkingxiao/dsh-any-background.git
cd dsh-any-background
pnpm install
pnpm run bundle
pnpm dsh plugin --profile web add "dsh-any-background"
pnpm dsh web
Compatibility
- **
dsh web0.1.5-rc.2 ~ <0.2.0** —engines.dsh, the seven@deepseek-ai/dsh-*peerDependenciesanddsh.compatibility.dshlist the0.1.5-rcand0.1.6-alphabuilds this plugin has been checked against one by one, then close the range with>=0.1.7-alpha.1 <0.2.0-alpha.0, so every 0.1.7-and-later release up to 0.2.0 loads (0.1.7-rc.1/0.1.7-rc.2were checked by diffing their tags, the builds before them hands-on). From0.1.7-rc.1the host itself enforces that peer list — a release the ranges do not name is disabled before its modules are imported — so naming it is what makes the plugin load, not documentation; the declarations indsh.compatibility.dshReleasesrecord which builds were checked. The host release is resolved on the Node half at runtime, and features that depend on a specific host release channel (the right Sidebar's panel blur, the official Sidebar's "Theme" card) enable themselves only where the corresponding host structure exists; everything else behaves identically across the range. - Isolated per-version adaptation: the release is resolved on the Node half from the app manifest the process was composed from (
ctx.profileContext.installAnchor, with the launcher's on-disk layout behind it — the client context exposes no version) and, once handed down through thereadRPC, is routed only by the front-layer adapter —src/host-compat/detects and buckets channels, whilesrc/client/host-compat/versions/holds one folder per release (v0-1-5-rc-2-3/v0-1-6-alpha-1-2/v0-1-7-alpha-1-2-rc-1/unknown), each describing that version's panel mechanics and header slot keys. Base code just asks the adapter questions (who owns the guide surface, which layer carries the blur) and never compares version strings. Another build on a verified patch line (0.1.6-alpha.4against a table checked atalpha.2) keeps that line's adapter, and a patch line nothing was checked against clamps to the nearest one with a log line saying so. Only a release that will not parse at all falls intounknownand probes the DOM shape instead of guessing (:has()dual arms); supporting a new host means adding one folder and registering it. - DSHA — DeepSeek Harness Android launcher (ROOT-free, Termux-free). Its bundled
dshis0.1.5-rc.2, inside the supported range; the mobile UI shell is provided bydsh-web-mobile. - deepseek-harness-desktop — Supported
Permissions, side effects & boundaries
- Integration form: official Profile Bundle —
package.jsondeclaresdsh.bundle.patch: ./cordis.patch.yml(a loader insert layer), the repository ships prebuilt runtime artifacts ready to use (lib/index.js,lib/invariant.js,lib/client.js), and there are no install scripts, nopostinstall, no native binaries, and no build step at install time. - Filesystem: the server half reads and writes only inside
<dsh home>/.dsh-any-background-data/(config JSON, wallpaper, rotation pool, video, font) and touches nothing outside it; config writes are atomic (temp file + rename). These files live on the real disk, so they are outside generation restore — it neither captures nor rolls them back; deleting the directory is a full plugin reset. - Network: one outbound fetch happens only when the user pastes an http/https image or video URL and presses Apply; no telemetry, no other external calls.
- Shell / native: none. No
child_process, no native modules, no dynamically downloaded executables. - HTTP surface: registers only
/dsh-any-background/{video,wallpaper,font}(GET/HEAD streaming) with matching*/uploadPOST routes (100 MB cap) and the dedicated RPC channel/dsh-any-backgroundunder the local dsh web server; no extra listening ports. - Restart requirements: the first install needs a (re)start of
dsh webto load the client bundle; settings changes afterwards apply live and persist automatically. Updating the plugin requires a restart to pick up the newlib/client.js. - Tests & verification:
pnpm run typecheck(full tsc check) andpnpm run bundle(tsdown emitslib/); no automated unit tests — behavior is verified manually. - Known limitations: the styling relies on stable host DOM markers (
[data-sidebar-right-panel],[data-dsh-bottom-panel], …) and CSS token names; a host restyle of those layers can leave a slider ineffective for its surface (cosmetic only — nothing breaks). The version-specific half of those selectors lives inside its own version folder, so a host revision normally means editing that one file.-webkit-text-strokemay clip about 1px at the edge of some single-line ellipsis containers.
Star History
License
MIT
Links
More in this category
Small-tailqwq/dsh-deep-whale#maid-atelier★ 2252
Whale-girl skin series for the DSH Web UI (maid-atelier).
elysia395/dsh-wallpaper-engine★ 384
Requires DeepSeek Harness 0.1.5-rc.1+ (DSH Desktop >= 2.0.7) and dsh-better-sidebar >= 0.19.0 - update both before installing or updating this plugin. Plays local Wallpaper Engine Video/Web wallpapers behind the chat, renders Scene wallpapers as extracted static frames, and adds content-rating/type filters, custom uploads and an iOS-style liquid-glass settings window.
d-dev0101/open-sea-skin★ 380
Realtime WebGPU ocean skin with quick controls for waves, daylight, glass opacity, and an automatic day cycle.
kingOfSoySauce/dsh-liang-skin★ 222
Adaptive reasoning slider skin that maps each model's available reasoning efforts onto a 0–30 visual intensity scale, with synchronized portraits, background, and interface colors.
RevolutionLA/dsh-dream-skin★ 192
One-command skin plugin: 8 original themes, translucent wallpaper with opacity/blur, per-user accent, and shareable theme-pack import/export, favorites and surprise-me — purely native on DSH's token system.
GGBond2424648901/deep-whale-day-night-theme★ 117
Non-commercial day/night whale-girl skin for official Harness rc.7: current no-viewport-frame layout, paired crystal-workshop and moon-tide scenes, chibi companions, translucent ornaments, and lightweight ambience.
Community comments
Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.