1) dsh-server-docs/ 从工作区(原 E:\...\aliyun-dsh-server\dsh-server-docs)**整体并入本仓**,
保留目录名 ⇒ 仓库内 dsh-server-docs/... 的相对引用天然继续有效;旧目录(含其 .git)已归档到
工作区 _中间产物_待清理/,未随本提交带入。
2) .gitattributes:新增 `dsh-server-docs/** -text` —— 原文档库是 `* -text` + autocrlf=false,
必须保持纯 LF,否则会被本仓的 CRLF 规则翻掉。
3) 活引用里的绝对路径已全部改到新位置(docs 的 INDEX / README / scripts / skills + 用户级 skills
+ ~/.workbuddy/settings.json 的 hooks);历史档案(04-调整方案/、archive/)按「只增不改」未动。
⚠️ hooks 路径改动需「完全重启会话」才生效(配置是会话启动快照)。
4) 交接单/T08:新增 §16「生产整体切换执行记录」(形态 / 落地动作 / **4 个只有真上线才暴露的真 bug** /
验收证据 / 回滚命令 / 残留项);台账 T08 行 → 已完成并归档;03-路线图 §二 登记 T08 收尾项。
5) 统一称谓:**「本机」只指跑 WorkBuddy 的开发机**,47 / 106 一律写「远程服务器」。
3.3 KiB
3.3 KiB
24 · 实例侧 401(launch token 过期)浏览器导航自动恢复
- 日期:2026-09-11
- 触发:用户刷新实例子域页面(
admin.alotbuy.com)看到dsh web authentication required; reopen the URL printed by dsh web.,既不自动跳转也不自动重启 - 结论一句话:代理只处理了"门户侧 401"(会话失效),没处理"实例侧 401"(launch token 过期) → 浏览器停在 dsh 的死端页。已修复:实例侧 401 + 浏览器导航 → 用当前实例的最新 token 302 回同一地址(拿不到则回门户)。
- 状态:已实施并上线(服务已重启,
lib/已验证)
一、现象与成因
| 环节 | 事实 |
|---|---|
| 触发场景 | 实例重启后 token 轮换(本次由我 00:14 为验证 picker 重启实例引起;此前 23:32 域名迁移 drain 亦同) |
| 浏览器侧 | 旧标签页 URL 形如 https://admin.alotbuy.com/?token=<旧token>,token 已失效 |
| dsh 侧 | 返回 401 + 文案 dsh web authentication required; reopen the URL printed by dsh web.(HTML) |
| 平台侧 | proxy.ts 的 401 处理只覆盖门户自身判定(resolveSubdomainAccess 的 unauthorized → 302 /login.html);上游(实例)返回的 401 被原样透传 → 用户看到死端页 |
| 为何没重启 | "自动重启"逻辑只在 not_running(404)分支触发;本例实例正在运行,只是 token 过期 |
二、修复(src/supervisor/proxy.ts)
proxyHttp新增参数freshAuthUrl?: () => Promise<string | undefined>;- 上游响应为 401 且是浏览器导航(
GET+accept: text/html)时:upRes.resume()释放上游连接;- 调用
freshAuthUrl()取恢复地址并 302;
- 子域 hook 传入的
freshAuthUrl:app.supervisor.status(userId).main?.launchToken→ 有 token 则https://<同一 Host>/?token=<新token>(原地恢复,无需重新登录),否则回门户根; - 路径式路由
/u/:slug/dsh/同样接入(复用prefix); SubdomainAccess成功分支补充userId(取 token 需要)。
三、验证
| 检查 | 结果 |
|---|---|
bash scripts/ci.sh(typecheck + build + 单测) |
✅ 38 pass / 0 fail |
| 运行产物 | ✅ lib/supervisor/proxy.js 含 freshAuthUrl ×3;lib/supervisor/orchestrator.js 含 symlink ×3(档案 23 的沙箱修复同时生效) |
| 服务重启(drain) | ✅ active / 残留实例 0 / 门户 200 |
| 端到端 | ⏳ 待用户实测:实例重启后刷新旧标签页应自动恢复(302 带新 token) |
四、回滚
- 代码:
/opt/dsh/backups/proxy.ts.bak-<TS>;或git revert d7ab5b4→npm run build→systemctl restart dshs。
五、顺带说明(本次一并上线)
- 档案 23 的沙箱修复同时生效:实例 bwrap 参数补齐
/bin、/sbin、/lib符号链接 → 实例内 bash 工具恢复可用(此前被 dsh 沙箱后端整体拒绝)。 - 本次重启后所有实例已清空,用户下次进入会以新参数启动。
六、红线遵守
- 只改编排器自身代码(
src/supervisor/proxy.ts),未触碰官方 dsh 主程序与缓存;修复走既有的"302 透明恢复"模式(与档案 13 的 not_running 自动重启同源)。