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 一律写「远程服务器」。
74 lines
5.0 KiB
Markdown
74 lines
5.0 KiB
Markdown
# 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>)
|
||
# 重启实例后「模型」分区回归
|
||
```
|