三条线合并入库(同一次部署批次,源码与生产此前已一致):
一、档案 138 · 平台共享模型:管理员逐用户授权(默认关闭)
用户口径原文:「admin 设置的共享模型,需要 admin 在用户列表中开启(新增选项,默认关闭),
用户才能在会话中使用(以及在设置的模型设置页面展示)」。
· DB 迁移 v11:新增 users.shared_model_granted(DEFAULT 0 = 默认关闭)。
⚠️ 刻意**不**复用 v6 的 shared_model_enabled —— 那是用户侧偏好(用户能自己关,默认 1),
而本需求要的是**管理员门禁**;共用一列则用户点一下就给自己授权,门禁形同不存在。
生效 = granted ∧ enabled(server.ts#sharedLandingRows)。
· 新路由 POST /api/admin/users/:id/models/shared(requireAdmin)+ 审计 shared_model_grant
+ **尽力而为**重启该用户实例(租约被占/实例未运行都不算失败)。
· admin 用户列表新增「共享模型」列;用户侧 /api/me/keys 增 shared.granted / sharedModelGranted;
插件 0.3.24:未授权时「平台共享模型」整块不渲染。
二、顺带修掉一个既有真缺陷:平台侧写用户 home 必须走 UserFs(用户卷在 worker 上)
landModels 原先 join(owner.home_dir, …) + 本机 fs ⇒ 对「实例不在控制面本机」的用户
读到空串(**不报错**)⇒ 模型落地一直是**静默空操作**(托管清单还被清空)
——即档案 87 的模型设置页对 guest 这类用户**从未生效**。
· UserFs 新增 readHomeFile/writeHomeFile + 文件名白名单(settings.yaml / .credentials.yaml)
· worker agent 新增 /fs/home-read /fs/home-write(只认白名单裸文件名)
· landModels 改走 userFs(与"文件面"同一份按归属路由 ⇒ 落地与实例必然同机)
· 同轮把 /api/me/locale(档案 102 语言偏好)也改成同一套(原先同样失效)
· home-files.ts 抽出 backupHomeFile(备份留平台侧,命名规则逐字不变)
三、档案 139 · 品牌中文名:能力枢纽 → 能力网络(其他语言仍 CapabilityNet)
落点四处:i18n 中文词条 / admin.html 顶栏 / favicon.svg 的 title+aria-label / design.css 注释;
test/i18n-brand.test.mjs 期望值同步。档案 137 顶部加"后续"指针,不改历史。
验证(全部真机实测):
· 红腿:未授权 → 106 上 guest 的 .credentials.yaml refs 变空(共享 key 被撤)
· 绿腿:授权 → key 回来 + 托管清单恢复 ["DEEPSEEK_API_KEY"]
· admin 列表带出 sharedModelGranted;用户侧 granted 随授权翻面(true/shared ↔ false/none)
· 开关两次均 200(不再假失败);插件实装 0.3.24 且含 gating 字符串
· 语言偏好:106 上 settings.yaml 出现 locale.preference=en(属主=实例属主,既有段逐字保留)
· 本机 npm test 226 tests / 225 pass / 0 fail / 1 skipped;四个 verify 脚本全绿
部署:47 推 51 个 lib 产物、106 推 12 个(lib/ 是 gitignore ⇒ 回滚点物化在
/opt/dsh/backups/seq138b-20260919-125345/,逐文件对账 0 不一致;先 106 后 47);
插件 business-plugins 0.3.24(两机 artifacts 与本机 pack md5 一致)。
10 KiB
10 KiB
137-品牌标识改造(去 DeepSeek 图形 → 平台自有标识)
⚠️ 后续(2026-09-19):中文品牌名已由「能力枢纽」改为 「能力网络」(其他语言仍
CapabilityNet) —— 见档案 139。本档正文保留当时的定名,不改历史。
一句话:把我们自己的页面上所有 DeepSeek 品牌标识(鲸鱼图标 / 「DeepSeek」文字图形 / favicon) 换成平台自有标识 —— 中文「能力枢纽」,英语及其他语言「CapabilityNet」。 触发:用户 2026-09-19 原话三句 —— ① 「登录和注册页面上的 deepseek的图标去掉,改为中文: 能力枢纽 小写 CapabilityNet ,英语和其他语言:CapabilityNet」 ② 「一并替换」(= 其余页面也一并办) ③ 「会话页面左上角的 deepseek 先不替换」(= 实例内官方 dsh 界面那处不动) 执行:会话
登录注册页品牌标识改造→品牌标识一并替换-admin portal favicon· 状态 ✅ 已上线
0. 替换范围(先划边界,这是本档案最重要的一节)
| 位置 | 处置 | 依据 |
|---|---|---|
login.html / register.html 页头品牌区 |
✅ 替换 | 用户① |
admin.html(管理台登录卡片) |
✅ 替换 | 用户②「一并替换」 |
portal.html(管理门户顶栏) |
✅ 换图标 | 用户②;文字「管理门户」保留(见 §1 注) |
| 四页的 favicon | ✅ 换新图标 | 用户②;logo.svg 就是 DeepSeek 图标 |
| 🔴 会话页面左上角(用户实例内的 dsh 会话窗口) | ⛔ 不替换 | 用户③明示「先不替换」。技术上它属官方 dsh 的 client bundle,不在本仓 web/ 目录 ⇒ 也不受红线 R2(不改官方 dsh 主程序)允许 |
index.html / wake.html |
— 无品牌标识 | 前者是纯跳转页、后者是启动过渡页,二者均无 logo/wordmark,且本来就没有 favicon link(未加,见 §4) |
⚠️ "会话页面"不在本次能力范围内:本仓 web/*.html 是平台自有的门户/管理页;
用户在实例里看到的会话界面由官方 @deepseek-ai/dsh 渲染 ⇒ 那处的标识要么属于官方、要么需走
profile 层官方插件机制(R2 的合规路径),不是"改个静态文件"能解决的。
1. 改了什么
| 文件 | 改动 |
|---|---|
web/login.html |
.auth-brand 内:删 <img class="logo" src="/logo.svg">(DeepSeek 鲸鱼,2109 B 的 #4D6BFE 图形)+ 删 内联 <svg><title>DeepSeek</title>…</svg>(131×24 文字图形)→ 换 <span class="wordmark" data-i18n="brand.name">CapabilityNet</span>。10758 → 6799 字节 |
web/register.html |
同上。20002 → 16919 字节 |
web/admin.html |
同构处理(它复用 .auth-brand):删图标 + 删内联 DeepSeek SVG → <span class="wordmark">能力枢纽</span>(该页是纯中文页、未接 i18n ⇒ 直接写中文)。11913 → 7928 字节 |
web/portal.html |
顶栏 .brand 只换图标:src="/logo.svg" → src="/favicon.svg";⭐ 文字「管理门户」保留 —— 它是页面定位名、不是 DeepSeek 痕迹,删掉属越界 |
web/favicon.svg |
新建(1008 B):平台自有图标,取「枢纽 / hub」意象 —— 圆角深底 + 中心节点 + 三条辐条 + 三个外环节点;配色用平台自己的 token(ink #0f1c33 底 / accent-2 #38d6d0 节点),刻意避开原 DeepSeek 的 #4D6BFE。同时兼作 favicon 与 portal 顶栏图标 |
| 四页 head | <link rel="icon" href="/logo.svg"> → href="/favicon.svg" |
web/i18n.js |
新增词条 brand.name:en → CapabilityNet、zh → 能力枢纽 |
web/design.css |
.auth-brand .wordmark 由「定高 22px(给 SVG 用)」改为文字排版(height:auto + 19px/600/行高 1.2) |
test/i18n-brand.test.mjs |
新增:node:vm + 最小 DOM 桩跑仓库里那份真实的 i18n.js,断言六条语言路径的实际渲染结果 |
scripts/verify-static.mjs |
新增 SVG 段:见 §3-1(踩坑后的防护) |
两个刻意的选择
- 登录/注册页走 i18n 词条,⛔ 不写死在 HTML:①
verify-static.mjs的I18N_PAGES已把这两页列入「不得出现裸中文文案」,硬写「能力枢纽」会被拦;② 「英语和其他语言」 要的正是回退语义 ——lookup()缺 key 时回退en,只写en一条即覆盖所有其他语言。 ⚠️admin.html/portal.html未接 i18n(既有的纯中文页)⇒ 那两处直接写中文, 不引入 i18n 运行时(引它会连带处理它们大量既有裸中文,属扩大范围)。 - 发子域名
favicon.svg而不是复用logo.svg:favicon 缓存按 URL 生效 ⇒ 换文件名 天然绕过浏览器里那份旧的 DeepSeek 图标缓存,不需要加?v=版本串。
2. 验证证据
| 项 | 实测 |
|---|---|
i18n 渲染自证(跑真实 i18n.js) |
六条全绿:浏览器 en-US → CapabilityNet|zh-CN → 能力枢纽|?lang=zh → 能力枢纽|?lang=en(覆盖中文浏览器)→ CapabilityNet|cookie dsh_lang=zh → 能力枢纽|ja-JP → 回退 CapabilityNet |
| 裸 key / 空文案 | 四种语言下均非 brand.name、非空 |
| SVG 合法性(真 XML 解析器) | favicon.svg 解析通过;children=[title, rect, g, circle×4]、paths 三条齐备;另两个既有 SVG 也一并验过 |
| 反向自证(坏样本必须被拦) | 故意往注释里注入 --accent ⇒ 真解析器报 not well-formed + 校验脚本报红;清理后复跑全绿 |
| 残留检查(本地 + 线上) | `web/*.html |
| 静态页不变量 | verify-static.mjs 全部合格(6 页 + 7 段内联脚本语法 + 3 个 css/js + 3 个 svg) |
| 全量单测 | 221 pass / 0 fail / 1 skipped(# tests 222,Node 22.22.2) |
线上(https://ai1net.com) |
favicon.svg = 200 + image/svg+xml;四页均 favicon=1 / logo.svg=0;admin.html 显示 <span class="wordmark">能力枢纽</span>;portal.html 显示新图标 + 「管理门户」 |
| 部署 md5 对账 | 5 个 web 文件两端逐一一致(admin 8736bcc7… / portal 164075c8… / login 2467bd50… / register dfbf996f… / favicon fe37ebbf…) |
| 行尾 | 逐字节核对:admin.html / portal.html 仍 CRLF、login.html / register.html / favicon.svg 仍 LF —— 与该目录既有风格逐一对应,无偏差 |
| 回滚点 | ① /opt/dsh/backups/rebrand-20260919-084220/pre.tar(第一批 4 文件)② /opt/dsh/backups/rebrand2-20260919-090205/pre.tar(本批) |
部署方式:静态文件 scp 即生效(不需要重启);未动任何服务或 env。
3. 踩坑记录
- 🔴 SVG 里的 XML 注释不能含 ASCII 双连字符
--(本次实际踩到)。 我在favicon.svg的注释里写了 CSS 变量名--ink/--accent-2⇒ XML 语法不允许 ⇒ 整份 SVG 解析失败 ⇒ 浏览器静默不显示图标,页面与接口都不报任何错。- 抓到它的方式:用真解析器验一遍(
ET.parse报not well-formed (invalid token)), 而不是只看标签配对或肉眼看 —— 肉眼 100% 看不出这处问题。 - ⚠️ 中文破折号
——(U+2014×2)是合法的,只有 ASCII--(U+002D×2)非法 —— 所以"注释里有破折号"不是判据,"注释里有两个连续半角减号"才是。 - 已固化为判据:
scripts/verify-static.mjs新增 SVG 段(开头/结尾/viewBox/去痕迹/注释双连字符), 并做了反向自证(注入坏样本 ⇒ 必须报红)。
- 抓到它的方式:用真解析器验一遍(
logo.svg同时兼作 favicon 与页面图标 ⇒ 换品牌时"页面上的图标"和"浏览器标签图标" 是同一份资产,改一处必须想到另一处(第一批只改了页面内,favicon 就漏了)。
4. 未做 / 已发现(只报告,未动手)
- 🟡
index.html/wake.html没有 favicon link ⇒ 这两个页面的标签图标是浏览器默认。 本轮未加(用户没要求,且属功能增量)。若要统一,改动 = 各加一行<link rel="icon" href="/favicon.svg">。 - 🟡 三个 DeepSeek 资产现已全部无引用:
web/logo.svg、web/deepseek-text.svg、web/deepseek.webp(grep全仓已无任何 HTML/CSS/JS 引用)。未删 —— 属"额外发现即先报告", 删除是不可逆动作、需你点头(git里可恢复,风险低)。 - ⚪
.topbar .wordmark那条 CSS 保留未改 ——admin.html用的是.auth-brand、portal.html用的是.brand,当前没有任何页面用.topbar .wordmark; 保留是为防样式回归(改它不影响现状,属无收益改动)。
5. 一条待澄清的表述(未阻塞交付)
用户原话里的「小写 CapabilityNet」有两种读法,本轮按读法一实现:
- 读法一(已实现):中文界面 = 「能力枢纽」;英语及其他语言 = 「CapabilityNet」。
- 读法二:中文界面 = 「能力枢纽」+ 其下一行小号
CapabilityNet(双语锁定); 或要求英文写成全小写capabilitynet。
⇒ 若是读法二,改动量 = i18n.js 一处词条 + design.css 一行(无需碰 HTML)。
6. 回滚
| 对象 | 方式 |
|---|---|
| 第一批(login/register/design.css/i18n.js) | /opt/dsh/backups/rebrand-20260919-084220/pre.tar → /opt/dshs/ |
| 本批(admin/portal/login/register/favicon/verify-static) | /opt/dsh/backups/rebrand2-20260919-090205/pre.tar → /opt/dshs/ |
| 生效方式 | tar 覆盖即生效,无需重启(纯静态资源) |
| ⚠️ 注意 | 回滚后页面会重新引用 /logo.svg(DeepSeek 图标仍在服务器上、文件没删)⇒ 回滚是完整的 |
7. 关联
- 同一会话的相邻改动:Cloudflare Turnstile 密钥配置并启用(见档案 134 §实现 E)。
- 旧域移除见 135;控制面并集立项见 136(并行线产物,本档案不重复)。