Files
dsh_shenxian/dsh-server-docs/04-调整方案/09-普通用户隐藏模型设置-角色化profile-patch.md
T
admin 5ad755116e chore(docs): 文档库并入代码仓(R4 选 a)+ 索引/台账跟进
1) dsh-server-docs/ 从工作区(原 E:\...\aliyun-dsh-server\dsh-server-docs)**整体并入本仓**,
   保留目录名 ⇒ 仓库内 dsh-server-docs/... 的相对引用天然继续有效;旧目录(含其 .git)已归档到
   工作区 _中间产物_待清理/,未随本提交带入。
2) .gitattributes:新增 `dsh-server-docs/** -text` —— 原文档库是 `* -text` + autocrlf=false,
   必须保持纯 LF,否则会被本仓的 CRLF 规则翻掉。
3) 活引用里的绝对路径已全部改到新位置(docs 的 INDEX / README / scripts / skills + 用户级 skills
   + ~/.workbuddy/settings.json 的 hooks);历史档案(04-调整方案/、archive/)按「只增不改」未动。
   ⚠️ hooks 路径改动需「完全重启会话」才生效(配置是会话启动快照)。
4) 交接单/T08:新增 §16「生产整体切换执行记录」(形态 / 落地动作 / **4 个只有真上线才暴露的真 bug** /
   验收证据 / 回滚命令 / 残留项);台账 T08 行 → 已完成并归档;03-路线图 §二 登记 T08 收尾项。
5) 统一称谓:**「本机」只指跑 WorkBuddy 的开发机**,47 / 106 一律写「远程服务器」。
2026-09-15 18:47:13 +08:00

74 lines
5.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 09-普通用户隐藏「模型」设置分区(角色化 profile patch)
> 日期:2026-09-09 | 状态:已落地 | 类型:功能改造(会话 UI 角色裁剪)
> 相关:档案 03(统一 KEY 管理员管控)、档案 05(portal-entry / settings.section 机制)
## 一、需求
普通用户在 dsh 设置面板不应出现「模型」分区(可配置 provider/key 的入口):
1. **管控一致性**:模型 KEY 由管理员统一管控(档案 03)——若普通用户能在自己实例里配 key,可绕过统一 key(用自己的 key);
2. **现状即故障感**:官方 web profile 的模型 provider 目录在此环境不可用(实测「加载提供方目录失败: settings are unavailable in this browser」),普通用户点进去看到报错,体验差;
3. **方案决策**:用户拍板 **B 方案 = 隐藏「模型」设置分区**(admin 保留),比"保留分区+报错"(A)体验好;不选改官方文案(C,触碰官方 client)。
## 二、机制调研(实证)
| 项 | 结论 |
|---|---|
| client 插件装载 | profile bundles(`package.json dsh.profile.bundles`,如 base/web-app)→ 展开为 cordis 树,client 插件行形态 `- id: ui-settings-models\n name: "@deepseek-ai/dsh-client-ui-settings-models"`(**id 是短 id 非包名**,`dsh --profile web --dump-config` 可见) |
| cordis patch disable | dsh-app-boot `applyEntryPatches`:非 insert patch 按 `id` 找到目标行 → overrides(含 `disabled: true`)合入 → 该 client 插件不装载、分区消失。官方 telemetry patch 亦用 `disabled: true`(profile-boot) |
| patch 落点 | **profile 层 `$DSH_HOME/profiles/web/cordis.patch.yml`**(dsh 组合顺序:bundle 层 → 此文件 → --patch overlays)。当前生产实例 spawn 不带 `--patch`(enablePatch=false 且 enter 传 undefined),故 --patch overlay 通道未启用——disable 只能写 profile 层 |
| 生效时机 | **必须重启实例**:client bundle 在实例启动时打包(同 v0.4.3 教训);`patchReload: live` 实测对 client 插件增减**不生效**(改文件后不重启,浏览器设置分区不变,5 次轮询确认) |
| dump 验证命令 | `DSH_HOME=<home> dsh --profile web --dump-config` → `ui-settings-models` 行出现 `disabled: true` 且注释 `# == ... patched by .../cordis.patch.yml` |
## 三、改动点
| 文件 | 内容 |
|---|---|
| `profiles/web/cordis.patch.yml`(普通用户,guest 已写) | 默认 `[]` → 管理标记头 + disable 块(见下) |
| `/opt/dshs/ensure-role-profile-patch.cjs`(**新增**,chmod 600) | 幂等工具:非 admin 用户检查/写入 disable 块;`--restart` 可 kill 实例由 watchdog 拉新。用法:`node ensure-role-profile-patch.cjs [--restart] [username...]`(不带用户名 = 全部非 admin) |
disable 块内容:
```yaml
# dshs role patch: 普通用户隐藏「模型」设置分区
# admin 保留;由 ensure-role-profile-patch.cjs 管理,勿手改
- id: ui-settings-models
name: "@deepseek-ai/dsh-client-ui-settings-models"
disabled: true
```
**admin profile 不动**(保留「模型」分区)。未来其他"角色化 UI 裁剪"沿用同一机制(在 ensure 脚本注册更多 disable 块 / 按 role 扩展)。
## 四、验证记录(guest 实测)
1. guest profile 写 disable 块 → `dsh --dump-config`:`ui-settings-models` 行带 `disabled: true` + patched 注释 ✅
2. 重启 guest 实例(POST /api/dsh/restart,port 37089→45255)→ 浏览器(沙箱外 Chrome + CDP + sid + token URL)设置面板:导航 = 通用设置/插件/Agent 预设(**无「模型」**)✅(截图 `guest-no-models.png`)
3. 还原 `[]` 不重启 → 5 次轮询模型分区不回来 → **live reload 对 client 增减无效**,需重启 ✅(反证生效时机)
4. ensure 脚本:幂等(已管理 → skip);wrote 分支演练(还原 [] → 跑 → 写入 disable 块 + dump 验证合入)✅
5. admin profile 未动(dump 正常,模型分区保留)
## 五、新增普通用户 SOP(模型分区隐藏)
```bash
# 1. 用户注册 → admin approve(role=active)
# 2. 用户首次登录一次(dsh spawn,创建 profiles/web/)后:
node /opt/dshs/ensure-role-profile-patch.cjs --restart <username>
# (--restart:kill 其实例 main,watchdog 拉起带 disable patch 的新实例)
# 或用户此时实例未运行 → 下次 enter spawn 自动读 disable,无需 --restart
```
## 六、后续
- P1「管理类插件化 / 编导工作区模板」落地时,评估把"角色化 profile patch 注入"收编为编排器原生(新用户 spawn 自动带),替代人工跑脚本;
- admin 若后续也不需要「模型」分区(统一 key 走门户 /api/me/keys),同样机制对 admin profile 执行即可。
## 七、回滚
```bash
# 恢复该用户 profile 默认空 patch + 重启实例:
echo '[]' > /var/lib/dshs/users/<id>/home/profiles/web/cordis.patch.yml
# (或先备份:cp cordis.patch.yml cordis.patch.yml.bak-<ts>)
# 重启实例后「模型」分区回归
```