在「Deep diving...」状态提示前,放一只动态小伙伴——GrokBot 风格动画头像,状态文字还会同步打字机变换。
安装
# npm 包(预构建)
dsh plugin --profile web add @dsh-plugin/dsh-thought-buddy
# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)
dsh plugin --profile web add github:dsh-plugins/dsh-thought-buddy
装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本。请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。
README
dsh-thought-buddy
A DeepSeek Harness Web plugin that puts a dynamic little buddy — a GrokBot-style animated avatar with a synchronized typewriter status line — right in front of the "Deep diving..." indicator.
English | 简体中文
dsh-thought-buddy is a pure client-side plugin for the DeepSeek Harness Web GUI. While the model is working, the status pill that reads Deep diving... grows a tiny Grok-style robot avatar: it blinks, swaps expressions with a springy morph, wanders its gaze, and gently bobs — all drawn live as SVG via requestAnimationFrame, with zero runtime dependencies. Every time the avatar switches expression, the status text rewrites itself with a typewriter effect (deleting character by character, then typing out the next word).
The avatar animation is ported from nasawz/GrokBot (a pure Flutter CustomPaint widget) to the web: all 25 expressions × 2 eyes × 48-point eye rings, 18 body shapes, and 39 states with their expression/blink cadences are preserved.

Features
| Feature | Description |
|---|---|
| GrokBot avatar | thinking-state expression pool [8,16,14,17,5] cycles automatically; springy morph between expressions; 320 ms blinks (random 3.5–7 s interval); spherical head-turn projection + wandering gaze; gentle 1.7 s breathing bob |
| Expression-synced typewriter | on every expression switch, the status text leaves Deep diving... via a typewriter effect (delete character by character, pause, then type out the next word) cycling through 55 candidates (Accomplishing…Working), e.g. Reticulating...; React re-renders never overwrite it (the text fiber's children string never changes, so React bails out) |
| Emoji mode | fallback mode that cycles an emoji list (default 🤿 🫧 🌊 🐙 🔍 🧠 💭) with a pop-in on every switch |
| Theme aware | follows prefers-color-scheme: light #5b7fe5/#fffdf7, dark #6689ea/#181a15 (matching the DSH theme) |
| Reduced motion | under prefers-reduced-motion: reduce, the bob and head-turn sway are disabled; expression changes and blinks remain |
| Self-cleaning | the animation stops as soon as the status pill leaves the DOM; inserted nodes survive React re-renders and are re-asserted on the next mutation if ever removed |
Install
Copy the block below and paste it to your DSH agent (the assistant in this web GUI). The agent performs the install and verification for you — no manual npm or profile editing needed:
Install the @dsh-plugin/dsh-thought-buddy plugin into the profile I specify (or ask me if I didn't name one). The npm package name is `@dsh-plugin/dsh-thought-buddy`; use the GitHub source `github:dsh-plugins/dsh-thought-buddy`, or `file:<path>` / `link:<path>` for local development.
Steps:
1. Add the plugin dependency: `dsh plugin --profile <PROFILE> add @dsh-plugin/dsh-thought-buddy` (or the equivalent plugin-manager command for my profile).
2. Verify `node_modules/@dsh-plugin/dsh-thought-buddy` resolves and holds a built `lib/` directory (at least `lib/index.js` and `lib/client.js`). The runtime has no dependencies; building the TypeScript sources needs the `typescript` devDependency (`npm ci`/`npm install` once). If the artifacts are missing, run `npm run build` in the plugin directory and re-add.
3. Make sure the profile manifest's `dsh.profile.bundles` includes `@dsh-plugin/dsh-thought-buddy` — the bundle patch (`cordis.patch.yml`) inserts the plugin row automatically at boot.
4. Do not start the profile — install and verify only, then report what you changed.
Then restart dsh web, refresh the page, and send the model a message — the buddy appears in front of Deep diving.... All runtime options are set via localStorage (see below); there is no settings page.
Install from a local checkout (link:)
For local development, wire the plugin into a web profile via a link: dependency (example: C:\Users\Administrator\.dsh\profiles\web):
// package.json (profile)
"dependencies": { "@dsh-plugin/dsh-thought-buddy": "link:C:/path/to/dsh-thought-buddy" },
"dsh": { "profile": { "bundles": [ /* ... */, "@dsh-plugin/dsh-thought-buddy" ] } }
- Build the artifacts:
npm run build→ compiles TypeScript and produceslib/client.js+lib/index.js - In the profile, run
pnpm install(works offline) - Restart
dsh web— the client-module manifest is composed at boot, so a new bundle needs a restart - Refresh the page and send the model a message
Configuration (localStorage, applied on reload)
| Key | Default | Description |
|---|---|---|
dsh-thought-buddy.enabled |
1 |
0 disables the plugin |
dsh-thought-buddy.mode |
avatar |
emoji switches to emoji cycling |
dsh-thought-buddy.size |
18 |
avatar size in px (8–64) |
dsh-thought-buddy.emojis |
🤿 🫧 🌊 🐙 🔍 🧠 💭 |
space/comma-separated emoji list (emoji mode) |
// console example
localStorage.setItem('dsh-thought-buddy.mode', 'emoji')
localStorage.setItem('dsh-thought-buddy.size', '22')
location.reload()
Development
dsh-thought-buddy/
├── ref/GrokBot/ # reference project (git-ignored, read-only)
├── src/
│ ├── index.ts # host half (no-op mount row)
│ └── client/
│ ├── data.ts # generated typed data: 25 expressions × 2 eyes × 48 points, 18 shapes, 39 states
│ └── index.ts # client engine: SVG avatar + typewriter + observer + apply()
├── scripts/
│ ├── gen-data-lib.mjs # Dart parsing + data.ts rendering helpers
│ ├── gen-data.mjs # regenerates data.ts from ref/GrokBot's Dart sources
│ └── build.mjs # assembles lib/client.js (__ModuleLoader__ contract) from tsc output
├── test/verify.mjs # browserless tests against the built bundle (SVG, pacing, typewriter)
├── tsconfig.json # host-half compile: src/index.ts → lib/ (node ESM)
├── tsconfig.client.json # client-half compile: src/client/*.ts → .build/client/ (plain scripts)
├── demo/ # local preview (node demo/server.mjs → 4173)
└── cordis.patch.yml # bundle patch: inserts the thought-buddy row
npm install # once — installs the typescript devDependency
npm run gen # refresh data (after upstream GrokBot data changes)
npm run typecheck # type-check both halves (no emit)
npm run build # compile TS → lib/ + .build/client/, then assemble lib/client.js
npm run verify # full browserless verification
node demo/server.mjs 4173 # preview http://127.0.0.1:4173/demo/demo.html (run npm run build first)
The client half is written as TypeScript "plain scripts" (no
import/export, so the types and data stay in one global scope).tsccompiles them to plain JS in.build/client/, andscripts/build.mjsconcatenates the two files into thewindow.__ModuleLoader__factory — the same loader contract as before.data.tsmust be evaluated beforeindex.ts(build order is fixed).
Architecture
- Host half: provides only the cordis bundle mount row (
cordis.patch.ymlinsertsthought-buddy), so client-modules discovers thedsh.clientdeclaration andexports["./client"], serving the browser half at/plugins/@dsh-plugin/dsh-thought-buddy/client.js. - Client half:
apply(ctx)registers aMutationObserverwatching[data-conversation-scroll] [role="status"]pills whose text contains "diving"; the avatar/typewriter mount in front of the text and live with the pill's DOM lifecycle. - Animation: a per-frame port of Flutter's
_GrokBotState._onTick— critically-damped spring expression morphing (ω=7, 1/120 substeps), thinking-pool expression switching, 320 ms blink curve, spherical head-turn projection (asin/cosdepth culling), wandering gaze; polygon coordinates are written to the SVGpointsattribute every frame. - Typewriter: a timer-driven state machine over the pill's text node. React never touches the node because the text fiber's
childrenstring is always"Deep diving..."(bail-out), exactly like the injected avatar node.
⚠️ Two different
injects: the bundle's exportedexports.injectis the cordis service dependency (this plugin only usesctx.effect, so it must be an empty array — putting package names there makes the fiber wait forever for a service that does not exist and boot fails withpending (waiting for service: ...));package.json'sdsh.client.injectis the client module dependency declaration (this plugin needs none, so it is omitted).
Links
- Repository: https://github.com/dsh-plugins/dsh-thought-buddy
- npm: https://www.npmjs.com/package/@dsh-plugin/dsh-thought-buddy
License
BSD-3-Clause. The eye-ring geometry, body shapes, and state cadences derive from nasawz/GrokBot (BSD-3-Clause, Copyright (c) 2026 nasawz), credited in the LICENSE file.
链接
同类插件
Small-tailqwq/dsh-deep-whale#maid-atelier★ 1011
DSH Web 鲸鱼娘皮肤系列(深海女仆工坊 maid-atelier)。
GGBond2424648901/deep-whale-day-night-theme★ 58
鲸鱼娘昼夜皮肤:白昼水晶工坊与夜晚月潮观测室双场景,成对角色、Q 版侧栏宠物、花边与气泡/星点轻量氛围。
RevolutionLA/dsh-dream-skin★ 23
一键换肤插件:8 套原创主题、背景壁纸(透明度/模糊)、强调色、主题包导入/导出+分享链接、收藏与随机,纯原生 token 系统接入。
KinGao294/dsh-skin★ 15
Codex 风格皮肤切换器 + 自定义壁纸层,可调透明度与模糊。
Tommy00748/dsh-theme-cyberpunk2077★ 8
Cyberpunk 2077 / 夜之城主题:NC 黄 × 霓虹青配色、CRT 扫描线、Kiroshi 悬停锁定、战斗状态 HUD、合成打字机与消息音效,以及隐藏彩蛋(relic / johnny)。
NoNameLeGo/dsh-catppuccin★ 7
DSH Web GUI 的 Catppuccin 主题插件:Latte、Frappé、Macchiato、Mocha 四套主题接入原生主题系统,一键切换并记住选择。