Files
dsh_shenxian/dsh-server-docs/04-调整方案/09-普通用户隐藏模型设置-角色化profile-patch.md
T

73 lines
5.0 KiB
Markdown
Raw Normal View History

# 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>)
# 重启实例后「模型」分区回归
```