Section icons for the settings navigation: replaces the uniform gear icons with per-section glyphs and fills the plugin-market card avatar slot with each plugin icon; a page reload after uninstall restores the official icons.
Install
# from npm (prebuilt)
dsh plugin --profile web add @mzzsfy/dsh-settings-nav-icons
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:mzzsfy/dsh-plugin#path:/packages/dsh-settings-nav-icons
Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).
README
This plugin publishes its README in Chinese only.
DeepSeek Harness 纯前端插件:设置弹窗左侧导航与 dsh-market 插件市场卡片的图标适配——原版 Shell 只为 models / agent-presets / plugins 三个分区 id 提供专属图标,其余分区(含通用设置)一律回退齿轮;本插件按分区显示文本把齿轮换成专属图形,并为市场卡片头像槽提供插件语义图标。
行为
| 场景 | 行为 |
|---|---|
| 分区当前是官方齿轮 | 改写官方 svg 内部内容为专属图形(用户覆盖 → 声明 → 内置映射 → 关键词 → 哈希) |
| 分区当前非齿轮(官方原生图标 / 第三方插件供给的图标) | 不干预,映射或声明命中也不例外 |
| 右键导航分区 | 打开图标编辑浮层:保存/清除用户覆盖(localStorage 持久),非法值行内提示 |
| 左侧导航分区溢出(弹窗高度不足) | 列表区域滚动,标题固定;官方无滚动机制,溢出被弹窗裁剪致底部分区不可达 |
| 市场卡片头像槽(有名称锚) | 按插件名取图替换作者头像/字母色块 |
| 语言切换导致 label 变化 | 已改写的分区按新 label 重新取图改写;双语分区覆盖/声明按等价组跨语言命中 |
| 面板关闭后重新打开 / 会话切换 | 新渲染的齿轮自动再改写 |
| 声明变更(注册新值/撤销) | 受影响分区 svg 内容就地重写,头像槽重新取图 |
| 插件卸载 | 观察器随 ctx.effect 销毁,重载页面即恢复官方默认 |
改写采用内容制:直接替换官方齿轮 svg 的内部内容,不新建节点、不动属性——节点、class、DOM 位置全部保持官方原样,其他插件针对官方图标的 CSS(如按 > svg:first-child 隐藏、伪元素 mask 叠加)照常作用于改写结果,不会出现双图标。
用户自定义覆盖
右键点击设置弹窗左侧导航任意分区,弹出图标编辑浮层:
- 输入内置 glyph 名(见下表)或完整 16×16
<svg>字符串,「保存」即时生效并写入 localStorage(__navicUserIcons),刷新页面后仍然生效 - 「清除」删除该分区覆盖,回到默认取图管线;Esc 或点击浮层外部关闭
- 浮层展示当前取图来源(用户覆盖 / 插件声明 / 内置映射 / 自动推导)与当前图标预览
- 覆盖值与声明走同一安全门(未知 glyph 拒绝、svg 过闸),存储值被篡改时该键跳过,不直通注入
- 官方双语分区(通用设置 / General)的覆盖与声明按等价组生效:写在任一语言键,两种语言下都命中;保存/清除/重写均按组内全键触达,两侧同步
插件卸载后浮层与样式随生命周期销毁;localStorage 中的覆盖数据不影响官方 UI,重装即恢复。
取图优先级
用户覆盖(localStorage) → 外部声明(register) → 内置映射(ICONS) → 名称关键词(NAME_RULES) → 稳定哈希备用池(FALLBACK)
- 外部声明:其他插件运行时注册自己的 label/插件名 → 图标,优先级最高(见下节)。
- 内置映射:官方分区与无法改源的第三方分区。
- 关键词:插件名/分区名整词命中语义关键词得主题图(git→分支、im→机器人、search→放大镜、usage→图表、wallet→钱包、dash→表盘等 21 组规则);整词边界匹配,
im不误伤important。 - 备用池:星芒/层叠/标签/网格四个中性图形,按名称稳定哈希取一个——同一名称永远同一图形,重渲染不闪动。dsh-market 目录内全部插件(含下载量前 1000)至此都有图标。
图标声明机制(其他插件接入)
设置分区或市场插件自定义图标,在 client 半区加载后调用:
// 方式一:nav-icons 已就绪时直接注册
window.__navicIcons.register({ '消息通知': 'bell' })
// 方式二:nav-icons 未就绪时入队,由其启动时排空
;(window.__navicIconQueue ??= []).push({ '消息通知': 'bell' })
- 键:分区显示文本(设置导航)或插件名(dsh-market 卡片)。两域共用一张表,同名时以先命中者生效,键请取不易与官方分区撞名的插件名。官方双语分区按等价组解析:任一语言 label 作键,两种语言下均命中(消除语言切换的声明键漂移)。
- 值:内置 glyph 名(
tune/theme/bot/market/cube/mcp/shield/cards/plan/bell/wrench/archive/spark/layers/tag/grid/git/search/term/chart/code/doc/db/flow/globe/lock/image/zap/wallet/gauge)或完整 16×16<svg>字符串。svg 字符串过安全门:完整开标签(大小写不敏感,拒绝<svgx残串)且单根闭合(首个</svg>后不得再有内容,堵尾缀活动 HTML);不带on*事件属性(\b前界堵斜杠分隔绕过)、不带<script>/<style>(内联样式全文档生效且 @import 可外联)/<foreignObject>/SMIL 动画(<animate>/<set>等)载体;不带href/xlink:href及attributeName="href"注入(16×16 静态图标无合法引用/动画场景,外联请求一并封死);不带javascript:(纵深);长度 ≤4096 字符;glyph 名查表经typeof收口,原型链成员不可能被注入。 - 声明值经归一化后写入注册表;同值重复注册幂等短路;非法值(未知 glyph/被安全门拒绝/非字符串)撤销该键声明,该分区回到内置映射或关键词/哈希默认管线,已改写的 nav svg 内容就地重写。
- 声明持久化在
window.__navicIconDeclarations:本插件 client 半区热重载会重跑工厂而生产者不重发注册,持久层让重装实例恢复声明,页面刷新随 window 释放。 - 污染面收敛在
window.__navicIcons单一命名空间,插件卸载时移除 API、取消已排定的重绘、队列恢复数组形态——卸载后生产者按上方「方式二」入队等待下一实例,不再驱动 DOM 改写;重载页面后全部还原为官方图标。
本仓库全部插件包(含本包自画像与仅 host 半区的包)都走此机制显式声明,不依赖关键词/哈希推导;键为「分区 label + 市场短名」双形态:usage-panel(账号余额、dsh-usage-panel → wallet)、usage-dash(使用统计/Usage、dsh-usage-dash → gauge)、turn-notify(消息通知、dsh-turn-notify → bell)、maintain(版本与运维、dsh-maintain → wrench)、session-manager(会话归档、dsh-session-manager → archive)、rs-workflow(若水工作流、dsh-rs-workflow → flow)、cron-board(dsh-cron-board → plan)、think-expand(dsh-think-expand → spark)、model-capability-editor(dsh-model-capability-editor → cube)、auto-trust-all(dsh-auto-trust-all → shield)、llm-pi-gateway(dsh-llm-pi-gateway → globe)、settings-nav-icons(dsh-settings-nav-icons → tune);仅 host 半区的 auto-trust-all 与 llm-pi-gateway 为声明专设最小 client 半区。注册样板由本包测试做契约锁定。
内置映射表
| 分区显示文本 | 图形 |
|---|---|
| 通用设置 / General | 调节滑杆 |
| Theme / 外观 | 明暗对比 |
| IM机器人 | 机器人 |
| 插件市场 | 店面 |
| Agent Plugins 市场 | 六边形魔方 |
| MCP 服务 | 服务器堆叠 |
| 认证 | 盾+勾 |
| 侧边卡片 | 分栏面板 |
图形为 16×16 stroke 1.5 轮廓,currentColor,与官方 IconOutline16 视觉节奏一致。模型 / 插件 / Agent 预设是官方专属图标、使用统计(usage-statistics-panel)自带柱状图,均不收录。
实现要点
- 导航滚动补偿:官方 navList 高度随内容撑开,弹窗(overflow hidden)裁掉溢出且无滚动途径,分区一多底部不可达。插件启动时向 head 注入一条样式规则(navList
flex:1 1 0 + min-height:0 + overflow-y:auto + scrollbar-width:thin),样式表形态对弹窗关闭重开等任意 React 重渲染持续生效;卸载即移除,零残留。类名锚定与图标改写同策略(VOzbGW_哈希前缀字面量)。 - 实现边界:
settings.*子槽位的声明权与渲染权均被原版dsh-client-ui-settings-general条目占用——renderSlot只授予声明了children的条目(dsh-client-ui-renderer),而 Slot 声明全局唯一、重复声明即already declared,因此任何插件都无法在保留设置页内容的前提下接管 Shell 重绘导航。DOM 观察是唯一不依赖官方契约变更的路径(dream-skin 与 dsh-better-sidebar 各自内置了同原理的一次性 hack)。 - 匹配锚点:分区显示文本而非分区 id——id 不进 DOM,文本是唯一稳定可见锚点;CSS Modules 哈希类名(
VOzbGW_*)取字面量。label 一律 trim 后匹配,空白 label 直接跳过。 - 内容改写制:决策只对官方齿轮(齿轮路径前缀
M14.0861识别)生效,applyDecision写官方 svg 的innerHTML并把记账(data-navic= label)落在官方 svg 自身;不新建节点、不改属性、不驱动 style。React 安全性依据:官方 nav 图标是静态子树,重渲染前后 element 引用相等即 bailout,改写内容稳定存活(0.1.x 的 NotFoundError 仅源于 remove 节点本身);升级残留的旧注入节点(data-navic="1")在改写前清除。改写后的 svg 非齿轮且带记账,与"未处理的官方原生非齿轮 svg"靠记账区分——因此声明变更不删记账,由registerIcons对命中键的 nav svg 以resolveForLabel全链(声明 → 内置映射 → 关键词 → 哈希)就地重写内容,头像槽(非 svg 节点)仍走清账重贴。 - 市场卡片头像槽记账为插件名,IMG/DIV 同构处理:原节点隐藏、注入图标跟随(不触碰 React 受管子树),换名重贴按父容器范围清理旧注入、不误删外来兄弟。
- 生命周期:单个
MutationObserver常驻document.body(childList+subtree+characterData;childList 通道仅元素级变更放行,characterData 通道按目标域精确放行——label 与市场卡片名所在行内的文本改写才唤醒,流式正文等域外文本变更不唤醒),变更去抖到requestAnimationFrame扫描,单元格与头像槽合并为单次全文档遍历,扫描结束takeRecords消除自产写入回波;ctx.effect持有,卸载即断开并取消已排定帧,已停止实例的注册入口短路、不驱动 DOM。观察器句柄、在途帧与滚动样式元素挂 window 代际槽(HMR 重评估先拆上一代三者,滚动样式对旧版槽缺字段宽松判空),帧句柄与槽同步(跨代取消真实可达)。常驻全文档观察是已知性能取舍:装饰性插件的目标域(设置弹窗/市场卡片)无稳定根锚点,两级观察的回归风险大于收益。 - 纯逻辑层(映射表 + 改写决策)在
src/logic.mjs,src/client.js内嵌同源实现,node --test以同一套场景对两份实现做 parity 验证(全表 deepEqual + 决策函数逐函数源码对比),另有编排层契约测试(注册校验/队列三态与时序/生命周期/头像槽编排/异常隔离)与四生产者样板契约测试。
安装
dsh plugin --profile web add @mzzsfy/dsh-settings-nav-icons
开发安装(仓库工作副本以 NTFS junction 挂进 profile,改代码刷新页面即生效,无需发版):
node scripts/dev-link.mjs dsh-settings-nav-icons
前提:profile package.json 的 dependencies 有本包 semver 行、dsh.profile.bundles 有本包名(未发布包 registry 拉取会失败,junction 覆盖 node_modules 物理目录后启动只走 realpath)。junction 会被 pnpm install / dsh plugin add 抹掉,之后重跑本脚本即可。
重启 dsh 后设置面板即生效;设置项即「用户自定义覆盖」的右键浮层,无独立设置页。
升级 / 卸载
dsh plugin --profile web add @mzzsfy/dsh-settings-nav-icons # 升级到最新发布版本
dsh plugin --profile web remove @mzzsfy/dsh-settings-nav-icons # 卸载
插件无 Host 端状态、无持久化副作用,卸载后重载页面即恢复官方默认齿轮。
测试
pnpm --dir packages/dsh-settings-nav-icons test
# 或
node --test packages/dsh-settings-nav-icons/test/*.test.mjs
覆盖:上表全部行为场景(齿轮强补 / 非齿轮不动 / svg 记账幂等与 label 重写 / trim 与空 label / 无 svg 降级 / 内容改写与不建节点 / 0.1.x 残留清理 / 声明安全门 / 撤销回退取图链 / 关键词边界 / 头像槽 img+div / 导航滚动样式注入与卸载)、映射表契约、双实现全量同源 parity、client.js 注册 id 守卫、编排层契约(注册校验 / 就地重写 / 队列三态 / 生命周期 / 异常隔离 / 持久层恢复)、用户覆盖(localStorage 恢复安全门 / 右键浮层保存与非法行内提示 / 清除回默认管线 / 等价组双语触达 / 浮层开闭)、别名等价查询(lookupWithAlias / aliasKeysOf / iconSourceOf)、四生产者样板契约。
License
MIT
dsh 版本兼容
三版本全部通过:导航图标接管。0.1.6 设置导航 5→6 标签(新增会话归档)属宿主演进,不构成不兼容。
Links
More in this category
zhu1090093659/dsh-web#packages/dsh-task-board★ 7725
Task board for the dsh web GUI: a sidebar multi-column kanban whose cards run in real DSH agent sessions and can also be scheduled with cron expressions, executed host-side even with the browser closed.
zhu1090093659/dsh-web#packages/dsh-web-all★ 7725
Plugin and skin collection for the DSH Web UI: task board, Git graph, right-side panel, remote mobile UI, pet, live token stats, and a skin center.
omdsh-dev/DSH-better-sidebar★ 3648
Full sidebar workbench with file rendering and editing, terminal, Git, and subagents; third-party plugins can register new tabs.
ccch1mneyyy/dsh-TUI★ 3086
Claude Code-style full-screen terminal UI: pixel-whale header, live status line, and streaming thought expansion.
MeteorNOX/DeepSeek-Balance-Whale-Widget★ 2641
A fixed-corner whale widget for the DSH web GUI — balance, today's usage and per-turn cost with peak/off-peak pricing, editable balance-alert and daily-budget bubbles, a module-based custom bubble queue with A/B weighted choices and random lines or images, 30+ vendor templates (OpenAI, OpenRouter, Kimi, SiliconFlow, Ark, Zhipu, MiniMax and more) with per-model balance and subscription quota, plus task-end sound, imported audio, custom roles and a resource manager. Local-only, no telemetry.
Devin-AXIS/deepseek-design#deepseek-idesign★ 1316
Visual design studio for websites, app prototypes, posters, cards, reports, and magazines, with templates, direct element editing, selection-aware AI draft handoff, and export.
Community comments
Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.