DeepSeek Harness Plugin Hub

发布与管理完整 Harness Profiles,发现适合你的插件。

探索

插件目录环境预设文档中心动态

社区

发布插件联系我们报告问题

相关链接

Plugin Hub GitHubDeepSeek Harness 官方项目系统状态隐私说明
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

独立、非官方社区项目,与 DeepSeek 官方无隶属、授权或背书关系。

Pinpu — DeepSeek Harness 插件(DSH Plugin)
DeepSeek Harness Plugin Hub
ProfilesPlugins分类动态文档登录管理 Profiles
ProfilesPlugins分类动态文档登录
← Plugins
P

dsh-pinpu

Pinpu

DeepSeek Harness 的音频响应式回合轨道:对话右侧边缘条带中的转录内容自身回合标记会随着系统正在播放的内容律动,并将内置的上一回合高亮替换为仅悬停时高亮

插件会安装到这里;不确定时保持 web。

npx -y @deepseek-ai/dsh plugin --profile web add github:sqslm/dsh-pinpu#fe9854a8721d49d4ae5a38f15f4f2a43760ab009
README兼容性版本
dancinghover highlight

兼容性与来源证明

Pinpu 以 dsh-pinpu 发布,当前版本为 0.4.0。Plugin Hub 会校验它的 manifest,并保存精确安装来源,便于复现安装结果。

DSH 兼容范围
*
运行环境
web
发布来源
github
Registry 更新时间
2026/10/14

版本

0.4.0stable
2026/10/14
0.3.3stable
2026/10/14

相关插件

正在加载相关插件…

最新版
0.4.0
DSH
*
HMR
重启进程
Tree shaking
未声明可安全裁剪
解包体积
未提供
文件数
未提供
Surface
web
许可证
MIT
发布源
github
GitHub
★ 0
周下载
0
最近提交
2026/10/14
查看源码 ↗
README Badge

点击下方 Badge 复制 Markdown,粘贴到 README 即可。

这是你的 Plugin?认领权益 · 优先安全扫描

验证 package.json 声明的 GitHub 仓库,即可管理这个公开页面。认领后,Hub 会优先安排当前版本的安全扫描,并在通过后公开展示结果。

认领这个 Plugin →
报告问题

相关插件

继续浏览 ui-customization 分类下经过校验的插件。

Client Ui Skill Explorer@linxin666/dsh-client-ui-skill-explorerDSH 技能中心:按来源(bundled / project / user / custom / runtime)浏览已加载的技能,在 Web GUI 面板中启用或禁用、创建和删除技能。Remote Web Ui@linxin666/dsh-remote-web-ui通过扫码配对访问 dsh Web GUI,共享一个官方界面:设置按钮旁的二维码可将手机和 PC 配对到同一个 Web GUI(手机采用竖屏触控适配层,PC 使用完整桌面界面),通过一次性令牌和 rClient Ui Task Board@linxin666/dsh-client-ui-task-board面向 DSH Web GUI 的主机权威任务面板,支持实际会话执行、主机 cron 调度以及可选的跨平台空闲睡眠保护;以挂载方式提供,无需修改 DSH 源代码。Client Ui Git Graph@linxin666/dsh-client-ui-git-graph外部 dsh Web GUI 插件:空会话 Git 分支选择器和 Git 图,包含实际的主机端 Git 操作与防护,作为 dsh 配置文件包

README

dsh-pinpu · Spectrum Rail

Takes over the transcript's own turn rail — the marks down the right edge of the conversation — and makes them dance to whatever the machine is playing, while replacing DSH's built-in "newest turn is highlighted" state with Codex's behaviour: nothing highlighted by default, highlight only under the pointer, click-to-jump unchanged.

dancing

That is not an illustration. tools/verify/rail-preview.mjs builds a real Chromium page from the shipped rail's own stylesheet and class names, extracted from the installed dsh-client-ui-chat bundle, then loads the real lib/client.js and drives it (only /api/dsh-pinpu/spectrum is stubbed). The differences in mark length are the spectrum: low frequencies at the foot of the rail, next to the newest turn.

Hovering brightens exactly one mark (the third screenshot from the same run):

hover highlight

Install

  • From this repository: add the GitHub repository sqslm/dsh-pinpu from DSH's plugin page, the same way any other GitHub plugin is installed, or
  • Locally packaged: node tools/install-profile.mjs (pnpm pack, then write the package into the profile's dsh.profile.bundles; --uninstall undoes it, --dry-run prints the plan).
  • Restart DSH once after the first install: the host half (capture, routes) is loaded at process start, the browser half with the page.
  • No dependencies to install: the native capture module ships with the plugin (see THIRD-PARTY.md), but it needs a CPython 3.12 interpreter — DSH bundles one and the plugin looks for it on its own.
  • Windows only for now (WASAPI loopback). On Linux this needs a different source (getUserMedia monitor or PulseAudio .monitor), which is not implemented.

hover highlight

中文说明 →

What it changes

The rail's states are CSS-module classes (mark, markActive, markPreview, markBusy, markUnloaded → build-hashed xpvNua_* names). The plugin reads no class name:

  1. Discovery by geometry — inside [data-conversation-scroll], find a group of sibling buttons with one size, one shared right edge and a constant vertical step (≈10px). That group is the rail.
  2. Tagging — the container gets data-pinpu-rail, each mark data-pinpu-tick="i" counting from the bottom mark (0) upwards.
  3. Overriding with one !important stylesheet —
    • every mark becomes the same dim colour and the same length, which removes the built-in highlight without knowing which class expresses it;
    • :hover brightens the mark under the pointer to full length — and only that;
    • while audio plays, each mark's length is its band's level (transform: scaleX(var(--pinpu-scale))), bands laid out logarithmically from 45 Hz to 16 kHz;
    • a mark the app is animating (markBusy, detected from the ::before animation) is left alone so its pulse survives.

Click-to-jump is untouched: only the ::before pseudo-element is restyled, the hit area is still the app's own button, and its click listener still fires (measured in the preview: clicks delivered to the app handler: ["7"]).

Measured in one preview run:

StateLast mark (the built-in highlight)Hovered markAn un-hovered mark
beforergb(249,250,251), scaleX(1)—dim
after, playingrgba(255,255,255,.2), scaleX(0.87)rgb(249,250,251), scaleX(1)dim, scaleX(0.49)

Audio: the system output itself (NetEase Cloud Music and friends)

any player → default output device → WASAPI loopback → spectrum → the rail
  • It captures the loopback of the default output device — literally what you hear. No virtual cable, and no player-specific support.
  • To pin one device (headphones plugged in, but capture the onboard card), pick it in the settings card's device list; empty means "follow the default output".
  • Capture happens in the host half: it runs vendor/loopback.py with the Python the harness ships, and that helper uses the vendored PyAudioWPatch (≈290 KB, the PortAudio build with loopback support) to open a [Loopback] input and stream mono float32 PCM on stdout. The host does the FFT and band mapping; the browser half only draws.
  • Therefore: no microphone permission, no user gesture, and not one line of capture code in the renderer.

Why not getUserMedia: it can only open capture endpoints. Measured on this machine, the registry has 立体声混音 (Realtek USB Audio) but disabled (DeviceState=0x10000001 where every endpoint Chromium lists is 0x1), so navigator.mediaDevices never shows it; more importantly Stereo Mix mirrors one render device, and this machine listens on that headset — so even enabled it would not carry what you hear. Loopback of the default output is the only thing that works.

Settings (Settings → 频谱律动)

The host owns the signal, the browser owns the presentation. Everything is .volatile(), so edits apply live (mounting the bundle still needs one restart).

FieldDefaultSideMeaning
enabledtruehostmaster switch; off spawns no capture process at all
device''hostempty follows the default output, else a [Loopback] device
fftSize1024hostFFT window, ≈21 ms at 48 kHz
smoothing0.78hostframe-to-frame smoothing
gain1hostgain after the level curve
autoGaintruehostnormalise per band against the loudest band
gate0.04hostat or below this is silence
minHz / maxHz45 / 16000hostspectrum range
disableActiveHighlighttruebrowserremove the built-in newest-turn highlight
hoverHighlighttruebrowserhighlight only under the pointer
restoreOnSilencetruebrowserstop moving once the audio has been quiet for a while
minScale / maxScale0.4 / 1browsershortest / longest mark, as a fraction of 20px (0.4 is the app's own "unloaded" length)
invertfalsebrowserput the low band at the top instead
colorModethemebrowsertheme keeps the rail's colour; spectrum hues by band; custom uses one colour

The two highlight modes

Both light up marks that are already there — nothing is drawn, added or moved. A highlighted mark takes the same bright colour a hovered mark gets, at full strength, while keeping the length the spectrum gave it.

  • Length threshold (hotScale): the comparison is made on the visible length — the very value written into --pinpu-scale — rather than on the level, so one parameter is only ever interpreted once. The default 0.85 lights a band that is nearly full length; 1.05 is equivalent to off (the spectrum cannot reach it), as is 0.
  • Random (spark): a rate, not a probability, because a per-frame chance is meaningless to tune. Each highlight picks one mark that is neither busy nor already lit and lights it for 160–420 ms; it releases by itself on a later poll, with no extra timer to leak. Silence never sparks, so ordinary listening gets an occasional accent rather than a strobe.
  • A mark that is still generating (markBusy) is left entirely alone, and a pointer on the rail still outranks both.

Measured in a real browser (tools/verify/rail-preview.mjs, 28 sampled frames):

samples with a highlighted mark: 23 of 28 (threshold 20, random 3)
a highlighted mark, computed: {"reason":"spark","background":"rgb(249, 250, 251)","opacity":"1","transform":"matrix(0.693…)","scale":"0.723"}

Bright colour, full strength, and the mark's own length (0.723) untouched.

Why auto-gain

Measured with the preview harness: without normalisation, 24 bands span only 0.51..0.76, which draws as six distinct lengths out of 37 — a flat wall. With it, the same signal spans 0.18..1.0 and eleven lengths. The same harness showed Chromium's default -100..-30 dB analyser window pegs normally-mastered material, so the ceiling is raised to -25 dB.

Verification status

MeansCoversResult
node --test test/*.mjs (55)manifest/patch contract, three-way default agreement, real schemastery validation, route auth and payloads, capture start/stop, FFT checked band-by-band against a naive DFT, band/resample/level contracts, the geometry rules that identify the rail, and the engine's whole take-over (discover → tag → poll → write lengths → hand back on silence → park on error → clean up when disabled)all green
node tools/verify/host-smoke.mjsthe real host chain: apply() → capture process → loopback PCM → FFT → route payloadstatus: live, device Speakers (Realtek Audio) [Loopback], peak 0.95, 11 distinct lengths, non-loopback Host rejected with 403
node tools/verify/rail-preview.mjsreal browser + the shipped rail CSS/classes + the real lib/client.js: built-in highlight gone, hover highlight, click still reaching the app's handler, lengths following the spectrumVERDICT: the shipped rail was taken over and dances
the plugin page and settings card inside the running appnot verified — a restart would kill the session that performed the workneeds one restart; see below

Checklist after a restart:

  1. the Plugins page lists dsh-pinpu / 频谱律动, enabled;
  2. Settings → 频谱律动 reads the configuration and its status line shows 采集中 plus the device name (i.e. the host capture is up);
  3. play something (NetEase Cloud Music is fine): the rail's marks start changing length and the newest turn is no longer permanently lit; hover a mark and only that one brightens; clicking still jumps to that turn. If the status says the Python runtime is missing, or 错误, the card names the reason.

Install / update / uninstall

cd path\to\dsh-pinpu
node --test test/*.mjs                 # run the tests first
node tools/verify/host-smoke.mjs       # optional: prove system audio is captured
node tools/install-profile.mjs         # pack, back up, edit the profile, pnpm install --offline
# then restart Harness once: a bundle row is applied at boot
  • Why a tarball, not link: — a link: dependency resolves to its real path outside the profile, so the host half's import z from '@deepseek-ai/schemastery' would be resolved against the source directory instead of the profile's node_modules, where the core packages live. dsh-purge documents the same trap. An installed tarball (including vendor/) resolves exactly like the harness's own packages.
  • Repack after every source change and bump the version: pnpm may consider an identical version already up to date and keep the stale copy.
  • Uninstall: node tools/install-profile.mjs --uninstall, then restart — or restore the .bak-pinpu-* backups of package.json / pnpm-lock.yaml.

Known limitations

  • The take-over depends on the rail's geometry (a column of equally sized, right-aligned, evenly stepped buttons). If DSH changes that layout the plugin will simply not recognise the rail — it will not damage the page, and the settings card reports zero marks.
  • It captures the loopback of the device you selected; following the default output is automatic, pinning a device is not.
  • The number of bands is the number of turns (one per mark); minScale/maxScale only change the length range.
  • A mark the app is animating (the busy pulse) does not dance; it keeps its own pulse.
  • Loopback capture needs a PortAudio build with loopback support (the Windows wheel of pyaudiowpatch ships in the package); other platforms need their own.

License

MIT.

customColor#4d93f8browserthe custom colour
glowtruebrowserlet each mark's brightness follow its own level
hotScale0.85browserlength threshold highlight: light a mark whose length reaches this fraction of full (0 = off)
spark1.5browserrandom highlight: expected highlights per second, each lighting one random mark for 160–420 ms (0 = off; silence never sparks)
demofalsebrowserdrive the marks with a synthetic waveform while nothing is captured