# 47-运行环境管理页(admin 可视化共享运行时与工具)(2026-09-11 落地) ## 背景与动机 用户澄清并提要求:「宿主是指用户吧,用户安装全员共享没问题,但需要给 admin 做个管理页面知道都装了些什么(是否需要升级或卸载)」。 术语更正(重要):**「宿主」= 服务器本身(47.77.182.89),不是某个用户**。安装由平台以 root 执行; 用户侧根本装不进 /usr(只读 + 无 sudo)。所以「共享」= 服务器装一次、全部用户共享, 用户**无法**自行安装或修改。 ## 实现 ### 服务端:GET /api/admin/runtime(admin 只读,档案 47) - 位置:src/web/routes/admin.ts(不新增路由文件,复用已注册的 admin 插件)。 - 数据全部用 shell 取(避免为此新增 import):版本 = 直接执行二进制; 基线 = cat /opt/dsh/state/runtime-baseline.json;清单 = cat SHARED-TOOLS.md; 体积 = du -sk;时间 = stat -c %y。 - 返回:items(名称/分组/类型/版本/来源/安装脚本/可否卸载)、baseline、drift(与基线比对)、 manifest、installScripts、baselineScript、note。 ### 门户:新增 #/runtime「运行环境」页 - 首页「管理」区新增卡片「📦 运行环境 · 共享运行时与工具」。 - 页面内容:漂移告警条(红/绿)、条目表格(名称/版本/来源/安装脚本/可卸载)、 目录+体积+最近变更、**折叠区**「升级 / 卸载 / 迁移怎么做?」与「安装清单原文」。 ### 升级 / 卸载怎么说清 - 升级:改脚本里的固定版本号 → 重跑对应安装脚本(幂等 + 官方 sha256 校验)→ **必须再跑 runtime-baseline.cjs --accept 刷新基线**,否则页面一直提示漂移(与档案 44 的版本冻结配套)。 - 卸载:删 /usr/local/bin/<名字> 软链即可;标注「平台必备」的项请勿删。 - 迁移:整个 /usr/local/dsh-runtime/ 一个打包单元。 ## 验证记录 | 检查 | 结果 | |---|---| | tsc 构建 | 通过(首轮因模板字符串把 RT 当字面量注入而失败,已修) | | 门户静态页 | curl 3080/portal.html 命中「运行环境」3 次、renderRuntime 2 次 | | API(临时 admin 会话,R4 模板,用完即删) | 见下方实测输出 | | 临时会话清理 | 已删(user_agent=poc-runtime-page) | ## 事故 / 踩坑记录 - ⚠️ **生成代码时模板字符串未转义**:补丁脚本用 JS 模板字符串生成 TS,其中的裸 RT 变量被原样写入 TS → tsc 报 TS2304 Cannot find name RT。**教训:用脚本生成代码时,被生成代码里的标识符要显式写成字面量。** - ⚠️ **又在 ssh 单引号里跟引号搏斗**(sed 的 -e 与 URL 斜杠冲突、node -e 里的 \x27 不被解释)→ 连续失败两轮。**再次验证技能 SOP:涉及复杂引号一律「本地写文件 → scp → 远端执行」,不要 inline。** ## 回滚 cp web/portal.html.bak- web/portal.html && cp src/web/routes/admin.ts.bak- src/web/routes/admin.ts && npm run build && systemctl restart dshs