feat(keys): 模型密钥开放给用户自配 —— 放开官方「模型」页 + 平台改预置凭据
用户要求「把配置模型密钥开放给用户自己配」且「界面交互和官方一模一样」⇒ 不仿制,直接放开官方 ui-settings-models 页(可选厂家:DeepSeek 内置 + 自定义 OpenAI 兼容网关含 baseURL/模型)。 - ensure-role-profile-patch.cjs:不再对普通用户禁用 ui-settings-models(保留 plugins/inventory/cordis 禁用);--force 时能把「还禁着 models」的旧块升级。 - src/web/server.ts:resolveApiKey 不再注入 DEEPSEEK_API_KEY env,改为把「平台共享密钥」预置进 $DSH_HOME/.credentials.yaml 的 refs 段(新增 ensureRefInCredentials:只在无该 ref 时写 / 只在 version:1 上插入 / 备份落平台目录 / 写完 chown 给实例 uid / 失败退回 env)。真因:dsh 凭据解析里 env 优先级最高,且 dsh-credentials-local.write() 的 assertUnshadowed() 会让用户在模型页保存直接报错 ⇒ 注入 env 等于锁死用户自配。 - src/web/routes/auth.ts:/api/me/keys 由 requireAdmin 放开为 requireAuth(平台侧密钥 API 保留,UI 不再暴露)。 - poc/business-plugins 0.3.4→0.3.8:「系统管理」对齐门户 6 个功能页(同名同构,PA_PAGES 逐函数移植 portal)/ 官方插件列表高度改为「离弹窗底部约 100px」/ 撤掉自造的「我的密钥」分区(改由官方模型页承担)。 - web/portal.html:keys 页语义改名「平台共享密钥(未自配密钥的用户默认使用;仅管理员可改)」。scripts/verify-platform-admin-section.mjs:断言同步升级(含 zh/en 词典键集一致性、内联 HTML class 扫描)。
This commit is contained in:
1 parent
f6d4ad9b15
commit
eb50ca2d5b
7 files changed
+1739
-471
No files matched your search
@@ -2,9 +2,16 @@
|
||||
/**
|
||||
* ensure-role-profile-patch.cjs — 按角色给 dsh profile 注入 cordis patch。
|
||||
*
|
||||
* 背景(2026-09-09):普通用户在设置面板不应看到「模型」分区(模型 KEY 由管理员
|
||||
* 经门户统一管控,档案 03;dsh 官方 web profile 的模型 provider 目录在此环境不可用,
|
||||
* 且避免普通用户误配自用 key 绕过统一 key)。cordis patch 支持对 client 插件行
|
||||
* 背景:
|
||||
* · 2026-09-09:普通用户在设置面板不应看到「模型」分区(模型 KEY 由管理员经门户统一
|
||||
* 管控,档案 03;且避免普通用户误配自用 key 绕过统一 key)。
|
||||
* · **2026-09-13(档案 86):「模型」分区对普通用户放开** —— 用户要求把配置模型密钥
|
||||
* 开放给用户自己配,且「界面交互和官方一模一样」(⇒ 直接用官方页,不仿制)。
|
||||
* 实测:官方页在本环境**可用**(`/api/session/modelCatalog` 返回 200,"provider 目录
|
||||
* 不可用"的旧判断已不成立)。配套改平台注入:用户自配 ⇒ 不注入共享 env
|
||||
* (`src/web/server.ts` `userHasOwnKey()`,否则 env 优先级会静默盖掉用户配的 key)。
|
||||
* 仍禁用:plugins / plugin-inventory / cordis(骨架插件禁任一都可能搞坏实例)。
|
||||
* cordis patch 支持对 client 插件行
|
||||
* `disabled: true`(dsh-app-boot applyEntryPatches:非 insert patch 按 id 合入
|
||||
* overrides)——生效位置 = profile 层 `cordis.patch.yml`(实例启动时打包 client
|
||||
* bundle,改后必须重启实例才生效;patchReload:live 对 client 增减不生效,已实测)。
|
||||
@@ -27,13 +34,14 @@ const MARK = '# dshs role patch'
|
||||
// --force:已由本脚本管理但内容落后(缺新版禁用项)时,整体升级为当前块。
|
||||
const FORCE = process.argv.includes('--force')
|
||||
const DISABLE_MODELS_BLOCK = [
|
||||
'# dshs role patch: 普通用户隐藏模型分区 + 收归核心插件开关(档案 15)',
|
||||
'# dshs role patch: 收归核心插件开关(档案 15)',
|
||||
'# admin 保留;由 ensure-role-profile-patch.cjs 管理,勿手改',
|
||||
'# 148 个 @deepseek-ai 官方插件均为运行骨架,用户禁用任一都可能搞坏实例,',
|
||||
'# 故插件栏 / 插件清单 / cordis 面板只对 admin 开放;ui-skill、ui-permission 保留给用户。',
|
||||
'- id: ui-settings-models',
|
||||
' name: "@deepseek-ai/dsh-client-ui-settings-models"',
|
||||
' disabled: true',
|
||||
'#',
|
||||
'# ⚠️ ui-settings-models **自 2026-09-13 起不再禁用**(档案 86):用户要自助配置模型厂家与',
|
||||
'# key(「界面交互和官方一模一样」)。配套:平台注入策略改为「用户自配则不注入共享 env」,',
|
||||
'# 使模型页配的 key 真能生效 —— 见 src/web/server.ts 的 userHasOwnKey()。',
|
||||
'- id: ui-settings-plugins',
|
||||
' name: "@deepseek-ai/dsh-client-ui-settings-plugins"',
|
||||
' disabled: true',
|
||||
@@ -60,13 +68,17 @@ function ensureUserPatch(user) {
|
||||
return { user: user.username, action: 'NO_PROFILE', detail: 'profile 尚未创建(用户未首登 spawn);请先登录一次再跑' }
|
||||
}
|
||||
const current = readFileSync(patchPath, 'utf8')
|
||||
if (current.includes(MARK)) {
|
||||
if (FORCE && !current.includes('ui-settings-plugins')) {
|
||||
writeFileSync(patchPath, DISABLE_MODELS_BLOCK, 'utf8')
|
||||
return { user: user.username, action: 'upgraded', detail: '已升级为新版禁用块(含核心插件开关收归)' }
|
||||
if (current.includes(MARK)) {
|
||||
// 需要升级的两种旧态:① 缺「插件开关收归」;② **还禁着 ui-settings-models**
|
||||
// (2026-09-13 之前写入的块 —— 那一版把「模型」分区也对用户藏了,现已放开,见档案 86)。
|
||||
const legacy =
|
||||
!current.includes('ui-settings-plugins') || /^-\s*id:\s*ui-settings-models\s*$/m.test(current)
|
||||
if (FORCE && legacy) {
|
||||
writeFileSync(patchPath, DISABLE_MODELS_BLOCK, 'utf8')
|
||||
return { user: user.username, action: 'upgraded', detail: '已升级(放开「模型」分区 + 保留核心插件开关收归)' }
|
||||
}
|
||||
return { user: user.username, action: 'skip', detail: '已由本脚本管理' }
|
||||
}
|
||||
return { user: user.username, action: 'skip', detail: '已由本脚本管理' }
|
||||
}
|
||||
if (!isEmptyPatch(current)) return { user: user.username, action: 'skip', detail: '用户已定制 cordis.patch.yml,不覆盖' }
|
||||
writeFileSync(patchPath, DISABLE_MODELS_BLOCK, 'utf8')
|
||||
return { user: user.username, action: 'wrote', detail: '已写入 disable models patch' }
|
||||
|
||||
Reference in new issue
Block a user