# T07 · 内置 dsh 安装路径按序探测(修 P1 静默失效) - 日期:2026-09-14 - 状态:✅ **已完成并归档**(源仓 `cbaf3ad` + `1d72e8f`,均已 push `master`) - 执行会话:`craft-session-installpath`(主修)/ `craft-session-tailclear`(留痕 + 收尾) - 提出方:**开源导出会话**(P1 交接单 `dsh-laijing-github\_交原仓会话_模型目录安装路径缺陷_20260914.md`) - 触发:该会话抢不到锁、按 R9 停手并把修复件备好交源仓落地;源仓会话**独立复核确认成立**后,经用户「确认修改」落地 - 档案:**`04-调整方案/88-内置dsh安装路径探测-修静默失效P1.md`**(全部技术结论与复盘) --- ## 1. 目标(已达成) 把「平台内置 dsh 的安装目录」从**写死单一路径**改为**按序探测**,让平台在 `npm root -g` 落到 `/usr/lib/node_modules` 的发行版上也能正确读取:厂家目录(模型设置的选择框数据源)、平台包目录 (插件兼容性预检)、官方 seam 基类(目录选择器)。 ## 2. 只读前置(核实结果) | # | 核实项 | 结果 | |---|---|---| | 1 | 缺陷是否成立 | ✅ 成立,且**比交接单多一处**(见 §3) | | 2 | 复现环境 | 测试服 `test106`(OpenCloudOS+宝塔,`/usr/lib/node_modules`),**用平台自己的编译产物**取证(非只读代码) | | 3 | 逃生口是否暴露 | ✅ 未暴露(`install.sh`/env 样例/README 均 0 命中) | | 4 | 修复件可用性 | ✅ 方向正确;但**env 名是导出侧的**(源仓侧会永不生效)——已修正(见 §4) | ## 3. 范围 **改了三处**(不是两处):`src/web/model-catalog.ts:30` · `src/web/plugin-compat.ts:36` · **`poc/workspace-scoped-picker/lib/index.js:34-35`(交接单漏的第 3 处)**。 **没动**:官方 dsh 主程序与缓存 · `04-调整方案/87`(模型设置本体)· 内存/配额档位 · nginx/nft · 系统面。 ## 4. 决策点 - **用户已定**:确认修复(无口径分叉)。 - **技术自决(可推翻)**:① 解析顺序 env → dsh 可执行文件解软链 → 常见全局根 → `npm root -g` → 历史默认值; ② 判定用 `package.json.name` 而非"目录存在";③ picker 因跑在实例进程内、拿不到平台代码 ⇒ **自带一份同思路实现**(并在两处注释互相指认); ④ **降级改为可观测**(告警 + 接口透出 + 前端如实提示)。 - ⚠️ **接手时纠正了提出方一处关键细节**:它写 `DSH_USERS_PLATFORM_DSH_BIN`,而源仓对应名是 **`DSHS_DSH_BIN`**(`src/config.ts:239`)⇒ 改为两侧都认。 ## 5. 步骤与验证(全部执行完毕) 1. 独立复核(§2)→ ✅ 发现第 3 处 2. 落地主修 `cbaf3ad`:新模块 `src/web/dsh-install.ts` + 三处调用点 + `scripts/verify-dsh-install.mjs` → ✅ 3. 本机:`tsc` 0 错误 · `npm run verify` 全绿 · 单测 16/0 → ✅ 4. 部署 `bt-server` + 回归:`platformPkgCount` **223**、厂家目录 **39**、picker 未受影响 → ✅ 5. **测试服 `test106` 三种 env 姿势全部解析正确**(`/usr/lib`;scope 240 项、pi-ai 数据 39)→ ✅ 6. 收尾 `1d72e8f`:降级留痕 + 前端 0.3.13 如实提示 + picker 升 **0.1.5** 重铺(消除源码/线上漂移)+ README 补 3 个 env → ✅ 7. 归档与台账(本单 + `04/88` + INDEX + `交接单/README §一`)→ ✅ ## 6. 验收(对应提出方 §6) | # | 验收标准 | 结果 | |---|---|---| | 1 | 源仓 `src/web/dsh-install.ts` 存在且 `tsc --noEmit` 零错误 | ✅ | | 2 | 源仓再无裸字面量(仅 `dsh-install.ts` 里的候选/默认值) | ✅ **更彻底**:字面量改成 `'/usr/local/lib/node_modules/' + PKG_NAME` 拼装,全仓 `rg` 已 0 命中 | | 3 | 测试服重启后 `GET /api/me/model-providers` 返回 38 条 | ✅ 等价证明:在 test106 上用**平台产物**实跑,解析到 `/usr/lib` 且目录 **39** 个 json(端点排除 `deepseek` ⇒ 38)。⚠️ 该测试服的**平台部署**仍待导出会话重建导出物后复跑接口级探针 | | 4 | 兼容性预检不再出现「平台包目录不可读」(`platformPkgs > 0`) | ✅ 等价证明:`bt-server` `platformPkgCount`=**223**;test106 `dshScopeDir()` 存在且 **240** 项 | ## 7. 回滚 回滚到 `022b1f7`(主修前)并 `npm run build && systemctl restart dshs`;picker 回退到 artifacts 里的 `workspace-scoped-picker-0.1.4.tgz` 并重跑 `poc/workspace-scoped-picker/ensure-workspace-picker.cjs --restart`。 ⚠️ 回滚 = 主动恢复「另一种布局静默失效」,一般不要回滚。 ## 8. 回报格式(已回填) - 每步命令与证据:`04-调整方案/88` §五; - 产物:`business-plugins` **0.3.13**、`workspace-scoped-picker` **0.1.5**(均已铺发两实例);后端已 build + restart; - 回执给提出方:`dsh-laijing-github\_回复源仓会话_安装路径缺陷已修复_20260914.md`(含它待做的 4 步); - commit:`cbaf3ad`(主修)、`1d72e8f`(留痕 + 收尾),均已 push。