admin
|
3efd68517f
|
chore: 并入已删除会话的在途成果(防丢失;原会话已删,未做功能验收)
**背景**:这些改动原属本工作区另外几个会话(T01/T02 等),**那些会话已被用户删除** ⇒
工作树里的成果处于"无主"状态,一次错误 checkout / 覆盖即**永久丢失** ⇒ 代入库保全。
口径遵循本项目**先例**(`39a1f2e` / `b617cdb`:**别人的活,代入库并在提交信息里注明**)。
**内容**:档案 101「能力管理」改名 + 页内 tab 分页|档案 102 语言切换搬入「用户设置」|
`07-实例UI分区登记表.md`|`scripts/find-ui*.mjs`(UI 元素定位工具)|`poc/portal-entry/`(0.5.3)|
`src/web/locale-pref.ts` + `home-files.ts`(语言偏好持久化)|`test/locale-pref.test.mjs`|
`package.json`|`BRIEF.md` / `INDEX.md` / `docs-manifest.json` / `03-路线图与待办.md` / 档案 100 增量。
**已做最小健全性检查**(⚠️ **未跑完整构建 / 单测** —— 那是原会话的验收职责,本次只求"不丢"):
- JSON 合法:`package.json` / `poc/business-plugins/package.json` / `docs-manifest.json` ✓
- 4 个 TS 文件 `{}`/`()` 配平 ✓;新增文件均非空 ✓
- 规模:13 文件改动 +340/−210,新增 12 条
**未 push**(按 §4 提交边界:用户说"提交",未说"推送")。
|
2026-09-15 21:17:12 +08:00 |
|
admin
|
c70d5d860e
|
feat(cluster): 集群化落地 —— Manager/Worker 拆分 + 归属租约 + 跨机验证(T08)
背景:把平台从「单机单进程」改造成「1 组 Manager + N 台 Worker + 共享归属状态」,
硬约束 = 全程兼容单例模式(deployMode 默认 local;生产切换前 47 一行未动)。
主要改动
1) 数据模型 v7(SQLite 与 PG 两方言同步):新增 dsh_hosts 注册表 +
dsh_instances.{host_id,epoch,heartbeat_at,lease_until};claimInstance 原子抢占
(UPDATE … WHERE host_id IS NULL OR lease_until < now)+ pinInstanceHost 钉住归属。
2) 租约与 fencing:src/supervisor/lease.ts(acquire/renew/release + stillHolder 判据 +
ttl > 2×renew 硬校验);心跳里续租,失权即向 worker 下发更高 epoch(self-fencing)。
⚠️ release 只清租约(lease_until),**保留 host_id** —— host_id 是「用户数据在哪台」的锚点。
3) Worker agent(src/worker/agent.ts,子命令 dshs worker):实例生命周期 + 文件面 /fs/*
+ 幂等键(operationId)+ 鉴权(timingSafeEqual);Worker 不写控制面数据
(apiKey/uid 由 Manager 随 launch 投递,R5 收窄)。
4) 远端 Spawner + LeasedSpawner:按 host 路由(**粘性优先**:有历史归属且那台 up 就留在原地,
否则按容量选最空的)+ 容量准入 + deployMode=cluster 装配(systemd drop-in,可回滚)。
5) bwrap 修正:**所有挂载点的中间目录统一前置 + 去重 + 由外到内**(「就近创建」会在嵌套前缀下
遮掉已绑挂载点 ⇒ bwrap: Can't chdir);且**只能用 --tmpfs**,用 --perms 会让 47 的
bwrap 0.4.0 直接拒启动(沙箱全挂)。
6) 跨机隧道 src/worker/tunnel.ts:SSH ControlMaster + 动态 -R 转发;**自愈由 agent 本地
20s 定时器驱动**(不能只放 /healthz —— 心跳本身经隧道进来,断了就没人触发它)。
7) 文件面按归属路由(RemoteUserFs):实例与文件必须落在同一台机器,否则实例看不到自己的文件。
8) 观测面:dshs doctor / dshs cluster status。
验证(本次均已实跑)
- test/lease.test.mjs:SQLite 10/10 == PG 10/10
- 组件级端到端 5 个:verify-cluster-{agent,lease,fs,migrate,live}.mjs
- 真跨机(47 Manager / 106 Worker,跨云 + 反向隧道)verify-cluster-cross.mjs 九步全绿
- 域名形态访问 verify-cluster-domain.mjs(<user>.域名 → Manager → 远端实例;越权 403)
- 冒烟 scripts/smoke-*:6/8,失败项与改动前基线完全相同(无回归)
- 生产切换与回滚剧本见 dsh-server-docs/交接单/T08-集群化落地-兼容单例模式.md §16
|
2026-09-15 18:47:02 +08:00 |
|
admin
|
29c57a8207
|
feat(web): 模型设置页复刻官方交互 + 官方推荐插件按 dsh 版本过滤(档案 91/92/93)
档案 91 ——「模型设置」页折行 + 复刻官方交互(插件 0.3.15)
· 折行根因不是"窄":原「我已添加的厂家」是 4 列表格(列宽 auto)⇒ 名称/状态/两按钮三处折行同源;
改官方 dsh-client-ui-settings-models 的**卡片行**(rowHead + rowActions margin-left:auto,两侧 nowrap)
· 「新增」改官方**两步式**:默认两个虚线按钮 → 点开才出卡片,主字段只剩「API 密钥」
(官方原文:页面从不询问环境变量名);次要字段收进 <details>「自定义设置」
· CSS 数值逐值照抄官方 CSS 模块;顺修「由 admin 配置」「密钥可留空」两处错文案,补删除二次确认
档案 92 —— 官方推荐插件列表按 dsh 版本过滤(插件 0.3.16)
· 官方目录不带 dsh 版本字段 ⇒ 逐包查 npm 声明与平台真实版本比,分类 match/none/newer/older/unknown
· 默认隐藏「仅兼容更旧版本」,「需更高版本」橙色标注;勾选框为逃生口;说明行给隐藏计数(不静默消失)
· ⚠️ 判 satisfies 必须带 includePrerelease(平台是 prerelease,默认语义会把在跑的 dshmarket 之类判成更旧)
档案 93 —— 兼容判定收口(服务器 CI 由红转绿)
· 「单测长期红」真相 = 服务器源码落后于 git(本机 48/0 全绿)⇒ 同步即修,非代码问题
· 伞包 @deepseek-ai/dsh 收口到 dsh-install.platformPackageVersion()(它不在自己的 node_modules 里,
原先恒判 null ⇒ 声明在伞包上的"要求更高版本"全被放行);闸门与列表共用同一份版本表
· 闸门判据 A 加 prerelease 兜底:实测抽样 300 里 prerelease-artifact 117 条(≈39% 假阳性,
含在跑的 dshmarket)⇒ 容忍下能满足则只计数(prereleaseOnly)不阻断
校验
· 新增 scripts/verify-dsh-compat.mjs(21 条回归锚点)与 verify-models-dict.mjs / verify-models-render.cjs
· verify-platform-admin-section.mjs:断言从旧 UI(表格/下拉「自定义厂家…」)改成断言新 UI
(含模拟点击两个新增入口 + 选中目录厂家)
· 两个仓库外的动作:服务器 npm run build + ci.sh(CI OK)+ systemctl restart dshs;插件 0.3.16 已铺发
⚠️ 本提交未包含 src/supervisor/orchestrator.ts —— 那是别人在途的内存配额改动
(BASE 160→448 / MIN 384→512 / MAX 1024→1536 / mcn 128→256),其对应的客户端常量尚未同步,
本机 verify-mem-model 因此有 4 项红;提交后仓库树两边均为旧值,该断言在 HEAD 上一致。
|
2026-09-14 21:13:32 +08:00 |
|
admin
|
1d72e8f9c8
|
chore(web): 降级留痕 + 收尾 —— 静默失效改为可观测;picker 升 0.1.5 消漂移(档案 88 / T07)
- 【留痕】model-catalog 读不到目录:console.warn(每进程一次)+ 新增 catalogDiagnostics(),并把结果透出到 GET /api/me/model-providers 的 catalog 字段;plugin-compat 的 platformPkgCount()=0 同样告警一次 ⇒「功能没做」与「做了但读不到目录」从此**可区分**(这正是那个 P1 长期潜伏的原因)
- 【前端】插件 0.3.13:厂家目录不可读 / 为空时**如实提示**(含目录路径),不再静默给空列表
- 【消漂移】poc/workspace-scoped-picker 升 0.1.5 并重打包铺发 —— 两实例已装 0.1.5 且含按序探测的新代码(此前只改了源码、线上还是旧候选)
- 【文档】README 补 DSHS_PACKAGE_DIR / DSHS_COMPAT_ROOT / DSHS_PI_AI_DATA_DIR(逃生口此前**未在任何地方暴露**)
- 【回归】verify-dsh-install 扩到 6 组(含「读不到 ≠ 目录为空」的区分);verify-platform-admin-section 加 2 条断言(词典 284/284)
- 真环境回归:picker 在 /usr/local 仍 import OK(没把本来能用的改坏)|providers 39(端点回 38)|platformPkgCount 223
|
2026-09-14 04:52:35 +08:00 |
|
admin
|
022b1f770c
|
feat(models): 「模型设置」接官方厂家目录 + 按官方页结构重做界面(档案 87 补做)
用户实测反馈:新增条目看不懂、厂家选择太少且国内一家都没有。根因是**第一版只做了手填表单**,没接官方 pi-ai 自带目录(实测 38 家,国内 11 家:蚂蚁 / 通义千问 / 小米 / 月之暗面 / 智谱 / MiniMax)。
- 新文件 src/web/model-catalog.ts:只读官方 data/*.json(10 分钟缓存,不导入 pi-ai 运行时);中文名走显示用静态表,选取范围以目录为准
- 新增 GET /api/me/model-providers(38 家 + cn 分组 + modelCount + 模型名;排除 deepseek —— 平台已有内置入口)
- POST /api/me/keys 新增 provider 参数:**目录厂家只需 API 密钥**(端点/协议/模型全由官方目录兜底 —— 官方 config.d.ts 明示 route 命中即继承默认)
- refForEntry 判据由「baseUrl 为空」改为「**没有 route**」:否则目录厂家的 key 会被写进 DEEPSEEK_API_KEY
- SettingsEntry 的 baseURL/api/models 改为可选:目录厂家只写 apiKeyEnv(写得越少越不容易漂)
- 前端按官方页结构重写:提供方行(厂家/说明/状态/操作)+ 新增**先选厂家**(中国大陆 / 国际分组 / 自定义)+ 保留并强化 admin 的「平台共享模型」区块
- 真环境验收:目录端点 38 家 / 国内 11 家;加 moonshotai-cn 只给 key → settings.yaml 仅 apiKeyEnv;删后整块消失
|
2026-09-14 00:15:17 +08:00 |
|
admin
|
918f1d3a51
|
feat(models): 平台自建「模型设置」—— 用户自配厂家 / 条目各自开关 / 共享模型开关(档案 87)
- 官方「设置 → 模型」页在平台环境**必然报错**(判据在**浏览器页面**的 loopback 判定;官方 README 原文 Non-loopback pages get no durable settings)⇒ 该分区对全角色(含 admin)隐藏,用户自配改走平台自建页(插件 0.3.11)
- DB 迁移 V6:credential_vault.route/base_url/api/models + users.shared_model_enabled;并**重定义 getEnabledCredentialKeyRef**(互斥删除后原实现无 ORDER BY ⇒ 「任取一条」)
- 新落地层 src/web/model-landing.ts:spawn 时把「已启用条目」写进实例 .credentials.yaml 与 settings.yaml 的 llm-pi-ai.providers.<route>;字段名与官方包实测对齐(apiKeyEnv / baseURL / api,**不是** protocol);只碰自己写过的 + 一次性交接
- 接口 /api/me/keys、/api/me/keys/:id/toggle、/api/me/models/shared;前端新增「设置 → 模型设置」分区(settings.section id=model-settings / order 100 / 全角色)
- 顺手修两处:ensure-role-profile-patch.cjs 的 --force 整文件覆盖会抹掉 admin 的 disable-hmr 与 workspace-scoped-picker 两个平台块(改为 stripManagedBlock 只替换自己那段);verify-mem-model.mjs 因档案 86 重构而长期失败的陈旧断言
⚠️ 本提交同时包含**档案 86(admin 跨用户实例管理 + 两处改名)**的代码改动 —— 该部分已上线并端到端验证;其 import/register 与本次改动同处 src/web/server.ts、poc/business-plugins/lib/client.js 等文件,按**文件粒度无法拆分**,且不带它会让仓库 tsc 直接失败(缺 src/web/routes/admin-user-ops.ts)。
|
2026-09-14 00:00:15 +08:00 |
|
admin
|
eb50ca2d5b
|
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 扫描)。
|
2026-09-13 22:27:49 +08:00 |
|
admin
|
f6d4ad9b15
|
fix(mem): 统一实例内存配额口径 + status 暴露真值(消灭「388 MiB」误报)
用户问「实例内存大小是不是调整过了,为什么功能设置中还是显示 388 多」。
实测:guest 真实 MemoryMax = 672 MiB、admin = 384 MiB(都真调整过);
而「功能管理」显示的是插件**自建的第二套模型**(基线 285 / univer 64 / mcn 39,
且把 clamp 下限 384 当硬上限)⇒ 全勾显示 388 并报「⚠ 将超出上限」,纯误报。
根因:档案 81 R1 把「写死 384」改为「按插件集合推导」时**只改了编排器**,
插件那份副本原地漂移,此后 univer 384→512、mcn-suite 128 都没同步。
平台侧(把已算好的真值透出来,零新增计算):
- spawner.ts 新增可选 quotaInfo?(userId)(照 breakerInfo 模式)
- orchestrator.ts 实现 quotaInfo(),走**同一个** instanceMemMb()/heapMbFor()
- /api/dsh/status 返回 quota: {memMb, heapMb}
防漂(根因是「同一事实两处副本」,必须让它不可能再漂):
- 新增 scripts/verify-mem-model.mjs,逐项交叉断言常量/成本表/clamp 算式/接线点,
接进 npm run verify —— 任一处漂移即构建失败(已做反向验证:改回 285 即 exit 1)
验证:build 零报错;verify 全绿(含新增 15 项断言);服务端 md5 与本机编译产物一致;
GET /api/dsh/status → quota {memMb:384,heapMb:256} 与实测 402653184 吻合。
注:poc/business-plugins/**(0.3.6)与其 package.json 未在此提交 —— 该文件被并行会话
连续改过两轮(0.3.4/0.3.5,0.3.5 已上线但未 commit),刻意留给他们一起提交。
|
2026-09-13 21:38:04 +08:00 |
|
admin
|
f25723b743
|
feat(R2)+refactor: 平台管理分区 + 删 3 桩页(档案80 #7)+ 无浏览器验收脚本
- R2:business-plugins 0.2.9 新增原生「平台管理」只读分区(已铺发到 admin/guest profile 并生效)
- 档案80 #7:删 web/{desktop,plugins,skills}.html(9→6 页)+ 5 处引用改直达 portal(nginx 已加 301)
- 新增 scripts/verify-platform-admin-section.mjs(打桩 react/jsx-runtime 真执行 client.js 做渲染断言)并接入 npm run verify
|
2026-09-13 19:27:30 +08:00 |
|
admin
|
43976fea6a
|
初始提交:DSH 多租户平台(dshs)
|
2026-09-13 16:18:10 +08:00 |
|