平台共享模型改为「管理员逐用户授权」+ 品牌中文名改「能力网络」+ 修掉跨机模型落地/语言偏好静默失效
三条线合并入库(同一次部署批次,源码与生产此前已一致):
一、档案 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 一致)。
This commit is contained in:
1 parent
971ccc3703
commit
c2b7c5ef71
30 files changed
+770
-70
No files matched your search
@@ -1,5 +1,8 @@
|
||||
# 137-品牌标识改造(去 DeepSeek 图形 → 平台自有标识)
|
||||
|
||||
> ⚠️ **后续(2026-09-19)**:中文品牌名已由「能力枢纽」改为 **「能力网络」**(其他语言仍 `CapabilityNet`)
|
||||
> —— 见档案 **139**。本档正文保留当时的定名,**不改历史**。
|
||||
|
||||
> **一句话**:把我们自己的页面上所有 **DeepSeek 品牌标识**(鲸鱼图标 / 「DeepSeek」文字图形 / favicon)
|
||||
> 换成**平台自有标识** —— 中文「**能力枢纽**」,英语及其他语言「**CapabilityNet**」。
|
||||
> **触发**:用户 2026-09-19 原话三句 ——
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
# 138 · 平台共享模型 —— 管理员**逐用户**授权(默认关闭)
|
||||
|
||||
- 日期:2026-09-19
|
||||
- 状态:✅ **已上线并端到端验证**(控制面 + 前端 + 插件 **0.3.24**;两腿实测:未授权撤销、授权恢复)
|
||||
- 触发(用户口径,原话):「**调整设计 admin设置的共享模型,需要admin在用户列表中开启(新增选项,默认关闭),用户才能在会话中使用(以及在设置的模型设置页面展示)**」
|
||||
- 落点:`src/db/{schema,types,repo,pg,sqlite,adapter}.ts`、`src/web/routes/{admin,auth}.ts`、`src/web/server.ts`、`web/admin.html`、`poc/business-plugins/lib/client.js`(**0.3.24**)+ **顺带修掉一个既有真缺陷**:`src/fs/{user-fs,local-user-fs,remote-user-fs}.ts`、`src/worker/agent.ts`、`src/web/home-files.ts`(见 §五)
|
||||
|
||||
> **TL;DR**|① 共享模型从「人人默认可用(用户可自关)」改成「**管理员逐用户授权**」——新增列
|
||||
> `users.shared_model_granted`(**默认 0 = 关闭**),**生效 = granted ∧ enabled**(前者 admin 在**用户列表**里开,
|
||||
> 后者是用户自己的偏好,保留不动);② 未授权时**设置页连"平台共享模型"那一块都不渲染**(用户原话"开启才展示");
|
||||
> ③ 🔴 **顺带发现并修掉一个既有真缺陷**:落地层原先用**本机 fs** 写用户 home,而用户卷在 worker 上
|
||||
> ⇒ 对"实例不在本机"的用户,**模型落地一直是静默空操作**(托管清单被清空、目标文件一个字节没动)
|
||||
> —— 也就是说档案 87 那套「模型设置页」对 **guest 这类用户从来就没生效过**;本档把它改成走
|
||||
> `UserFs`(与"文件面"同一份按归属路由),并给 worker agent 补了两个**白名单**端点。
|
||||
|
||||
---
|
||||
|
||||
## 一、为什么是"新开一列"而不是改旧列的默认值(本轮最关键的设计判断)
|
||||
|
||||
| 事实 | 依据 |
|
||||
|---|---|
|
||||
| 旧列 `users.shared_model_enabled`(v6)语义 = **用户侧偏好**(用户自己能在设置页关掉,默认 1) | `schema.ts` 的 `SQLITE_V6` 注释 + `dashboard`(档案 87 口径②) |
|
||||
| 用户要的是**管理员门禁** —— "只有 admin 开了,用户才能用" | 本轮触发原话 |
|
||||
| 若两者共用一列:**用户在自己设置页点一下就把自己"授权"了** ⇒ 门禁形同不存在 | 直接推论 |
|
||||
|
||||
⇒ 故**两列两人**:`shared_model_granted`(admin,默认 **0**)+ `shared_model_enabled`(用户,默认 1,**不变**),
|
||||
**生效 = `granted ∧ enabled`**(`server.ts#sharedLandingRows`)。缺一不给。
|
||||
|
||||
> ⚠️ `DEFAULT 0` 让**存量行也一并变 0**(两个方言加列都用默认值回填)⇒ 迁移后所有既有用户都"未授权"。
|
||||
> 这正是"默认关闭"的字面语义;代价是 **guest 需要 admin 开一次**才会重新拿到共享模型(见 §四-③)。
|
||||
|
||||
## 二、改动清单
|
||||
|
||||
| 层 | 文件 | 改动 |
|
||||
|---|---|---|
|
||||
| DB 迁移 | `src/db/schema.ts` | **v11**:`ALTER TABLE users ADD COLUMN shared_model_granted INTEGER NOT NULL DEFAULT 0;`(两方言同款;注释写清"为什么新开列") |
|
||||
| 类型 | `src/db/types.ts` | `User.shared_model_granted` + `PublicUser.sharedModelGranted`;`toUser` 用 **`Number(row.x ?? 0) !== 0`** |
|
||||
| 仓储 | `src/db/repo.ts` | `USER_COLS` 加列、`findSessionWithUser` 补列、新增 `get/setSharedModelGranted`(缺失行按 **false** = 失败关闭) |
|
||||
| PG | `src/db/pg.ts` | 🔴 **本文件另有一份 `USER_COLS`** —— 加列未同步它 ⇒ `listPublicUsers` 读不到该列、admin 列表恒显示"未开启"(**实测踩到**,见 §六-2) |
|
||||
| SQLite | `src/db/sqlite.ts` / `adapter.ts` | 转发 + 接口声明 |
|
||||
| 生效判据 | `src/web/server.ts` | `sharedLandingRows` 三条件(**granted ∧ enabled ∧ 不是那个 admin 本人**);`resolveApiKey` 的回退注入**也判门禁**(失败关闭) |
|
||||
| 管理面路由 | `src/web/routes/admin.ts` | 新增 **`POST /api/admin/users/:id/models/shared`**(`requireAdmin`,body `{enabled}`)→ 落库 + 审计 `shared_model_grant` + **尽力而为**重启该用户实例 |
|
||||
| 用户面接口 | `src/web/routes/auth.ts` | `sharedKeyInfo` 加 `granted`;`keySourceOf` 加门禁(未授权 ⇒ `none`);`GET /api/me/keys` 增 `sharedModelGranted` |
|
||||
| 管理页 | `web/admin.html` | 用户表**新增「共享模型」列**(已开启/已关闭按钮;admin 与 pending 行显示「—」)+ 一行说明 |
|
||||
| 插件 | `poc/business-plugins/lib/client.js`(0.3.24) | 「平台共享模型」区块改为 **`shared.granted` 为真才渲染**(未授权整块不出现) |
|
||||
| 测试 | `test/db.test.mjs`、`test/local-user-fs.test.mjs`、`scripts/verify-platform-admin-section.mjs` | 新增 4 条:granted 默认关 ∧ 可开关 ∧ 与偏好互不影响、列表带出该列、**未授权 ⇒ 区块不渲染(正反两腿)** |
|
||||
|
||||
## 三、🔴 三条判据(都是踩出来的)
|
||||
|
||||
1. **门禁类判据一律"失败关闭"**:`getSharedModelGranted` 对"查不到这个人"返回 **false**(而 `getSharedModelEnabled`
|
||||
对同样情形返回 true —— 两条**故意相反**,已在单测里钉死)。
|
||||
2. **门禁判在"使用点",不判在"归属判据"里**(本轮红腿实测):`sharedDeepseekKey()` 同时被
|
||||
① 「一次性交接」用来**认领**老实现写下的那行 key(这是**归属**问题)② 回退 env 注入(这是**授权**问题)。
|
||||
第一版把门禁加在函数内部 ⇒ 被撤销授权的用户**认不出自己写过的行** ⇒ 那行永远删不掉
|
||||
⇒ "关掉即生效"不成立。**修法**:函数保持不判,门禁挪到 `resolveApiKey` 的调用点。
|
||||
3. **授权路由里的"重启实例"必须尽力而为**:授权已落库才是真结果;实例没在跑、或归属租约被别的持有者占着,
|
||||
都**不算开启失败**(第一版直接 `await restartMain` ⇒ 租约被占时回 500,admin 界面显示"操作失败",
|
||||
而库里其实已经改对了)。
|
||||
|
||||
## 四、验证(全部真机实测)
|
||||
|
||||
| # | 项 | 证据 |
|
||||
|---|---|---|
|
||||
| ① | **迁移 v11 生效** | `SELECT version FROM schema_migrations` ⇒ `11`;`\d users` 出现 `shared_model_granted integer not null default 0`;四个用户该列全 0(默认关闭) |
|
||||
| ② | **红腿:未授权 ⇒ 共享 key 被撤** | guest(实例在 **w-106**)设为 `false` → 重启实例 → 106 上 `.credentials.yaml` 的 `refs:` **变空**(`DEEPSEEK_API_KEY` 消失)、托管清单 `{"refs":[],"routes":[]}` |
|
||||
| ③ | **绿腿:授权 ⇒ 恢复** | 设为 `true` → 重启 → `refs: DEEPSEEK_API_KEY: 'sk-…'` **回来**、托管清单 `{"refs":["DEEPSEEK_API_KEY"]}` |
|
||||
| ④ | **admin 列表带出状态** | `GET /api/admin/users` ⇒ guest `sharedModelGranted=True`(其余 false) |
|
||||
| ⑤ | **用户侧展示判据翻面** | guest 会话 `GET /api/me/keys`:授权时 `shared.granted=true effective=shared`;撤销后立刻 `granted=false effective=none` |
|
||||
| ⑥ | **开关不再报假失败** | 撤销/开启两次调用均 **200** `{ok:true, sharedModelGranted:…, restarted:false}`(实例未运行) |
|
||||
| ⑦ | **插件实装** | 106 上 guest 的 `profiles/web/node_modules/@dsh-local/business-plugins` = **0.3.24**,`lib/client.js` 含 `shared.granted` ×2;`.dsh-stage/` 有 0.3.24.tgz(本机 pack 与 `/opt/dsh/artifacts/` md5 一致 `75f342eb…`) |
|
||||
| ⑧ | **零回归(本机)** | `npm test` **226 tests / 225 pass / 0 fail / 1 skipped**;`verify-static` / `verify-inject` / `verify-platform-admin-section`(含新 2 条)/ `verify-models-render` 全绿 |
|
||||
| ⑨ | **语言偏好跨机修复生效** | guest(实例在 **w-106**)`POST /api/me/locale {locale:'en'}` ⇒ 200 `changed:true`;106 上 `settings.yaml` 出现 `locale: preference: en`(属主 = 实例属主,既有段逐字保留);平台侧备份 `settings-<id>-<ts>.yaml` 同步落地 |
|
||||
|
||||
⚠️ **未做**:无浏览器的 UI 目视(admin 表格多了一列、「共享模型」区块的隐藏效果)—— 留给你看一眼。
|
||||
⛔ 未重启任何**正在服务**的用户实例去做验证(验证用的 guest 实例由我自己停/起,收口时回到 stopped)。
|
||||
|
||||
## 五、🔴 顺带修掉的既有真缺陷:**跨机用户的"模型落地"一直是空操作**
|
||||
|
||||
**怎么发现的**:按上面 §四-② 第一次跑红腿时,guest 的凭据文件**一个字节没动**、而托管清单却被清空了。
|
||||
根因链(文件级):
|
||||
|
||||
| # | 位置 | 事实 |
|
||||
|---|---|---|
|
||||
| 1 | `server.ts#landModels`(改前) | `join(owner.home_dir, '.credentials.yaml')` + **本机 fs** 读 —— 而 `home_dir` 是**worker 上的路径** |
|
||||
| 2 | 实测 | 47 上 `/var/lib/dshs/users/<guest>/` **只有 `ws/`**、没有 `home/` ⇒ 读到空串(**不报错**) |
|
||||
| 3 | 后果 | `reconcileCredentials('', [], [...])` ⇒ 无变化 ⇒ 不写盘;但 `writeManaged()` 照写 ⇒ **托管清单被清成空**(平台从此"忘记"自己写过的那行) |
|
||||
|
||||
⇒ 影响面**不止本档**:**档案 87 的整套「模型设置页」对"实例不在控制面本机"的用户从来就没生效过**
|
||||
(guest 的实例在 w-106 ⇒ 用户改模型设置不生效);档案 102 的**语言偏好**(`/api/me/locale`)走的是同一套
|
||||
`home-files` 写入,**同样命中这个缺陷**(⚠️ 本档**未修**它,见 §七-3)。
|
||||
|
||||
**修法**(与既有"文件面"设计对齐 —— `server.ts:848-850` 那段注释原本就写着"文件写到 A、实例起在 B"的教训):
|
||||
|
||||
| 层 | 改动 |
|
||||
|---|---|
|
||||
| `src/fs/user-fs.ts` | 新增 `readHomeFile` / `writeHomeFile` + **文件名白名单** `HOME_FILE_NAMES = ['settings.yaml','.credentials.yaml']`(⛔ 只收裸文件名,等于"平台只管自己那两个配置") |
|
||||
| `local-user-fs.ts` | 本机实现(`0600` + chown 给 home 属主);非白名单名 ⇒ `bad_path` |
|
||||
| `remote-user-fs.ts` | 走 agent 的 `/fs/home-read` `/fs/home-write`,目标是 `hostIdFor` **钉住的那台机**(与实例同机) |
|
||||
| `worker/agent.ts` | 新增两个端点(**只认白名单裸文件名**,非法即 400 `bad_path`) |
|
||||
| `web/home-files.ts` | 抽出 `backupHomeFile()`(**平台侧**备份;`writeHomeFile` 改为复用它,命名规则逐字不变) |
|
||||
| `web/server.ts` | `landModels` 的读写**全部改走 `userFs`**:`readHomeFile(...) ?? ''` ∧ `backupHomeFile(...)` + `userFs.writeHomeFile(...)` |
|
||||
|
||||
**为什么这是"必须做"而不是"顺手优化"**:不做 ⇒ 用户这条需求("admin 开了才能在会话中使用")
|
||||
对 guest 这类用户**永远不成立**(授权改了、实例里什么也没变)。R11「只做正向迭代」不允许留这种"看起来做了"的状态。
|
||||
|
||||
**部署面**(`lib/` 是 gitignore 的 ⇒ 回滚点只能物化,⛔ 别指望 `git checkout`):
|
||||
|
||||
- **106** `/opt/dshs-cluster/lib`:`fs/*` + `worker/agent.*` 共 12 个(回滚点 `/opt/dsh/backups/seq138b-20260919-125345/opt/dshs-cluster/lib`,先抓旧版再覆盖,对账 0 不一致)
|
||||
- **47** `/opt/dshs/lib`:42 + 3 + 3 个(同上,回滚点同目录 `/opt/dsh/backups/seq138b-…/opt/dshs/lib`);`restart dshs dshs-worker`
|
||||
- 顺序:**先 worker(106)后 Manager(47)** —— 新端点必须先在位;两版并存时表现为"落地仍不生效"(= 改前状态),⛔ 不会更糟
|
||||
- ⚠️ **106 上跑 `ensure-biz-plugins.cjs` 需要补丁**:它 `require('/opt/dshs/node_modules/better-sqlite3')`
|
||||
而 106 只有 `/opt/dshs-cluster/node_modules`(且该原生模块在 106 上没为 node 22 编译)⇒ 用**临时副本**
|
||||
`/tmp/ebp-106.cjs`(只改两处:require 置空、用户清单改由 `DSH_USERS_JSON` 注入,清单取自权威 PG)。
|
||||
⛔ 正本 `scripts/ensure-biz-plugins.cjs` **未动**。
|
||||
|
||||
## 六、事故 / 踩坑
|
||||
|
||||
1. **用户卷在远端时,"落地"与"备份"要分开**:备份(平台自己的副本)留在控制面 `/opt/dsh/backups` 正合适;
|
||||
⛔ 不要为了备份再往远端开第二条通道。
|
||||
2. 🔴 **`pg.ts` 有自己的一份 `USER_COLS`**(与 `repo.ts` 那份是**两份**)⇒ 加列必须**两处都改**。
|
||||
只改 `repo.ts` 时:SQLite 路径正常、**PG 路径(= 生产)读不到新列**,admin 用户列表**恒显示"未开启"**
|
||||
(而 DB 里其实是 1)—— 这种"两个方言行为不一致"的缺陷只在生产暴露,本档已实测踩到。
|
||||
3. **临时会话(`mksess.cjs`)TTL = 10 分钟** ⇒ 验证脚本必须"现建现用";跨多次手工调用必撞 401
|
||||
(本轮撞了两次,写成了 `seq138-leg.sh` 一次跑完)。
|
||||
4. `scp [email protected]:` 不通(无对应密钥/别名),要用别名 `test106`。
|
||||
|
||||
## 七、未做 / 待办
|
||||
|
||||
1. **UI 目视**留给用户(无浏览器验收已全绿):admin 用户列表多一列「共享模型」、未授权时设置页不出现共享区块。
|
||||
2. **`.lock-131/132/133/134/138` 空目录堆积**(占号后没清)—— 文档库卫生,`docs-audit.py` 不报。
|
||||
3. ✅ **已修(同轮收口时一并做掉)**:`/api/me/locale`(档案 102 的语言偏好)原先**也走本机 fs**
|
||||
⇒ 对远端用户同样失效。改法与 `landModels` **完全同构**(`userFs.readHomeFile('settings.yaml')`
|
||||
+ `backupHomeFile` + `userFs.writeHomeFile`)。
|
||||
**实测**:guest(实例在 106)`POST /api/me/locale {locale:'en'}` ⇒ **200 `changed:true`**;
|
||||
106 上 `settings.yaml` 出现 `locale: preference: en`、属主 = 实例属主 `dsh-<hash>`、
|
||||
既有段(`agent-default-model` / `agent-presets` / `llm-pi-ai`)**逐字保留**;
|
||||
平台侧备份同步落地 `settings-<userId>-<ts>.yaml`。
|
||||
⇒ **本档之后,平台侧"写用户 home"只剩 `UserFs` 这一条路**(`readTextOrEmpty` / `writeHomeFile`
|
||||
的**本地版**仍保留给 `deployMode=local` 的单机形态与 `home-files.ts` 内部复用)。
|
||||
4. ⚠️ **`shared_model_enabled`(用户偏好)现在只在"已授权"时才有可见效果**:用户侧那条
|
||||
`POST /api/me/models/shared` 路由**未加门禁**(有意 —— 见 `auth.ts` 该路由注释:让用户能先关掉自己不想用的、
|
||||
也允许先打开,授权一到即生效;且不泄露"管理员是否授权了别人")。若将来要"授权后用户不得自关",需另立需求。
|
||||
|
||||
## 八、回滚
|
||||
|
||||
```bash
|
||||
# ① 控制面代码:从本仓重建 HEAD 版 lib 并覆盖(lib/ 不入仓,⛔ 不能用 git checkout)
|
||||
git -C <本机仓> show HEAD:src/... # 或直接在 47 侧用回滚点:
|
||||
cp -r /opt/dsh/backups/seq138b-20260919-125345/opt/dshs/lib/* /opt/dshs/lib/ && systemctl restart dshs
|
||||
# ② worker(106):同样用该回滚点下的 /opt/dshs-cluster/lib
|
||||
# ③ 插件:确保产物回落 0.3.23(/opt/dsh/artifacts 保留旧包)
|
||||
# ④ DB:v11 的 ADD COLUMN 不回滚(SQLite 无 down migration;空列不影响旧代码)
|
||||
```
|
||||
⚠️ 回滚 ① 会把 §五 的跨机落地修复一起回退 ⇒ 远端用户的模型落地重新变成空操作(不致命,但那是既有缺陷)。
|
||||
@@ -0,0 +1,55 @@
|
||||
# 139 · 品牌中文名:能力枢纽 → **能力网络**
|
||||
|
||||
- 日期:2026-09-19
|
||||
- 状态:✅ **已上线**(静态资源直覆,无需重启;页面与接口双端实测)
|
||||
- 触发(用户口径,原话):「**把页面上的能力枢纽 改为能力网络**」(同轮先说过「能力领域」,随即更正为「能力网络」)
|
||||
- 上游:档案 **137**(品牌标识去 DeepSeek 图形,定名「能力枢纽」)—— 本档**只改名,不动结构**
|
||||
- 落点:`web/i18n.js`、`web/admin.html`、`web/favicon.svg`、`web/design.css`(注释)、`test/i18n-brand.test.mjs`
|
||||
|
||||
> **TL;DR**|中文品牌名 **「能力枢纽」→「能力网络」**;**其他语言不变**(仍 `CapabilityNet`,
|
||||
> 走 `en` 词条 = 所有其他语言的回退)。改名落在**四处**:i18n 的中文词条、`admin.html` 顶栏文字、
|
||||
> **`favicon.svg` 的 `<title>` 与 `aria-label`**(浏览器标签页/读屏可见 —— 最容易漏)、`design.css` 注释。
|
||||
> 回归测试与 `verify-static`(含 SVG 真解析)全绿;线上 4 文件两端 md5 一致。
|
||||
|
||||
---
|
||||
|
||||
## 一、为什么改这几处(判据:**用户可见面**,不是"字符串出现即改")
|
||||
|
||||
| 落点 | 是否用户可见 | 处置 |
|
||||
|---|---|---|
|
||||
| `web/i18n.js` 的 `zh` 表 `brand.name` | ✅ 登录 / 注册 / 唤醒 / 工作台页头 | **改** 为 `能力网络` |
|
||||
| `web/i18n.js` 的 `en` 表 `brand.name` | ✅ 其他语言**全靠它回退** | **不动**(仍是 `CapabilityNet`) |
|
||||
| `web/admin.html` 顶栏 `<span class="wordmark">` | ✅ 管理页页头(该页纯中文、未接 i18n) | **改** |
|
||||
| `web/favicon.svg` 的 `<title>` / `aria-label` | ✅ 标签页提示 / 读屏 | **改** —— 只 grep 改 `.html/.js` 会漏掉它(本轮第一版就漏了) |
|
||||
| `web/design.css` 第 53 行注释 | ❌ 不可见,但**写的是现行事实** | 顺手更正(留着会误导下一个人) |
|
||||
| `test/i18n-brand.test.mjs` | — 测试断言 | 六条语言路径的期望值同步 |
|
||||
| 档案 137 / 本档引用的历史记述 | — | **不改历史**(137 保持原样,仅由 TOP 指针指过来) |
|
||||
|
||||
## 二、验证
|
||||
|
||||
| 项 | 结果 |
|
||||
|---|---|
|
||||
| 品牌回归测试 | `test/i18n-brand.test.mjs` **2/2 通过**(中文三条路径 = 能力网络;英文与未支持语言 = CapabilityNet) |
|
||||
| 静态校验 | `verify-static.mjs` 全合格(含 `favicon.svg` 段) |
|
||||
| SVG 真解析 | `xml.etree.ElementTree.parse('web/favicon.svg')` = **OK**(⚠️ 137 那次踩过"注释含 `--` 导致整份 SVG 静默失效",本档只改文本节点,仍逐次复验) |
|
||||
| 旧名残留 | `grep -rn 能力枢纽\|能力领域 web/ test/ scripts/ poc/ src/` ⇒ **仅剩 i18n 注释里一句"此前用过哪个名"的留痕**(有意保留) |
|
||||
| 线上 | 4 文件(`admin.html` / `i18n.js` / `design.css` / `favicon.svg`)本机 ↔ `/opt/dshs/web/` **md5 逐一致**;回滚点 `/opt/dsh/backups/seq138-web-20260919-125345/`(4 个旧文件) |
|
||||
| 零回归 | 全量 `npm test` **226 / 225 pass / 0 fail / 1 skipped** |
|
||||
|
||||
## 三、两个执行细节(都是既有经验的重用,不是新坑)
|
||||
|
||||
1. **行尾按"目标目录既有风格"逐文件对齐**(⛔ 不按 HEAD 判):服务器 `web/` 目录实测
|
||||
`admin.html = CRLF` / `design.css = CRLF` / `i18n.js = LF` / `favicon.svg = LF` ⇒ 推 `admin.html` 前先用
|
||||
脚本转 CRLF 并断言 `CR 数 == 行数`(本机工作树是 LF,直接 scp 会把整文件行尾翻掉)。
|
||||
2. **改 i18n 的"改名类"改动必须配断言**:品牌词条漏配/写错是**静默失败**(中文用户看到英文名),
|
||||
所以 `test/i18n-brand.test.mjs` 用 `node:vm` 跑**仓库里那份真实 `i18n.js`**,断言六条语言解析路径的
|
||||
实际渲染结果 —— 本轮把期望值从「能力枢纽」改为「能力网络」,跑通即证。
|
||||
|
||||
## 四、未做 / 待办
|
||||
|
||||
1. 🔴 **`alotbuy.com` 的旧域页面仍会显示旧名?** 不会 —— 旧域已降级为 301 过渡装置(档案 135),
|
||||
页面由同一份 `/opt/dshs/web/` 直出 ⇒ 旧域访客看到的也是新名。
|
||||
2. ⚠️ **会话页面左上角**(用户实例内的 dsh 会话窗口)不属本仓 `web/`,由官方 `@deepseek-ai/dsh` 的 client bundle
|
||||
渲染、受 **R2** 约束 ⇒ 本档不涉及(与档案 137 的范围声明一致)。
|
||||
3. ⚠️ **词条语义澄清**:用户曾提到「小写 CapabilityNet」;本档按「中文=能力网络/其他语言=CapabilityNet」实现。
|
||||
若原意是"再加一行小写英文",改动量 = `i18n.js` 一处 + `design.css` 一行(⛔ 不碰 HTML)。
|
||||
@@ -44,7 +44,7 @@
|
||||
|
||||
## 二、全量清单
|
||||
|
||||
> **状态摘要**(**机器生成,勿手改**):档案 **121** 份(`04-*`),另含根级编号 5 条(01/02/03/06/07),另有非编号行 14 条(README / INDEX / 技能 / poc 等)—— ✅ 20 | 🔄 5 | 🔍 1 | 📋 23 | 🟡 1 | 未标记 76。复跑 `python3 scripts/docs-index-stats.py` 取数,`--write` 就地刷新本行。
|
||||
> **状态摘要**(**机器生成,勿手改**):档案 **123** 份(`04-*`),另含根级编号 5 条(01/02/03/06/07),另有非编号行 14 条(README / INDEX / 技能 / poc 等)—— ✅ 22 | 🔄 5 | 🔍 1 | 📋 23 | 🟡 1 | 未标记 76。复跑 `python3 scripts/docs-index-stats.py` 取数,`--write` 就地刷新本行。
|
||||
> **分层与机读明细**(路径 / 日期 / 字符数 / 被引次数 / tier,可 `jq` 先筛后读):**`docs-manifest.json`**;复跑 `scripts/docs-manifest.py` 即刷新。
|
||||
> 图例:✅已落地 | 🔄维护中 | 🧪PoC | 📝待开发 | 🔍核查完成 | 📋评估 | 🟡保留兜底 | 🗄归档|🔧修复|🔴|🚧|❓|PoC 实证完成(插件 v0|已上线|生效|已实施|已实施 + API 全链路验|已冻结|已落地 + 验证通过|审计已完成 → 加固项待用户|已上线,页面全部 200|已封板,实施中|核查完成 → 收敛项 H1-|✅ 已实施并在 admin/|🔄 批次 1 因改走 bun|方案 A + handoff|根因已定位并修复(nginx|修复已编译(CI ✅),待重|已实施并上线|已修复并上线(服务已重启|清单建立|✅ 已实施并端到端验证|✅ 已实施并 live 验证|✅ 已实施并视觉验证|🔍 核查完成,P0 待决策|✅ 已实施(commit 见|✅ 已实施(commit `|✅ 已修复(commit `|🔍 取证完成|🔍 核查完成|✅ 已实施(`99de8c5|✅ 已落地|✅ 已修复|已落地并实测验证|已落地并端到端验证|🔄 第一批已修复|✅ 已实施(两批):第一批|✅ 已实施并端到端验证(co|✅ 已实施并验证(服务器已生|admin 侧已实施|✅ 已部署并生效(服务器 `|✅ 已实现、已验证、已部署|✅ 已完成并部署|✅ 全部完成并验证|✅ 已完成(2026-09-|✅ 已止损|✅ 已落地并部署(2026-|✅ 已完成并部署(2026-|✅ 已实现并单点验证|✅ 已落地并实测验证(配置|📋 标准已立|✅ 代码改造 + 组件级验证|✅ 已落地并验证(服务器 `|✅ 已部署并验证(2026-|✅ 已修复并部署|📋 评估中|🚧 执行中(R0 已完成|🚧 代码完成、产物已出|✅ 已完成并上线验证|✅ 已上线并端到端验证(后端|✅ 已修复并验证(源仓 `c|🔄 进行中(L2 机制级已验
|
||||
|
||||
@@ -182,6 +182,8 @@
|
||||
| 04-135 | ✅ | **旧域 `alotbuy.com` 从项目移除**(2026-09-19 落地):代码 / 服务端 / 文档技能三层收敛为 `ai1net.com` 单域;旧域站点**降级为 301 过渡装置**(保留 ACME + `/dshs-relay` + `/dshs-overlay/bootstrap`,**30 天零流量**后退役);relay 候选 **5 → 3**(删掉两条“摘名不同、同落 47”的伪多样性);修 `wake.html` 转义点残留 + 演练脚本硬编码域造成的**假红**;参数表 2 键与 §10 指纹同步 |
|
||||
| 04-136 | 📋 | **控制面按两台中继取并集 —— 立项交接单**(2026-09-19 立项 · **未落地**):平台 web 层只取 47 中继 ⇒ 106 中继不被使用;根因链 7 行(取址路径 `src/web/server.ts` / `rendezvous.ts`)、**先红后绿**强制、候选 A/B 各带优缺点、验收 E1–E8 + 回滚 |
|
||||
| 04-137 | ✅ | **品牌标识改造 —— 去 DeepSeek 图形 → 平台自有标识**(2026-09-19 上线):**四页 + favicon 一并替换** —— `login` / `register` / `admin` 页头删 **DeepSeek 鲸鱼图标 +「DeepSeek」文字图形** 改平台标识(中文「**能力枢纽**」/英语及其他语言「**CapabilityNet**」,走 i18n 词条 `brand.name`,`en` 一条即覆盖其他语言回退);`portal` 顶栏换图标(页面名「管理门户」保留);**新建 `web/favicon.svg`**(平台自有 hub 图标,避开 DeepSeek 蓝);🔴 **会话页面左上角那处不动**(用户明示「先不替换」+它属官方 dsh client bundle,受 R2 约束);🔴 踩坑:**SVG 的 XML 注释不得含 ASCII 双连字符 `--`**(写 CSS 变量名即踩)⇒ 整份 SVG 解析失败、图标**静默不显示**,已加进 `verify-static.mjs` 并做反向自证;新增 `test/i18n-brand.test.mjs`|档案 `04-调整方案/137-品牌标识改造-去DeepSeek图形.md` |
|
||||
| 04-138 | ✅ | **平台共享模型 —— 管理员逐用户授权(默认关闭)**(2026-09-19 上线):新增列 `users.shared_model_granted`(v11,**默认 0**),**生效 = `granted ∧ enabled`** —— 前者 admin 在**用户列表**里逐个开(新增「共享模型」列),后者仍是用户自己的偏好(保留);未授权时设置页**连"平台共享模型"那一块都不渲染**(插件 0.3.24);🔴 **顺带修掉一个既有真缺陷**:落地层原先用**本机 fs** 写用户 home,而用户卷在 worker 上 ⇒ **模型落地对"实例不在本机"的用户一直是静默空操作**(托管清单被清空、目标文件一字节没动;档案 87 的模型设置页对 guest 这类用户从未生效)⇒ 改为走 `UserFs` + worker agent 新增**白名单**端点 `/fs/home-read|write`;两腿实测(未授权撤销 / 授权恢复)|档案 `04-调整方案/138-平台共享模型-管理员逐用户授权.md` |
|
||||
| 04-139 | ✅ | **品牌中文名:能力枢纽 → 能力网络**(2026-09-19 上线):其他语言仍 `CapabilityNet`(en 词条即回退);落点四处 = i18n 中文词条 / `admin.html` 顶栏 / **`favicon.svg` 的 `<title>`+`aria-label`**(最易漏)/ `design.css` 注释;品牌回归测试期望值同步,`verify-static` + SVG 真解析全绿;🔴 行尾按**目标目录既有风格**逐文件对齐(服务器 `admin.html`=CRLF 而本机=LF,直传会翻掉整个文件)|档案 `04-调整方案/139-品牌中文名改为能力网络.md` |
|
||||
| — | 🗄 | `archive/dsh-improvement-plan-20260909-full.md`:拆分前 19 章 |
|
||||
| — | ✅ | `skills/dsh-change-workflow/SKILL.md`:六阶段 + **红线 R1-R11**(工作副本在本机 `.workbuddy/skills/`)|
|
||||
| — | ✅ | `skills/dsh-decision-method/SKILL.md`:**改造决策方法论**(用户有效决策 U1-U12 / AI 有效决策 A1-A13 / 反例 X1-X8 + 确认最优解十问 + 交互 UI 专项清单)(工作副本在本机 `.workbuddy/skills/`)|
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
{
|
||||
"generatedFrom": "scripts/docs-manifest.py",
|
||||
"counts": {
|
||||
"files": 194,
|
||||
"chars": 2050190
|
||||
"files": 196,
|
||||
"chars": 2062355
|
||||
},
|
||||
"tiers": {
|
||||
"hot": 6,
|
||||
"cur": 25,
|
||||
"warm": 61,
|
||||
"cold": 42,
|
||||
"cold": 44,
|
||||
"doc": 60
|
||||
},
|
||||
"domains": {
|
||||
"platform": 75,
|
||||
"platform": 76,
|
||||
"method": 47,
|
||||
"ui": 17,
|
||||
"ui": 18,
|
||||
"plugin": 27,
|
||||
"ops": 16,
|
||||
"?": 8,
|
||||
@@ -22,7 +22,7 @@
|
||||
},
|
||||
"layers": {
|
||||
"L0": 1,
|
||||
"L5": 149,
|
||||
"L5": 151,
|
||||
"L4": 22,
|
||||
"L2": 3,
|
||||
"?": 4,
|
||||
@@ -218,7 +218,7 @@
|
||||
"date": "04-10",
|
||||
"chars": 6261,
|
||||
"lines": 129,
|
||||
"refs": 58,
|
||||
"refs": 60,
|
||||
"refsCurrent": 4,
|
||||
"tier": "hot",
|
||||
"layer": "L5",
|
||||
@@ -713,7 +713,7 @@
|
||||
"date": "04-13",
|
||||
"chars": 2444,
|
||||
"lines": 58,
|
||||
"refs": 9,
|
||||
"refs": 12,
|
||||
"refsCurrent": 0,
|
||||
"tier": "warm",
|
||||
"layer": "L5",
|
||||
@@ -786,8 +786,8 @@
|
||||
"title": "137-品牌标识改造(去 DeepSeek 图形 → 平台自有标识)",
|
||||
"status": "✅",
|
||||
"date": "09-19",
|
||||
"chars": 6287,
|
||||
"lines": 119,
|
||||
"chars": 6401,
|
||||
"lines": 122,
|
||||
"refs": 0,
|
||||
"refsCurrent": 0,
|
||||
"tier": "cold",
|
||||
@@ -795,6 +795,36 @@
|
||||
"domain": "ui",
|
||||
"tldr": ""
|
||||
},
|
||||
{
|
||||
"path": "04-调整方案/138-平台共享模型-管理员逐用户授权.md",
|
||||
"num": "138",
|
||||
"title": "138 · 平台共享模型 —— 管理员**逐用户**授权(默认关闭)",
|
||||
"status": "✅ 已上线并端到端验证(控制",
|
||||
"date": "2026-09-19",
|
||||
"chars": 8578,
|
||||
"lines": 148,
|
||||
"refs": 0,
|
||||
"refsCurrent": 0,
|
||||
"tier": "cold",
|
||||
"layer": "L5",
|
||||
"domain": "platform",
|
||||
"tldr": "① 共享模型从「人人默认可用(用户可自关)」改成「**管理员逐用户授权**」——新增列"
|
||||
},
|
||||
{
|
||||
"path": "04-调整方案/139-品牌中文名改为能力网络.md",
|
||||
"num": "139",
|
||||
"title": "139 · 品牌中文名:能力枢纽 → **能力网络**",
|
||||
"status": "✅ 已上线(静态资源直覆,无",
|
||||
"date": "2026-09-19",
|
||||
"chars": 2666,
|
||||
"lines": 56,
|
||||
"refs": 0,
|
||||
"refsCurrent": 0,
|
||||
"tier": "cold",
|
||||
"layer": "L5",
|
||||
"domain": "ui",
|
||||
"tldr": "中文品牌名 **「能力枢纽」→「能力网络」**;**其他语言不变**(仍 `CapabilityNet`,"
|
||||
},
|
||||
{
|
||||
"path": "04-调整方案/14-实例会话敏感信息暴露面审计与加固.md",
|
||||
"num": "14",
|
||||
@@ -1898,7 +1928,7 @@
|
||||
"date": "2026-09-13",
|
||||
"chars": 14028,
|
||||
"lines": 218,
|
||||
"refs": 14,
|
||||
"refs": 18,
|
||||
"refsCurrent": 0,
|
||||
"tier": "warm",
|
||||
"layer": "L5",
|
||||
@@ -2181,8 +2211,8 @@
|
||||
"title": "dsh 平台文档导航(INDEX)",
|
||||
"status": "?",
|
||||
"date": "",
|
||||
"chars": 24468,
|
||||
"lines": 268,
|
||||
"chars": 25275,
|
||||
"lines": 270,
|
||||
"refs": 0,
|
||||
"refsCurrent": 0,
|
||||
"tier": "doc",
|
||||
|
||||
Reference in new issue
Block a user