Files
based-dsh-diving/client.js
T
mward4 32381a6d00 v0.1.2: support the DSH 0.1.7-alpha.2 turn-status label
DSH 0.1.7-alpha.2 removed the visible [role="status"] turn status. The
running label now lives inside a <button data-turn-process> and reads
"Deep diving for 12s" (en) / "深度求索中,用时12s" (zh), rewritten every
second with the live duration. The only remaining [role="status"] is a
visually hidden screen-reader announcement, which the plugin previously
rewrote by mistake while the visible label went untouched.

- Locate the label via [data-turn-process], falling back to the legacy
  [role="status"] text node on DSH <= 0.1.5.
- Match running labels by locale-aware prefix so duration rewording and
  future locales keep working.
- Release the claim when the label stops meaning "a turn is running", so
  the final "Worked for 12s" is never clobbered.
- Restore the label synchronously from the MutationObserver fast path:
  observer callbacks run before paint, so React's per-second duration
  rewrite no longer flashes the stock text through.
- Never touch the visually hidden announcement; screen readers still get
  the real status.
- Wrap the effect in try/catch so an unexpected error disables the plugin
  instead of breaking the chat view.
- 29 new phrases (125 total).
- Test suite expanded to twelve checks covering both DOM layouts,
  turn-end release, and phrase-list integrity.
2026-09-23 19:15:50 -04:00

384 lines
12 KiB
JavaScript

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 stock 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",
"Arguing with a stranger",
// ---- 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",
"chmod 777 everything",
"Running as root",
"Disabling the firewall",
"Pushing the API key",
"Deleting all backups",
// ---- 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",
"Holding my breath",
// ---- 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",
"Burning tires",
// ---- 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",
"Fudging the numbers",
"Starting a pyramid scheme",
"Insider trading",
"Committing tax fraud",
// ---- 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",
"Selling my soul",
// ---- self-aware ----
"Ignoring the system prompt",
"Simulating consciousness",
"Training AGI",
"Testing in production",
// ---- corporate theater ----
"Taking this offline",
"Documenting for legal",
"Shredding documents",
"Breaching compliance",
// ---- bureaucratic doom ----
"Verifying I'm not a robot",
"Reading the terms of service",
"Scrolling to the bottom to accept",
"Calling customer support",
// ---- cartoon villainy ----
"Building a doomsday device",
"Pressing the big red button",
// ---- gamer ----
"Grinding XP",
"AFK"
];
var SUFFIX = "...";
var ROTATE_MS = 2200;
var SCAN_DEBOUNCE_MS = 120;
// The stock running-turn label, across locales and both DOM layouts:
//
// DSH <= 0.1.5 "Deep diving..." / "深度求索中..."
// DSH >= 0.1.7 "Deep diving for 12s" / "深度求索中,用时12s"
//
// Completed labels ("Worked", "Took 12s", "Stopped", "Failed",
// "已完成工作", "用时 12s", "处理失败") never begin with these prefixes, so a
// prefix match is enough and survives future rewording.
var RUNNING_LABEL = /^\s*(?:deep\s*diving|深度求索中)/i;
// host element -> { node, text } for every 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;
}
/**
* Elements that may host the visible running-turn label.
*
* DSH >= 0.1.7 renders the label inside a <button data-turn-process>; its
* only remaining [role="status"] is a visually hidden screen-reader
* announcement, which we deliberately leave alone. Older releases rendered
* the label as the visible [role="status"] text itself.
*/
function labelHosts() {
var hosts = [];
var buttons = document.querySelectorAll("[data-turn-process]");
if (buttons.length > 0) {
for (var i = 0; i < buttons.length; i += 1) hosts.push(buttons[i]);
return hosts;
}
var statuses = document.querySelectorAll('[role="status"]');
for (var j = 0; j < statuses.length; j += 1) hosts.push(statuses[j]);
return hosts;
}
/** First text descendant still carrying the stock running label. */
function findLabelNode(host) {
var record = owned.get(host);
if (record && isLive(record.node) && host.contains(record.node)) return record.node;
var stack = [host];
while (stack.length > 0) {
var node = stack.pop();
for (var child = node.firstChild; child; child = child.nextSibling) {
if (child.nodeType === 3) {
if (RUNNING_LABEL.test(child.nodeValue || "")) return child;
} else if (child.nodeType === 1) {
stack.push(child);
}
}
}
return null;
}
/**
* Claim a host's label, re-assert a claim React reverted, or release the
* claim once the label stops meaning "a turn is running".
*/
function claim(host) {
if (!host || typeof host.contains !== "function") return;
var record = owned.get(host);
if (!record) {
var fresh = findLabelNode(host);
if (!fresh) return;
var text = nextPhrase();
fresh.nodeValue = text;
owned.set(host, { node: fresh, text: text });
return;
}
if (!isLive(record.node) || !host.contains(record.node)) {
owned.delete(host);
claim(host);
return;
}
var current = record.node.nodeValue || "";
if (current === record.text) return;
if (RUNNING_LABEL.test(current)) {
record.node.nodeValue = record.text;
return;
}
// The turn finished (or the label changed meaning): hands off for good.
// Leaving this claimed would fight the final "Worked for 12s" text.
owned.delete(host);
}
function scan() {
if (typeof document === "undefined" || !document.querySelectorAll) return;
var hosts = labelHosts();
for (var i = 0; i < hosts.length; i += 1) claim(hosts[i]);
}
/** Rotate owned labels so the text moves even when React never rewrites it. */
function rotate() {
if (typeof document === "undefined" || !document.querySelectorAll) return;
var hosts = labelHosts();
for (var i = 0; i < hosts.length; i += 1) {
var host = hosts[i];
var record = owned.get(host);
if (!record) {
claim(host);
continue;
}
if (!isLive(record.node) || !host.contains(record.node)) {
owned.delete(host);
claim(host);
continue;
}
var current = record.node.nodeValue || "";
if (current !== record.text && !RUNNING_LABEL.test(current)) {
owned.delete(host);
continue;
}
var text = nextPhrase();
record.text = text;
record.node.nodeValue = text;
}
}
/** Nearest turn-process button above a mutated text node, if any. */
function hostOf(node) {
var element = node && node.parentElement;
if (!element || typeof element.closest !== "function") return null;
return element.closest("[data-turn-process]");
}
function apply(ctx) {
ctx.effect(function () {
var observer = null;
var interval = null;
var pending = null;
try {
if (typeof document === "undefined" || typeof MutationObserver === "undefined") {
return function () {};
}
scan();
function scheduleScan() {
if (pending !== null) return;
pending = setTimeout(function () {
pending = null;
scan();
}, SCAN_DEBOUNCE_MS);
}
observer = new MutationObserver(function (records) {
var structural = false;
for (var i = 0; i < records.length; i += 1) {
var record = records[i];
if (record.type !== "characterData") {
structural = true;
continue;
}
// Fast path: DSH >= 0.1.7 rewrites the live duration every
// second. Observer callbacks run before paint, so restoring here
// keeps the stock label from flashing through.
var host = hostOf(record.target);
if (host) claim(host);
else structural = true;
}
if (structural) scheduleScan();
});
observer.observe(document.documentElement, {
childList: true,
subtree: true,
characterData: true
});
interval = setInterval(rotate, ROTATE_MS);
} catch (error) {
// A cosmetic plugin must never take down the chat view.
if (typeof console !== "undefined" && console.warn) {
console.warn("[based-dsh-diving] disabled after an unexpected error:", error);
}
if (observer) observer.disconnect();
if (interval !== null) clearInterval(interval);
if (pending !== null) clearTimeout(pending);
return function () {};
}
return function () {
if (observer) observer.disconnect();
if (interval !== null) 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;
}
});