浏览器标签页 favicon 实时反映 DSH 会话状态(待机 / 运行中 / 提问 / 完成):单个 base.svg 在浏览器端上色与动画,颜色与特效均可在设置页配置。
安装
# npm 包(预构建)
dsh plugin --profile web add dsh-web-icon-indicator
# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)
dsh plugin --profile web add github:waknow/dsh-web-icon-indicator
装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本——pnpm 默认拦截,所以安装可能停在 ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED 或 ERR_PNPM_IGNORED_BUILDS;dsh 会打印出需要添加的确切键名,把它加进该 profile 的 pnpm-workspace.yaml 的 allowBuilds 下,重跑一次即可装上。放行构建本身就是一次信任判断:请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。
README
⚠️ DSH 版本支持 —— 需要 DSH ≥ 0.1.2-rc.1。同一份插件同时兼容两代 settings 契约:新一代(≥ 0.1.7-alpha.1:导出
Configschema +configForms+plugins.bundle.config)与旧一代(≤ 0.1.6-alpha.1:settings.installSection+settingsScope+settings.plugin.item)。已在 DSH 0.1.5-rc.3 与 DSH 0.1.7-alpha.1 上验证;更早的宿主上 favicon 仍可用,只是配置页可能不可达。
浏览器标签页 favicon 实时反映 DSH 会话状态——待机 / 运行中 / 提问 / 完成——让你在标签页置于后台时也能一眼看出是否有会话需要处理。
🎨 在线演示 — https://waknow.github.io/dsh-web-icon-indicator/ · 在浏览器里直接体验四种状态、多 Agent 计数与全部特效,无需安装。试玩间还能驱动演示页自身标签页的真实 favicon——正如插件在 DSH 页面里做的那样。
✨ 功能特性
- 标签页 favicon 实时反映会话状态 —— 浏览器标签页图标同步
idle/running/asking/done(聚合优先级:asking>running>done>idle),后台标签页也能一眼看清 agent 们在做什么——包括ask_user_question提问,以及审批 / 沙箱提权等待(这两种情况会把图标钉在asking态)。 - 单个 SVG,浏览器内上色与动画 —— 只内置一个鲸鱼模板(
icons/base.svg);每个状态、颜色、每一帧都在客户端渲染为data:image/svg+xmlURI,不再有按颜色拆分的图标文件。 - 六种内置特效 ——
static(静止)、blink(闪烁)、breath(呼吸)、rainbow(彩虹)、heartbeat(心跳)、bounce(跳动),全部由 JavaScript 驱动(favicon 不会播放 SVG CSS 动画)。 - 完全可配置、即时生效 —— 每个状态的颜色、特效、周期,以及提问 / 完成驻留时长,改动约 1 秒内同步到已打开的标签页——无需刷新、无需重启。
- 内置配置 UI,无需手写 YAML —— 标签页图标指示器 页面可编辑整套配置,带实时色块预览并自动持久化(新宿主:profile patch;旧宿主:profile
settings.yaml,路径见下)。 - 后台标签页与重启抗性 —— 隐藏标签页中
requestAnimationFrame被暂停时,动画态会按墙钟时间补帧;状态轮询还能扛住 host 重启、后端停止:故障期间标签页图标绝不丢失(还原启动时缓存的原始图标data:-URI 副本,或保留最后一帧插件图标),端点恢复后自动回到实时状态。切回前台时会立刻触发一次状态拉取并重绘——后台标签页的定时器会被浏览器节流,轮询可能滞后,所以回到标签页的瞬间就刷新最新状态(比如done保持期在隐藏期间过期、图标应退回idle的情况)。 - 多 agent 一目了然 —— 当同时有超过一个活动 agent(非待机:
asking/running/done)时,favicon 从鲸鱼切换为占满整帧的数字块,实时显示活动数(上限99+),颜色与动画和该状态下鲸鱼完全一致;活动数回到 0–1 时恢复鲸鱼。(视觉与demo/badge.html的「满幅数字」通道一致。)
🛠 配置界面——怎么找到它
| # | 步骤 |
|---|---|
| 1 | 打开 DSH Web GUI,进入 设置 → 插件。 |
| 2 | ≥ 0.1.7:展开 dsh-web-icon-indicator bundle,在其 dsh-web-icon-indicator 行上点击 配置;≤ 0.1.6-alpha.1:在该选项卡里打开 插件配置。 |
| 3 | 打开 标签页图标指示器(Favicon indicator) 配置页。 |
| 4 | 先用 默认图标颜色 设置待机鲸鱼的颜色(这是待机唯一的设置项——待机只画一种颜色、不做动画),再展开状态行(running / asking / done)编辑 特效、颜色(每个色块即原生取色器),以及周期(毫秒)——仅动画状态显示,静态状态无周期;用 提问驻留 / 完成驻留 调整两个时长。 |
改动会通过 settings 传输层持久化到 profile patch,约 1 秒内应用到已打开的标签页——无需刷新、无需重启。完整键说明见 配置。
🐳 插件页会显示本插件自己的图标 —— DSH ≥ 0.1.7 的 设置 → 插件 页面会为每个 bundle 卡片画一个 48px 图标(每一行 40px),来源是
package.json→icon。本仓库声明了"icon": "icons/plugin.svg",所以卡片显示的是鲸鱼而不是通用占位图。图标由宿主读取(readPluginMeta→iconOf),并以 base64data:URL 传给浏览器;图标缺失或不合规不会把卡片变空——而是点亮该插件的meta.error,卡片上出现「问题」标签,所以路径必须相对、必须在包内、且 ≤ 256 KiB。加这个字段不需要任何配置、代码或宿主重启,只需重新安装或发一个新版本;详见插件页图标。
🎬 默认配置,可视化
四个默认状态在浏览器标签页中的实际效果(asking 那条鲸鱼真的在闪烁):
| 状态 | 颜色(默认) | 特效(默认) |
|---|---|---|
idle 待机 |
#1a1a1a——深色鲸鱼(可用 defaultColor 替换) |
static |
running 运行中 |
#FACC15——黄色 |
static |
asking 提问 |
#E5484D ⇄ #FACC15——红/黄 |
blink(400ms) |
done 完成 |
#22A06B——绿色 |
static,保持 doneHoldMs 后回到 idle |
多 agent 可视化
当多个 agent 同时运行时,favicon 本身就是计数器:只要活动 agent 超过一个
(非待机:asking / running / done,含短暂的 done 保持期),鲸鱼就换成
占满整帧的数字块——实时显示 active 计数,底色取聚合状态色、特效与鲸鱼完全
同源(照常闪烁 / 呼吸 / 彩虹);活动数回到 0–1 时恢复鲸鱼。
active(非待机 agent 数) |
favicon |
|---|---|
0 |
深色 idle 鲸鱼 |
1 |
对应状态的鲸鱼(running 黄色,…) |
2–99 |
占满整帧的数字块,数字高度约占图标的 31%–52%(1 位 26、2 位 20、3+ 位 15.5)——16px 与固定标签页都可读 |
100+ |
99+ |
状态优先级不变:asking 仍以红 ⇄ 黄 400ms 闪烁接管(闪烁的是数字块),
done 按其颜色驻留 doneHoldMs,计数随状态轮询实时刷新(约 1 秒)。
视觉与 demo/badge.html 的「满幅数字」通道一致。
✨ 全部特效,动画演示
下面每个预览都是真实的鲸鱼路径,按插件实际渲染方式做动画(预览是自包含的动画 SVG,在浏览器里直接播放):
| 特效 | 效果 | 预览 |
|---|---|---|
static |
纯色单帧,无动画——使用 colors[0] |
|
blink |
在 colors[0] ⇄ colors[1] 之间按 speed 切换(缺省时自动推导更深的第二色) |
|
breath |
在 colors[0] 与 colors[1] 之间平滑呼吸过渡(缺省时推导) |
|
rainbow |
以 colors[0] 为起始色相,在 speed 内绕色轮循环 |
|
heartbeat |
在 speed 内做「lub-dub」式的尖锐缩放脉冲——颜色为 colors[0] |
|
bounce |
鲸鱼在 speed 内上下跳动——颜色为 colors[0] |
想改颜色并实时观察标签页 favicon 变化?打开自包含 demo(demo/dynamic-color.html)——选择状态 + 特效并实时改色,favicon 即时更新(无构建、无依赖)。
安装
这是一个标准 DSH bundle 插件。安装到 web profile(GUI/TUI profile 会自动通过 cordis patch 层加载):
从 npm 安装(推荐):
dsh plugin --profile web add dsh-web-icon-indicator@latest
从 Git 源码安装:
dsh plugin --profile web add github:waknow/dsh-web-icon-indicator
或从本地目录 / tarball 安装:
dsh plugin --profile web add <路径或tarball>
或将目录放进 ~/.dsh/profiles/web/node_modules/<name>/,并附带与包内一致的 cordis.patch.yml。
ℹ️ 官方插件页的图标读取的是已安装包的
package.json.icon,因此只有在安装 (或发布新版本)之后才会出现——已经打开的插件页会一直显示上一次的快照,直到你刷新。 详见插件页图标。
配置
所有键均可选,默认值如下。statusPath 与 iconPathPrefix 是注册期键:
只能在合成条目(composition entry)里设置——它们在插件挂载时就被烘进路由表与注入
脚本,因此刻意不进入配置页的实时表单(它们是 Config 字段,但非 .volatile())。
| 键 | 默认值 | 含义 |
|---|---|---|
iconsDir |
<package>/icons/ |
单个 base.svg 所在目录 |
statusPath |
/dsh-web-icon-status.json |
JSON 状态端点 —— 注册期(仅合成条目) |
iconPathPrefix |
/dsh-web-icon-indicator |
base.svg 的 URL 前缀 —— 注册期(仅合成条目) |
askingHoldMs |
3500 |
提问状态的最小保持时长 |
doneHoldMs |
5000 |
完成状态保持时长,随后回到 idle |
defaultColor |
(未设置) | 默认图标颜色(待机鲸鱼的主色)—— 用于区分多个 DSH 实例;与其它状态颜色过于接近时会告警 |
states |
见下 | 每个状态的视觉配置 |
插件页的图标不是配置键——它来自
package.json.icon(见插件页图标)。iconsDir只告诉 favicon 路由去哪里取base.svg。
states 中每个状态是一个对象:{ 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— 取static | blink | breath | rainbow | heartbeat | bounce之一。colors— 数组,多个 hex 颜色(#rgb/#rrggbb;非法项会被逐项忽略,全部无效时才回退到该状态的内置颜色)。colors[0]为主色。多色特效读取更多项:blink用colors[0]⇄colors[1],breath在colors[0]⇄colors[1]间过渡(缺省时自动推导更深的第二色),rainbow仅用colors[0]作起始色相。speed— 可选,该状态的周期(ms),也是blink的切换间隔。默认1200。
idle 比较特殊:它的颜色就是 defaultColor 键,设置卡片不为它提供状态条目
(一种颜色、不做动画、也没有周期)。若 states.idle 来自合成条目或手写的
设置文档的用户层,仍然会被沿用——这属于向后兼容,只是无法在配置页里编辑。
每个状态条目会在默认值之上做浅合并,因此只需覆盖少量状态。示例:
- 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'] }
区分多个实例(defaultColor)
同时开多个 DSH 实例(不同项目 / profile / 端口)时,给每个实例设一个自己的默认图标 颜色,浏览器标签页就能一眼区分,不必去改整套状态配色:
- id: dsh-web-icon-indicator
name: 'dsh-web-icon-indicator'
config:
defaultColor: '#5B8DEF'
defaultColor就是待机鲸鱼的主色。它会被折叠进states.idle.colors[0], 因此 idle 仍保留自己配置的特效与第二色,其它状态的颜色语义(黄=运行、红/黄=提问、 绿=完成)不受影响;不设置(默认)即等于「沿用 idle 自己的颜色」,行为与之前完全一致。- 这是按 DSH 实例生效的设置,不是按标签页:同一实例的所有标签页共用它;另一个实例
(自己的 profile,例如
dsh web --port 3081)可以用另一种颜色。 - 恢复默认会把你的覆盖清回合成条目。当颜色本来就来自合成条目(
base层, 用户层的unset触及不到)时,卡片改为写入 idle 自己的颜色——这样「恢复默认」真的 能让图标回到朴素的鲸鱼色,而合成条目里配置的值仍可通过「清除覆盖」一键取回。 - 相似度告警:当默认颜色与其它状态颜色在感知上过于接近时,你会收到告警 —— 设置卡片里
实时显示(保存前即可见)、host 日志里记录、状态端点
warnings中返回 —— 但该颜色 仍然会被应用(告警绝不阻断保存)。度量方式是 CIELAB 中的 CIE76 ΔE:ΔE < 25告警,ΔE < 12视为几乎相同(ΔE 2.3 是人眼恰可分辨的阈值)。比较覆盖每个状态实际 会画出的所有填充:asking闪烁的两种颜色、breath的插值中间色;而rainbow会扫过所有色相,因此任何有色默认色都会被标记。出厂默认中running与asking刻意 共用#FACC15,所以状态之间互不比较,只把默认色与它们逐一比较。格式非法的值会被 忽略并上报,而不会被画到图标上。
设置页(DSH ≥ 0.1.2-rc.1,兼容两代 settings 契约)
插件把上面整套配置作为 Cordis Config schema 导出(lib/index.js 中的
schemastery schema),并在宿主仍提供旧版服务时用同一份 schema 走
settings.installSection 注册——两条路径在挂载时按能力探测,因此同一份 bundle
两代宿主都能用。命名空间随代际不同:≥ 0.1.7 按 profile entry id 组织实时
表单,即 dsh-web-icon-indicator(bundle patch 声明的行 id);≤ 0.1.6-alpha.1
使用插件自定的 web-icon-indicator,与 0.5.x 保持一致,老用户的 section 继续生效:
- Web GUI: 打开 设置 → 插件,点开 dsh-web-icon-indicator 卡片,
设置表单就直接出现在插件页上(与官方插件的位置一致);0.1.6-alpha.2 虽然还在用
旧的
settingsScope,但它同样渲染 bundle 插槽,因此表单位置一致。可编辑:提问/完成驻留、 默认图标颜色(带配色一览与相似度告警),以及running/asking/done三个状态各自的特效 / 颜色 / 周期。这三个状态 各占一行可折叠条目,行首是一个色块——多色状态(asking)会左右分格同时显示 红黄两色,旁边是一行「特效 · 周期」摘要(如Blink · 400ms)。点击色块即打开 系统取色弹窗(十六进制值在那里显示/输入),卡片本身不打印颜色代码——唯一例外是相似度 告警,它会给出具体的 hex 以便定位(例如「与「运行中」的颜色 #FACC15 几乎相同(ΔE 0)」)。 展开该行后只列出当前 特效实际会用到的颜色:blink/breath在还有空位时才多出一个+色块 (它默认停在浏览器本来就会推导的那个更深的第二色上,且不会重复添加已有颜色),第一个 之后的色块都可以删除;单色特效则只显示、也只保存一个色块,不会留下看不见的第二色。rainbow不携带颜色列表:字段与色块都显示彩虹色环,色环旁另有一个可选的起始色相 色块(也就是存下的colors[0])。idle刻意不占 一行——它只画一种颜色、不做动画,默认图标颜色就是它的全部配置。所有修改都通过 settings 传输层暂存并保存。 - 持久化: ≥ 0.1.7 写入 profile patch
(
~/.dsh/profiles/<profile>/cordis.patch.yml)中dsh-web-icon-indicator行的config:段;≤ 0.1.6-alpha.1 写入~/.dsh/settings.yaml的web-icon-indicator:段。两者都保持合成条目为base层;解析顺序为 schema 默认值 → 合成条目 → 用户层。 - 无需重启服务器、无需刷新标签页即可让配置页的修改生效:≥ 0.1.7 时实时写入
直接提交到运行中插件的配置引用(
loader/volatile-update——loader 不会重启插件); 旧一代则由 settings 服务回调注册的onChange。两种情况askingHoldMs/doneHoldMs都在主机侧即时生效;各状态的视觉配置(特效 / 颜色 / 周期)会随状态 轮询同步进正在运行的标签页,约 1 秒内生效。只有改lib/index.js里的代码级默认值 才需要重载标签页(或重新构建 DSH Web)。 - 路由路径不是实时设置项。
statusPath/iconPathPrefix由Config校验,但 刻意不加.volatile(),因此不出现在实时表单里:它们已被烘进路由表与注入脚本, 在那里生效只会让浏览器去请求服务器根本没有提供的路径。它们只存在于合成条目 (见上方表格),改动会重新挂载插件。 - 因此实时设置面覆盖
askingHoldMs、doneHoldMs、iconsDir、defaultColor与states。iconsDir没有 schema 默认值,用户未设置时不会出现在解析后的表单中。 - 浏览器半区是手写的
lib/client.js(ModuleLoader factory 格式——无构建步骤、 无额外运行期依赖,仅用 shell 自带的react)。它按宿主实际声明的插槽注册 (≥ 0.1.7 用plugins.bundle.config,这样插件列表的卡片点开即见表单;否则退回plugins.row.config——两者都按「Host 是否提供该命名空间」门控;另有旧的settings.plugin.item),并在渲染时按宿主实际提供的服务解析表单 (configForms或settingsScope),因此两者都不是模块的硬依赖。DSH 客户端 扫描器会在下次启动 profile 时识别新的dsh.client声明。 - 未组合 settings 服务的部署不受影响:插件继续使用挂载时的合成条目 + schema 默认值。
插件页图标
DSH ≥ 0.1.7 会在官方插件页为每个插件渲染图标:bundle 卡片 48px、每一行
40px(@deepseek-ai/dsh-client-ui-plugin-manager 的 PackageArtwork,未声明时
回退到通用占位图)。图标直接来自包清单,所以给出它纯粹是元数据——不需要改代码、
不需要配置、不需要重启宿主:
// package.json
{
"name": "dsh-web-icon-indicator",
"icon": "icons/plugin.svg" // 相对 package.json,且必须留在包内
}
宿主在不执行任何插件代码的前提下读取它(@deepseek-ai/dsh-app-boot 的
readPluginMeta → iconOf):
| 规则 | 取值 |
|---|---|
| 字段 | 顶层 package.json.icon(与 name/version 同级,不是放在 dsh 下) |
| 路径形式 | 相对清单所在目录;绝对路径、Windows 盘符(C:\…)与 URL 都会被拒绝 |
| 包含关系 | 经 realpath 解析后必须仍在清单目录内(.. 越界会被拒绝) |
| 格式 | .svg → image/svg+xml,.png → image/png,.jpg / .jpeg → image/jpeg,.webp → image/webp |
| 大小 | ≤ 256 KiB(stat 与实际读到的字节数各校验一次) |
| 传输 | 读成字节后以 base64 data: URL 随元数据下发(PluginLocalizedMeta.icon) |
⚠️ 坏的图标比没有图标更糟。 任何不合规都不是静默回退,而是元数据错误: 读取器返回
meta.error,宿主把它暴露出来,卡片上会给这个插件打上问题标签。 所以文件要留在包内(files里已包含icons/),并且必须是独立可用的 SVG—— 直接用icons/base.svg是无效的,因为它里面的#p { fill: __COLOR__ }占位符并不是颜色。本仓库因此提供预填好的icons/plugin.svg(即base.svg把__COLOR__换成#1a1a1a),并在test/verify.js里把整套约束都断言下来(F62–F65)。
由于图标是从已安装的包读取的,本地改动只有在重新安装插件
(dsh plugin --profile web add <path>)或发布新版本之后才会生效。
实现原理
- Host 插件 + 一个小型浏览器半区:在现有
webServer上注册路由——状态 JSON 端点、静态/dsh-web-icon-indicator/base.svg(鲸鱼模板),以及一个tapIndex向每个index.html注入小段浏览器脚本。整套配置就是插件导出的Configschema,DSH settings 服务按dsh-web-icon-indicatorentry id 把它投射为实时配置页(见上)。 - 状态按
agents.list()聚合,优先级asking > running > done > idle。每次请求都会执行一次reconcile()检测 running → idle 的转换,因为agent/status的 idle 事件在回合结束时并不保证送达。状态端点还会上报active——非待机 agent 数——当该数 > 1 时,注入脚本改为渲染占满整帧的数字块(demo/badge.html的「满幅数字」通道:圆角色块,填充色与鲸鱼同源的逐帧状态色/特效,白色粗体数字约占图标高度 31%–52%,上限99+),而不是鲸鱼,这样即使在 16px 的固定标签页里也能一眼看出同时有几个 agent 在忙。 ask_user_question工具调用(通过tools/pre-execute/tools/result)把会话置为asking,带可配置的最小保持时长,即使你立刻回答,图标也会保持可见。- 权限 / 沙箱拦截等待同样会显示为
asking:当 agent 命中沙箱拒绝并请求提权(sandbox_permissions+justification),或其他工具需要征得同意时,审批服务会先写入一条approval/asked会话事件并阻塞 agent,直到你做出决定。插件监听session/event(并以实时会话日志的权威折叠作为兜底)在整个等待期间将会话置为asking状态,收到approval/decided后清除。 - 浏览器脚本每秒轮询
/dsh-web-icon-status.json(轮询间隔在注入脚本里固定为 1000 ms,不是配置项),首次获取base.svg,然后每个requestAnimationFrame周期把 favicon 重建为data:image/svg+xml,…URI——把__COLOR__占位符替换为状态配置的颜色,并应用该状态配置的特效。状态响应还会携带当前的每状态视觉配置,因此设置保存后约 1 秒内(下一个轮询 tick)即同步到已打开的标签页,无需刷新。浏览器不会播放 SVG favicon 的 CSS 动画,所以一切动画都由 JS 驱动。由于浏览器在隐藏(后台)标签页会暂停requestAnimationFrame,轮询还会为动画态补绘一帧按墙钟时间计算的画面——后台标签页保持粗粒度动画(约每 1 秒)而不会冻结,切回前台后恢复满速动画。回到前台时还会通过visibilitychange立即触发一次状态拉取并重绘——后台定时器会被节流,轮询可能滞后,所以切回标签页的瞬间就能看到最新状态(例如隐藏期间done保持期已过、图标应退回idle)。轮询还能扛住 host 重启 / 后端停止:启动时会把原始 favicon 缓存为离线安全的data:-URI 副本,请求失败时还原该副本(副本未取到则保留最后一帧插件图标)——绝不写回原始的服务端 URL(后端停止时它恰恰不可达,写回正是「图标丢失」的根因);每个 tick 持续重试,端点恢复后第一个成功轮询即换回实时图标(SPA 原地重连,无需手动刷新)。
浏览器支持与已知限制
favicon 本质是一张图片,浏览器不会在标签页 UI 里运行 SVG 自带的 CSS/JS 动画——每一帧都在本插件里由 JavaScript 生成。
| 浏览器 | SVG favicon | 逐帧换色 / 换特效 | 说明 |
|---|---|---|---|
| Chrome / Edge | ✅ | ✅ 顺滑 | 实时重读 <link rel=icon>;data: URI 的 SVG 可用。 |
| Firefox | ✅ | ✅ 顺滑 | 对 SVG favicon 支持良好(且会响应其 prefers-color-scheme,本插件未使用)。 |
| Safari(macOS) | ✅ 渲染为静态图 | ⚠️ 尽力而为 | 忽略 SVG 内嵌 CSS;favicon 缓存激进。 |
| Safari(iOS) | ✅ 渲染为静态图 | ⚠️ 基本不刷 | 通常需重新访问标签页才刷新。 |
已知限制(截至 Safari 26.3):
- favicon 有专属缓存。 Chrome 用 favicon 数据库、Firefox 用
favicons.sqlite、Safari 用系统级图标缓存——清普通缓存都清不掉,WebKit 甚至会把「无图标」这一状态也缓存起来。这就是改了图标后,已打开的标签页还可能显示旧图标的原因。本插件已通过「给base.svg与状态端点设置Cache-Control: no-store、请求携带 freshness 参数(?t=Date.now())、每次切换状态时重建<link rel=icon>节点」来缓解。 - 必须先折叠「按主题配对」的两个 favicon link(DSH ≥ 0.1.7)。 宿主的
index.html里有两个rel=icon——favicon-dark.svg对应prefers-color-scheme: dark、favicon.svg对应浅色(0.1.6-alpha.2 及更早只有一个)。浏览器取的是最后一个 media 命中的已连接 link,所以只重绘第一个的话,无论会话状态怎么变,标签页始终显示宿主自己的图标。插件现在会在首次绘制前把这一组规范成唯一一个不带 media 的 link(保留你当前配色方案对应的那个)。如果你用的是 0.5.2 之前的版本、且标签页图标完全不变化,原因就在这里。 - Safari 渲染 SVG favicon,但忽略其内部 CSS——不支持
@media、prefers-color-scheme、CSS 动画。所以所有上色必须烘焙进每一帧的标记(本插件正是这么做的),而不能依赖 CSS 变量。 data:URI 的 SVG favicon 在 Safari 不可靠(WebKit bug 236616,仍未关闭;Safari 17.6 复现)。本插件当前每帧都生成data:image/svg+xmlURI,因此在 Safari 上标签页图标可能完全不显示——这是最大的已知缺口。- Safari 的动态 JS 更新为 hit-or-miss,可能需要刷新一次;Safari 会「锁定」它首次看到的图标。目前没有保证可靠的、符合规范的手段能在 Safari 中实时更换 favicon。
- 固定标签页图标(
<link rel="mask-icon">)使用独立缓存,与普通 favicon 分开;它是靠color属性着色的单色剪影——仅 macOS + 固定标签页、页面加载时读取一次、并非实时。
完整机制与来源(WebKit bugs、Stack Overflow、浏览器工程博客)以及让 Safari 更顺滑变色/切换的推荐路径见 docs/safari-favicon-research.md。
已知限制
- favicon 的 SVG CSS 动画在浏览器标签页 UI 中不会运行——所有特效都由 JavaScript 每帧重建 data-URI 实现,这是零依赖设计的刻意取舍。(本文档中的动画预览只是演示素材——真实 favicon 的动画始终由 JS 驱动。)
- favicon 行为因浏览器而异,其中 Safari 限制最多——见 浏览器支持与已知限制。
base.svg模板必须保留#p { fill: … }规则中的__COLOR__占位符;浏览器会替换该标记为每帧上色。- 插件运行在 host 平面,必须挂载进 profile 的组合配置,不能作为会话级 agent preset。
- 文件读取走
fs服务,以配置的iconsDir为cwd。请确保该路径在部署环境的沙箱策略下可读。
许可
MIT
链接
同类插件
zhu1090093659/dsh-web#packages/dsh-task-board★ 8405
侧边栏多列任务看板:卡片交给真实 DSH 智能体会话执行,支持 cron 定时(Host 侧到点执行,关浏览器也生效)。
zhu1090093659/dsh-web#packages/dsh-web-all★ 8405
DSH Web UI 插件与皮肤合集:任务看板、git 图、右侧面板、远程移动端 UI、桌宠、实时 token 统计与皮肤中心。
ccch1mneyyy/dsh-TUI★ 4088
Claude Code 风格全屏终端 UI:像素鲸鱼顶栏、实时工作状态行、思考流式展开。
MeteorNOX/DeepSeek-Balance-Whale-Widget★ 4076
右下角常驻的小鲸鱼挂件:余额、今日已用与每轮对话消耗(含峰谷价),余额预警与今日预算的泡泡内容都可编辑;泡泡点击序列模块化自定义,支持并列加权 A/B、随机台词与随机图片;内置 30+ 厂商模板(OpenAI / OpenRouter / Kimi / 硅基流动 / 方舟 / 智谱 / MiniMax 等),按模型查余额与订阅额度;另有任务结束音效、导入音频、自定义角色与资源管理。数据全在本机,无遥测。
omdsh-dev/DSH-better-sidebar★ 4009
侧边栏完整工作台:内置文件渲染编辑、终端、Git 与子代理,支持三方插件注册新 Tab。
Devin-AXIS/deepseek-design#deepseek-idesign★ 1423
可视化设计工作室,支持网站、App 原型、海报、信息卡、报告和杂志的模板创建、元素编辑、选区级 AI 草稿衔接与导出。
社区评论
评论公开保存在 GitHub Discussions。加载评论会连接 GitHub 和 Giscus;发表内容需要 GitHub 账号。