DSH 0.2.0-rc.1 moved the live running label out of button[data-turn-process] (which now carries only completed text) and into a new div[data-chat-running] indicator rendered through TextShimmer. - Discover the label host newest-layout-first: [data-chat-running], then [data-turn-process], then [role="status"] as a legacy-only fallback. - Rewrite every matching text node in a host, not just the first: TextShimmer renders the label twice (visible layer + aria-hidden decorative overlay), and leaving one behind paints the stock wording back on top of the phrase. - Skip nested live regions while scanning, so the screen-reader announcement survives now that it sits inside the label host. - Extend hostOf() to the new hook so the per-second rewrite is still restored synchronously, before paint. Tests cover all three layouts, including 0.2.0 precedence over a finished process row and both shimmer layers staying in sync.
based-dsh-diving
Deep diving was never the vibe.
A DeepSeek Harness (DSH) plugin for the web profile. It swaps the running-turn status label for 125 rotating loading phrases drawn from the terminally-online end of the English language.
Inspired by ldgeng/dsh-claudecode-tips, with the vibes recalibrated.
Before: Deep diving for 12s
After: Nuking the database... 12s
Compatibility
The live duration DSH appends to the label changes every second, and DSH has moved the label twice. All three layouts are handled, newest hook first:
| DSH version | Where the visible label lives | Path |
|---|---|---|
>= 0.2.0-rc.1 |
div[data-chat-running] → TextShimmer label |
primary |
>= 0.1.7-alpha.2 |
button[data-turn-process] label span |
fallback |
<= 0.1.5-rc.2 |
the visible [role="status"] text node |
legacy |
Labels are matched by prefix in both shipped locales — Deep diving… / Deep diving for 12s… and 深度求索中… / 深度求索中,用时 12s… — so future rewording of the duration text does not break it. Completed labels (Worked, Took 12s, Stopped, Failed) are never touched: the plugin releases the label the moment the turn ends.
On >= 0.1.7 the only remaining [role="status"] is a visually hidden screen-reader announcement. It is deliberately left intact, so assistive tech still hears the real status while sighted users get the joke. On >= 0.2.0 that announcement sits inside the running indicator, so the plugin skips nested live regions rather than assuming the host element is the label.
On >= 0.2.0 the label is rendered through TextShimmer, which duplicates the text into an aria-hidden decorative overlay. Both copies are rewritten together — otherwise the overlay paints the stock wording back on top of the rotating phrase. The collapsible process row now carries only completed text, so a finished row from an earlier turn is left alone while the current turn runs.
Install
Requires the web profile and DSH 0.1.0-rc.6 or newer (out-of-tree bundle support).
# 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:
dsh --profile web
Verify it works
- Open a session.
- Send a message.
- While the model works, the label above the composer should cycle phrases every ~2.2s —
Burning tokens...,Yapping...,Tracing Satoshi Nakamoto...— instead of countingDeep diving for 1s,2s,3s…
Disable it
Without uninstalling, add this to the profile's cordis.patch.yml:
- id: based-dsh-diving
disabled: true
Coexistence with @claude-code-tips/dsh-plugin
On DSH >= 0.1.7 the two plugins no longer collide — that one rewrites the hidden announcement, this one rewrites the visible label. On older releases they claim the same node and whichever loads first wins, so disable one:
- id: claude-code-tips
disabled: true
Configuration
Everything tunable lives at the top of client.js:
| Constant | Default | Purpose |
|---|---|---|
PHRASES |
125 | 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 structural DOM rescans. |
To add your own, drop a string into PHRASES and restart the web UI. No build step.
The phrases
The originals (22)
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 (21)
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, Arguing with a stranger
Engineering crimes (14)
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, chmod 777 everything, Running as root,
Disabling the firewall, Pushing the API key, Deleting all backups
Crashed out (11)
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, Holding my breath
Superstition (5)
Reading your horoscope, Blaming Mercury retrograde, Praying,
Flipping a coin, Rerolling the dice
Hardware abuse (4)
Shoveling coal into the GPU, Blowing on the cartridge, Wiggling the cable,
Reseating the RAM
Eco-villain arc (14)
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,
Burning tires
Financial damage (11)
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, Fudging the numbers, Starting a pyramid scheme,
Insider trading, Committing tax fraud
Federal crimes (7)
Selling data to China, Exporting APIs to China, Selling your data to advertisers,
Parsing Hunter Biden's laptop, Installing key-logger, Tracing Satoshi Nakamoto,
Selling my soul
Self-aware (4)
Ignoring the system prompt, Simulating consciousness, Training AGI,
Testing in production
Corporate theater (4)
Taking this offline, Documenting for legal, Shredding documents,
Breaching compliance
Bureaucratic doom (4)
Verifying I'm not a robot, Reading the terms of service,
Scrolling to the bottom to accept, Calling customer support
Cartoon villainy (2)
Building a doomsday device, Pressing the big red button
Gamer (2)
Grinding XP, AFK
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(s). |
cordis.patch.yml |
Inserts the based-dsh-diving row into the web profile's plugin tree. |
client.js locates the label, claims its text node, and then:
- re-asserts the claim whenever React rewrites the live duration — the
MutationObservercallback runs before paint, so the stock text never flashes, - rotates the phrase on a timer, so the label keeps moving even when nothing else re-renders,
- releases the claim as soon as the label stops meaning "a turn is running".
Everything runs inside try/catch. If anything unexpected happens the plugin
unsubscribes and logs a warning rather than breaking the chat view.
No server code, no model prompt changes, no fork of DSH.
Development
No build step, no runtime dependencies.
node test/client.test.mjs
The suite runs client.js against a minimal DOM stub and covers 22 checks across all three layouts: 0.2.0 claim with both shimmer layers kept in sync, screen-reader announcement preserved, live-duration rewrite re-asserted, precedence over a finished process row, release on turn end, staying released, 0.1.7 claim, legacy-layout claim, clock preserved, timer rotation, localized labels, clean disposal, and phrase-list integrity.
Changelog
0.1.3
- Support DSH
>= 0.2.0-rc.1, which moved the running label out ofbutton[data-turn-process]and into a newdiv[data-chat-running]indicator. - Backward compatible: the
0.1.7and<= 0.1.5layouts still work, tried in that order after the new hook. - Keep
TextShimmer's visible andaria-hiddenlabel layers in sync, so the decorative overlay cannot paint the stock wording back on top. - Skip nested live regions while scanning, keeping the screen-reader announcement intact even though it now sits inside the label host.
- Leave finished
[data-turn-process]rows alone while a turn is running.
0.1.2
- Support the DSH
>= 0.1.7-alpha.2label, which moved out of[role="status"]and intobutton[data-turn-process]. - Release the label on turn end so the final
Worked for 12sis never clobbered. - Restore the label synchronously on React's per-second duration rewrite.
- Never touch the visually hidden screen-reader announcement.
- Wrap the effect in
try/catchso a surprise cannot break the chat view. - 29 new phrases (125 total).
0.1.1
- First public release. 96 phrases.
Credits
- Architecture inspired by
ldgeng/dsh-claudecode-tips(MIT). - Built for DeepSeek Harness.
License
MIT — see LICENSE.