dshbase

插件目录 / Developer / dsh-web-icon-indicator

dsh-web-icon-indicator

未验证 waknow

✓ 持续维护 2 位贡献者 基于 2 个官方 DSH 包

查看 GitHub ↗ ← 返回插件目录

1Stars
0Forks
0未关闭 issue
语言
2026-08-24最近推送
跨平台平台

功能简介

DSH browser tab favicon reflecting session state: idle / running / asking / done. · DSH 标签页 favicon 实时反映会话状态:待机 / 运行中 / 提问 / 完成

我们的评价
未验证 — 尚未实测

DSH browser tab favicon reflecting session state: idle / running / asking / done. · DSH 标签页 favicon 实时反映会话状态:待机 / 运行中 / 提问 / 完成 尚未验证——请自行安装测试。

「未验证」表示我们的自动化 CI 尚未安装过该插件。功能描述与版本兼容性均为作者声明。这不是安全审计,也不代表对第三方代码的背书。

你是插件作者? 想拿到「已验证」标签——提交你自己的验证证据(截图、日志或短视频),我们审核通过后即改为「已验证」。

提交验证证据 ↗

README

dsh-web-icon-indicator

📖 中文文档 · English · 📝 Changelog · Releases

awesome · DSH plugin

Browser tab favicon reflects the current DSH session state — idle / running / asking / done — so you can see at a glance whether a session needs your attention, even when the tab is in the background.

✨ What it does

  • Live session state on the tab favicon — the browser-tab icon mirrors idle / running / asking / done (aggregate priority: asking > running > done > idle), so background tabs tell you at a glance what your agents are doing — including ask_user_question prompts and approval / sandbox-escalation waits, which pin the icon to asking.
  • One SVG, recolored & animated in the browser — ships a single whale template (icons/base.svg); every state, color and frame is rendered client-side as a data:image/svg+xml URI. No per-color icon files.
  • Six built-in effectsstatic, blink, breath, rainbow, heartbeat, bounce — all driven by JavaScript, since favicons don't play SVG CSS animations.
  • Fully configurable, applied live — every state's color, effect and cycle speed, plus the asking/done hold timings, apply to the running tab within ~1 s — no reload, no restart.
  • Built-in settings UI, zero YAML — a Favicon indicator card in the DSH settings page edits the whole config with live color-swatch previews and persists it to settings.yaml for you (path below).
  • Background-tab & restart-proof — animated states keep a wall-clock fallback while requestAnimationFrame is paused in hidden tabs, and the status poll self-heals across host restarts.

🛠 Configuration UI — how to get there

# Step
1 Open the DSH Web GUI and go to Settings / 设置.
2 In the Plugins / 插件 tab, open Plugin config / 插件配置.
3 Find the Favicon indicator / 标签页图标指示器 card.
4 Expand a state row (idle / running / asking / done) to edit Effect / 特效, Colors / 颜色 (each swatch is a native color picker) and Cycle (ms) / 周期(毫秒) (shown only for animated states — static states have no cycle); use Asking hold / 提问驻留 and Done hold / 完成驻留 for the two timings.

Changes are saved through the settings transport into the profile's settings.yaml and applied to the running tab within ~1 s — no reload, no restart. See Configure for the full key reference.

🎬 Default configuration, visualized

The four default states, exactly as they appear in the browser tab (the asking whale really blinks):

Default states: idle dark whale, running yellow, asking red/yellow blinking, done green

State Default color Default effect
idle #1a1a1a — deep whale static
running #FACC15 — yellow static
asking #E5484D#FACC15 — red/yellow blink (400 ms)
done #22A06B — green static, stays doneHoldMs, then back to idle

✨ All effects, animated

Every preview below is the real whale path, animated the same way the plugin renders it (the previews are self-contained animated SVGs — they play right in your browser):

Effect What it does Preview
static A single colored frame, no motion — uses colors[0] static effect preview
blink Toggles colors[0]colors[1] (a darker second color is derived if missing) over speed blink effect preview
breath Pulsates smoothly between colors[0] and colors[1] (derived if missing) over speed breath effect preview
rainbow Uses colors[0] as the starting hue, then cycles the color wheel over speed rainbow effect preview
heartbeat Scale pulses with a sharp lub-dub beat over speed — color is colors[0] heartbeat effect preview
bounce The whale hops up and down over speed — color is colors[0] bounce effect preview

Want to tweak colors and watch the tab favicon change live? Open the self-contained demo (demo/dynamic-color.html) — pick a state + effect, edit colors, and the favicon updates in real time (no build, no dependencies).

Install

This is a standard DSH bundle plugin. Install it into the web profile (the GUI/TUI profiles pick it up automatically through the cordis patch layer).

From npm (recommended):

dsh plugin --profile web add dsh-web-icon-indicator@latest

From the Git source:

dsh plugin --profile web add github:waknow/dsh-web-icon-indicator

Or from a local directory / tarball:

dsh plugin --profile web add <path-or-tarball>

Or drop the directory into ~/.dsh/profiles/web/node_modules/<name>/ and ship a cordis.patch.yml that matches the one shipped here.

Configure

All keys are optional; defaults shown.

Key Default Meaning
iconsDir <package>/icons/ Directory holding the single base.svg
statusPath /dsh-web-icon-status.json JSON status endpoint
iconPathPrefix /dsh-web-icon-indicator URL prefix base.svg is served under
askingHoldMs 3500 Minimum visibility of the asking state
doneHoldMs 5000 Time the done state stays before falling back to idle
states see below Per-state visual config

Each entry in states is one object per state: { effect, colors[], speed? }:

config:
  states:
    idle:    { effect: static,    colors: ['#1a1a1a'] }
    running: { effect: static,    colors: ['#FACC15'] }
    asking:  { effect: blink,     colors: ['#E5484D', '#FACC15'], speed: 400 }
    done:    { effect: static,    colors: ['#22A06B'] }
  • effect — one of static | blink | breath | rainbow | heartbeat | bounce.
  • colors — an array of hex colors. colors[0] is the primary. Multi-color effects read more entries: blink uses colors[0]colors[1], breath breathes colors[0]colors[1] (each derives a darker second color if omitted), rainbow uses only colors[0] as the starting hue.
  • speed — optional per-state cycle length in ms (also the blink toggle interval). Default 1200.

Entries are shallow-merged over the defaults, so you can override only a few states. Example:

- id: dsh-web-icon-indicator
  name: 'dsh-web-icon-indicator'
  config:
    states:
      running: { effect: breath,    colors: ['#FF9900', '#FFD9A0'], speed: 900 }
      asking:  { effect: rainbow,   colors: ['#FF0000'] }
      done:    { effect: heartbeat, colors: ['#2ECC71'] }

Settings page & settings.yaml (DSH ≥ rc7)

The plugin registers the whole config surface above with the DSH settings
service under the web-icon-indicator namespace (a schemastery schema in
lib/index.js):

  • Web GUI: open 设置 → 插件 → 插件配置 — a Favicon indicator card
    edits the same keys (asking/done hold, and per-state effect / colors /
    cycle), staged and saved through the settings transport. Each state is a
    collapsible row showing a color dot and a one-line summary (blink · #E5484D ⇄ #FACC15 · 400ms); expanding a row reveals its three fields, and
    the colors field previews parsed swatches live.
  • Persistence: values land in the profile's settings.yaml (default
    ~/.dsh/settings.yaml) as a web-icon-indicator: section. The composition
    entry stays the base layer; resolution order is schema defaults →
    composition entry → settings document user layer.
  • No server restart, no tab reload for settings-card saves: askingHoldMs /
    doneHoldMs apply live host-side, and per-state visual config (effect /
    colors / cycle) is synced into the running tab through the status poll within
    ~1 s. Only code-level default changes in lib/index.js need a tab reload (or
    a DSH web rebuild).
  • The browser half is a hand-written lib/client.js (ModuleLoader factory
    format — no build step, no runtime deps beyond the shell's react). The DSH
    client scanner picks a new dsh.client declaration up on the next profile
    start.
  • Deployments without a settings service are unaffected: the plugin falls back
    to reading the composition entry exactly as before.

How it works

  • Host plugin with a small browser half: registers routes on the existing webServer — the status JSON endpoint, a static /dsh-web-icon-indicator/base.svg (the whale template), and one tapIndex that injects a small browser script into every served index.html. The config surface is registered with the DSH settings service (web-icon-indicator namespace) for validation, persistence, and the settings-page card (see above).
  • Status is aggregated across live agents.list() with priority asking > running > done > idle. The aggregation runs a reconcile() step on every request to detect running → idle transitions, because agent/status's idle delivery is not guaranteed at turn end.
  • ask_user_question tool calls (via tools/pre-execute / tools/result) flip the session into asking with a configurable minimum-hold so the icon stays visible even when the user answers immediately.
  • Permission / sandbox-interception waits are also surfaced as asking: when the agent hits a sandbox denial and escalates (sandbox_permissions + justification), or any other tool asks for approval, the approval service appends an approval/asked session event and blocks the agent until you decide. The plugin watches session/event (with an authoritative fold over the live session log as a fallback) and pins the session into the asking state for that whole wait, clearing it on approval/decided.
  • The browser script polls /dsh-web-icon-status.json once a second, fetches base.svg once, and then on every requestAnimationFrame tick rebuilds the favicon as a data:image/svg+xml,… URI — replacing the __COLOR__ placeholder with the state's configured color and applying the state's configured effect. The status response also echoes the current per-state visual config, so a settings save reaches the running tab on the next poll (~1 s) without a reload. Browsers don't play favicon SVG CSS animations, so all motion is JS-driven. Because browsers pause requestAnimationFrame in hidden tabs, the poll also repaints a wall-clock frame for animated states, so background tabs keep animating (coarsely) instead of freezing; full-speed animation resumes when the tab is visible again. The poll also survives host restarts: a transient fetch failure restores the original icon and retries on the next tick (the SPA reconnects in place, so the icon comes back without a manual refresh).

Browser support & known limitations

The favicon is a plain image, so browsers never run the SVG's own CSS/JS animation inside the tab UI — every frame is rendered here in JavaScript. How well a changing favicon is displayed differs by browser:

Browser SVG favicon Live per-state color/effect Why
Chrome / Edge ✅ smooth Re-reads <link rel=icon> live; data:-URI SVGs are fine.
Firefox ✅ smooth Renders SVG favicons well (and honors their prefers-color-scheme, unused here).
Safari (macOS) ✅ rendered static ⚠️ best-effort Ignores in-SVG CSS; aggressive icon caching.
Safari (iOS) ✅ rendered static ⚠️ rarely Unlikely to refresh without revisiting the tab.

Known limitations (current as of Safari 26.3):

  • Favicons have their own cache. Chrome keeps a favicon database, Firefox a favicons.sqlite, and Safari a system-level icon cache — none of which a normal clear cache touches, and WebKit even caches the "no icon" case. That is why a changed icon can linger for an existing tab. The plugin already mitigates this: it serves base.svg and the status endpoint with Cache-Control: no-store, bundles a freshness query (?t=Date.now()) on its fetches, and replaces the <link rel=icon> node on each state change.
  • Safari renders SVG favicons but ignores their internal CSS — no @media, no prefers-color-scheme, no CSS animation. So all recoloring must be baked into each frame's markup (which the plugin does) rather than driven by CSS variables.
  • data:-URI SVG favicons are unreliable in Safari (WebKit bug 236616, still open; reproduced on Safari 17.6). The plugin currently builds each frame as a data:image/svg+xml URI, so on Safari the tab icon may not render at all — the biggest known gap.
  • Dynamic JS updates in Safari are hit-or-miss; they may require a reload, and Safari "locks onto" the first icon it sees. There is no guaranteed, spec-supported way to swap a favicon live in Safari today.
  • Pinned-tab icon (<link rel="mask-icon">) uses its own cache, separate from the regular favicon, and is a single-colour silhouette tinted by the color attribute — macOS + pinned-tab only, read at page load, not live.

Full mechanics with sources (WebKit bugs, Stack Overflow, browser-engineering blogs) and a recommended path toward smoother Safari colour changes live in docs/safari-favicon-research.md.

Caveats

  • Favicon SVG CSS animations do not run inside the browser's tab UI — all effects are produced in JavaScript by rebuilding the data-URI each frame. This is a deliberate, zero-dependency design. (The animated previews in this README are demo assets for illustration only — the favicon itself is JS-animated.)
  • Favicon behavior differs by browser, and Safari is the most limited — see Browser support & known limitations.
  • The base template must keep its __COLOR__ placeholder in the #p { fill: … } rule; the browser replaces that token to color each frame.
  • The plugin runs in the host plane; it must be mounted into a profile's composition, not a session-scoped agent preset.
  • File reads go through the fs service with the configured iconsDir as cwd. Make sure that path is readable under your deployment's sandbox policy.

License

MIT

安装

🧩 让 Agent 自动装(推荐)

装一次目录插件,之后本站所有插件都能让 DeepSeek Harness 自动找、自动装:

dsh plugin add dshbase-catalog

然后对 agent 说「帮我装 dsh-web-icon-indicator」,它会在目录里找到并自动安装。文档:dshbase-catalog · 已验证场景包

该插件是 GitHub 源码(未发 npm)——直接从仓库装:

Web profile:

dsh plugin --profile web add github:waknow/dsh-web-icon-indicator

Headless(CLI)profile:

dsh plugin --profile headless add github:waknow/dsh-web-icon-indicator

实测报告

尚未 L3 验证——若已跑过,见下方失败备注。

状态:pending · 最近测试 2026-08-26 · 标记 webonly
备注:验证: web-only;待 L4 web CDP;L4 web CDP runtime-fail on dsh 0.1.0-rc.8. 浏览全部待验证失败 →
安全:尚未扫描——我们的每日静态扫描将很快覆盖它。

分享徽章

Developer 里更多

浏览全部 7789 个插件 →