Files
workbuddy_skills/dsh-workflow/references/dsh-change-workflow/00-平台速查.md
T
admin e03465c398 按用户令提交:把此前未纳管的 9 个技能目录一并入库
用户令逐字:「E:/ProgramData/.workbuddy/skills  提交仓库是指的这里」——
即本目录就是仓库(2026-10-07 已在本目录建仓,见当日日志 §22),本轮把余下未纳管的 9 个技能一并提交。

本次入库(9 个技能,46 个文件):
1、`AI HOT`
2、`draw-ui`
3、`dsh-diagnose`
4、`dsh-knowledge`
5、`dsh-local-env`
6、`dsh-opensource-release`
7、`dsh-workflow`
8、`oil-motion`
9、`skills-security-check`

提交前核对:
· **凭据类扫描**(`*.env` / `*token*` / `*.key` / `*secret*` / `*.pem`)⇒ **零命中** ✓;
· 体积合计约 20 MB(`draw-ui` 12M + `oil-motion` 6.5M 是大头,形态为配图/素材 ——
  仓库 `.gitignore` 里明写「`assets/*.png` 是内容不是产物」⇒ 属刻意入库);
· 运行产物仍按既定规则排除(`__pycache__` / `logs/` / `tmp/` / `.venv/` / `*.egg-info` / `uv.lock` / `.workbuddy/`)。
2026-10-08 22:29:08 +08:00

11 KiB
Raw Blame History

平台速查(硬编码事实,勿猜)

归属:技能 dsh-change-workflow 的详情档(按需读,不是每次都要读)。 本档覆盖:平台速查(硬编码事实,勿猜)(原行 L14–L92)。 主文件 / 判据与流程主干 = ../SKILL.md(§1 六阶段流程 · §2 红线 R1–R8 原文速查 · §3 本机 Git Bash 环境坑 · §4 并行调度结论)。 来源:2026-09-22「技能重组线」把 ../SKILL.md 的 L14–L92 段逐行原样下沉到本文件,未改一字。 跨档引用:正文里的「§N / 见 §8 坑 N / 见下表」等编号,用 ../SKILL.md 末节「详情索引」的原章节列定位。 维护:本文件与 ../SKILL.md 的指针行成对;改内容时同时核对主文件的指针描述是否仍准确。


平台速查(硬编码事实,勿猜)

⚠️ 正确域名 = ai1net.com(2026-09-19 由 alotbuy.com 迁入);alotbuy.com 是旧域名、已降为 nginx 301 过渡装置 ——对它抓页面只会拿到 301 HTML,别误判为"改动没生效"(2026-09-11 踩过)。 平台页由门户直出(127.0.0.1:3080),生效副本只有 /opt/dshs/web/ 一份。 存量会话提示(档案 45)落在 web/login.html:告知「shell 频繁要求审批 → 新开一个会话即可」。

⚠️ *.ai1net.com(含每个用户子域)都由同一个 vhost 先 proxy_pass 127.0.0.1:3080(门户), 再由门户的 src/supervisor/proxy.ts 转发到实例 → 想改"子域访问行为"要改 proxy.ts, nginx 的 error_page / location 到不了实例层(档案 49 实测)。 实例空闲回收后首次访问的链路(档案 49):导航(GET+Accept: text/html)→ 立刻 302 到 web/wake.html(门户同源,动画 + 自动调 /api/dsh/enter 跳回);XHR/API → 等实例就绪后 继续转发(不是回错误/动画 —— 让请求最终成功,dsh 自身 loading 即反馈)。

⚠️ 实例的浏览器凭证 cookie 名带随机后缀:dsh-auth-<随机后缀>=v1.<base64>.<sig>(HttpOnly/Secure)。 实例重建后这个后缀会变(不是"过期",是"名字都不对")→ 已打开的页面手里那份对新实例永远无效。 档案 51 的修法在 proxy.ts:非导航请求遇实例侧 401 → 取当前实例 token → GET /?token= 换新 cookie → 覆盖 cookie 头透明重放同一请求 → 响应追加 Set-Cookie 回写浏览器(此后含 SSE 自动重连直接成功)。 重放闸门是 canReplay = mayHaveBody ? bodyBuf !== undefined : true —— GET/HEAD 无请求体,一样要能重放。

⚠️ "空闲回收"实际从未生效(2026-09-11 核实,别再拿它解释现象): ① TTL instanceIdleTtlSeconds 默认 = 7 天(src/config.ts:167 60*60*24*7),线上 env 未设 → 等于不会触发; ② LRU 上限 maxIdleInstances 默认 = 4,只有第 5 个用户拉起实例时才淘汰最久未活跃者(现有 2 用户永远达不到); ③ reapOnce() 只看 lastActive,而 proxy.ts::resolveSubdomainAccess() 每个子域请求都 touch(), dsh 前端还有常驻 SSE /plugins/events → 页面开着就永远"活跃",TTL 规则不可能命中。 历史实证:全历史 grep -c "idle-reap" = 1(09-09 12:24 stop … idle>20s,是档案 08 拿 TTL=20s 做验证那次)。

⛔ 别把"回收没生效"外推成"实例不会中断"(2026-09-11 我犯过这个错,被用户当面纠正)

「页面等一会就模型断开、必须刷新」的真凶是中断,与"空闲回收"是两码事。实测统计:

中断来源 实证 机制
① 门户服务重启(主因) 2026-09-11 一天重启 48 次(全是部署/探活) 重启后 supervisor 内存 mains 表清空 → 旧实例变孤儿(进程还在但不被跟踪)→ 再访问判 not_running → 重新拉起新实例(新端口/token/cookie 名) → 旧页面带旧 cookie → 401。这正是档案 51 的触发源
② 实例崩溃后自动重启 近 4 天 crash-restart 69 次(admin 34 / guest 16 / 测试号 19) admin 根因 = duplicate loader entry id: permission(exitCode 1)——启用与官方 permission 撞 id 的候选插件所致;guest = 信号终止(无 exitCode),紧跟服务重启
③ 空闲回收 全历史 [idle-reap] 仅 1 次(09-09 测试值 20s) 从来没生效,不构成中断来源

必查手法:journalctl -u dshs --since "-1d" | grep -c "Started DSH server login orchestrator"(重启次数)

  • grep -c crash-restart + grep -c idle-reap —— 三个数一比就知道该往哪查。

治本方向(待办):① 部署攒批重启(别每改一处重启一次);② supervisor 启动时收养已存在 scope (本地模式目前无收养逻辑,reconcile.ts 只覆盖 k8s)→ 重启不再产生"新实例 + 401";③ 业务插件探活失败自动摘 bundle。 ⚠️ 配置风险:maxIdleInstances=4 × MemoryMax=1024M(硬限上界) = 4096M 远超 宿主总量 1870MB(上限非预留,但真跑满必然换页)→ 撑不住,建议调 2。

⚠️ dsh web 客户端的会话事件流走 SSE(EventSource),不是 WebSocket(源码 dsh-api-session-controller/lib/types/client/sessions/session.js)。凡"页面内自愈"类注入脚本, 只 hook fetch/XMLHttpRequest 是够不到主链路的 —— EventSource 遇 401 只静默 onerror 重连, 界面什么都不显示(档案 50 因此对真实用户无效,档案 51 才在传输层根治)。 判断前端用什么传输别猜:grep -rl "new WebSocket\|EventSource" <dsh 包>。

⛔ 注入脚本(src/supervisor/proxy.ts 的 SESSION_*_JS)两条铁律 —— 2026-09-13 事故换来的: ① 它是 TS 模板字面量,里面的 \n / ${ / 反引号会在模板求值时先被处理一次。   写 .join('\n')(单反斜杠)⇒ 求值后变裸换行 ⇒ 注入的 JS 直接 SyntaxError ⇒   整段脚本静默不执行(浮层 / 自愈 / 助手面板全废,页面只剩 dsh 自己的「连接异常」)。   → 用 String.fromCharCode(10);校验必须"先模板求值、再 node --check":   node 07-scripts/verify-inject.cjs lib/supervisor/proxy.js(已接入 npm test,勿绕过)。   ⚠️ new Function(原文) 与「grep 页面 HTML 有没有标记」都是假绿 —— 前者跳过求值,后者验不出"跑不跑得起来"。 ② 触发面必须覆盖"页面开着不动":用户盯着页面时无任何事件;现已有 可见时 25 s 心跳   + EventSource / WebSocket 断流包装,且两者都连续两次失败才恢复(恢复=原地 replace,会丢未保存输入)。

🔴 浏览器自动化:唯一允许 browser-harness(⚠️ 2026-09-25 用户明令:「改为 browser-harness,只允许使用这个」   ⇒ 此前「两件(含 agent-browser)」的口径作废): ① browser-harness(CDP)—— 唯一允许的一条:全局 console script browser-harness(~/.local/bin);   ⛔ 动手前必须先 list_tabs();默认起独立 headless 实例(BU_CDP_URL 指向 9223),⛔ 绝不附着用户日常 Chrome   —— 旧事故:在其浏览器里登录测试号 → 覆盖了用户的 .ai1net.com 的 sid。   📂 正确调用(含 2026-09-25 实测路径更正)⇒ 08-浏览器验证栈详解.md。 ⛔ agent-browser 已禁用(2026-09-13 曾定为「本项目默认」,2026-09-25 用户明令收窄 ⇒ 新增此禁); ⛔ 禁止 Playwright / playwright-core(含「独立无头」用法)(用户 2026-09-13 明令:「playwright 禁止使用,加到规则中」)。 静态页与 API 取数优先 curl / WebFetch,别动浏览器。

项 值
服务器 47.77.182.89(Alibaba Cloud Linux al8);SSH:ssh -i ~/.ssh/id_ed25519 -p 22 [email protected](🔴 2026-09-22 实测更正:~/.ssh/config 里的别名 bt-server 写死 Port 32022,而 sshd 只监听 22 ⇒ 用它必 Connection refused;私钥真名 ~/.ssh/id_ed25519,⛔ 技能旧文里的 id_ed25519_dsh 不存在)
门户 dshs(systemd dshs,127.0.0.1:3080);源码 /opt/dshs(git master)
数据 /var/lib/dshs/users/<id>/{home,ws};DB /var/lib/dshs/dshs.db(root 600)
域名 ai1net.com(门户,CF 代理 + 通配证书,源站 443);用户子域 <用户名>.ai1net.com 经 portal proxy 转发实例;旧 alotbuy.com 301 → ai1net.com(档案 22 / 2026-09-19 迁入)
实例 门户 spawn node /usr/local/bin/dsh --profile web --host 127.0.0.1 --port <动态>;ISOLATION account(setpriv,uid∈[100000,199999];admin=114801)
文档 本机 git 工作树 = 唯一源:🔴 D:/github/dsh_shenxian/dsh-server-docs(仓库 dsh_shenxian_doc)→ 同步到服务器 /opt/dsh/docs(无 .git 的部署镜像;08-skills/** 与根 README.md/INDEX.md 均 600 root:root)。⚠️ 2026-09-22 实测更正:旧文写的 E://ProgramData//AI技能//aliyun-dsh-server//dsh-server-docs 该目录不存在(本工作区里只有 docs/,那是会话规则副本);⚠️ 根 README.md/INDEX.md 也在服务器上有一份 ⇒ 登记跟改后要连它们一起推。⛔ 本行 2026-09-13 更正:原文写「服务器唯一源 / 本地不保留副本 / dsh-server-docs/ 已废弃」——那是更早的状态,现已作废
文档同步 改完跑四件套:docs-audit.py → docs-index-stats.py --write(INDEX 状态摘要机器生成)→ docs-manifest.py → docs-sync-check.sh → docs-consistency.py;只 scp 自己本次改的文件、推前复跑对账。⛔ docs-status/ 机制已不存在(原文作废)
硬规则 动文档 / 代码 / 服务器之前先抢全局执行锁(bash dsh-server-docs/07-scripts/handoff-guard.sh --claim-exec "<会话名>");要动生产再占服务器侧 07-scripts/op-lock.sh;同一时刻只放一个执行会话。规则实体在项目根 CODEBUDDY.md(§3 红线 R1–R9 / §6 并发纪律)—— 本技能不复述、也不得与之冲突。⚠️ 释放 op-lock 必须带 ME=<原占用者>,否则按 R9 被拒
档案号 复跑取号,勿写死(`ls 04-调整方案/