Skip to content
dsh.fish
Bundle

dsh-plugin-custom-css

Custom CSS injection for DeepSeek Harness — a Settings section with an on/off toggle and a CSS textarea injected live into the Web GUI

Source
nguyenduclong-ict
License
MIT
Updated
Updated 9 hours ago

Readme

# dsh-plugin-custom-css

[English](README.md) | [Tiếng Việt](README.vi.md)

Custom CSS injection for **DeepSeek Harness (DSH / DSH Desktop)**.

It adds one row to the Settings modal — **Custom CSS** — which opens a page with:

- an **on/off toggle** that enables or disables injection, and
- a **CSS textarea** whose contents are injected into the Web GUI live, as you type.

---

## 1. What it does

| Piece | Behavior |
|---|---|
| Settings entry | Registers a `settings.section` row (order `40`) labelled **Custom CSS** in the Settings modal nav rail. |
| Toggle | Injects or stops injecting the snippet. Turning it off **keeps** the saved code. |
| Textarea | Injected on every keystroke (debounced host write, `500 ms`). Flushed to the host on blur. |
| Injection target | A single `<style id="dsh-custom-css-style">` element, re-appended to the end of `<head>` on every write so it wins the cascade against styles the Harness appends while booting. |
| Storage | `~/.dsh/plugins/dsh-plugin-custom-css/config.json` (`$DSH_HOME` wins when set), served over `GET/POST /api/custom-css/config`, mirrored into `localStorage` so the snippet is applied before the first paint of the next launch. |
| Locales | `zh`, `en`, `vi` dictionaries are registered under the `custom-css` namespace (falls back to `en`). |

Nothing else is touched: styles injected by other sources are never removed, and the plugin does not modify the Harness installation.

---

## 2. Installation (DSH Desktop, Windows)

```powershell
# 1. From this repository's parent directory, install the package into the web profile
cd "$env:APPDATA\dsh-desktop\harness\profiles\web"
& "$env:APPDATA\dsh-desktop\harness\.desktop-bin\pnpm.cmd" add <path-to-this-package>
#   e.g. pnpm add C:\Users\you\Desktop\Code\dsh-plugins\dsh-plugin-custom-css
#   or   pnpm add https://github.com/<user>/dsh-plugin-custom-css
```

Then add the package name to the profile's bundle list — edit
`%APPDATA%\dsh-desktop\harness\profiles\web\package.json`:

```json
{
  "dsh": {
    "profile": {
      "bundles": [
        "@deepseek-ai/dsh-base",
        "@deepseek-ai/dsh-web-app",
        "dsh-plugin-custom-css"
      ]
    }
  }
}
```

Restart **DSH Desktop**. The plugin must be in `dsh.profile.bundles`, otherwise the
Harness never loads it.

> **Note** — any entry in `dsh.profile.bundles` must activate during boot. If the
> plugin cannot activate, the whole Web UI fails to boot with
> `web boot: N entries did not activate`.

### macOS / Linux

```bash
cd "$HOME/Library/Application Support/dsh-desktop/harness/profiles/web"   # macOS
"$HOME/Library/Application Support/dsh-desktop/harness/.desktop-bin/pnpm" add <path-to-this-package>
# Linux: ~/.config/dsh-desktop/harness/profiles/web
```

### DSH CLI

```bash
dsh plugin --profile web add <path-to-this-package>
```

---

## 3. Usage

1. Open **Settings** (sidebar foot) → the **Custom CSS** row in the left nav.
2. Flip **Enable custom CSS** on.
3. Paste or write CSS into the textarea. It is injected immediately.
4. Close the modal — the styles stay applied and are restored on the next launch.

### Example snippets

```css
/* Recolor the brand accent */
:root {
  --dsw-alias-brand-primary: #22d3ee;
}

/* Wider, calmer conversation column */
[data-conversation-scroll] {
  font-size: 15px;
  line-height: 1.7;
}
```

Design tokens available to a snippet are the Harness CSS custom properties
(`--dsw-alias-*`, `--dsw-font-*`), so a theme can stay consistent with whatever
light/dark variant DSH is using.

---

## 4. Files

| File | Role |
|---|---|
| `package.json` | Manifest: `dsh.bundle.patch` + `dsh.client` (`platform: web`, `immediately`, `inject`). |
| `cordis.patch.yml` | Bundle patch that inserts this package into the loader tree. |
| `index.js` | Host half: `GET/POST /api/custom-css/config` and the `$DSH_HOME`-based JSON store. |
| `client.js` | Browser half: style injection, Settings section, toggle + textarea. |
| `install.ps1` | Windows installer (pnpm add + register the bundle entry). |
| `config.json` | Created at runtime under `~/.dsh/plugins/dsh-plugin-custom-css/`. |
| `smoke-test.mjs` | Browser-half test: runs `client.js` against a DOM/React stub and asserts the injection, toggle, and persistence behavior. |
| `host-test.mjs` | Host-half test: mounts the real route on `node:http` and asserts GET/POST/OPTIONS, merge semantics, and restart recovery. |
| `LICENSE` | MIT. |
| `.gitignore` | Keeps runtime state (`config.json`, `plugins/`) out of the repository. |

### Tests

```bash
node smoke-test.mjs   # browser half
node host-test.mjs    # host half
```

## 5. HTTP API

| Method | Path | Body | Response |
|---|---|---|---|
| `GET` | `/api/custom-css/config` | — | `{ "enabled": boolean, "css": string }` |
| `POST` | `/api/custom-css/config` | `{ "enabled"?: boolean, "css"?: string }` | current config plus `saved: boolean` |

## 6. Development notes

- The browser bundle is hand-written framework-form CJS (`window.__ModuleLoader__.load`)
  and requires only platform **seed** modules — `react`, `react/jsx-runtime` — so it
  declares no `dsh.client.external` edges.
- Edit `client.js` and restart the app (or let the Harness HMR reload the plugin
  bundle if your setup watches it).
- To reset everything, delete `~/.dsh/plugins/dsh-plugin-custom-css/config.json`.

## License

MIT © [nguyenduclong-ict](https://github.com/nguyenduclong-ict)

Install

dsh plugin --profile web add github:nguyenduclong-ict/dsh-plugin-custom-css#cdbee9bd8c7f41bb2eac2fc37eb05d8d7de231f0

Profile: web

Source