回收 411 MB(470 M → 58.8 M),全部经回收站,可恢复: - 待清理/(146.2 M,含 relay 分片 128 M 与 42 项过程目录) - tmp/(32.4 M,按接续棒命名的过程临时区) - .workbuddy/tmp/(39.5 M) - 4 份 workbuddy.db 冗余副本(101 M,09-23 事故的坏副本 / 抢救产物) - tmp/im16/gw/centrifugo 二进制(63.9 M,可重下)+ 缓存残留 入库范围:常驻规则(CODEBUDDY.md / README.md / state.py)、在途接续入口与 接续包、docs/、交付物/、交接单/、归档/、scripts/、.codebuddy/、 .workbuddy/memory/;共 398 件,其中 >60 KB 的 26 件全为文档。 排除(.gitignore):tmp/、待清理/、运行态日志与缓存、*.db 与 DB 备份整目录、 打包二进制(*.tar.gz / *.tgz)、记忆修复前备份。
7.7 KiB
IM 群组 UI 插件投放 · 线上取证操作单
工作区:
E:\ProgramData\AI技能\aliyun-dsh-server|线:IM 线(第 14 棒)|日期:2026-09-23 20:2x 插件:@dsh-local/im-conversation-tabsv0.1.0(E 单主交付,落点 = 实例内 dsh 会话页 tab) 投放物指纹:tgz sha256c9b1184aca8eadd6c84316d2e79427546a65f59f0614a2ec9704c895a311bfb1(21,494 B) |lib/client.jsmd521fbc52fdedc9915238dd1c3f5c5e827(= 本机源 / 包内 / 47 共享层三处逐字一致)
一、服务端侧已完成(第 14 棒,⛔ 无需再做)
| 步骤 | 结果 | 证据 |
|---|---|---|
打包(tgz,package/ 布局) |
✅ | 包内 4 文件;三件齐(exports['./client'] / dsh.client.platform='web' / dsh.bundle.patch)断言 rc=0 |
| admin 导入候选池 | ✅ http=200 | replaced:false · trustedOverride:false · compat.level=unknown(非 incompatible)· blocked 无 P0 ⇒ 未用信任放行;审计 audit_log id 360 upload_business_plugin |
| 池内可见 | ✅ 4 → 5 条 | GET /api/plugins/business 命中 @dsh-local/im-conversation-tabs v0.1.0 |
发布到共享层(link: 装配前提) |
✅ action:"created" |
目录 /var/lib/dshs/bundled-plugins/_dsh-local_im-conversation-tabs(root:root,全 world-readable);fileRef = link:/var/lib/dshs/bundled-plugins/_dsh-local_im-conversation-tabs;审计 id 361 share_business_plugin |
| 回滚素材 | ✅ | /opt/dsh/backups/plugins/_dsh-local_im-conversation-tabs/0.1.0.tgz |
| 临时 admin 会话 | ✅ 已删 | deleted_sessions=1;临时文件(payload / 响应 / 暂存 tgz)零残留 |
⚠️ 为何必须做「发布到共享层」:装配协议 = link:(2026-09-23 拍板)⇒ profile 里写的是软链依赖,目标即共享层目录。只进候选池不发布,用户点启用会撞 plugin_bundle_missing(friendlyError 把它翻成「该插件尚未发布到共享包库,请先联系管理员完成发布」)⇒ 半成品投放。
二、待用户动作(3 步,约 2 分钟)
步 1 · 在实例内启用
实例 → 设置 → 功能管理 → 找到 @dsh-local/im-conversation-tabs → 打开开关。
- 该插件未声明数据面(
dataPlane.state = none)⇒ 不会被「未建库不许开启」门禁拦。 - 点开后平台自动执行:写 profile(
link:引用)→ pnpm 建链 → 重启实例 + 探活(无需另做重启)。
步 2 · 确认实例真的带上了包(只读,一条命令)
ssh bt-server 'ls -la /var/lib/dshs/users/<你的 uid>/home/profiles/web/node_modules/@dsh-local/ | grep im-conversation-tabs'
期望:一行软链,形如 im-conversation-tabs -> …/bundled-plugins/_dsh-local_im-conversation-tabs;退出码 0。
(uid 查法:ssh bt-server 'ls /var/lib/dshs/users/',目录名 = 你的 userId。)
步 3 · 线上取证(浏览器,见第三节三条)
三、线上取证判据(生效链路第 ④ 关)
🔴 口径更正(本棒实测):IM 链路在服务端一条日志都不写 ——
src/im/ws.ts/src/web/routes/im.ts/src/supervisor/proxy.ts三处process.stderr/console.*零命中;reject()只回一帧error再destroy(),不落日志。⇒ 判据必须在客户端取,⛔journalctl | grep bad-op恒空(空 ≠ 没发生)。
| # | 判据 | 命令 / 操作 | 期望(+退出码) |
|---|---|---|---|
| ① | 会话区被接管,tab 行出现 | 浏览器 DevTools Console:document.querySelectorAll('.imtabs-bar').length |
1 |
| ② | tab 行内容(dsh 会话 + 群组 tab) | document.querySelectorAll('.imtabs-tab').length |
>= 1(首屏 = dsh 会话 tab;开群组 tab 后递增) |
| ③ | 🔴 协议对齐(原 P0 不复现) | DevTools → Network → WS → /api/im/ws → Messages:看帧流水 |
出站只有 {"op":"subscribe"…} / {"op":"ping"} / {"op":"resume"…};入站首帧 {"op":"hello"…};不出现 {"op":"error","error":"bad-op"…} |
| ④ | 连接态健康 | document.querySelector('.imtabs-conn').className |
不含 imtabs-connBad(含 connWarn 视为未通过) |
| ⑤ | 槽位命中(失效时可见) | document.querySelector('.imtabs-alert') |
null(非 null ⇒ 官方槽名又变了,见 .imtabs-alert 提示文案) |
| ⑥ | 房间消息真的渲染 | 在房间里发一条消息 → 群组 tab 内消息流 | 消息出现在列表中(游标补齐走 REST pull + WS resume,两侧按 m.id 去重) |
判定口径:①②③④⑤⑥ 全过 ⇒ E 单「线上可见面」通过,E 单可判「已交付」;任一条不过 ⇒ 本项记「未通过」,把 ③ 的帧流水原文回传(那是定位 P0 类的唯一凭据)。
四、前置条件与两个已知缺口
- 🔴 实例在哪台机决定成败:
- 实例在 47(Manager) ⇒ 共享层已就绪,直接可用 ✅(47 现有实例 =
admin,uid114801)。 ⚠️ 47 上该实例的 bwrap 当前没有--ro-bind-try /var/lib/dshs/bundled-plugins(启动于 09-21 00:55,早于该绑定上线)⇒ 必须让它走一次重启(步 1 的启用动作自带重启,即已满足)。 - 实例在 106(worker) ⇒ 共享层缺该包(106 只有
_dsh-local_storyforge/dsh-plugin-mcn-suite)⇒ 启用会失败。已知缺口:跨节点内容分发无平台侧通路(投放线 §5-2 记为「需单独立项」)。临时办法(手工同步,沿用第 8 棒做法):(第二条会整体覆盖 106 的 manifest ⇒ 执行前先比对两边内容,只差新增那一条才可覆盖。)ssh bt-server 'tar -C /var/lib/dshs/bundled-plugins -czf - _dsh-local_im-conversation-tabs' \ | ssh test106 'tar -C /var/lib/dshs/bundled-plugins -xzf - && chown -R root:root /var/lib/dshs/bundled-plugins/_dsh-local_im-conversation-tabs' ssh bt-server 'cat /var/lib/dshs/bundled-plugins/.manifest.json' | ssh test106 'cat > /var/lib/dshs/bundled-plugins/.manifest.json'
- 实例在 47(Manager) ⇒ 共享层已就绪,直接可用 ✅(47 现有实例 =
- ⚠️ admin 实例 profile 里有一条陈旧软链(
node_modules/@dsh-local/storyforge,09-21 建立,但dependencies/bundles里都已无该项)—— 第 8 棒探针残留。本轮只报告未动(R7)。与本次取证无关。
五、回滚(任一步出问题)
| 目的 | 动作 |
|---|---|
| 只关插件(保留投放) | 实例 → 设置 → 功能管理 → 关掉开关(平台自动 pnpm remove + 重启探活) |
| 撤出用户面(停止发布) | POST /api/plugins/business/share 的逆操作:DELETE /api/plugins/business/:id/share(⛔ 若仍有用户启用会被 409 挡下 —— 这是设计) |
| 彻底下架 | DELETE /api/plugins/business/%40dsh-local%2Fim-conversation-tabs(清池行 + tgz) |
| 换回旧包 | 回滚素材 /opt/dsh/backups/plugins/_dsh-local_im-conversation-tabs/0.1.0.tgz |
六、本单未做 / 未验(⛔ 不假装做了)
- ⛔ 未替用户点启用 —— 「启用」是用户动作(投放语义 = 用户自助开通),本单只把可自动部分做完。
- ⛔ 未做网关部署(选型单 §十五 的 gateway 侧部署)|⛔ 未接在线态取数(
stats().presenceIngest='not-wired')—— 两项与本次投放解耦,排在再后。 - ⛔ 未同步 106 共享层 —— 见 §四-1,属「跨节点内容分发」立项面;本单给出命令但未执行(避免无谓的多机生产改动)。
- ⛔ 未 commit / push / scp 源码 | ⛔ 未改
poc/im-conversation-tabs/**与src/im/**任何一行 | ⛔ 未引新依赖 | ⛔ 未铺 profile。