Replaces the "Deep diving..." status text at the bottom of rounds in DSH Web interface, featuring stage-aware switching, typewriter effect, colorful gradient, and visual vocabulary editing.
- Language
- JavaScript
- License
- MIT
- Branch
- main
Install
$ dsh plugin --profile web add dsh-status-rotatorRun the command above in your terminal to install this plugin via the dsh CLI. You can switch Profile in the top-right corner. New to dsh? Read the beginner tutorial
Install via your agent
Install the DeepSeek Harness plugin 01Virex/dsh-status-rotator for me: review the repository at https://github.com/01Virex/dsh-status-rotator first, then run the install command and verify the plugin loads successfully.
Paste this instruction to the DSH Web GUI assistant — it will install and verify for you.
One-Line Description
Replace the fixed "Deep diving..." status text at the bottom of the DSH Web interface turn display with your own text: switchable by turn phase, typewriter character-by-character appearance, flowing rainbow gradient (can be disabled), and automatically switch between Chinese and English based on DSH language.
Core Features
- Replace turn status text: Take over the TurnStatus copy at the bottom of DSH chat, no longer showing "Deep diving..."
- Switch copy by turn phase: thinking (turn just started) / running (after clock appears) / long (exceeds threshold) three phrase libraries
- Typewriter character-by-character output: Each phrase is typed character by character at configurable intervals, 0 to disable
- Flowing rainbow gradient text: Seven-color gradient enabled by default, can be disabled with one click or customized for colors and flow speed
- Auto-switch Chinese/English copy: Follows DSH settings language in real-time, falls back to Chinese for unknown languages
- DSH settings page phrase editor: Plugin adds a "Status Copy" page to the settings sidebar, with Chinese/English × three-stage text boxes for visual editing
- Hot reload: Reads configuration periodically when page is open, reloads immediately when switching back to the tab, no need to refresh or restart to apply changes
Technical Implementation
- Language: JavaScript (ESM)
- Key Dependencies: No external npm dependencies; node side only uses
node:fs/promises,node:url,node:path; browser side uses DSH's built-in React (from__ModuleLoader__.load) and built-inlocale/slotsservices - Architecture: Cordis dual-end plugin; node side
lib/index.jsregistersGET/PUT /plugins/dsh-status-rotator/config.jsonroutes viactx.webServer.registerto read/write localconfig.json; client sidelib/client.jsinjects Web UI viawindow.__ModuleLoader__.load, listens to DOM to find[role="status"][aria-live="polite"]element and rotates copy; registers settings panel viactx.slots.inject("settings.section") - Entry Files:
lib/index.js(node side) +lib/client.js(browser side), exposed viamainandexportsinpackage.json
Use Cases
Users who want to customize the DSH Web interface turn waiting experience: can replace with more colloquial Chinese ("正在帮你想", "再等一下下"), English ("Cooking up a response", "Still thinking…"), or even QQ group member rotation Easter egg copy to make the waiting process more relaxing.
Prerequisites & Compatibility
| Dependency | Minimum Version | Notes |
|---|---|---|
| DSH | Not declared | No dsh version dependency declared in package.json; runs by cordis.patch.yml and service names webServer / locale / slots in lib/index.js |
| Node.js | Not declared | Node scripts gen-config.cjs and scripts/fetch-qq-group.cjs use CommonJS, require Node 14+; lib/index.js uses node: protocol, requires Node 18+ |
| Platform | Cross-platform | Pure frontend injection + pure node file I/O, no native module dependencies |
| Native modules | None | — |
Installation
dsh plugin --profile web add github:01Virex/dsh-status-rotator
Configuration
The phrase library is saved in config.json in the plugin root directory (first installation requires running node gen-config.cjs to initialize from config.example.json).
| Config | Type | Description | Default |
|---|---|---|---|
config.intervalMs | Number (ms) | Interval to rotate to the next phrase within the same phase | 10000 |
config.typeSpeedMs | Number (ms/char) | Typewriter interval per character, 0 disables typewriter and shows full copy immediately | 30 |
config.longAfterMs | Number (ms) | Threshold to enter long phase (slow/stuck turn) | 60000 |
config.reloadIntervalMs | Number (ms) | Auto re-read config.json interval while page stays open, 0 to disable | 15000 |
config.debug | Boolean | Whether to output diagnostic logs to browser console | false |
config.gradient.enabled | Boolean | Whether to add flowing rainbow gradient to status text | true |
config.gradient.colors | String array (≥2) | Gradient color sequence, loops end-to-end | ["#ff5f6d", "#ffc371", "#ffdd55", "#7dff7d", "#5fd4ff", "#a78bfa", "#ff8adb"] |
config.gradient.speed | Number (seconds/loop) | Gradient flow speed | 4 |
phrases.zh.thinking | String array | Chinese thinking phase copy (turn just started, clock not yet appeared) | From config.example.json |
phrases.zh.running | String array | Chinese running phase copy (clock appeared, threshold not exceeded) | From config.example.json |
phrases.zh.long | String array | Chinese long phase copy (exceeds longAfterMs) | From config.example.json |
phrases.en.thinking | String array | English thinking phase copy | From config.example.json |
phrases.en.running | String array | English running phase copy | From config.example.json |
phrases.en.long | String array | English long phase copy | From config.example.json |
FAQ
Q: Do I need to restart dsh web after first installation?
A: Yes. The node-side HTTP route (/plugins/dsh-status-rotator/config.json) is only registered after restarting dsh web; after that, modifying copy and saving the phrase library doesn't require restarting again.
Q: Do I need to refresh the page after modifying copy?
A: No. The plugin automatically re-reads config.json every reloadIntervalMs (15 seconds by default), and also re-reads immediately when switching back to the browser tab; saving via DSH Settings → Status Copy page applies hot immediately.
Q: Can't see rainbow gradient text, what should I do?
A: Check if gradient.enabled in config.json is true. If your browser or DSH theme has special handling for animations, the gradient may be compressed to solid color; you can temporarily change gradient.colors to two high-contrast colors to verify.
Q: After editing, page still shows old copy, console has ⚠ warning?
A: Browser localStorage has dsh-status-rotator.texts, dsh-status-rotator.config, or dsh-status-rotator.url overriding config.json. In DevTools → Application → Local Storage, clear the corresponding key and refresh.
Q: How to generate copy from QQ group members?
A: Default group number is 684306814. After connecting to OneBot v11 HTTP API, run node scripts/fetch-qq-group.cjs --url http://127.0.0.1:3000 --token yourtoken, adding --activate will directly overwrite current config.json (old file backed up as config.backup-<timestamp>.json); without a bot, you can also prepare members.txt (one nickname per line) and use --input members.txt.
Q: Will the plugin affect the runtime clock that appears after 15 seconds?
A: No. The plugin only replaces the text in TurnStatus, the clock itself remains unchanged, and the clock reading is used to determine the phase (appeared = running, exceeded longAfterMs = long).
Q: How to uninstall?
A: Delete the status-rotator line from cordis.patch.yml (for manual installation), then restart dsh web.
Learning Curve
Beginner — No coding required, just edit config.json or modify copy in DSH settings panel to use; only need one extra step if you want to use QQ group member generator or custom external JSON.
Known Issues & Limitations
- Clock text parsing only recognizes a few DSH-localized formats (
15秒/1分02秒/15s/1m 02s/mm:ss/h:mm:ss); numbers appearing in regular copy won't be mistakenly interpreted as duration - Settings page
PUTrequest body limit is 5 MiB (MAX_BODY_BYTESinlib/index.js), returns 413 when exceeded - If browser localStorage has
dsh-status-rotator.texts/.config/.urlset, it will silently overrideconfig.json; only versions injected via__ModuleLoader__will output[status-rotator] ⚠ localStorage override activewarning to console - Settings page "Save" button doesn't touch styles outside DSH theme; modifying config items requires saving before they take effect
- Old pure-copy JSON format (
{ "zh": [...] }or{ "thinking": [...] }) is still compatible and will be treated as thinking phase, other phases fallback automatically
English | 中文
Replaces the Deep diving... status line in the DeepSeek Harness (dsh) Web UI's turn footer with your own text: phase-aware switching, typewriter output, animated rainbow gradient (optional), and timed rotation. The elapsed-time clock (which appears after 15 seconds) is untouched.
Installation
Two ways to install: the recommended dsh plugin add command, or the manual copy. Either way, you need to restart dsh web once after first install.
Option A: dsh plugin add (recommended)
The plugin's package.json declares a dsh.bundle.patch manifest, so it's recognized automatically after install — no extra flags needed. The command syntax is dsh plugin --profile <name> add <package> (e.g. --profile web):
- From npm (easiest):
dsh plugin --profile web add dsh-status-rotator - From a clone:
dsh plugin --profile web add ./dsh-status-rotator - From a release package: download the packaged tarball from the Release page, then
dsh plugin --profile web add /path/to/dsh-status-rotator-<version>.tgz.
Option B: manual install
-
Put this project directory under your profile's node_modules (default
C:\Users\<you>\.dsh\profiles\node_modules\dsh-status-rotator\); -
Insert the following into the profile's
cordis.patch.yml:- insert: - id: status-rotator name: dsh-status-rotator -
Run
node gen-config.cjsto initialize the localconfig.json(copied fromconfig.example.json); -
Restart
dsh weband hard-refresh the browser with Ctrl+F5.
Features
- Phase-aware: three sets of phrases —
thinking(just started) /running(after 15s) /long(past the threshold). Switches immediately when the clock appears or the timeout hits, no need to wait for the rotation interval; - Typewriter effect: phrases are typed out character by character, speed configurable, 0 disables it;
- Rainbow gradient: text rendered with an animated gradient, colors and speed configurable, can be turned off with one switch;
- Phrases separated from code: all phrases live in
config.json, editing them requires zero code and no restart; - Settings page: a new "Status Texts" page in DSH's Settings, with visual editing for the Chinese/English × three-phase phrase banks, saves take effect immediately;
- Auto-loading: the node half registers an HTTP route to serve
config.json, works out of the box with no localStorage or deployment needed; - Hot reload: while the page stays open it re-reads
config.jsonperiodically, and re-reads immediately when you switch back to the tab — no refresh needed to apply new phrases; - Multilingual: phrases switch live between Chinese and English following Settings → Language, unknown languages fall back to Chinese;
- Zero-intrusion targeting: locates TurnStatus precisely by
role="status"+aria-live="polite", so it never touches code snippets in the chat history or other aria-live regions, and never touches the clock.
Phase Awareness
Phrases are split into three groups based on turn progress (determined by whether a clock has appeared in the TurnStatus element and its reading):
| Phase | Trigger | Default duration |
|---|---|---|
thinking | Turn just started, no clock | 0 ~ 15s |
running | Clock visible, under the limit | 15s ~ longAfterMs |
long | Clock past longAfterMs | ≥ 60s |
Phase changes swap the phrase immediately without waiting for the rotation interval. If a phase has no phrase group, it falls back automatically (running → thinking → any non-empty group).
Rainbow Gradient
Status text is shown with an animated rainbow gradient by default (applies to the text only, not the clock). Can be disabled or re-colored in the config:
"gradient": {
"enabled": false, // false to disable; true for default colors
"colors": ["#ff5f6d", "#00ff88", "#4da6ff"], // gradient color sequence (at least 2, first/last cycle)
"speed": 4 // animation speed (seconds per cycle)
}
Configuration
Phrases are fully separated from the source code and live in JSON config files. There are two config files at the project root:
config.example.json— the complete template committed to the repo: default config + all phrases (bilingual, split into three phases);config.json— your local personalized config, initialized bynode gen-config.cjs(only created when missing, never overwrites your changes). It's in.gitignore, so edit freely without polluting git.
Auto-loading (default): the plugin's node half registers an HTTP route (/plugins/dsh-status-rotator/config.json) that serves the config.json next to the plugin (read from disk on every request). The browser fetches it automatically by default, and while the page stays open it re-reads every reloadIntervalMs, plus immediately when you switch back to the tab, so as long as config.json sits in the plugin directory, phrase edits take effect without a refresh or restart. The only restart of dsh web needed is on first install.
{
"config": { "intervalMs": 10000, "typeSpeedMs": 30, "longAfterMs": 60000, "reloadIntervalMs": 15000, "debug": false, "gradient": { "enabled": true, "colors": ["#ff5f6d", "#ffc371", "#ffdd55", "#7dff7d", "#5fd4ff", "#a78bfa", "#ff8adb"], "speed": 4 } },
"phrases": { "zh": { "thinking": ["…"], "running": ["…"], "long": ["…"] }, "en": { "thinking": ["…"], "running": ["…"], "long": ["…"] } }
}
| Key | Default | Description |
|---|---|---|
intervalMs | 10000 | Rotation interval (ms) |
typeSpeedMs | 30 | Typewriter delay per character (ms), 0 disables the typewriter |
longAfterMs | 60000 | Threshold for entering the long phase |
reloadIntervalMs | 15000 | Interval for auto re-reading config.json while the page is open (ms), 0 disables |
debug | false | Console diagnostic logs |
gradient | see above | Rainbow gradient: false / true / {enabled, colors, speed} |
phrases | from config file | The phrases (Chinese/English × three phases; partial entries allowed, missing ones fall back to other sources) |
Phrase source priority, highest first:
- localStorage single-text override
dsh-status-rotator.texts[.<locale>]/texts; - localStorage full config
dsh-status-rotator.config(paste JSON, applies after refresh); - External JSON:
dsh-status-rotator.url>EXTERNAL_URLconstant > local auto-load (/plugins/dsh-status-rotator/config.json); - Built-in defaults: only
DEFAULT_CONFIGat the top oflib/client.js(no phrases).
If a localStorage override matches, the external config.json is silently suppressed; the new version logs a [status-rotator] ⚠ localStorage override active warning in the browser console — when you see it, clear the corresponding key.
Old phrase-only external JSON ({ "zh": [...], "en": [...] } or { "thinking": [...] }) is still supported and treated as a "phrases-only config".
Phrases switch live between Chinese and English following Settings → Language; unknown languages fall back to Chinese.
Editing the Phrase Bank in the Settings Page
Open Settings in the bottom-left of DSH and a new Status Texts page appears in the navigation:
- 中文 / English tabs, each with three text boxes for
thinking/running/long, one phrase per line, blank lines are ignored; - Each phase shows the current phrase count in real time;
- Basic settings (rotation interval, typewriter speed, long-task threshold, auto-reload interval) live on the same page;
- Clicking "Save Phrase Bank" makes the browser
PUTthe full JSON to/plugins/dsh-status-rotator/config.json; the node half validates it and writes it back atomically, and already-open pages hot-apply it immediately without a refresh; - Submitted content is validated (phrases must be string arrays, etc.); invalid content returns 400 and shows an error on the page, so the config file can't be corrupted.
After upgrading to a version with the settings page, restart dsh web once (so the node half registers the write endpoint); everything after that can be done from the page.
QQ Group Member Phrase Generator
To turn every member of a QQ group into a phrase like 正在路由(群成员)写代码... (meaning "routing (group member) to write code..."), use scripts/fetch-qq-group.cjs to generate a standalone config file in one go — no need to type out the member list by hand.
Prerequisites: the bot is in the target group and you have a OneBot v11 compatible HTTP API (e.g. NapCat / LLOneBot / go-cqhttp / OpenShamrock).
# The default group is 684306814; generates config.qq684306814.json directly
node scripts/fetch-qq-group.cjs --url http://127.0.0.1:3000 --token your-token
# Directly replace the config.json the plugin actually uses (the old one is backed up as config.backup-<timestamp>.json)
node scripts/fetch-qq-group.cjs --url http://127.0.0.1:3000 --token your-token --activate
# No bot API? Save the member list as members.txt (one nickname per line) and generate from it
node scripts/fetch-qq-group.cjs --input members.txt
| Option | Default | Description |
|---|---|---|
-g, --group | 684306814 | QQ group ID (also reads the QQ_GROUP_ID env var) |
-u, --url | http://127.0.0.1:3000 | OneBot HTTP URL (also reads ONEBOT_HTTP_URL) |
-t, --token | empty | Access token (also reads ONEBOT_ACCESS_TOKEN) |
-a, --action | get_group_member_list | Action path; frameworks with a prefix use /api/... |
-i, --input | none | Local member list: txt (one per line) / json (array) / csv (first column) |
-o, --output | config.qq684306814.json | Output file |
--activate | off | Write back to config.json directly and back up the old file |
--dry-run | off | Preview only, writes nothing |
The display name prefers the group card name, falling back to the nickname. The generated file contains only the zh.thinking group: per this plugin's fallback rules, the thinking phase uses it directly and the other phases fall back to the same group. Template: config.qq684306814.example.json; the generated config.qq684306814.json is gitignored.
Project Structure
dsh-status-rotator/
├── lib/
│ ├── index.js # node half: registers the HTTP route for config.json
│ └── client.js # client half: status text replacement / gradient / typewriter
├── config.example.json # complete template (default config + all phrases, committed)
├── config.qq684306814.example.json # QQ group member phrase template (scripts/fetch-qq-group.cjs generates the real file)
├── config.json # local personalized config (gitignored)
├── gen-config.cjs # script that initializes config.json
├── scripts/
│ └── fetch-qq-group.cjs # fetches QQ group members and generates the phrase config
├── package.json
├── README.md # English docs
├── README_ZH.md # Chinese docs
├── CONTRIBUTORS.md # English contributors
├── CONTRIBUTORS_ZH.md # Chinese contributors
└── LICENSE
Uninstall
Remove the status-rotator line from cordis.patch.yml and restart dsh web.
Contributing
Issues and pull requests are welcome. The easiest way to add phrases: edit the phrases field in config.json or config.example.json directly — no code changes needed.
Credits
This project wouldn't exist without the help of its contributors — see CONTRIBUTORS.md.
License
Read the usage guide →
Install steps, key points, FAQ and compatibility for this plugin — auto-derived from indexed fields.
Listing badge
[](https://deepseek-plugin.org/plugins/01Virex/dsh-status-rotator)Paste this markdown into your GitHub README to link back to this listing. The badge only states the listing — not a security endorsement.