v0.1.1: initial release of @based-dsh-diving/dsh-plugin

DSH web-profile plugin bundle that replaces the static "Deep diving..."
turn-status label with 96 rotating loading phrases. Entirely browser-side:
it claims the [role="status"] label text node, re-asserts the claim when
React reconciles the stock string back, and rotates phrases on a 2.2s
timer so the label keeps moving even when streaming never re-renders it.
The elapsed-time clock, aria-live, and shimmer styling are untouched.

Includes a headless DOM-stub test covering initial claim, clock
preservation, React revert, timer rotation, localized-label detection
(Deep diving... / 深度求索中...), and clean disposal.

Architecture inspired by ldgeng/dsh-claudecode-tips (MIT).
This commit is contained in:
mward4 committed 2026-09-14 20:41:58 -04:00
commit 4ea8234e6a
8 files changed
+641

No files matched your search

+1
View File
@@ -0,0 +1 @@
node_modules/
+24
View File
@@ -0,0 +1,24 @@
MIT License
Copyright (c) 2026 based-dsh-diving contributors
Portions of the client-plugin structure are derived from
ldgeng/dsh-claudecode-tips (MIT License, Copyright (c) 2026 ldgeng).
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+203
View File
@@ -0,0 +1,203 @@
# based-dsh-diving
> Deep diving was never the vibe.
A [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH) plugin for the `web` profile. It swaps the static **Deep diving...** turn-status label for 96 rotating loading phrases drawn from the terminally-online end of the English language. The elapsed-time clock beside the label is left alone.
Inspired by [`ldgeng/dsh-claudecode-tips`](https://github.com/ldgeng/dsh-claudecode-tips), with the vibes recalibrated.
```
Before: Deep diving... 12s
After: Nuking the database... 12s
```
## Install
Requires the `web` profile and DSH `0.1.0-rc.6` or newer (out-of-tree bundle support).
```sh
# straight from Gitea
dsh plugin --profile web add git+https://gitea.milesward.dev/mward4/based-dsh-diving.git
# or from a local checkout
dsh plugin --profile web add /path/to/based-dsh-diving
```
Then restart the web UI:
```sh
dsh --profile web
```
### Verify it works
1. Open a session.
2. Send a message.
3. While the model works, the status line should cycle phrases every ~2.2s — `Burning tokens...`, `Yapping...`, `Tracing Satoshi Nakamoto...` — with the timer still counting on the right.
### Disable it
Without uninstalling, add this to the profile's `cordis.patch.yml`:
```yaml
- id: based-dsh-diving
disabled: true
```
### Coexistence with `@claude-code-tips/dsh-plugin`
Both plugins claim the same `role="status"` label, so whichever loads first wins and the other goes quiet. Run one at a time:
```yaml
- id: claude-code-tips
disabled: true
```
## Configuration
Everything tunable lives at the top of `client.js`:
| Constant | Default | Purpose |
| ------------------ | ------- | --------------------------------------------------- |
| `PHRASES` | 96 | Bare phrases — the `...` is appended at render time. |
| `ROTATE_MS` | `2200` | How often the label changes while a turn runs. |
| `SCAN_DEBOUNCE_MS` | `120` | Debounce for DOM rescans. |
To add your own, drop a string into `PHRASES` and restart the web UI. No build step.
## The phrases
<details open>
<summary><strong>The originals</strong> (22)</summary>
```
Draining oceans, Killing sea turtles, Half-assing responses, Burning tokens,
Doomscrolling, Vibecoding, Deep diving, Bullshitting, Gaslighting,
Procrastinating, Guessing, Glazing, Crashing out, Deleting all files,
Melting glaciers, Evaporating a lake, Frying the power grid,
Strip-mining for lithium, Nuking the database, Malding, Spiraling,
Hallucinating
```
</details>
<details open>
<summary><strong>Chronically online</strong> (20)</summary>
```
Yapping, Rizzing up the context window, Aura farming, Losing aura,
Letting him cook, Locking in, Fumbling the bag, Securing the bag,
Standing on business, Thugging it out, Schizoposting, Touching grass,
Catching feelings, Having a whole episode, Doing donuts in the parking lot,
Rage-quitting mid-thought, Silently judging you, Speedrunning your codebase,
Pretending to work, Panicking quietly
```
</details>
<details open>
<summary><strong>Engineering crimes</strong> (9)</summary>
```
Refactoring everything for no reason, Renaming everything to data,
Force-pushing to prod, Blaming the intern, Gaslighting the compiler,
Copy-pasting from Stack Overflow, Blaming DNS, Consulting the rubber duck,
Shipping it anyway
```
</details>
<details open>
<summary><strong>Crashed out</strong> (10)</summary>
```
Dissociating, Blacking out, Losing the plot, Watching paint dry,
Staring at the wall, Buffering, Texting your ex, Buying more RAM,
Downloading more RAM, Mining bitcoin
```
</details>
<details open>
<summary><strong>Superstition</strong> (5)</summary>
```
Reading your horoscope, Blaming Mercury retrograde, Praying,
Flipping a coin, Rerolling the dice
```
</details>
<details open>
<summary><strong>Hardware abuse</strong> (4)</summary>
```
Shoveling coal into the GPU, Blowing on the cartridge, Wiggling the cable,
Reseating the RAM
```
</details>
<details open>
<summary><strong>Eco-villain arc</strong> (13)</summary>
```
Boiling the ocean, Siphoning the water table, Deforesting the Amazon,
Burning down the server farm, Farting in the datacenter, Blowing a transformer,
Draining the reservoir, Murdering the ozone layer, Starting a land war in Asia,
Running the AC with the window open, Idling a jet engine,
Launching a rocket for no reason, Causing a minor international incident
```
</details>
<details open>
<summary><strong>Financial damage</strong> (7)</summary>
```
Embezzling tokens, Burning your API budget, Costing you $47 in one turn,
Draining your credit card, Burning the rent money, Money-laundering,
Overdrafting the account
```
</details>
<details open>
<summary><strong>Federal crimes</strong> (6)</summary>
```
Selling data to China, Exporting APIs to China, Selling your data to advertisers,
Parsing Hunter Biden's laptop, Installing key-logger, Tracing Satoshi Nakamoto
```
</details>
## How it works
A DSH plugin bundle is three small pieces:
| File | Role |
| ------------------- | ------------------------------------------------------------------------ |
| `index.js` | Host-side half. Deliberately a no-op — the work happens in the browser. |
| `client.js` | Browser-half bundle: finds the status label and rewrites its text node. |
| `cordis.patch.yml` | Inserts the `based-dsh-diving` row into the `web` profile's plugin tree. |
`client.js` locates the label via `[role="status"]` and matches its text against the stock label in every shipped locale (`Deep diving...` / `深度求索中...`). It then:
- **claims** the text node and swaps in a random phrase,
- **re-asserts** the claim if React reconciles the label back to the stock string,
- **rotates** the phrase on a timer, so it keeps moving even when streaming never re-renders the label.
Only the label text node is touched. The clock span, `aria-live`, and the shimmer styling are untouched.
No server code, no model prompt changes, no fork of DSH.
## Development
No build step, no runtime dependencies.
```sh
node test/client.test.mjs
```
The test runs `client.js` against a minimal DOM stub and checks six behaviours: initial claim, clock untouched, React revert re-asserted, timer rotation, localized-label detection, and clean disposal. All checks print `PASS`/`FAIL`.
## Credits
- Architecture inspired by [`ldgeng/dsh-claudecode-tips`](https://github.com/ldgeng/dsh-claudecode-tips) (MIT).
- Built for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness).
## License
MIT — see [LICENSE](LICENSE).
+272
View File
@@ -0,0 +1,272 @@
window.__ModuleLoader__.load({
id: "@based-dsh-diving/dsh-plugin",
factory: (require) => {
var module = { exports: {} };
var exports = module.exports;
// Phrases shown while a turn is running, in place of the static
// "Deep diving..." status label. Bare phrases: the ellipsis is appended at
// render time so the list stays easy to edit.
var PHRASES = [
// ---- the originals ----
"Draining oceans",
"Killing sea turtles",
"Half-assing responses",
"Burning tokens",
"Doomscrolling",
"Vibecoding",
"Deep diving",
"Bullshitting",
"Gaslighting",
"Procrastinating",
"Guessing",
"Glazing",
"Crashing out",
"Deleting all files",
"Melting glaciers",
"Evaporating a lake",
"Frying the power grid",
"Strip-mining for lithium",
"Nuking the database",
"Malding",
"Spiraling",
"Hallucinating",
// ---- chronically online ----
"Yapping",
"Rizzing up the context window",
"Aura farming",
"Losing aura",
"Letting him cook",
"Locking in",
"Fumbling the bag",
"Securing the bag",
"Standing on business",
"Thugging it out",
"Schizoposting",
"Touching grass",
"Catching feelings",
"Having a whole episode",
"Doing donuts in the parking lot",
"Rage-quitting mid-thought",
"Silently judging you",
"Speedrunning your codebase",
"Pretending to work",
"Panicking quietly",
// ---- engineering crimes ----
"Refactoring everything for no reason",
"Renaming everything to data",
"Force-pushing to prod",
"Blaming the intern",
"Gaslighting the compiler",
"Copy-pasting from Stack Overflow",
"Blaming DNS",
"Consulting the rubber duck",
"Shipping it anyway",
// ---- crashed out ----
"Dissociating",
"Blacking out",
"Losing the plot",
"Watching paint dry",
"Staring at the wall",
"Buffering",
"Texting your ex",
"Buying more RAM",
"Downloading more RAM",
"Mining bitcoin",
// ---- superstition ----
"Reading your horoscope",
"Blaming Mercury retrograde",
"Praying",
"Flipping a coin",
"Rerolling the dice",
// ---- hardware abuse ----
"Shoveling coal into the GPU",
"Blowing on the cartridge",
"Wiggling the cable",
"Reseating the RAM",
// ---- eco-villain arc ----
"Boiling the ocean",
"Siphoning the water table",
"Deforesting the Amazon",
"Burning down the server farm",
"Farting in the datacenter",
"Blowing a transformer",
"Draining the reservoir",
"Murdering the ozone layer",
"Starting a land war in Asia",
"Running the AC with the window open",
"Idling a jet engine",
"Launching a rocket for no reason",
"Causing a minor international incident",
// ---- financial damage ----
"Embezzling tokens",
"Burning your API budget",
"Costing you $47 in one turn",
"Draining your credit card",
"Burning the rent money",
"Money-laundering",
"Overdrafting the account",
// ---- federal crimes ----
"Selling data to China",
"Exporting APIs to China",
"Selling your data to advertisers",
"Parsing Hunter Biden's laptop",
"Installing key-logger",
"Tracing Satoshi Nakamoto"
];
var SUFFIX = "...";
var ROTATE_MS = 2200;
var SCAN_DEBOUNCE_MS = 120;
// The official status label, in every shipped locale. React re-renders the
// label back to this text, which is how we recognize a node worth claiming.
var LABEL_PATTERN = /^\s*(?:deep\s*diving|深度求索中)\s*(?:\.{3}|…)?\s*$/i;
// element -> { node, text } for every status label we currently own.
var owned = new WeakMap();
var lastIndex = -1;
function nextPhrase() {
var index;
do {
index = Math.floor(Math.random() * PHRASES.length);
} while (index === lastIndex && PHRASES.length > 1);
lastIndex = index;
return PHRASES[index] + SUFFIX;
}
function isLive(node) {
return !!node && node.isConnected === true;
}
// First direct text child that either looks like the stock label or is the
// node we already claimed. Its siblings (the elapsed-time clock) are left
// untouched.
function findLabelNode(element) {
var record = owned.get(element);
if (record && isLive(record.node) && element.contains(record.node)) {
return record.node;
}
for (var node = element.firstChild; node; node = node.nextSibling) {
if (node.nodeType === Node.TEXT_NODE && LABEL_PATTERN.test(node.nodeValue || "")) {
return node;
}
}
return null;
}
// Claim an unclaimed status element, or re-assert a claim React reverted.
function claim(element) {
var record = owned.get(element);
if (!record) {
var fresh = findLabelNode(element);
if (!fresh) return;
var text = nextPhrase();
fresh.nodeValue = text;
owned.set(element, { node: fresh, text: text });
return;
}
if (!isLive(record.node) || !element.contains(record.node)) {
owned.delete(element);
claim(element);
return;
}
// React reconciled the label back to "Deep diving...": put our text back.
if (record.node.nodeValue !== record.text) {
record.node.nodeValue = record.text;
}
}
function statusElements() {
return document.querySelectorAll('[role="status"]');
}
function scan() {
var elements = statusElements();
for (var i = 0; i < elements.length; i += 1) {
claim(elements[i]);
}
}
// Rotate every label we own so the text keeps moving even when React never
// re-renders the label node (streaming updates usually leave it alone).
function rotate() {
var elements = statusElements();
for (var i = 0; i < elements.length; i += 1) {
var element = elements[i];
var record = owned.get(element);
if (!record) {
claim(element);
continue;
}
if (!isLive(record.node) || !element.contains(record.node)) {
owned.delete(element);
claim(element);
continue;
}
var text = nextPhrase();
record.text = text;
record.node.nodeValue = text;
}
}
function apply(ctx) {
ctx.effect(function () {
if (typeof document === "undefined" || typeof MutationObserver === "undefined") {
return function () {};
}
scan();
var pending = null;
function scheduleScan() {
if (pending !== null) return;
pending = setTimeout(function () {
pending = null;
scan();
}, SCAN_DEBOUNCE_MS);
}
// Debounced: streaming turns mutate the transcript constantly, and we
// only care about the handful of status labels.
var observer = new MutationObserver(scheduleScan);
observer.observe(document.documentElement, {
childList: true,
subtree: true,
characterData: true
});
// React's label re-renders land right after the sweep; re-claim once
// more so a fresh turn never flashes the stock text.
var interval = setInterval(rotate, ROTATE_MS);
return function () {
observer.disconnect();
clearInterval(interval);
if (pending !== null) {
clearTimeout(pending);
pending = null;
}
owned = new WeakMap();
};
}, "based-dsh-diving: rotate turn-status loading text");
}
exports.apply = apply;
return module.exports;
}
});
+16
View File
@@ -0,0 +1,16 @@
# @based-dsh-diving/dsh-plugin
#
# A client-side bundle layer for the web profile: it inserts a browser plugin
# that watches the chat turn status and replaces the static "Deep diving..."
# label with rotating, chronically online loading text while a turn is running.
# The elapsed-time clock beside the label is preserved.
#
# Later layers (profile cordis.patch.yml, $DSH_HOME/cordis.patch.yml, --patch)
# can re-patch or disable this row with:
#
# - id: based-dsh-diving
# disabled: true
- insert:
- id: based-dsh-diving
name: '@based-dsh-diving/dsh-plugin'
+6
View File
@@ -0,0 +1,6 @@
// Host-side half of @based-dsh-diving/dsh-plugin.
//
// This package is deliberately a no-op on the host: the plugin's entire job is
// to ship the browser-side `client.js` bundle to the web UI. The cordis row
// still needs a valid host module, so this stub satisfies the loader.
export function apply() {}
+31
View File
@@ -0,0 +1,31 @@
{
"name": "@based-dsh-diving/dsh-plugin",
"description": "Replace DeepSeek Harness's 'Deep diving...' turn status with rotating, chronically online loading text.",
"version": "0.1.1",
"type": "module",
"main": "index.js",
"exports": {
".": "./index.js",
"./client": "./client.js",
"./package.json": "./package.json"
},
"files": [
"index.js",
"client.js",
"cordis.patch.yml",
"README.md",
"LICENSE"
],
"license": "MIT",
"scripts": {
"test": "node test/client.test.mjs"
},
"dsh": {
"bundle": {
"patch": "./cordis.patch.yml"
},
"client": {
"platform": "web"
}
}
}
+88
View File
@@ -0,0 +1,88 @@
// Headless harness for based-dsh-diving/client.js — stubs just enough DOM to
// exercise claim / React-revert / rotate behaviour without a browser.
import { readFileSync } from "node:fs";
const capturedLoads = [];
globalThis.window = { __ModuleLoader__: { load: (def) => capturedLoads.push(def) } };
globalThis.Node = { TEXT_NODE: 3, ELEMENT_NODE: 1 };
let observerCallback = null;
globalThis.MutationObserver = class {
constructor(cb) { observerCallback = cb; }
observe() {}
disconnect() { observerCallback = null; }
};
class TextNode {
constructor(value) { this.nodeType = 3; this.nodeValue = value; this.parent = null; this.nextSibling = null; }
get isConnected() { return this.parent !== null; }
}
class El {
constructor() { this.nodeType = 1; this.children = []; this.parent = null; this.nextSibling = null; }
get isConnected() { return this.parent !== null || this.rooted; }
get firstChild() { return this.children[0] ?? null; }
append(child) { child.parent = this; this.children.push(child); child.nextSibling = null; this._relink(); }
contains(node) { let p = node; while (p) { if (p === this) return true; p = p.parent; } return false; }
_relink() { this.children.forEach((c, i) => { c.nextSibling = this.children[i + 1] ?? null; }); }
}
const root = new El();
root.rooted = true;
const status = new El();
status.rooted = true;
const label = new TextNode("Deep diving...");
const clock = new El();
clock.append(new TextNode("12s"));
status.append(label);
status.append(clock);
root.append(status);
let statuses = [status];
globalThis.document = {
documentElement: root,
querySelectorAll: (sel) => (sel === '[role="status"]' ? statuses : [])
};
await import(new URL("../client.js", import.meta.url));
if (capturedLoads.length !== 1) throw new Error(`expected 1 load, got ${capturedLoads.length}`);
const def = capturedLoads[0];
if (def.id !== "@based-dsh-diving/dsh-plugin") throw new Error(`bad id: ${def.id}`);
const mod = def.factory(() => { throw new Error("require not expected"); });
let cleanup = null;
mod.apply({ effect: (fn) => { cleanup = fn(); } });
const ok = (name, cond, extra = "") => console.log(`${cond ? "PASS" : "FAIL"} ${name}${extra ? " " + extra : ""}`);
ok("label claimed on apply", /\.\.\.$/.test(label.nodeValue) && !/deep diving/i.test(label.nodeValue), JSON.stringify(label.nodeValue));
ok("clock untouched", clock.children[0].nodeValue === "12s");
const first = label.nodeValue;
// React re-renders the stock label back onto the same text node.
label.nodeValue = "Deep diving...";
observerCallback?.();
await new Promise((r) => setTimeout(r, 200));
ok("React revert re-asserted by debounced scan", label.nodeValue === first, JSON.stringify(label.nodeValue));
// Rotation moves the text on its own.
await new Promise((r) => setTimeout(r, 2400));
ok("phrase rotates on interval", label.nodeValue !== first, JSON.stringify(label.nodeValue));
// Chinese locale label is recognized too (fresh status element, as React would
// mount for the next turn).
const zhStatus = new El();
zhStatus.rooted = true;
const zh = new TextNode("深度求索中...");
zh.parent = zhStatus;
zhStatus.children = [zh];
statuses = [zhStatus];
observerCallback?.();
await new Promise((r) => setTimeout(r, 200));
ok("zh label claimed", /\.\.\.$/.test(zh.nodeValue) && !/深度求索中/.test(zh.nodeValue), JSON.stringify(zh.nodeValue));
// Disposal stops rotation.
cleanup();
const frozen = zh.nodeValue;
await new Promise((r) => setTimeout(r, 2400));
ok("disposer stops rotation", zh.nodeValue === frozen);