Files
dsh_shenxian/dsh-server-docs/04-调整方案/82-R2管理面就地化-原生平台管理分区.md
T
admin 5ad755116e chore(docs): 文档库并入代码仓(R4 选 a)+ 索引/台账跟进
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 一律写「远程服务器」。
2026-09-15 18:47:13 +08:00

146 KiB
Raw Blame History

82 · R2 管理面就地化(原生「平台管理」分区)

  • 日期:2026-09-13
  • 状态:🚧 代码完成、产物已出;待投放 + 启用 + 浏览器验收
  • 触发:档案 81 §四 R2(原「实例内弹窗 iframe」);形态经用户 2026-09-13 拍板改为原生弹窗(§9.2b)
  • 原则:只读优先(写操作回跳平台域);不改官方 dsh;不把门户 UI 复制进插件

TL;DR|① R2 的 R5 权限影响评估已在档案 81 §9.2 出齐并获批(扩大点=实例内出现可操作的管理入口 ⇒ 仅 admin 可见 + 只读 + 写操作回跳); ② 本轮把「平台管理」分区写进 @dsh-local/business-plugins 插件(原生渲染,非 iframe)—— 数据直接调平台只读 API; ③ 产物 dsh-local-business-plugins-0.2.9.tgz 已出(node --check 通过、包结构合规); ④ 未做:投放候选池 / 实例启用 / 浏览器验收(卡在需要 admin 登录态,见 §五);/admin 路由族 + 删 3 桩页 亦未做。


一、形态(与档案 81 §9.2b 一致)

维度 取值
渲染 原生渲染(复用插件自有 token --dsw-* + 06-工作台UI规范 字号阶梯),非 iframe
数据 直接调平台只读 API(跨子域 fetch + credentials: "include",门户 CORS 白名单已就绪)
范围 只读子集:实例 / 熔断 / 用户 / 存储 / 候选池 / 运行时
写操作 一律回跳平台管理台(portalHost() + "/portal.html")—— 不复制门户写 UI(否则双源维护 + 与档案 39「收窄执行面」相冲)
可见性 仅 admin:先 GET /api/auth/me 判 role === "admin",否则只渲染一行说明
落点 poc/business-plugins/lib/client.js(设置面板 settings.section,id: platform-admin, order: 102)

二、改了哪些文件

文件 改动
poc/business-plugins/lib/client.js 895 → 1083 行:① zh/en 词典各 +29 个 pa.* 键;② 新增 PaCard(指标卡)+ PlatformAdminSection;③ 新增一个 settings.section 注册(platform-admin)
poc/business-plugins/package.json 版本 0.2.8 → 0.2.9
产物 dsh-local-business-plugins-0.2.9.tgz(16,712 B;顶层仅 package/;无 .tgz/node_modules/.bak)

三、数据来源(均为平台既有路由,零新增后端)

卡片 API 权限
角色门禁 GET /api/auth/me requireAuth
当前实例 / 熔断 GET /api/dsh/status requireAuth
用户 GET /api/admin/users requireAdmin
存储 GET /api/admin/storage requireAdmin
候选池 GET /api/plugins/business requireAdmin
运行时 GET /api/admin/runtime requireAdmin

全部只读;任一失败降级为 null 并照常渲染其余卡片(不整页报错)。

四、已验证 / 未验证

项 状态 证据
语法 ✅ node --check lib/client.js 通过
包结构 ✅ 顶层仅 package/;4 条目;无违规文件;lib/client.js 在内
词条键集 ✅ zh/en 各 +29 键,键名一一对应
渲染 / 交互 / 权限门禁 ⏸ 未验证 需投放 + 启用(见 §五)

五、⛔ 未完成:投放与验收需要 admin 登录态

  • 投放走 POST /api/plugins/business(requireAdmin)⇒ 必须有 admin 的会话。
  • 平台 CLI 只有 start / bootstrap-admin / file-service,无投放命令;文档内无测试口令 ⇒ 执行会话拿不到凭据。
  • 三条可选路径(待用户定):① 用户自己在门户投放(2 分钟);② 给 admin 口令;③ 用 bootstrap-admin 建临时 admin,用完删(会动生产 auth)。

六、R2 剩余(本次未做,属同期的另一半)

  1. /admin 路由族 + 删 3 个跳转桩页(web/desktop.html / plugins.html / skills.html,各 247–265 B,title=跳转中…)—— 档案 81 §四表格口径;⚠️ 删桩页必须同时加 301 到 /admin(否则既有书签断)。删后静态页 9 → 6,需同步改 scripts/verify-static.mjs 的页数断言。
  2. 注入层 CSS 类统一为 .dshs-*(档案 81 §四:.__dsh-* / .wk-* → .dshs-*)。

七、回滚

  • 插件侧:把候选池里的 business-plugins 回落 0.2.8(旧 tgz 若已删,可从本机 git 历史取 lib/client.js 重建)。
  • 本轮改动全部在 poc/business-plugins/,未动 src/、未动官方 dsh、未动服务器 ⇒ 回滚只需还原该目录 + 重新投放。

八、口径提醒

⚠️ 不能两头都要(档案 81 §9.2b):若日后要求「弹窗里能完成全部管理动作」,那就等于把整个门户重写进插件(双源维护 + 扩大执行面)⇒ 届时应把门户收敛成 API 客户端,而不是继续复制 UI。# 82 · R2 管理面就地化(原生「平台管理」分区)

  • 日期:2026-09-13
  • 状态:🚧 代码完成、产物已出;待投放 + 启用 + 浏览器验收
  • 触发:档案 81 §四 R2(原「实例内弹窗 iframe」);形态经用户 2026-09-13 拍板改为原生弹窗(§9.2b)
  • 原则:只读优先(写操作回跳平台域);不改官方 dsh;不把门户 UI 复制进插件

TL;DR|① R2 的 R5 权限影响评估已在档案 81 §9.2 出齐并获批(扩大点=实例内出现可操作的管理入口 ⇒ 仅 admin 可见 + 只读 + 写操作回跳); ② 本轮把「平台管理」分区写进 @dsh-local/business-plugins 插件(原生渲染,非 iframe)—— 数据直接调平台只读 API; ③ 产物 dsh-local-business-plugins-0.2.9.tgz 已出(node --check 通过、包结构合规); ④ 未做:投放候选池 / 实例启用 / 浏览器验收(卡在需要 admin 登录态,见 §五);/admin 路由族 + 删 3 桩页 亦未做。


一、形态(与档案 81 §9.2b 一致)

维度 取值
渲染 原生渲染(复用插件自有 token --dsw-* + 06-工作台UI规范 字号阶梯),非 iframe
数据 直接调平台只读 API(跨子域 fetch + credentials: "include",门户 CORS 白名单已就绪)
范围 只读子集:实例 / 熔断 / 用户 / 存储 / 候选池 / 运行时
写操作 一律回跳平台管理台(portalHost() + "/portal.html")—— 不复制门户写 UI(否则双源维护 + 与档案 39「收窄执行面」相冲)
可见性 仅 admin:先 GET /api/auth/me 判 role === "admin",否则只渲染一行说明
落点 poc/business-plugins/lib/client.js(设置面板 settings.section,id: platform-admin, order: 102)

二、改了哪些文件

文件 改动
poc/business-plugins/lib/client.js 895 → 1083 行:① zh/en 词典各 +29 个 pa.* 键;② 新增 PaCard(指标卡)+ PlatformAdminSection;③ 新增一个 settings.section 注册(platform-admin)
poc/business-plugins/package.json 版本 0.2.8 → 0.2.9
产物 dsh-local-business-plugins-0.2.9.tgz(16,712 B;顶层仅 package/;无 .tgz/node_modules/.bak)

三、数据来源(均为平台既有路由,零新增后端)

卡片 API 权限
角色门禁 GET /api/auth/me requireAuth
当前实例 / 熔断 GET /api/dsh/status requireAuth
用户 GET /api/admin/users requireAdmin
存储 GET /api/admin/storage requireAdmin
候选池 GET /api/plugins/business requireAdmin
运行时 GET /api/admin/runtime requireAdmin

全部只读;任一失败降级为 null 并照常渲染其余卡片(不整页报错)。

四、已验证 / 未验证

项 状态 证据
语法 ✅ node --check lib/client.js 通过
包结构 ✅ 顶层仅 package/;4 条目;无违规文件;lib/client.js 在内
词条键集 ✅ zh/en 各 +29 键,键名一一对应
渲染 / 交互 / 权限门禁 ⏸ 未验证 需投放 + 启用(见 §五)

五、⛔ 未完成:投放与验收需要 admin 登录态

  • 投放走 POST /api/plugins/business(requireAdmin)⇒ 必须有 admin 的会话。
  • 平台 CLI 只有 start / bootstrap-admin / file-service,无投放命令;文档内无测试口令 ⇒ 执行会话拿不到凭据。
  • 三条可选路径(待用户定):① 用户自己在门户投放(2 分钟);② 给 admin 口令;③ 用 bootstrap-admin 建临时 admin,用完删(会动生产 auth)。

六、R2 剩余(本次未做,属同期的另一半)

  1. /admin 路由族 + 删 3 个跳转桩页(web/desktop.html / plugins.html / skills.html,各 247–265 B,title=跳转中…)—— 档案 81 §四表格口径;⚠️ 删桩页必须同时加 301 到 /admin(否则既有书签断)。删后静态页 9 → 6,需同步改 scripts/verify-static.mjs 的页数断言。
  2. 注入层 CSS 类统一为 .dshs-*(档案 81 §四:.__dsh-* / .wk-* → .dshs-*)。

七、回滚

  • 插件侧:把候选池里的 business-plugins 回落 0.2.8(旧 tgz 若已删,可从本机 git 历史取 lib/client.js 重建)。
  • 本轮改动全部在 poc/business-plugins/,未动 src/、未动官方 dsh、未动服务器 ⇒ 回滚只需还原该目录 + 重新投放。

八、口径提醒

⚠️ 不能两头都要(档案 81 §9.2b):若日后要求「弹窗里能完成全部管理动作」,那就等于把整个门户重写进插件(双源维护 + 扩大执行面)⇒ 届时应把门户收敛成 API 客户端,而不是继续复制 UI。


九、追加(2026-09-13 18:1x–19:2x):部署完成 + 无浏览器渲染验收通过 + 一并做掉档案 80 第 7 项

9.1 部署链路(关键:不走候选池)

@dsh-local/business-plugins 不是池内插件 —— 它由 scripts/ensure-biz-plugins.cjs 铺发:从 /opt/dsh/artifacts/ 取版本号最大的 business-plugins-*.tgz(--all 含 admin;--restart 让 bundle 生效)。

步 结果
投放产物 business-plugins-0.2.9.tgz → /opt/dsh/artifacts/(前一版为 0.2.8)
铺发 node scripts/ensure-biz-plugins.cjs --all --restart ⇒ admin 与 guest 的 profile 均 0.2.8 → 0.2.9、bundles 均含该包 ✓
磁盘层断言 两实例 node_modules/@dsh-local/business-plugins/lib/client.js 含「平台管理」× 5 ✓
实例 两实例均已重启并 running;实例页 HTTP 200 ✓

9.2 渲染验收:改用无浏览器 harness(因 agent-browser daemon 起不来)

  • ⚠️ 本机 [email protected] 的 daemon 起不来:open 挂住且零输出(--version / node -e 均正常;~/.agent-browser 里留下的 default.port 实测不通、清掉僵尸状态后仍不通)。Chrome 153 已由 agent-browser install 装好,但 daemon 不通 ⇒ 浏览器截图验收受阻(属环境问题,未解)。
  • ⚠️ 06-工作台UI规范 §7.3 的三段式在按需动态加载的 bundle 上拿不到带 rev 的完整 URL(该 bundle 不出现在实例首页 HTML 里)⇒ ②③ 段也不适用。
  • ✅ 替代做法(已沉淀为可复跑脚本):scripts/verify-platform-admin-section.mjs —— 打桩 react / react/jsx-runtime + 最小 hooks 渲染循环 + 真执行 client.js,直接断言结构与门禁。
✓ 注册了两个 settings.section  -> business-plugins, platform-admin
✓ 存在 platform-admin 分区    ✓ 其 order = 102
✓ admin:含分区标题「平台管理」  ✓ admin:6 张卡齐全  ✓ admin:含只读声明
✓ 非 admin:被门禁挡住         ✓ 非 admin:不出现任何指标卡
结论:全绿 ✅   exit=0

admin 视角实际渲染文本(实测):

平台管理 | 只读 | 本分区为只读;写操作请在平台管理台完成。 当前实例 | 运行中 | 端口 43095 · 自动重启 2 | 熔断 | 正常 | — 用户 | 4 | 待审核 1 · 已禁用 1 | 存储 | 2 | 报告每小时刷新 候选池 | 3 | 已投放插件 | 运行时 | 5 | 条目 | 打开完整管理台

已接入 npm run verify(&& node scripts/verify-platform-admin-section.mjs)⇒ 今后 UI 改动可 CI 式防回归。

9.3 一并做掉:档案 80 第 7 项 / 档案 81 §四「删 3 个跳转桩页」

  • 删 web/{desktop,plugins,skills}.html ⇒ 静态页 9 → 6 ✓;改 5 处引用(admin.html / index.html / login.html×2 / dsh.ts 注释)。verify-static.mjs 是自动发现页面的,无需改。
  • nginx alotbuy.com.conf 两个 server 块各加 3 条精确匹配 301 ⇒ 实测 /desktop.html→301 /portal.html、/plugins.html→#/plugins、/skills.html→#/skills ✓;login.html 仍 200 ✓。
  • ⚠️ 本机 nginx 由宝塔托管:systemctl reload nginx 失效,须用 nginx -s reload。

9.4 🔴 期间修掉一个由本次改名引入的真回归(如实记录)

  • 症状:admin 实例页 502,journal = plugin tree failed to load … corrupt session log。
  • 根因:会话日志是 session.jsonl.zstd(zstd 压缩)。改名只改了目录名与纯文本文件,压缩流 header 里的 cwd 仍是旧路径 ⇒ dsh 启动做一致性校验(header cwd vs 目录推导 cwd)不匹配 ⇒ 抛错 ⇒ 插件树加载失败 ⇒ 崩溃循环。
  • 修复:_fix_sesslog.cjs(node 内置 zlib.zstdDecompressSync/zstdCompressSync,22.15+)—— 解压 → 替换 → 重压 → 回读校验。26 个文件 24 个待修 → 全修完,复查 0 残留 ✓;实例恢复 200,corrupt session log 归零。
  • 📌 教训:压缩文件里的路径 grep/sed 够不到 —— 与「SQLite 改名必须带 -wal/-shm」同类。已写进项目 MEMORY.md 铁律。

9.5 期间发现的两个平台缺陷(待修)

  1. op-lock 不可用:锁根 /opt/dsh/state/.op-lock 不存在,且 scripts/op-lock.sh 自身解析 bt-server 失败 ⇒ 它报「已存在 → 停手」是假警报,无法用于互斥。
  2. agent-browser daemon 起不来(见 §9.2)—— 浏览器验收链路的唯一可用工具受阻。

9.6 尚未做

  • D / J / Q(T03 遗留)与登录/注册/门户/设置面板的体验审计(用户 18:1x 关注的第三块)。

82 · R2 管理面就地化(原生「平台管理」分区)

  • 日期:2026-09-13
  • 状态:🚧 代码完成、产物已出;待投放 + 启用 + 浏览器验收
  • 触发:档案 81 §四 R2(原「实例内弹窗 iframe」);形态经用户 2026-09-13 拍板改为原生弹窗(§9.2b)
  • 原则:只读优先(写操作回跳平台域);不改官方 dsh;不把门户 UI 复制进插件

TL;DR|① R2 的 R5 权限影响评估已在档案 81 §9.2 出齐并获批(扩大点=实例内出现可操作的管理入口 ⇒ 仅 admin 可见 + 只读 + 写操作回跳); ② 本轮把「平台管理」分区写进 @dsh-local/business-plugins 插件(原生渲染,非 iframe)—— 数据直接调平台只读 API; ③ 产物 dsh-local-business-plugins-0.2.9.tgz 已出(node --check 通过、包结构合规); ④ 未做:投放候选池 / 实例启用 / 浏览器验收(卡在需要 admin 登录态,见 §五);/admin 路由族 + 删 3 桩页 亦未做。


一、形态(与档案 81 §9.2b 一致)

维度 取值
渲染 原生渲染(复用插件自有 token --dsw-* + 06-工作台UI规范 字号阶梯),非 iframe
数据 直接调平台只读 API(跨子域 fetch + credentials: "include",门户 CORS 白名单已就绪)
范围 只读子集:实例 / 熔断 / 用户 / 存储 / 候选池 / 运行时
写操作 一律回跳平台管理台(portalHost() + "/portal.html")—— 不复制门户写 UI(否则双源维护 + 与档案 39「收窄执行面」相冲)
可见性 仅 admin:先 GET /api/auth/me 判 role === "admin",否则只渲染一行说明
落点 poc/business-plugins/lib/client.js(设置面板 settings.section,id: platform-admin, order: 102)

二、改了哪些文件

文件 改动
poc/business-plugins/lib/client.js 895 → 1083 行:① zh/en 词典各 +29 个 pa.* 键;② 新增 PaCard(指标卡)+ PlatformAdminSection;③ 新增一个 settings.section 注册(platform-admin)
poc/business-plugins/package.json 版本 0.2.8 → 0.2.9
产物 dsh-local-business-plugins-0.2.9.tgz(16,712 B;顶层仅 package/;无 .tgz/node_modules/.bak)

三、数据来源(均为平台既有路由,零新增后端)

卡片 API 权限
角色门禁 GET /api/auth/me requireAuth
当前实例 / 熔断 GET /api/dsh/status requireAuth
用户 GET /api/admin/users requireAdmin
存储 GET /api/admin/storage requireAdmin
候选池 GET /api/plugins/business requireAdmin
运行时 GET /api/admin/runtime requireAdmin

全部只读;任一失败降级为 null 并照常渲染其余卡片(不整页报错)。

四、已验证 / 未验证

项 状态 证据
语法 ✅ node --check lib/client.js 通过
包结构 ✅ 顶层仅 package/;4 条目;无违规文件;lib/client.js 在内
词条键集 ✅ zh/en 各 +29 键,键名一一对应
渲染 / 交互 / 权限门禁 ⏸ 未验证 需投放 + 启用(见 §五)

五、⛔ 未完成:投放与验收需要 admin 登录态

  • 投放走 POST /api/plugins/business(requireAdmin)⇒ 必须有 admin 的会话。
  • 平台 CLI 只有 start / bootstrap-admin / file-service,无投放命令;文档内无测试口令 ⇒ 执行会话拿不到凭据。
  • 三条可选路径(待用户定):① 用户自己在门户投放(2 分钟);② 给 admin 口令;③ 用 bootstrap-admin 建临时 admin,用完删(会动生产 auth)。

六、R2 剩余(本次未做,属同期的另一半)

  1. /admin 路由族 + 删 3 个跳转桩页(web/desktop.html / plugins.html / skills.html,各 247–265 B,title=跳转中…)—— 档案 81 §四表格口径;⚠️ 删桩页必须同时加 301 到 /admin(否则既有书签断)。删后静态页 9 → 6,需同步改 scripts/verify-static.mjs 的页数断言。
  2. 注入层 CSS 类统一为 .dshs-*(档案 81 §四:.__dsh-* / .wk-* → .dshs-*)。

七、回滚

  • 插件侧:把候选池里的 business-plugins 回落 0.2.8(旧 tgz 若已删,可从本机 git 历史取 lib/client.js 重建)。
  • 本轮改动全部在 poc/business-plugins/,未动 src/、未动官方 dsh、未动服务器 ⇒ 回滚只需还原该目录 + 重新投放。

八、口径提醒

⚠️ 不能两头都要(档案 81 §9.2b):若日后要求「弹窗里能完成全部管理动作」,那就等于把整个门户重写进插件(双源维护 + 扩大执行面)⇒ 届时应把门户收敛成 API 客户端,而不是继续复制 UI。# 82 · R2 管理面就地化(原生「平台管理」分区)

  • 日期:2026-09-13
  • 状态:🚧 代码完成、产物已出;待投放 + 启用 + 浏览器验收
  • 触发:档案 81 §四 R2(原「实例内弹窗 iframe」);形态经用户 2026-09-13 拍板改为原生弹窗(§9.2b)
  • 原则:只读优先(写操作回跳平台域);不改官方 dsh;不把门户 UI 复制进插件

TL;DR|① R2 的 R5 权限影响评估已在档案 81 §9.2 出齐并获批(扩大点=实例内出现可操作的管理入口 ⇒ 仅 admin 可见 + 只读 + 写操作回跳); ② 本轮把「平台管理」分区写进 @dsh-local/business-plugins 插件(原生渲染,非 iframe)—— 数据直接调平台只读 API; ③ 产物 dsh-local-business-plugins-0.2.9.tgz 已出(node --check 通过、包结构合规); ④ 未做:投放候选池 / 实例启用 / 浏览器验收(卡在需要 admin 登录态,见 §五);/admin 路由族 + 删 3 桩页 亦未做。


一、形态(与档案 81 §9.2b 一致)

维度 取值
渲染 原生渲染(复用插件自有 token --dsw-* + 06-工作台UI规范 字号阶梯),非 iframe
数据 直接调平台只读 API(跨子域 fetch + credentials: "include",门户 CORS 白名单已就绪)
范围 只读子集:实例 / 熔断 / 用户 / 存储 / 候选池 / 运行时
写操作 一律回跳平台管理台(portalHost() + "/portal.html")—— 不复制门户写 UI(否则双源维护 + 与档案 39「收窄执行面」相冲)
可见性 仅 admin:先 GET /api/auth/me 判 role === "admin",否则只渲染一行说明
落点 poc/business-plugins/lib/client.js(设置面板 settings.section,id: platform-admin, order: 102)

二、改了哪些文件

文件 改动
poc/business-plugins/lib/client.js 895 → 1083 行:① zh/en 词典各 +29 个 pa.* 键;② 新增 PaCard(指标卡)+ PlatformAdminSection;③ 新增一个 settings.section 注册(platform-admin)
poc/business-plugins/package.json 版本 0.2.8 → 0.2.9
产物 dsh-local-business-plugins-0.2.9.tgz(16,712 B;顶层仅 package/;无 .tgz/node_modules/.bak)

三、数据来源(均为平台既有路由,零新增后端)

卡片 API 权限
角色门禁 GET /api/auth/me requireAuth
当前实例 / 熔断 GET /api/dsh/status requireAuth
用户 GET /api/admin/users requireAdmin
存储 GET /api/admin/storage requireAdmin
候选池 GET /api/plugins/business requireAdmin
运行时 GET /api/admin/runtime requireAdmin

全部只读;任一失败降级为 null 并照常渲染其余卡片(不整页报错)。

四、已验证 / 未验证

项 状态 证据
语法 ✅ node --check lib/client.js 通过
包结构 ✅ 顶层仅 package/;4 条目;无违规文件;lib/client.js 在内
词条键集 ✅ zh/en 各 +29 键,键名一一对应
渲染 / 交互 / 权限门禁 ⏸ 未验证 需投放 + 启用(见 §五)

五、⛔ 未完成:投放与验收需要 admin 登录态

  • 投放走 POST /api/plugins/business(requireAdmin)⇒ 必须有 admin 的会话。
  • 平台 CLI 只有 start / bootstrap-admin / file-service,无投放命令;文档内无测试口令 ⇒ 执行会话拿不到凭据。
  • 三条可选路径(待用户定):① 用户自己在门户投放(2 分钟);② 给 admin 口令;③ 用 bootstrap-admin 建临时 admin,用完删(会动生产 auth)。

六、R2 剩余(本次未做,属同期的另一半)

  1. /admin 路由族 + 删 3 个跳转桩页(web/desktop.html / plugins.html / skills.html,各 247–265 B,title=跳转中…)—— 档案 81 §四表格口径;⚠️ 删桩页必须同时加 301 到 /admin(否则既有书签断)。删后静态页 9 → 6,需同步改 scripts/verify-static.mjs 的页数断言。
  2. 注入层 CSS 类统一为 .dshs-*(档案 81 §四:.__dsh-* / .wk-* → .dshs-*)。

七、回滚

  • 插件侧:把候选池里的 business-plugins 回落 0.2.8(旧 tgz 若已删,可从本机 git 历史取 lib/client.js 重建)。
  • 本轮改动全部在 poc/business-plugins/,未动 src/、未动官方 dsh、未动服务器 ⇒ 回滚只需还原该目录 + 重新投放。

八、口径提醒

⚠️ 不能两头都要(档案 81 §9.2b):若日后要求「弹窗里能完成全部管理动作」,那就等于把整个门户重写进插件(双源维护 + 扩大执行面)⇒ 届时应把门户收敛成 API 客户端,而不是继续复制 UI。


九、追加(2026-09-13 18:1x–19:2x):部署完成 + 无浏览器渲染验收通过 + 一并做掉档案 80 第 7 项

9.1 部署链路(关键:不走候选池)

@dsh-local/business-plugins 不是池内插件 —— 它由 scripts/ensure-biz-plugins.cjs 铺发:从 /opt/dsh/artifacts/ 取版本号最大的 business-plugins-*.tgz(--all 含 admin;--restart 让 bundle 生效)。

步 结果
投放产物 business-plugins-0.2.9.tgz → /opt/dsh/artifacts/(前一版为 0.2.8)
铺发 node scripts/ensure-biz-plugins.cjs --all --restart ⇒ admin 与 guest 的 profile 均 0.2.8 → 0.2.9、bundles 均含该包 ✓
磁盘层断言 两实例 node_modules/@dsh-local/business-plugins/lib/client.js 含「平台管理」× 5 ✓
实例 两实例均已重启并 running;实例页 HTTP 200 ✓

9.2 渲染验收:改用无浏览器 harness(因 agent-browser daemon 起不来)

  • ⚠️ 本机 [email protected] 的 daemon 起不来:open 挂住且零输出(--version / node -e 均正常;~/.agent-browser 里留下的 default.port 实测不通、清掉僵尸状态后仍不通)。Chrome 153 已由 agent-browser install 装好,但 daemon 不通 ⇒ 浏览器截图验收受阻(属环境问题,未解)。
  • ⚠️ 06-工作台UI规范 §7.3 的三段式在按需动态加载的 bundle 上拿不到带 rev 的完整 URL(该 bundle 不出现在实例首页 HTML 里)⇒ ②③ 段也不适用。
  • ✅ 替代做法(已沉淀为可复跑脚本):scripts/verify-platform-admin-section.mjs —— 打桩 react / react/jsx-runtime + 最小 hooks 渲染循环 + 真执行 client.js,直接断言结构与门禁。
✓ 注册了两个 settings.section  -> business-plugins, platform-admin
✓ 存在 platform-admin 分区    ✓ 其 order = 102
✓ admin:含分区标题「平台管理」  ✓ admin:6 张卡齐全  ✓ admin:含只读声明
✓ 非 admin:被门禁挡住         ✓ 非 admin:不出现任何指标卡
结论:全绿 ✅   exit=0

admin 视角实际渲染文本(实测):

平台管理 | 只读 | 本分区为只读;写操作请在平台管理台完成。 当前实例 | 运行中 | 端口 43095 · 自动重启 2 | 熔断 | 正常 | — 用户 | 4 | 待审核 1 · 已禁用 1 | 存储 | 2 | 报告每小时刷新 候选池 | 3 | 已投放插件 | 运行时 | 5 | 条目 | 打开完整管理台

已接入 npm run verify(&& node scripts/verify-platform-admin-section.mjs)⇒ 今后 UI 改动可 CI 式防回归。

9.3 一并做掉:档案 80 第 7 项 / 档案 81 §四「删 3 个跳转桩页」

  • 删 web/{desktop,plugins,skills}.html ⇒ 静态页 9 → 6 ✓;改 5 处引用(admin.html / index.html / login.html×2 / dsh.ts 注释)。verify-static.mjs 是自动发现页面的,无需改。
  • nginx alotbuy.com.conf 两个 server 块各加 3 条精确匹配 301 ⇒ 实测 /desktop.html→301 /portal.html、/plugins.html→#/plugins、/skills.html→#/skills ✓;login.html 仍 200 ✓。
  • ⚠️ 本机 nginx 由宝塔托管:systemctl reload nginx 失效,须用 nginx -s reload。

9.4 🔴 期间修掉一个由本次改名引入的真回归(如实记录)

  • 症状:admin 实例页 502,journal = plugin tree failed to load … corrupt session log。
  • 根因:会话日志是 session.jsonl.zstd(zstd 压缩)。改名只改了目录名与纯文本文件,压缩流 header 里的 cwd 仍是旧路径 ⇒ dsh 启动做一致性校验(header cwd vs 目录推导 cwd)不匹配 ⇒ 抛错 ⇒ 插件树加载失败 ⇒ 崩溃循环。
  • 修复:_fix_sesslog.cjs(node 内置 zlib.zstdDecompressSync/zstdCompressSync,22.15+)—— 解压 → 替换 → 重压 → 回读校验。26 个文件 24 个待修 → 全修完,复查 0 残留 ✓;实例恢复 200,corrupt session log 归零。
  • 📌 教训:压缩文件里的路径 grep/sed 够不到 —— 与「SQLite 改名必须带 -wal/-shm」同类。已写进项目 MEMORY.md 铁律。

9.5 期间发现的两个平台缺陷(待修)

  1. op-lock 不可用:锁根 /opt/dsh/state/.op-lock 不存在,且 scripts/op-lock.sh 自身解析 bt-server 失败 ⇒ 它报「已存在 → 停手」是假警报,无法用于互斥。
  2. agent-browser daemon 起不来(见 §9.2)—— 浏览器验收链路的唯一可用工具受阻。

9.6 尚未做

  • D / J / Q(T03 遗留)与登录/注册/门户/设置面板的体验审计(用户 18:1x 关注的第三块)。

十、追加(2026-09-13 19:3x–19:5x):从「只读」升级为「就地全量管理」(用户要求)

10.1 用户的三条要求

  1. dsh 设置里的「用户管理」改名为「用户设置」,且去掉里面的「打开管理平台」入口
  2. 「平台管理」不要再跳新页面 —— 把所有管理项都放进「系统管理」,每项点开是弹窗

10.2 落地

项 改动 产物
「用户管理」→「用户设置」 @dsh-local/portal-entry:section id: user-management → user-settings、label 改名、order 102 → 103(让位给平台管理);删除「打开管理台」按钮;内容改为「账号:<用户名> 角色:<管理员/普通用户>」+ 退出登录 portal-entry-0.5.2.tgz(已铺发到 admin+guest)
「平台管理」→「系统管理」+ 管理项 + 弹窗 @dsh-local/business-plugins:删掉 window.open(portal.html) 跳转按钮;分区改为「管理项列表」,5 项(用户管理 / 候选池 / 运行时 / 存储 / 当前实例)每项点开是原生弹窗;用户管理弹窗内可直接 通过 / 禁用 / 启用 / 删除(调平台既有 admin API,不跳门户) business-plugins-0.3.0.tgz(已铺发)

10.3 验收(npm run verify 内)

✓ 注册了两个 settings.section  -> business-plugins, platform-admin
✓ admin:含分区标题「系统管理」   ✓ admin:5 个管理项齐全
✓ admin:不再是只读(提示改为弹窗内管理)
✓ 非 admin:被门禁挡住            ✓ 非 admin:不出现任何管理项
结论:全绿 ✅

另:磁盘复核 —— 两 profile 的 business-plugins 均 0.3.0、含「系统管理」、window.open 计数 = 0(跳新页彻底移除)✓

10.4 尚未做的(下一批)

  • 弹窗内目前只有「用户管理」是可写的;候选池 / 运行时 / 存储 / 实例 三项为只读列表(写操作待补)。
  • portal-entry 源码不在仓库(只有铺发脚本 + artifacts 里的 tgz)⇒ 本次是在产物上改的。建议:把 portal-entry/business-plugins 源码纳入仓库(档案 75 · B5 的旧账)。

82 · R2 管理面就地化(原生「平台管理」分区)

  • 日期:2026-09-13
  • 状态:🚧 代码完成、产物已出;待投放 + 启用 + 浏览器验收
  • 触发:档案 81 §四 R2(原「实例内弹窗 iframe」);形态经用户 2026-09-13 拍板改为原生弹窗(§9.2b)
  • 原则:只读优先(写操作回跳平台域);不改官方 dsh;不把门户 UI 复制进插件

TL;DR|① R2 的 R5 权限影响评估已在档案 81 §9.2 出齐并获批(扩大点=实例内出现可操作的管理入口 ⇒ 仅 admin 可见 + 只读 + 写操作回跳); ② 本轮把「平台管理」分区写进 @dsh-local/business-plugins 插件(原生渲染,非 iframe)—— 数据直接调平台只读 API; ③ 产物 dsh-local-business-plugins-0.2.9.tgz 已出(node --check 通过、包结构合规); ④ 未做:投放候选池 / 实例启用 / 浏览器验收(卡在需要 admin 登录态,见 §五);/admin 路由族 + 删 3 桩页 亦未做。


一、形态(与档案 81 §9.2b 一致)

维度 取值
渲染 原生渲染(复用插件自有 token --dsw-* + 06-工作台UI规范 字号阶梯),非 iframe
数据 直接调平台只读 API(跨子域 fetch + credentials: "include",门户 CORS 白名单已就绪)
范围 只读子集:实例 / 熔断 / 用户 / 存储 / 候选池 / 运行时
写操作 一律回跳平台管理台(portalHost() + "/portal.html")—— 不复制门户写 UI(否则双源维护 + 与档案 39「收窄执行面」相冲)
可见性 仅 admin:先 GET /api/auth/me 判 role === "admin",否则只渲染一行说明
落点 poc/business-plugins/lib/client.js(设置面板 settings.section,id: platform-admin, order: 102)

二、改了哪些文件

文件 改动
poc/business-plugins/lib/client.js 895 → 1083 行:① zh/en 词典各 +29 个 pa.* 键;② 新增 PaCard(指标卡)+ PlatformAdminSection;③ 新增一个 settings.section 注册(platform-admin)
poc/business-plugins/package.json 版本 0.2.8 → 0.2.9
产物 dsh-local-business-plugins-0.2.9.tgz(16,712 B;顶层仅 package/;无 .tgz/node_modules/.bak)

三、数据来源(均为平台既有路由,零新增后端)

卡片 API 权限
角色门禁 GET /api/auth/me requireAuth
当前实例 / 熔断 GET /api/dsh/status requireAuth
用户 GET /api/admin/users requireAdmin
存储 GET /api/admin/storage requireAdmin
候选池 GET /api/plugins/business requireAdmin
运行时 GET /api/admin/runtime requireAdmin

全部只读;任一失败降级为 null 并照常渲染其余卡片(不整页报错)。

四、已验证 / 未验证

项 状态 证据
语法 ✅ node --check lib/client.js 通过
包结构 ✅ 顶层仅 package/;4 条目;无违规文件;lib/client.js 在内
词条键集 ✅ zh/en 各 +29 键,键名一一对应
渲染 / 交互 / 权限门禁 ⏸ 未验证 需投放 + 启用(见 §五)

五、⛔ 未完成:投放与验收需要 admin 登录态

  • 投放走 POST /api/plugins/business(requireAdmin)⇒ 必须有 admin 的会话。
  • 平台 CLI 只有 start / bootstrap-admin / file-service,无投放命令;文档内无测试口令 ⇒ 执行会话拿不到凭据。
  • 三条可选路径(待用户定):① 用户自己在门户投放(2 分钟);② 给 admin 口令;③ 用 bootstrap-admin 建临时 admin,用完删(会动生产 auth)。

六、R2 剩余(本次未做,属同期的另一半)

  1. /admin 路由族 + 删 3 个跳转桩页(web/desktop.html / plugins.html / skills.html,各 247–265 B,title=跳转中…)—— 档案 81 §四表格口径;⚠️ 删桩页必须同时加 301 到 /admin(否则既有书签断)。删后静态页 9 → 6,需同步改 scripts/verify-static.mjs 的页数断言。
  2. 注入层 CSS 类统一为 .dshs-*(档案 81 §四:.__dsh-* / .wk-* → .dshs-*)。

七、回滚

  • 插件侧:把候选池里的 business-plugins 回落 0.2.8(旧 tgz 若已删,可从本机 git 历史取 lib/client.js 重建)。
  • 本轮改动全部在 poc/business-plugins/,未动 src/、未动官方 dsh、未动服务器 ⇒ 回滚只需还原该目录 + 重新投放。

八、口径提醒

⚠️ 不能两头都要(档案 81 §9.2b):若日后要求「弹窗里能完成全部管理动作」,那就等于把整个门户重写进插件(双源维护 + 扩大执行面)⇒ 届时应把门户收敛成 API 客户端,而不是继续复制 UI。# 82 · R2 管理面就地化(原生「平台管理」分区)

  • 日期:2026-09-13
  • 状态:🚧 代码完成、产物已出;待投放 + 启用 + 浏览器验收
  • 触发:档案 81 §四 R2(原「实例内弹窗 iframe」);形态经用户 2026-09-13 拍板改为原生弹窗(§9.2b)
  • 原则:只读优先(写操作回跳平台域);不改官方 dsh;不把门户 UI 复制进插件

TL;DR|① R2 的 R5 权限影响评估已在档案 81 §9.2 出齐并获批(扩大点=实例内出现可操作的管理入口 ⇒ 仅 admin 可见 + 只读 + 写操作回跳); ② 本轮把「平台管理」分区写进 @dsh-local/business-plugins 插件(原生渲染,非 iframe)—— 数据直接调平台只读 API; ③ 产物 dsh-local-business-plugins-0.2.9.tgz 已出(node --check 通过、包结构合规); ④ 未做:投放候选池 / 实例启用 / 浏览器验收(卡在需要 admin 登录态,见 §五);/admin 路由族 + 删 3 桩页 亦未做。


一、形态(与档案 81 §9.2b 一致)

维度 取值
渲染 原生渲染(复用插件自有 token --dsw-* + 06-工作台UI规范 字号阶梯),非 iframe
数据 直接调平台只读 API(跨子域 fetch + credentials: "include",门户 CORS 白名单已就绪)
范围 只读子集:实例 / 熔断 / 用户 / 存储 / 候选池 / 运行时
写操作 一律回跳平台管理台(portalHost() + "/portal.html")—— 不复制门户写 UI(否则双源维护 + 与档案 39「收窄执行面」相冲)
可见性 仅 admin:先 GET /api/auth/me 判 role === "admin",否则只渲染一行说明
落点 poc/business-plugins/lib/client.js(设置面板 settings.section,id: platform-admin, order: 102)

二、改了哪些文件

文件 改动
poc/business-plugins/lib/client.js 895 → 1083 行:① zh/en 词典各 +29 个 pa.* 键;② 新增 PaCard(指标卡)+ PlatformAdminSection;③ 新增一个 settings.section 注册(platform-admin)
poc/business-plugins/package.json 版本 0.2.8 → 0.2.9
产物 dsh-local-business-plugins-0.2.9.tgz(16,712 B;顶层仅 package/;无 .tgz/node_modules/.bak)

三、数据来源(均为平台既有路由,零新增后端)

卡片 API 权限
角色门禁 GET /api/auth/me requireAuth
当前实例 / 熔断 GET /api/dsh/status requireAuth
用户 GET /api/admin/users requireAdmin
存储 GET /api/admin/storage requireAdmin
候选池 GET /api/plugins/business requireAdmin
运行时 GET /api/admin/runtime requireAdmin

全部只读;任一失败降级为 null 并照常渲染其余卡片(不整页报错)。

四、已验证 / 未验证

项 状态 证据
语法 ✅ node --check lib/client.js 通过
包结构 ✅ 顶层仅 package/;4 条目;无违规文件;lib/client.js 在内
词条键集 ✅ zh/en 各 +29 键,键名一一对应
渲染 / 交互 / 权限门禁 ⏸ 未验证 需投放 + 启用(见 §五)

五、⛔ 未完成:投放与验收需要 admin 登录态

  • 投放走 POST /api/plugins/business(requireAdmin)⇒ 必须有 admin 的会话。
  • 平台 CLI 只有 start / bootstrap-admin / file-service,无投放命令;文档内无测试口令 ⇒ 执行会话拿不到凭据。
  • 三条可选路径(待用户定):① 用户自己在门户投放(2 分钟);② 给 admin 口令;③ 用 bootstrap-admin 建临时 admin,用完删(会动生产 auth)。

六、R2 剩余(本次未做,属同期的另一半)

  1. /admin 路由族 + 删 3 个跳转桩页(web/desktop.html / plugins.html / skills.html,各 247–265 B,title=跳转中…)—— 档案 81 §四表格口径;⚠️ 删桩页必须同时加 301 到 /admin(否则既有书签断)。删后静态页 9 → 6,需同步改 scripts/verify-static.mjs 的页数断言。
  2. 注入层 CSS 类统一为 .dshs-*(档案 81 §四:.__dsh-* / .wk-* → .dshs-*)。

七、回滚

  • 插件侧:把候选池里的 business-plugins 回落 0.2.8(旧 tgz 若已删,可从本机 git 历史取 lib/client.js 重建)。
  • 本轮改动全部在 poc/business-plugins/,未动 src/、未动官方 dsh、未动服务器 ⇒ 回滚只需还原该目录 + 重新投放。

八、口径提醒

⚠️ 不能两头都要(档案 81 §9.2b):若日后要求「弹窗里能完成全部管理动作」,那就等于把整个门户重写进插件(双源维护 + 扩大执行面)⇒ 届时应把门户收敛成 API 客户端,而不是继续复制 UI。


九、追加(2026-09-13 18:1x–19:2x):部署完成 + 无浏览器渲染验收通过 + 一并做掉档案 80 第 7 项

9.1 部署链路(关键:不走候选池)

@dsh-local/business-plugins 不是池内插件 —— 它由 scripts/ensure-biz-plugins.cjs 铺发:从 /opt/dsh/artifacts/ 取版本号最大的 business-plugins-*.tgz(--all 含 admin;--restart 让 bundle 生效)。

步 结果
投放产物 business-plugins-0.2.9.tgz → /opt/dsh/artifacts/(前一版为 0.2.8)
铺发 node scripts/ensure-biz-plugins.cjs --all --restart ⇒ admin 与 guest 的 profile 均 0.2.8 → 0.2.9、bundles 均含该包 ✓
磁盘层断言 两实例 node_modules/@dsh-local/business-plugins/lib/client.js 含「平台管理」× 5 ✓
实例 两实例均已重启并 running;实例页 HTTP 200 ✓

9.2 渲染验收:改用无浏览器 harness(因 agent-browser daemon 起不来)

  • ⚠️ 本机 [email protected] 的 daemon 起不来:open 挂住且零输出(--version / node -e 均正常;~/.agent-browser 里留下的 default.port 实测不通、清掉僵尸状态后仍不通)。Chrome 153 已由 agent-browser install 装好,但 daemon 不通 ⇒ 浏览器截图验收受阻(属环境问题,未解)。
  • ⚠️ 06-工作台UI规范 §7.3 的三段式在按需动态加载的 bundle 上拿不到带 rev 的完整 URL(该 bundle 不出现在实例首页 HTML 里)⇒ ②③ 段也不适用。
  • ✅ 替代做法(已沉淀为可复跑脚本):scripts/verify-platform-admin-section.mjs —— 打桩 react / react/jsx-runtime + 最小 hooks 渲染循环 + 真执行 client.js,直接断言结构与门禁。
✓ 注册了两个 settings.section  -> business-plugins, platform-admin
✓ 存在 platform-admin 分区    ✓ 其 order = 102
✓ admin:含分区标题「平台管理」  ✓ admin:6 张卡齐全  ✓ admin:含只读声明
✓ 非 admin:被门禁挡住         ✓ 非 admin:不出现任何指标卡
结论:全绿 ✅   exit=0

admin 视角实际渲染文本(实测):

平台管理 | 只读 | 本分区为只读;写操作请在平台管理台完成。 当前实例 | 运行中 | 端口 43095 · 自动重启 2 | 熔断 | 正常 | — 用户 | 4 | 待审核 1 · 已禁用 1 | 存储 | 2 | 报告每小时刷新 候选池 | 3 | 已投放插件 | 运行时 | 5 | 条目 | 打开完整管理台

已接入 npm run verify(&& node scripts/verify-platform-admin-section.mjs)⇒ 今后 UI 改动可 CI 式防回归。

9.3 一并做掉:档案 80 第 7 项 / 档案 81 §四「删 3 个跳转桩页」

  • 删 web/{desktop,plugins,skills}.html ⇒ 静态页 9 → 6 ✓;改 5 处引用(admin.html / index.html / login.html×2 / dsh.ts 注释)。verify-static.mjs 是自动发现页面的,无需改。
  • nginx alotbuy.com.conf 两个 server 块各加 3 条精确匹配 301 ⇒ 实测 /desktop.html→301 /portal.html、/plugins.html→#/plugins、/skills.html→#/skills ✓;login.html 仍 200 ✓。
  • ⚠️ 本机 nginx 由宝塔托管:systemctl reload nginx 失效,须用 nginx -s reload。

9.4 🔴 期间修掉一个由本次改名引入的真回归(如实记录)

  • 症状:admin 实例页 502,journal = plugin tree failed to load … corrupt session log。
  • 根因:会话日志是 session.jsonl.zstd(zstd 压缩)。改名只改了目录名与纯文本文件,压缩流 header 里的 cwd 仍是旧路径 ⇒ dsh 启动做一致性校验(header cwd vs 目录推导 cwd)不匹配 ⇒ 抛错 ⇒ 插件树加载失败 ⇒ 崩溃循环。
  • 修复:_fix_sesslog.cjs(node 内置 zlib.zstdDecompressSync/zstdCompressSync,22.15+)—— 解压 → 替换 → 重压 → 回读校验。26 个文件 24 个待修 → 全修完,复查 0 残留 ✓;实例恢复 200,corrupt session log 归零。
  • 📌 教训:压缩文件里的路径 grep/sed 够不到 —— 与「SQLite 改名必须带 -wal/-shm」同类。已写进项目 MEMORY.md 铁律。

9.5 期间发现的两个平台缺陷(待修)

  1. op-lock 不可用:锁根 /opt/dsh/state/.op-lock 不存在,且 scripts/op-lock.sh 自身解析 bt-server 失败 ⇒ 它报「已存在 → 停手」是假警报,无法用于互斥。
  2. agent-browser daemon 起不来(见 §9.2)—— 浏览器验收链路的唯一可用工具受阻。

9.6 尚未做

  • D / J / Q(T03 遗留)与登录/注册/门户/设置面板的体验审计(用户 18:1x 关注的第三块)。

82 · R2 管理面就地化(原生「平台管理」分区)

  • 日期:2026-09-13
  • 状态:🚧 代码完成、产物已出;待投放 + 启用 + 浏览器验收
  • 触发:档案 81 §四 R2(原「实例内弹窗 iframe」);形态经用户 2026-09-13 拍板改为原生弹窗(§9.2b)
  • 原则:只读优先(写操作回跳平台域);不改官方 dsh;不把门户 UI 复制进插件

TL;DR|① R2 的 R5 权限影响评估已在档案 81 §9.2 出齐并获批(扩大点=实例内出现可操作的管理入口 ⇒ 仅 admin 可见 + 只读 + 写操作回跳); ② 本轮把「平台管理」分区写进 @dsh-local/business-plugins 插件(原生渲染,非 iframe)—— 数据直接调平台只读 API; ③ 产物 dsh-local-business-plugins-0.2.9.tgz 已出(node --check 通过、包结构合规); ④ 未做:投放候选池 / 实例启用 / 浏览器验收(卡在需要 admin 登录态,见 §五);/admin 路由族 + 删 3 桩页 亦未做。


一、形态(与档案 81 §9.2b 一致)

维度 取值
渲染 原生渲染(复用插件自有 token --dsw-* + 06-工作台UI规范 字号阶梯),非 iframe
数据 直接调平台只读 API(跨子域 fetch + credentials: "include",门户 CORS 白名单已就绪)
范围 只读子集:实例 / 熔断 / 用户 / 存储 / 候选池 / 运行时
写操作 一律回跳平台管理台(portalHost() + "/portal.html")—— 不复制门户写 UI(否则双源维护 + 与档案 39「收窄执行面」相冲)
可见性 仅 admin:先 GET /api/auth/me 判 role === "admin",否则只渲染一行说明
落点 poc/business-plugins/lib/client.js(设置面板 settings.section,id: platform-admin, order: 102)

二、改了哪些文件

文件 改动
poc/business-plugins/lib/client.js 895 → 1083 行:① zh/en 词典各 +29 个 pa.* 键;② 新增 PaCard(指标卡)+ PlatformAdminSection;③ 新增一个 settings.section 注册(platform-admin)
poc/business-plugins/package.json 版本 0.2.8 → 0.2.9
产物 dsh-local-business-plugins-0.2.9.tgz(16,712 B;顶层仅 package/;无 .tgz/node_modules/.bak)

三、数据来源(均为平台既有路由,零新增后端)

卡片 API 权限
角色门禁 GET /api/auth/me requireAuth
当前实例 / 熔断 GET /api/dsh/status requireAuth
用户 GET /api/admin/users requireAdmin
存储 GET /api/admin/storage requireAdmin
候选池 GET /api/plugins/business requireAdmin
运行时 GET /api/admin/runtime requireAdmin

全部只读;任一失败降级为 null 并照常渲染其余卡片(不整页报错)。

四、已验证 / 未验证

项 状态 证据
语法 ✅ node --check lib/client.js 通过
包结构 ✅ 顶层仅 package/;4 条目;无违规文件;lib/client.js 在内
词条键集 ✅ zh/en 各 +29 键,键名一一对应
渲染 / 交互 / 权限门禁 ⏸ 未验证 需投放 + 启用(见 §五)

五、⛔ 未完成:投放与验收需要 admin 登录态

  • 投放走 POST /api/plugins/business(requireAdmin)⇒ 必须有 admin 的会话。
  • 平台 CLI 只有 start / bootstrap-admin / file-service,无投放命令;文档内无测试口令 ⇒ 执行会话拿不到凭据。
  • 三条可选路径(待用户定):① 用户自己在门户投放(2 分钟);② 给 admin 口令;③ 用 bootstrap-admin 建临时 admin,用完删(会动生产 auth)。

六、R2 剩余(本次未做,属同期的另一半)

  1. /admin 路由族 + 删 3 个跳转桩页(web/desktop.html / plugins.html / skills.html,各 247–265 B,title=跳转中…)—— 档案 81 §四表格口径;⚠️ 删桩页必须同时加 301 到 /admin(否则既有书签断)。删后静态页 9 → 6,需同步改 scripts/verify-static.mjs 的页数断言。
  2. 注入层 CSS 类统一为 .dshs-*(档案 81 §四:.__dsh-* / .wk-* → .dshs-*)。

七、回滚

  • 插件侧:把候选池里的 business-plugins 回落 0.2.8(旧 tgz 若已删,可从本机 git 历史取 lib/client.js 重建)。
  • 本轮改动全部在 poc/business-plugins/,未动 src/、未动官方 dsh、未动服务器 ⇒ 回滚只需还原该目录 + 重新投放。

八、口径提醒

⚠️ 不能两头都要(档案 81 §9.2b):若日后要求「弹窗里能完成全部管理动作」,那就等于把整个门户重写进插件(双源维护 + 扩大执行面)⇒ 届时应把门户收敛成 API 客户端,而不是继续复制 UI。# 82 · R2 管理面就地化(原生「平台管理」分区)

  • 日期:2026-09-13
  • 状态:🚧 代码完成、产物已出;待投放 + 启用 + 浏览器验收
  • 触发:档案 81 §四 R2(原「实例内弹窗 iframe」);形态经用户 2026-09-13 拍板改为原生弹窗(§9.2b)
  • 原则:只读优先(写操作回跳平台域);不改官方 dsh;不把门户 UI 复制进插件

TL;DR|① R2 的 R5 权限影响评估已在档案 81 §9.2 出齐并获批(扩大点=实例内出现可操作的管理入口 ⇒ 仅 admin 可见 + 只读 + 写操作回跳); ② 本轮把「平台管理」分区写进 @dsh-local/business-plugins 插件(原生渲染,非 iframe)—— 数据直接调平台只读 API; ③ 产物 dsh-local-business-plugins-0.2.9.tgz 已出(node --check 通过、包结构合规); ④ 未做:投放候选池 / 实例启用 / 浏览器验收(卡在需要 admin 登录态,见 §五);/admin 路由族 + 删 3 桩页 亦未做。


一、形态(与档案 81 §9.2b 一致)

维度 取值
渲染 原生渲染(复用插件自有 token --dsw-* + 06-工作台UI规范 字号阶梯),非 iframe
数据 直接调平台只读 API(跨子域 fetch + credentials: "include",门户 CORS 白名单已就绪)
范围 只读子集:实例 / 熔断 / 用户 / 存储 / 候选池 / 运行时
写操作 一律回跳平台管理台(portalHost() + "/portal.html")—— 不复制门户写 UI(否则双源维护 + 与档案 39「收窄执行面」相冲)
可见性 仅 admin:先 GET /api/auth/me 判 role === "admin",否则只渲染一行说明
落点 poc/business-plugins/lib/client.js(设置面板 settings.section,id: platform-admin, order: 102)

二、改了哪些文件

文件 改动
poc/business-plugins/lib/client.js 895 → 1083 行:① zh/en 词典各 +29 个 pa.* 键;② 新增 PaCard(指标卡)+ PlatformAdminSection;③ 新增一个 settings.section 注册(platform-admin)
poc/business-plugins/package.json 版本 0.2.8 → 0.2.9
产物 dsh-local-business-plugins-0.2.9.tgz(16,712 B;顶层仅 package/;无 .tgz/node_modules/.bak)

三、数据来源(均为平台既有路由,零新增后端)

卡片 API 权限
角色门禁 GET /api/auth/me requireAuth
当前实例 / 熔断 GET /api/dsh/status requireAuth
用户 GET /api/admin/users requireAdmin
存储 GET /api/admin/storage requireAdmin
候选池 GET /api/plugins/business requireAdmin
运行时 GET /api/admin/runtime requireAdmin

全部只读;任一失败降级为 null 并照常渲染其余卡片(不整页报错)。

四、已验证 / 未验证

项 状态 证据
语法 ✅ node --check lib/client.js 通过
包结构 ✅ 顶层仅 package/;4 条目;无违规文件;lib/client.js 在内
词条键集 ✅ zh/en 各 +29 键,键名一一对应
渲染 / 交互 / 权限门禁 ⏸ 未验证 需投放 + 启用(见 §五)

五、⛔ 未完成:投放与验收需要 admin 登录态

  • 投放走 POST /api/plugins/business(requireAdmin)⇒ 必须有 admin 的会话。
  • 平台 CLI 只有 start / bootstrap-admin / file-service,无投放命令;文档内无测试口令 ⇒ 执行会话拿不到凭据。
  • 三条可选路径(待用户定):① 用户自己在门户投放(2 分钟);② 给 admin 口令;③ 用 bootstrap-admin 建临时 admin,用完删(会动生产 auth)。

六、R2 剩余(本次未做,属同期的另一半)

  1. /admin 路由族 + 删 3 个跳转桩页(web/desktop.html / plugins.html / skills.html,各 247–265 B,title=跳转中…)—— 档案 81 §四表格口径;⚠️ 删桩页必须同时加 301 到 /admin(否则既有书签断)。删后静态页 9 → 6,需同步改 scripts/verify-static.mjs 的页数断言。
  2. 注入层 CSS 类统一为 .dshs-*(档案 81 §四:.__dsh-* / .wk-* → .dshs-*)。

七、回滚

  • 插件侧:把候选池里的 business-plugins 回落 0.2.8(旧 tgz 若已删,可从本机 git 历史取 lib/client.js 重建)。
  • 本轮改动全部在 poc/business-plugins/,未动 src/、未动官方 dsh、未动服务器 ⇒ 回滚只需还原该目录 + 重新投放。

八、口径提醒

⚠️ 不能两头都要(档案 81 §9.2b):若日后要求「弹窗里能完成全部管理动作」,那就等于把整个门户重写进插件(双源维护 + 扩大执行面)⇒ 届时应把门户收敛成 API 客户端,而不是继续复制 UI。


九、追加(2026-09-13 18:1x–19:2x):部署完成 + 无浏览器渲染验收通过 + 一并做掉档案 80 第 7 项

9.1 部署链路(关键:不走候选池)

@dsh-local/business-plugins 不是池内插件 —— 它由 scripts/ensure-biz-plugins.cjs 铺发:从 /opt/dsh/artifacts/ 取版本号最大的 business-plugins-*.tgz(--all 含 admin;--restart 让 bundle 生效)。

步 结果
投放产物 business-plugins-0.2.9.tgz → /opt/dsh/artifacts/(前一版为 0.2.8)
铺发 node scripts/ensure-biz-plugins.cjs --all --restart ⇒ admin 与 guest 的 profile 均 0.2.8 → 0.2.9、bundles 均含该包 ✓
磁盘层断言 两实例 node_modules/@dsh-local/business-plugins/lib/client.js 含「平台管理」× 5 ✓
实例 两实例均已重启并 running;实例页 HTTP 200 ✓

9.2 渲染验收:改用无浏览器 harness(因 agent-browser daemon 起不来)

  • ⚠️ 本机 [email protected] 的 daemon 起不来:open 挂住且零输出(--version / node -e 均正常;~/.agent-browser 里留下的 default.port 实测不通、清掉僵尸状态后仍不通)。Chrome 153 已由 agent-browser install 装好,但 daemon 不通 ⇒ 浏览器截图验收受阻(属环境问题,未解)。
  • ⚠️ 06-工作台UI规范 §7.3 的三段式在按需动态加载的 bundle 上拿不到带 rev 的完整 URL(该 bundle 不出现在实例首页 HTML 里)⇒ ②③ 段也不适用。
  • ✅ 替代做法(已沉淀为可复跑脚本):scripts/verify-platform-admin-section.mjs —— 打桩 react / react/jsx-runtime + 最小 hooks 渲染循环 + 真执行 client.js,直接断言结构与门禁。
✓ 注册了两个 settings.section  -> business-plugins, platform-admin
✓ 存在 platform-admin 分区    ✓ 其 order = 102
✓ admin:含分区标题「平台管理」  ✓ admin:6 张卡齐全  ✓ admin:含只读声明
✓ 非 admin:被门禁挡住         ✓ 非 admin:不出现任何指标卡
结论:全绿 ✅   exit=0

admin 视角实际渲染文本(实测):

平台管理 | 只读 | 本分区为只读;写操作请在平台管理台完成。 当前实例 | 运行中 | 端口 43095 · 自动重启 2 | 熔断 | 正常 | — 用户 | 4 | 待审核 1 · 已禁用 1 | 存储 | 2 | 报告每小时刷新 候选池 | 3 | 已投放插件 | 运行时 | 5 | 条目 | 打开完整管理台

已接入 npm run verify(&& node scripts/verify-platform-admin-section.mjs)⇒ 今后 UI 改动可 CI 式防回归。

9.3 一并做掉:档案 80 第 7 项 / 档案 81 §四「删 3 个跳转桩页」

  • 删 web/{desktop,plugins,skills}.html ⇒ 静态页 9 → 6 ✓;改 5 处引用(admin.html / index.html / login.html×2 / dsh.ts 注释)。verify-static.mjs 是自动发现页面的,无需改。
  • nginx alotbuy.com.conf 两个 server 块各加 3 条精确匹配 301 ⇒ 实测 /desktop.html→301 /portal.html、/plugins.html→#/plugins、/skills.html→#/skills ✓;login.html 仍 200 ✓。
  • ⚠️ 本机 nginx 由宝塔托管:systemctl reload nginx 失效,须用 nginx -s reload。

9.4 🔴 期间修掉一个由本次改名引入的真回归(如实记录)

  • 症状:admin 实例页 502,journal = plugin tree failed to load … corrupt session log。
  • 根因:会话日志是 session.jsonl.zstd(zstd 压缩)。改名只改了目录名与纯文本文件,压缩流 header 里的 cwd 仍是旧路径 ⇒ dsh 启动做一致性校验(header cwd vs 目录推导 cwd)不匹配 ⇒ 抛错 ⇒ 插件树加载失败 ⇒ 崩溃循环。
  • 修复:_fix_sesslog.cjs(node 内置 zlib.zstdDecompressSync/zstdCompressSync,22.15+)—— 解压 → 替换 → 重压 → 回读校验。26 个文件 24 个待修 → 全修完,复查 0 残留 ✓;实例恢复 200,corrupt session log 归零。
  • 📌 教训:压缩文件里的路径 grep/sed 够不到 —— 与「SQLite 改名必须带 -wal/-shm」同类。已写进项目 MEMORY.md 铁律。

9.5 期间发现的两个平台缺陷(待修)

  1. op-lock 不可用:锁根 /opt/dsh/state/.op-lock 不存在,且 scripts/op-lock.sh 自身解析 bt-server 失败 ⇒ 它报「已存在 → 停手」是假警报,无法用于互斥。
  2. agent-browser daemon 起不来(见 §9.2)—— 浏览器验收链路的唯一可用工具受阻。

9.6 尚未做

  • D / J / Q(T03 遗留)与登录/注册/门户/设置面板的体验审计(用户 18:1x 关注的第三块)。

十、追加(2026-09-13 19:3x–19:5x):从「只读」升级为「就地全量管理」(用户要求)

10.1 用户的三条要求

  1. dsh 设置里的「用户管理」改名为「用户设置」,且去掉里面的「打开管理平台」入口
  2. 「平台管理」不要再跳新页面 —— 把所有管理项都放进「系统管理」,每项点开是弹窗

10.2 落地

项 改动 产物
「用户管理」→「用户设置」 @dsh-local/portal-entry:section id: user-management → user-settings、label 改名、order 102 → 103(让位给平台管理);删除「打开管理台」按钮;内容改为「账号:<用户名> 角色:<管理员/普通用户>」+ 退出登录 portal-entry-0.5.2.tgz(已铺发到 admin+guest)
「平台管理」→「系统管理」+ 管理项 + 弹窗 @dsh-local/business-plugins:删掉 window.open(portal.html) 跳转按钮;分区改为「管理项列表」,5 项(用户管理 / 候选池 / 运行时 / 存储 / 当前实例)每项点开是原生弹窗;用户管理弹窗内可直接 通过 / 禁用 / 启用 / 删除(调平台既有 admin API,不跳门户) business-plugins-0.3.0.tgz(已铺发)

10.3 验收(npm run verify 内)

✓ 注册了两个 settings.section  -> business-plugins, platform-admin
✓ admin:含分区标题「系统管理」   ✓ admin:5 个管理项齐全
✓ admin:不再是只读(提示改为弹窗内管理)
✓ 非 admin:被门禁挡住            ✓ 非 admin:不出现任何管理项
结论:全绿 ✅

另:磁盘复核 —— 两 profile 的 business-plugins 均 0.3.0、含「系统管理」、window.open 计数 = 0(跳新页彻底移除)✓

10.4 尚未做的(下一批)

  • 弹窗内目前只有「用户管理」是可写的;候选池 / 运行时 / 存储 / 实例 三项为只读列表(写操作待补)。
  • portal-entry 源码不在仓库(只有铺发脚本 + artifacts 里的 tgz)⇒ 本次是在产物上改的。建议:把 portal-entry/business-plugins 源码纳入仓库(档案 75 · B5 的旧账)。

10.5 视觉层补齐(2026-09-13 20:1x,用户反馈「像毛坯房、参考门户样式、把 UI 规范记脑袋里」)

做法:按 06-工作台UI规范 重做视觉层(此前只做了功能骨架、无样式):

元素 采纳的规范条目 取值
管理项卡片 §4.5 .data-card r12 / 16px 18px / box-shadow: 0 1px 3px rgba(0,0,0,.08) / hover 上浮 translateY(-2px) + 蓝边 + 0 4px 12px rgba(47,111,237,.15) / transition .15s cubic-bezier(.16,1,.3,1)
卡片布局 §3 grid-template-columns: repeat(auto-fill, minmax(158px, 1fr)) + gap 12;minHeight 104px 保证等高
弹窗 §4.7 .modal / .modal-mask mask rgba(0,0,0,.35) + flex 居中;面板 r14 / 22px 26px / width 520px / max-width 92vw / 0 8px 30px;进场 paIn .18s
按钮 §4.1 .btn-sm 量级 3px 10px / r6 / 12–13px;hover 蓝边蓝字 + 淡蓝底
数值 §5 计数右对齐 + font-variant-numeric: tabular-nums
字号 §2.2 阶梯 卡片标题 15/500、说明 13/次级色、计数 17/500
动效降级 §4.5 @media (prefers-reduced-motion: reduce) 关动画与位移

色彩:继续用 dsh 官方 token --dsw-*(刻意不硬编码亮色——本 section 嵌在 dsh 设置面板内,须自动跟随 dsh 主题;硬编码会在暗色主题下瞎)。规范里的硬色值是给门户静态页的。

产物:business-plugins-0.3.1.tgz(已铺发 admin+guest);npm run verify 全绿。

⚠️ 教训(已入库):上一轮只做了功能、没做视觉就交付,被指「像毛坯房」。做页面的默认动作必须包含「查规范 → 落地 §4.5/§4.7 等具体条目」,不能等用户来提。

82 · R2 管理面就地化(原生「平台管理」分区)

  • 日期:2026-09-13
  • 状态:🚧 代码完成、产物已出;待投放 + 启用 + 浏览器验收
  • 触发:档案 81 §四 R2(原「实例内弹窗 iframe」);形态经用户 2026-09-13 拍板改为原生弹窗(§9.2b)
  • 原则:只读优先(写操作回跳平台域);不改官方 dsh;不把门户 UI 复制进插件

TL;DR|① R2 的 R5 权限影响评估已在档案 81 §9.2 出齐并获批(扩大点=实例内出现可操作的管理入口 ⇒ 仅 admin 可见 + 只读 + 写操作回跳); ② 本轮把「平台管理」分区写进 @dsh-local/business-plugins 插件(原生渲染,非 iframe)—— 数据直接调平台只读 API; ③ 产物 dsh-local-business-plugins-0.2.9.tgz 已出(node --check 通过、包结构合规); ④ 未做:投放候选池 / 实例启用 / 浏览器验收(卡在需要 admin 登录态,见 §五);/admin 路由族 + 删 3 桩页 亦未做。


一、形态(与档案 81 §9.2b 一致)

维度 取值
渲染 原生渲染(复用插件自有 token --dsw-* + 06-工作台UI规范 字号阶梯),非 iframe
数据 直接调平台只读 API(跨子域 fetch + credentials: "include",门户 CORS 白名单已就绪)
范围 只读子集:实例 / 熔断 / 用户 / 存储 / 候选池 / 运行时
写操作 一律回跳平台管理台(portalHost() + "/portal.html")—— 不复制门户写 UI(否则双源维护 + 与档案 39「收窄执行面」相冲)
可见性 仅 admin:先 GET /api/auth/me 判 role === "admin",否则只渲染一行说明
落点 poc/business-plugins/lib/client.js(设置面板 settings.section,id: platform-admin, order: 102)

二、改了哪些文件

文件 改动
poc/business-plugins/lib/client.js 895 → 1083 行:① zh/en 词典各 +29 个 pa.* 键;② 新增 PaCard(指标卡)+ PlatformAdminSection;③ 新增一个 settings.section 注册(platform-admin)
poc/business-plugins/package.json 版本 0.2.8 → 0.2.9
产物 dsh-local-business-plugins-0.2.9.tgz(16,712 B;顶层仅 package/;无 .tgz/node_modules/.bak)

三、数据来源(均为平台既有路由,零新增后端)

卡片 API 权限
角色门禁 GET /api/auth/me requireAuth
当前实例 / 熔断 GET /api/dsh/status requireAuth
用户 GET /api/admin/users requireAdmin
存储 GET /api/admin/storage requireAdmin
候选池 GET /api/plugins/business requireAdmin
运行时 GET /api/admin/runtime requireAdmin

全部只读;任一失败降级为 null 并照常渲染其余卡片(不整页报错)。

四、已验证 / 未验证

项 状态 证据
语法 ✅ node --check lib/client.js 通过
包结构 ✅ 顶层仅 package/;4 条目;无违规文件;lib/client.js 在内
词条键集 ✅ zh/en 各 +29 键,键名一一对应
渲染 / 交互 / 权限门禁 ⏸ 未验证 需投放 + 启用(见 §五)

五、⛔ 未完成:投放与验收需要 admin 登录态

  • 投放走 POST /api/plugins/business(requireAdmin)⇒ 必须有 admin 的会话。
  • 平台 CLI 只有 start / bootstrap-admin / file-service,无投放命令;文档内无测试口令 ⇒ 执行会话拿不到凭据。
  • 三条可选路径(待用户定):① 用户自己在门户投放(2 分钟);② 给 admin 口令;③ 用 bootstrap-admin 建临时 admin,用完删(会动生产 auth)。

六、R2 剩余(本次未做,属同期的另一半)

  1. /admin 路由族 + 删 3 个跳转桩页(web/desktop.html / plugins.html / skills.html,各 247–265 B,title=跳转中…)—— 档案 81 §四表格口径;⚠️ 删桩页必须同时加 301 到 /admin(否则既有书签断)。删后静态页 9 → 6,需同步改 scripts/verify-static.mjs 的页数断言。
  2. 注入层 CSS 类统一为 .dshs-*(档案 81 §四:.__dsh-* / .wk-* → .dshs-*)。

七、回滚

  • 插件侧:把候选池里的 business-plugins 回落 0.2.8(旧 tgz 若已删,可从本机 git 历史取 lib/client.js 重建)。
  • 本轮改动全部在 poc/business-plugins/,未动 src/、未动官方 dsh、未动服务器 ⇒ 回滚只需还原该目录 + 重新投放。

八、口径提醒

⚠️ 不能两头都要(档案 81 §9.2b):若日后要求「弹窗里能完成全部管理动作」,那就等于把整个门户重写进插件(双源维护 + 扩大执行面)⇒ 届时应把门户收敛成 API 客户端,而不是继续复制 UI。# 82 · R2 管理面就地化(原生「平台管理」分区)

  • 日期:2026-09-13
  • 状态:🚧 代码完成、产物已出;待投放 + 启用 + 浏览器验收
  • 触发:档案 81 §四 R2(原「实例内弹窗 iframe」);形态经用户 2026-09-13 拍板改为原生弹窗(§9.2b)
  • 原则:只读优先(写操作回跳平台域);不改官方 dsh;不把门户 UI 复制进插件

TL;DR|① R2 的 R5 权限影响评估已在档案 81 §9.2 出齐并获批(扩大点=实例内出现可操作的管理入口 ⇒ 仅 admin 可见 + 只读 + 写操作回跳); ② 本轮把「平台管理」分区写进 @dsh-local/business-plugins 插件(原生渲染,非 iframe)—— 数据直接调平台只读 API; ③ 产物 dsh-local-business-plugins-0.2.9.tgz 已出(node --check 通过、包结构合规); ④ 未做:投放候选池 / 实例启用 / 浏览器验收(卡在需要 admin 登录态,见 §五);/admin 路由族 + 删 3 桩页 亦未做。


一、形态(与档案 81 §9.2b 一致)

维度 取值
渲染 原生渲染(复用插件自有 token --dsw-* + 06-工作台UI规范 字号阶梯),非 iframe
数据 直接调平台只读 API(跨子域 fetch + credentials: "include",门户 CORS 白名单已就绪)
范围 只读子集:实例 / 熔断 / 用户 / 存储 / 候选池 / 运行时
写操作 一律回跳平台管理台(portalHost() + "/portal.html")—— 不复制门户写 UI(否则双源维护 + 与档案 39「收窄执行面」相冲)
可见性 仅 admin:先 GET /api/auth/me 判 role === "admin",否则只渲染一行说明
落点 poc/business-plugins/lib/client.js(设置面板 settings.section,id: platform-admin, order: 102)

二、改了哪些文件

文件 改动
poc/business-plugins/lib/client.js 895 → 1083 行:① zh/en 词典各 +29 个 pa.* 键;② 新增 PaCard(指标卡)+ PlatformAdminSection;③ 新增一个 settings.section 注册(platform-admin)
poc/business-plugins/package.json 版本 0.2.8 → 0.2.9
产物 dsh-local-business-plugins-0.2.9.tgz(16,712 B;顶层仅 package/;无 .tgz/node_modules/.bak)

三、数据来源(均为平台既有路由,零新增后端)

卡片 API 权限
角色门禁 GET /api/auth/me requireAuth
当前实例 / 熔断 GET /api/dsh/status requireAuth
用户 GET /api/admin/users requireAdmin
存储 GET /api/admin/storage requireAdmin
候选池 GET /api/plugins/business requireAdmin
运行时 GET /api/admin/runtime requireAdmin

全部只读;任一失败降级为 null 并照常渲染其余卡片(不整页报错)。

四、已验证 / 未验证

项 状态 证据
语法 ✅ node --check lib/client.js 通过
包结构 ✅ 顶层仅 package/;4 条目;无违规文件;lib/client.js 在内
词条键集 ✅ zh/en 各 +29 键,键名一一对应
渲染 / 交互 / 权限门禁 ⏸ 未验证 需投放 + 启用(见 §五)

五、⛔ 未完成:投放与验收需要 admin 登录态

  • 投放走 POST /api/plugins/business(requireAdmin)⇒ 必须有 admin 的会话。
  • 平台 CLI 只有 start / bootstrap-admin / file-service,无投放命令;文档内无测试口令 ⇒ 执行会话拿不到凭据。
  • 三条可选路径(待用户定):① 用户自己在门户投放(2 分钟);② 给 admin 口令;③ 用 bootstrap-admin 建临时 admin,用完删(会动生产 auth)。

六、R2 剩余(本次未做,属同期的另一半)

  1. /admin 路由族 + 删 3 个跳转桩页(web/desktop.html / plugins.html / skills.html,各 247–265 B,title=跳转中…)—— 档案 81 §四表格口径;⚠️ 删桩页必须同时加 301 到 /admin(否则既有书签断)。删后静态页 9 → 6,需同步改 scripts/verify-static.mjs 的页数断言。
  2. 注入层 CSS 类统一为 .dshs-*(档案 81 §四:.__dsh-* / .wk-* → .dshs-*)。

七、回滚

  • 插件侧:把候选池里的 business-plugins 回落 0.2.8(旧 tgz 若已删,可从本机 git 历史取 lib/client.js 重建)。
  • 本轮改动全部在 poc/business-plugins/,未动 src/、未动官方 dsh、未动服务器 ⇒ 回滚只需还原该目录 + 重新投放。

八、口径提醒

⚠️ 不能两头都要(档案 81 §9.2b):若日后要求「弹窗里能完成全部管理动作」,那就等于把整个门户重写进插件(双源维护 + 扩大执行面)⇒ 届时应把门户收敛成 API 客户端,而不是继续复制 UI。


九、追加(2026-09-13 18:1x–19:2x):部署完成 + 无浏览器渲染验收通过 + 一并做掉档案 80 第 7 项

9.1 部署链路(关键:不走候选池)

@dsh-local/business-plugins 不是池内插件 —— 它由 scripts/ensure-biz-plugins.cjs 铺发:从 /opt/dsh/artifacts/ 取版本号最大的 business-plugins-*.tgz(--all 含 admin;--restart 让 bundle 生效)。

步 结果
投放产物 business-plugins-0.2.9.tgz → /opt/dsh/artifacts/(前一版为 0.2.8)
铺发 node scripts/ensure-biz-plugins.cjs --all --restart ⇒ admin 与 guest 的 profile 均 0.2.8 → 0.2.9、bundles 均含该包 ✓
磁盘层断言 两实例 node_modules/@dsh-local/business-plugins/lib/client.js 含「平台管理」× 5 ✓
实例 两实例均已重启并 running;实例页 HTTP 200 ✓

9.2 渲染验收:改用无浏览器 harness(因 agent-browser daemon 起不来)

  • ⚠️ 本机 [email protected] 的 daemon 起不来:open 挂住且零输出(--version / node -e 均正常;~/.agent-browser 里留下的 default.port 实测不通、清掉僵尸状态后仍不通)。Chrome 153 已由 agent-browser install 装好,但 daemon 不通 ⇒ 浏览器截图验收受阻(属环境问题,未解)。
  • ⚠️ 06-工作台UI规范 §7.3 的三段式在按需动态加载的 bundle 上拿不到带 rev 的完整 URL(该 bundle 不出现在实例首页 HTML 里)⇒ ②③ 段也不适用。
  • ✅ 替代做法(已沉淀为可复跑脚本):scripts/verify-platform-admin-section.mjs —— 打桩 react / react/jsx-runtime + 最小 hooks 渲染循环 + 真执行 client.js,直接断言结构与门禁。
✓ 注册了两个 settings.section  -> business-plugins, platform-admin
✓ 存在 platform-admin 分区    ✓ 其 order = 102
✓ admin:含分区标题「平台管理」  ✓ admin:6 张卡齐全  ✓ admin:含只读声明
✓ 非 admin:被门禁挡住         ✓ 非 admin:不出现任何指标卡
结论:全绿 ✅   exit=0

admin 视角实际渲染文本(实测):

平台管理 | 只读 | 本分区为只读;写操作请在平台管理台完成。 当前实例 | 运行中 | 端口 43095 · 自动重启 2 | 熔断 | 正常 | — 用户 | 4 | 待审核 1 · 已禁用 1 | 存储 | 2 | 报告每小时刷新 候选池 | 3 | 已投放插件 | 运行时 | 5 | 条目 | 打开完整管理台

已接入 npm run verify(&& node scripts/verify-platform-admin-section.mjs)⇒ 今后 UI 改动可 CI 式防回归。

9.3 一并做掉:档案 80 第 7 项 / 档案 81 §四「删 3 个跳转桩页」

  • 删 web/{desktop,plugins,skills}.html ⇒ 静态页 9 → 6 ✓;改 5 处引用(admin.html / index.html / login.html×2 / dsh.ts 注释)。verify-static.mjs 是自动发现页面的,无需改。
  • nginx alotbuy.com.conf 两个 server 块各加 3 条精确匹配 301 ⇒ 实测 /desktop.html→301 /portal.html、/plugins.html→#/plugins、/skills.html→#/skills ✓;login.html 仍 200 ✓。
  • ⚠️ 本机 nginx 由宝塔托管:systemctl reload nginx 失效,须用 nginx -s reload。

9.4 🔴 期间修掉一个由本次改名引入的真回归(如实记录)

  • 症状:admin 实例页 502,journal = plugin tree failed to load … corrupt session log。
  • 根因:会话日志是 session.jsonl.zstd(zstd 压缩)。改名只改了目录名与纯文本文件,压缩流 header 里的 cwd 仍是旧路径 ⇒ dsh 启动做一致性校验(header cwd vs 目录推导 cwd)不匹配 ⇒ 抛错 ⇒ 插件树加载失败 ⇒ 崩溃循环。
  • 修复:_fix_sesslog.cjs(node 内置 zlib.zstdDecompressSync/zstdCompressSync,22.15+)—— 解压 → 替换 → 重压 → 回读校验。26 个文件 24 个待修 → 全修完,复查 0 残留 ✓;实例恢复 200,corrupt session log 归零。
  • 📌 教训:压缩文件里的路径 grep/sed 够不到 —— 与「SQLite 改名必须带 -wal/-shm」同类。已写进项目 MEMORY.md 铁律。

9.5 期间发现的两个平台缺陷(待修)

  1. op-lock 不可用:锁根 /opt/dsh/state/.op-lock 不存在,且 scripts/op-lock.sh 自身解析 bt-server 失败 ⇒ 它报「已存在 → 停手」是假警报,无法用于互斥。
  2. agent-browser daemon 起不来(见 §9.2)—— 浏览器验收链路的唯一可用工具受阻。

9.6 尚未做

  • D / J / Q(T03 遗留)与登录/注册/门户/设置面板的体验审计(用户 18:1x 关注的第三块)。

82 · R2 管理面就地化(原生「平台管理」分区)

  • 日期:2026-09-13
  • 状态:🚧 代码完成、产物已出;待投放 + 启用 + 浏览器验收
  • 触发:档案 81 §四 R2(原「实例内弹窗 iframe」);形态经用户 2026-09-13 拍板改为原生弹窗(§9.2b)
  • 原则:只读优先(写操作回跳平台域);不改官方 dsh;不把门户 UI 复制进插件

TL;DR|① R2 的 R5 权限影响评估已在档案 81 §9.2 出齐并获批(扩大点=实例内出现可操作的管理入口 ⇒ 仅 admin 可见 + 只读 + 写操作回跳); ② 本轮把「平台管理」分区写进 @dsh-local/business-plugins 插件(原生渲染,非 iframe)—— 数据直接调平台只读 API; ③ 产物 dsh-local-business-plugins-0.2.9.tgz 已出(node --check 通过、包结构合规); ④ 未做:投放候选池 / 实例启用 / 浏览器验收(卡在需要 admin 登录态,见 §五);/admin 路由族 + 删 3 桩页 亦未做。


一、形态(与档案 81 §9.2b 一致)

维度 取值
渲染 原生渲染(复用插件自有 token --dsw-* + 06-工作台UI规范 字号阶梯),非 iframe
数据 直接调平台只读 API(跨子域 fetch + credentials: "include",门户 CORS 白名单已就绪)
范围 只读子集:实例 / 熔断 / 用户 / 存储 / 候选池 / 运行时
写操作 一律回跳平台管理台(portalHost() + "/portal.html")—— 不复制门户写 UI(否则双源维护 + 与档案 39「收窄执行面」相冲)
可见性 仅 admin:先 GET /api/auth/me 判 role === "admin",否则只渲染一行说明
落点 poc/business-plugins/lib/client.js(设置面板 settings.section,id: platform-admin, order: 102)

二、改了哪些文件

文件 改动
poc/business-plugins/lib/client.js 895 → 1083 行:① zh/en 词典各 +29 个 pa.* 键;② 新增 PaCard(指标卡)+ PlatformAdminSection;③ 新增一个 settings.section 注册(platform-admin)
poc/business-plugins/package.json 版本 0.2.8 → 0.2.9
产物 dsh-local-business-plugins-0.2.9.tgz(16,712 B;顶层仅 package/;无 .tgz/node_modules/.bak)

三、数据来源(均为平台既有路由,零新增后端)

卡片 API 权限
角色门禁 GET /api/auth/me requireAuth
当前实例 / 熔断 GET /api/dsh/status requireAuth
用户 GET /api/admin/users requireAdmin
存储 GET /api/admin/storage requireAdmin
候选池 GET /api/plugins/business requireAdmin
运行时 GET /api/admin/runtime requireAdmin

全部只读;任一失败降级为 null 并照常渲染其余卡片(不整页报错)。

四、已验证 / 未验证

项 状态 证据
语法 ✅ node --check lib/client.js 通过
包结构 ✅ 顶层仅 package/;4 条目;无违规文件;lib/client.js 在内
词条键集 ✅ zh/en 各 +29 键,键名一一对应
渲染 / 交互 / 权限门禁 ⏸ 未验证 需投放 + 启用(见 §五)

五、⛔ 未完成:投放与验收需要 admin 登录态

  • 投放走 POST /api/plugins/business(requireAdmin)⇒ 必须有 admin 的会话。
  • 平台 CLI 只有 start / bootstrap-admin / file-service,无投放命令;文档内无测试口令 ⇒ 执行会话拿不到凭据。
  • 三条可选路径(待用户定):① 用户自己在门户投放(2 分钟);② 给 admin 口令;③ 用 bootstrap-admin 建临时 admin,用完删(会动生产 auth)。

六、R2 剩余(本次未做,属同期的另一半)

  1. /admin 路由族 + 删 3 个跳转桩页(web/desktop.html / plugins.html / skills.html,各 247–265 B,title=跳转中…)—— 档案 81 §四表格口径;⚠️ 删桩页必须同时加 301 到 /admin(否则既有书签断)。删后静态页 9 → 6,需同步改 scripts/verify-static.mjs 的页数断言。
  2. 注入层 CSS 类统一为 .dshs-*(档案 81 §四:.__dsh-* / .wk-* → .dshs-*)。

七、回滚

  • 插件侧:把候选池里的 business-plugins 回落 0.2.8(旧 tgz 若已删,可从本机 git 历史取 lib/client.js 重建)。
  • 本轮改动全部在 poc/business-plugins/,未动 src/、未动官方 dsh、未动服务器 ⇒ 回滚只需还原该目录 + 重新投放。

八、口径提醒

⚠️ 不能两头都要(档案 81 §9.2b):若日后要求「弹窗里能完成全部管理动作」,那就等于把整个门户重写进插件(双源维护 + 扩大执行面)⇒ 届时应把门户收敛成 API 客户端,而不是继续复制 UI。# 82 · R2 管理面就地化(原生「平台管理」分区)

  • 日期:2026-09-13
  • 状态:🚧 代码完成、产物已出;待投放 + 启用 + 浏览器验收
  • 触发:档案 81 §四 R2(原「实例内弹窗 iframe」);形态经用户 2026-09-13 拍板改为原生弹窗(§9.2b)
  • 原则:只读优先(写操作回跳平台域);不改官方 dsh;不把门户 UI 复制进插件

TL;DR|① R2 的 R5 权限影响评估已在档案 81 §9.2 出齐并获批(扩大点=实例内出现可操作的管理入口 ⇒ 仅 admin 可见 + 只读 + 写操作回跳); ② 本轮把「平台管理」分区写进 @dsh-local/business-plugins 插件(原生渲染,非 iframe)—— 数据直接调平台只读 API; ③ 产物 dsh-local-business-plugins-0.2.9.tgz 已出(node --check 通过、包结构合规); ④ 未做:投放候选池 / 实例启用 / 浏览器验收(卡在需要 admin 登录态,见 §五);/admin 路由族 + 删 3 桩页 亦未做。


一、形态(与档案 81 §9.2b 一致)

维度 取值
渲染 原生渲染(复用插件自有 token --dsw-* + 06-工作台UI规范 字号阶梯),非 iframe
数据 直接调平台只读 API(跨子域 fetch + credentials: "include",门户 CORS 白名单已就绪)
范围 只读子集:实例 / 熔断 / 用户 / 存储 / 候选池 / 运行时
写操作 一律回跳平台管理台(portalHost() + "/portal.html")—— 不复制门户写 UI(否则双源维护 + 与档案 39「收窄执行面」相冲)
可见性 仅 admin:先 GET /api/auth/me 判 role === "admin",否则只渲染一行说明
落点 poc/business-plugins/lib/client.js(设置面板 settings.section,id: platform-admin, order: 102)

二、改了哪些文件

文件 改动
poc/business-plugins/lib/client.js 895 → 1083 行:① zh/en 词典各 +29 个 pa.* 键;② 新增 PaCard(指标卡)+ PlatformAdminSection;③ 新增一个 settings.section 注册(platform-admin)
poc/business-plugins/package.json 版本 0.2.8 → 0.2.9
产物 dsh-local-business-plugins-0.2.9.tgz(16,712 B;顶层仅 package/;无 .tgz/node_modules/.bak)

三、数据来源(均为平台既有路由,零新增后端)

卡片 API 权限
角色门禁 GET /api/auth/me requireAuth
当前实例 / 熔断 GET /api/dsh/status requireAuth
用户 GET /api/admin/users requireAdmin
存储 GET /api/admin/storage requireAdmin
候选池 GET /api/plugins/business requireAdmin
运行时 GET /api/admin/runtime requireAdmin

全部只读;任一失败降级为 null 并照常渲染其余卡片(不整页报错)。

四、已验证 / 未验证

项 状态 证据
语法 ✅ node --check lib/client.js 通过
包结构 ✅ 顶层仅 package/;4 条目;无违规文件;lib/client.js 在内
词条键集 ✅ zh/en 各 +29 键,键名一一对应
渲染 / 交互 / 权限门禁 ⏸ 未验证 需投放 + 启用(见 §五)

五、⛔ 未完成:投放与验收需要 admin 登录态

  • 投放走 POST /api/plugins/business(requireAdmin)⇒ 必须有 admin 的会话。
  • 平台 CLI 只有 start / bootstrap-admin / file-service,无投放命令;文档内无测试口令 ⇒ 执行会话拿不到凭据。
  • 三条可选路径(待用户定):① 用户自己在门户投放(2 分钟);② 给 admin 口令;③ 用 bootstrap-admin 建临时 admin,用完删(会动生产 auth)。

六、R2 剩余(本次未做,属同期的另一半)

  1. /admin 路由族 + 删 3 个跳转桩页(web/desktop.html / plugins.html / skills.html,各 247–265 B,title=跳转中…)—— 档案 81 §四表格口径;⚠️ 删桩页必须同时加 301 到 /admin(否则既有书签断)。删后静态页 9 → 6,需同步改 scripts/verify-static.mjs 的页数断言。
  2. 注入层 CSS 类统一为 .dshs-*(档案 81 §四:.__dsh-* / .wk-* → .dshs-*)。

七、回滚

  • 插件侧:把候选池里的 business-plugins 回落 0.2.8(旧 tgz 若已删,可从本机 git 历史取 lib/client.js 重建)。
  • 本轮改动全部在 poc/business-plugins/,未动 src/、未动官方 dsh、未动服务器 ⇒ 回滚只需还原该目录 + 重新投放。

八、口径提醒

⚠️ 不能两头都要(档案 81 §9.2b):若日后要求「弹窗里能完成全部管理动作」,那就等于把整个门户重写进插件(双源维护 + 扩大执行面)⇒ 届时应把门户收敛成 API 客户端,而不是继续复制 UI。


九、追加(2026-09-13 18:1x–19:2x):部署完成 + 无浏览器渲染验收通过 + 一并做掉档案 80 第 7 项

9.1 部署链路(关键:不走候选池)

@dsh-local/business-plugins 不是池内插件 —— 它由 scripts/ensure-biz-plugins.cjs 铺发:从 /opt/dsh/artifacts/ 取版本号最大的 business-plugins-*.tgz(--all 含 admin;--restart 让 bundle 生效)。

步 结果
投放产物 business-plugins-0.2.9.tgz → /opt/dsh/artifacts/(前一版为 0.2.8)
铺发 node scripts/ensure-biz-plugins.cjs --all --restart ⇒ admin 与 guest 的 profile 均 0.2.8 → 0.2.9、bundles 均含该包 ✓
磁盘层断言 两实例 node_modules/@dsh-local/business-plugins/lib/client.js 含「平台管理」× 5 ✓
实例 两实例均已重启并 running;实例页 HTTP 200 ✓

9.2 渲染验收:改用无浏览器 harness(因 agent-browser daemon 起不来)

  • ⚠️ 本机 [email protected] 的 daemon 起不来:open 挂住且零输出(--version / node -e 均正常;~/.agent-browser 里留下的 default.port 实测不通、清掉僵尸状态后仍不通)。Chrome 153 已由 agent-browser install 装好,但 daemon 不通 ⇒ 浏览器截图验收受阻(属环境问题,未解)。
  • ⚠️ 06-工作台UI规范 §7.3 的三段式在按需动态加载的 bundle 上拿不到带 rev 的完整 URL(该 bundle 不出现在实例首页 HTML 里)⇒ ②③ 段也不适用。
  • ✅ 替代做法(已沉淀为可复跑脚本):scripts/verify-platform-admin-section.mjs —— 打桩 react / react/jsx-runtime + 最小 hooks 渲染循环 + 真执行 client.js,直接断言结构与门禁。
✓ 注册了两个 settings.section  -> business-plugins, platform-admin
✓ 存在 platform-admin 分区    ✓ 其 order = 102
✓ admin:含分区标题「平台管理」  ✓ admin:6 张卡齐全  ✓ admin:含只读声明
✓ 非 admin:被门禁挡住         ✓ 非 admin:不出现任何指标卡
结论:全绿 ✅   exit=0

admin 视角实际渲染文本(实测):

平台管理 | 只读 | 本分区为只读;写操作请在平台管理台完成。 当前实例 | 运行中 | 端口 43095 · 自动重启 2 | 熔断 | 正常 | — 用户 | 4 | 待审核 1 · 已禁用 1 | 存储 | 2 | 报告每小时刷新 候选池 | 3 | 已投放插件 | 运行时 | 5 | 条目 | 打开完整管理台

已接入 npm run verify(&& node scripts/verify-platform-admin-section.mjs)⇒ 今后 UI 改动可 CI 式防回归。

9.3 一并做掉:档案 80 第 7 项 / 档案 81 §四「删 3 个跳转桩页」

  • 删 web/{desktop,plugins,skills}.html ⇒ 静态页 9 → 6 ✓;改 5 处引用(admin.html / index.html / login.html×2 / dsh.ts 注释)。verify-static.mjs 是自动发现页面的,无需改。
  • nginx alotbuy.com.conf 两个 server 块各加 3 条精确匹配 301 ⇒ 实测 /desktop.html→301 /portal.html、/plugins.html→#/plugins、/skills.html→#/skills ✓;login.html 仍 200 ✓。
  • ⚠️ 本机 nginx 由宝塔托管:systemctl reload nginx 失效,须用 nginx -s reload。

9.4 🔴 期间修掉一个由本次改名引入的真回归(如实记录)

  • 症状:admin 实例页 502,journal = plugin tree failed to load … corrupt session log。
  • 根因:会话日志是 session.jsonl.zstd(zstd 压缩)。改名只改了目录名与纯文本文件,压缩流 header 里的 cwd 仍是旧路径 ⇒ dsh 启动做一致性校验(header cwd vs 目录推导 cwd)不匹配 ⇒ 抛错 ⇒ 插件树加载失败 ⇒ 崩溃循环。
  • 修复:_fix_sesslog.cjs(node 内置 zlib.zstdDecompressSync/zstdCompressSync,22.15+)—— 解压 → 替换 → 重压 → 回读校验。26 个文件 24 个待修 → 全修完,复查 0 残留 ✓;实例恢复 200,corrupt session log 归零。
  • 📌 教训:压缩文件里的路径 grep/sed 够不到 —— 与「SQLite 改名必须带 -wal/-shm」同类。已写进项目 MEMORY.md 铁律。

9.5 期间发现的两个平台缺陷(待修)

  1. op-lock 不可用:锁根 /opt/dsh/state/.op-lock 不存在,且 scripts/op-lock.sh 自身解析 bt-server 失败 ⇒ 它报「已存在 → 停手」是假警报,无法用于互斥。
  2. agent-browser daemon 起不来(见 §9.2)—— 浏览器验收链路的唯一可用工具受阻。

9.6 尚未做

  • D / J / Q(T03 遗留)与登录/注册/门户/设置面板的体验审计(用户 18:1x 关注的第三块)。

十、追加(2026-09-13 19:3x–19:5x):从「只读」升级为「就地全量管理」(用户要求)

10.1 用户的三条要求

  1. dsh 设置里的「用户管理」改名为「用户设置」,且去掉里面的「打开管理平台」入口
  2. 「平台管理」不要再跳新页面 —— 把所有管理项都放进「系统管理」,每项点开是弹窗

10.2 落地

项 改动 产物
「用户管理」→「用户设置」 @dsh-local/portal-entry:section id: user-management → user-settings、label 改名、order 102 → 103(让位给平台管理);删除「打开管理台」按钮;内容改为「账号:<用户名> 角色:<管理员/普通用户>」+ 退出登录 portal-entry-0.5.2.tgz(已铺发到 admin+guest)
「平台管理」→「系统管理」+ 管理项 + 弹窗 @dsh-local/business-plugins:删掉 window.open(portal.html) 跳转按钮;分区改为「管理项列表」,5 项(用户管理 / 候选池 / 运行时 / 存储 / 当前实例)每项点开是原生弹窗;用户管理弹窗内可直接 通过 / 禁用 / 启用 / 删除(调平台既有 admin API,不跳门户) business-plugins-0.3.0.tgz(已铺发)

10.3 验收(npm run verify 内)

✓ 注册了两个 settings.section  -> business-plugins, platform-admin
✓ admin:含分区标题「系统管理」   ✓ admin:5 个管理项齐全
✓ admin:不再是只读(提示改为弹窗内管理)
✓ 非 admin:被门禁挡住            ✓ 非 admin:不出现任何管理项
结论:全绿 ✅

另:磁盘复核 —— 两 profile 的 business-plugins 均 0.3.0、含「系统管理」、window.open 计数 = 0(跳新页彻底移除)✓

10.4 尚未做的(下一批)

  • 弹窗内目前只有「用户管理」是可写的;候选池 / 运行时 / 存储 / 实例 三项为只读列表(写操作待补)。
  • portal-entry 源码不在仓库(只有铺发脚本 + artifacts 里的 tgz)⇒ 本次是在产物上改的。建议:把 portal-entry/business-plugins 源码纳入仓库(档案 75 · B5 的旧账)。

82 · R2 管理面就地化(原生「平台管理」分区)

  • 日期:2026-09-13
  • 状态:🚧 代码完成、产物已出;待投放 + 启用 + 浏览器验收
  • 触发:档案 81 §四 R2(原「实例内弹窗 iframe」);形态经用户 2026-09-13 拍板改为原生弹窗(§9.2b)
  • 原则:只读优先(写操作回跳平台域);不改官方 dsh;不把门户 UI 复制进插件

TL;DR|① R2 的 R5 权限影响评估已在档案 81 §9.2 出齐并获批(扩大点=实例内出现可操作的管理入口 ⇒ 仅 admin 可见 + 只读 + 写操作回跳); ② 本轮把「平台管理」分区写进 @dsh-local/business-plugins 插件(原生渲染,非 iframe)—— 数据直接调平台只读 API; ③ 产物 dsh-local-business-plugins-0.2.9.tgz 已出(node --check 通过、包结构合规); ④ 未做:投放候选池 / 实例启用 / 浏览器验收(卡在需要 admin 登录态,见 §五);/admin 路由族 + 删 3 桩页 亦未做。


一、形态(与档案 81 §9.2b 一致)

维度 取值
渲染 原生渲染(复用插件自有 token --dsw-* + 06-工作台UI规范 字号阶梯),非 iframe
数据 直接调平台只读 API(跨子域 fetch + credentials: "include",门户 CORS 白名单已就绪)
范围 只读子集:实例 / 熔断 / 用户 / 存储 / 候选池 / 运行时
写操作 一律回跳平台管理台(portalHost() + "/portal.html")—— 不复制门户写 UI(否则双源维护 + 与档案 39「收窄执行面」相冲)
可见性 仅 admin:先 GET /api/auth/me 判 role === "admin",否则只渲染一行说明
落点 poc/business-plugins/lib/client.js(设置面板 settings.section,id: platform-admin, order: 102)

二、改了哪些文件

文件 改动
poc/business-plugins/lib/client.js 895 → 1083 行:① zh/en 词典各 +29 个 pa.* 键;② 新增 PaCard(指标卡)+ PlatformAdminSection;③ 新增一个 settings.section 注册(platform-admin)
poc/business-plugins/package.json 版本 0.2.8 → 0.2.9
产物 dsh-local-business-plugins-0.2.9.tgz(16,712 B;顶层仅 package/;无 .tgz/node_modules/.bak)

三、数据来源(均为平台既有路由,零新增后端)

卡片 API 权限
角色门禁 GET /api/auth/me requireAuth
当前实例 / 熔断 GET /api/dsh/status requireAuth
用户 GET /api/admin/users requireAdmin
存储 GET /api/admin/storage requireAdmin
候选池 GET /api/plugins/business requireAdmin
运行时 GET /api/admin/runtime requireAdmin

全部只读;任一失败降级为 null 并照常渲染其余卡片(不整页报错)。

四、已验证 / 未验证

项 状态 证据
语法 ✅ node --check lib/client.js 通过
包结构 ✅ 顶层仅 package/;4 条目;无违规文件;lib/client.js 在内
词条键集 ✅ zh/en 各 +29 键,键名一一对应
渲染 / 交互 / 权限门禁 ⏸ 未验证 需投放 + 启用(见 §五)

五、⛔ 未完成:投放与验收需要 admin 登录态

  • 投放走 POST /api/plugins/business(requireAdmin)⇒ 必须有 admin 的会话。
  • 平台 CLI 只有 start / bootstrap-admin / file-service,无投放命令;文档内无测试口令 ⇒ 执行会话拿不到凭据。
  • 三条可选路径(待用户定):① 用户自己在门户投放(2 分钟);② 给 admin 口令;③ 用 bootstrap-admin 建临时 admin,用完删(会动生产 auth)。

六、R2 剩余(本次未做,属同期的另一半)

  1. /admin 路由族 + 删 3 个跳转桩页(web/desktop.html / plugins.html / skills.html,各 247–265 B,title=跳转中…)—— 档案 81 §四表格口径;⚠️ 删桩页必须同时加 301 到 /admin(否则既有书签断)。删后静态页 9 → 6,需同步改 scripts/verify-static.mjs 的页数断言。
  2. 注入层 CSS 类统一为 .dshs-*(档案 81 §四:.__dsh-* / .wk-* → .dshs-*)。

七、回滚

  • 插件侧:把候选池里的 business-plugins 回落 0.2.8(旧 tgz 若已删,可从本机 git 历史取 lib/client.js 重建)。
  • 本轮改动全部在 poc/business-plugins/,未动 src/、未动官方 dsh、未动服务器 ⇒ 回滚只需还原该目录 + 重新投放。

八、口径提醒

⚠️ 不能两头都要(档案 81 §9.2b):若日后要求「弹窗里能完成全部管理动作」,那就等于把整个门户重写进插件(双源维护 + 扩大执行面)⇒ 届时应把门户收敛成 API 客户端,而不是继续复制 UI。# 82 · R2 管理面就地化(原生「平台管理」分区)

  • 日期:2026-09-13
  • 状态:🚧 代码完成、产物已出;待投放 + 启用 + 浏览器验收
  • 触发:档案 81 §四 R2(原「实例内弹窗 iframe」);形态经用户 2026-09-13 拍板改为原生弹窗(§9.2b)
  • 原则:���读优先(写操作回跳平台域);不改官方 dsh;不把门户 UI 复制进插件

TL;DR|① R2 的 R5 权限影响评估已在档案 81 §9.2 出齐并获批(扩大点=实例内出现可操作的管理入口 ⇒ 仅 admin 可见 + 只读 + 写操作回跳); ② 本轮把「平台管理」分区写进 @dsh-local/business-plugins 插件(原生渲染,非 iframe)—— 数据直接调平台只读 API; ③ 产物 dsh-local-business-plugins-0.2.9.tgz 已出(node --check 通过、包结构合规); ④ 未做:投放候选池 / 实例启用 / 浏览器验收(卡在需要 admin 登录态,见 §五);/admin 路由族 + 删 3 桩页 亦未做。


一、形态(与档案 81 §9.2b 一致)

维度 取值
渲染 原生渲染(复用插件自有 token --dsw-* + 06-工作台UI规范 字号阶梯),非 iframe
数据 直接调平台只读 API(跨子域 fetch + credentials: "include",门户 CORS 白名单已就绪)
范围 只读子集:实例 / 熔断 / 用户 / 存储 / 候选池 / 运行时
写操作 一律回跳平台管理台(portalHost() + "/portal.html")—— 不复制门户写 UI(否则双源维护 + 与档案 39「收窄执行面」相冲)
可见性 仅 admin:先 GET /api/auth/me 判 role === "admin",否则只渲染一行说明
落点 poc/business-plugins/lib/client.js(设置面板 settings.section,id: platform-admin, order: 102)

二、改了哪些文件

文件 改动
poc/business-plugins/lib/client.js 895 → 1083 行:① zh/en 词典各 +29 个 pa.* 键;② 新增 PaCard(指标卡)+ PlatformAdminSection;③ 新增一个 settings.section 注册(platform-admin)
poc/business-plugins/package.json 版本 0.2.8 → 0.2.9
产物 dsh-local-business-plugins-0.2.9.tgz(16,712 B;顶层仅 package/;无 .tgz/node_modules/.bak)

三、数据来源(均为平台既有路由,零新增后端)

卡片 API 权限
角色门禁 GET /api/auth/me requireAuth
当前实例 / 熔断 GET /api/dsh/status requireAuth
用户 GET /api/admin/users requireAdmin
存储 GET /api/admin/storage requireAdmin
候选池 GET /api/plugins/business requireAdmin
运行时 GET /api/admin/runtime requireAdmin

全部只读;任一失败降级为 null 并照常渲染其余卡片(不整页报错)。

四、已验证 / 未验证

项 状态 证据
语法 ✅ node --check lib/client.js 通过
包结构 ✅ 顶层仅 package/;4 条目;无违规文件;lib/client.js 在内
词条键集 ✅ zh/en 各 +29 键,键名一一对应
渲染 / 交互 / 权限门禁 ⏸ 未验证 需投放 + 启用(见 §五)

五、⛔ 未完成:投放与验收需要 admin 登录态

  • 投放走 POST /api/plugins/business(requireAdmin)⇒ 必须有 admin 的会话。
  • 平台 CLI 只有 start / bootstrap-admin / file-service,无投放命令;文档内无测试口令 ⇒ 执行会话拿不到凭据。
  • 三条可选路径(待用户定):① 用户自己在门户投放(2 分钟);② 给 admin 口令;③ 用 bootstrap-admin 建临时 admin,用完删(会动生产 auth)。

六、R2 剩余(本次未做,属同期的另一半)

  1. /admin 路由族 + 删 3 个跳转桩页(web/desktop.html / plugins.html / skills.html,各 247–265 B,title=跳转中…)—— 档案 81 §四表格口径;⚠️ 删桩页必须同时加 301 到 /admin(否则既有书签断)。删后静态页 9 → 6,需同步改 scripts/verify-static.mjs 的页数断言。
  2. 注入层 CSS 类统一为 .dshs-*(档案 81 §四:.__dsh-* / .wk-* → .dshs-*)。

七、回滚

  • 插件侧:把候选池里的 business-plugins 回落 0.2.8(旧 tgz 若已删,可从本机 git 历史取 lib/client.js 重建)。
  • 本轮改动全部在 poc/business-plugins/,未动 src/、未动官方 dsh、未动服务器 ⇒ 回滚只需还原该目录 + 重新投放。

八、口径提醒

⚠️ 不能两头都要(档案 81 §9.2b):若日后要求「弹窗里能完成全部管理动作」,那就等于把整个门户重写进插件(双源维护 + 扩大执行面)⇒ 届时应把门户收敛成 API 客户端,而不是继续复制 UI。


九、追加(2026-09-13 18:1x–19:2x):部署完成 + 无浏览器渲染验收通过 + 一并做掉档案 80 第 7 项

9.1 部署链路(关键:不走候选池)

@dsh-local/business-plugins 不是池内插件 —— 它由 scripts/ensure-biz-plugins.cjs 铺发:从 /opt/dsh/artifacts/ 取版本号最大的 business-plugins-*.tgz(--all 含 admin;--restart 让 bundle 生效)。

步 结果
投放产物 business-plugins-0.2.9.tgz → /opt/dsh/artifacts/(前一版为 0.2.8)
铺发 node scripts/ensure-biz-plugins.cjs --all --restart ⇒ admin 与 guest 的 profile 均 0.2.8 → 0.2.9、bundles 均含该包 ✓
磁盘层断言 两实例 node_modules/@dsh-local/business-plugins/lib/client.js 含「平台管理」× 5 ✓
实例 两实例均已重启并 running;实例页 HTTP 200 ✓

9.2 渲染验收:改用无浏览器 harness(因 agent-browser daemon 起不来)

  • ⚠️ 本机 [email protected] 的 daemon 起不来:open 挂住且零输出(--version / node -e 均正常;~/.agent-browser 里留下的 default.port 实测不通、清掉僵尸状态后仍不通)。Chrome 153 已由 agent-browser install 装好,但 daemon 不通 ⇒ 浏览器截图验收受阻(属环境问题,未解)。
  • ⚠️ 06-工作台UI规范 §7.3 的三段式在按需动态加载的 bundle 上拿不到带 rev 的完整 URL(该 bundle 不出现在实例首页 HTML 里)⇒ ②③ 段也不适用。
  • ✅ 替代做法(已沉淀为可复跑脚本):scripts/verify-platform-admin-section.mjs —— 打桩 react / react/jsx-runtime + 最小 hooks 渲染循环 + 真执行 client.js,直接断言结构与门禁。
✓ 注册了两个 settings.section  -> business-plugins, platform-admin
✓ 存在 platform-admin 分区    ✓ 其 order = 102
✓ admin:含分区标题「平台管理」  ✓ admin:6 张卡齐全  ✓ admin:含只读声明
✓ 非 admin:被门禁挡住         ✓ 非 admin:不出现任何指标卡
结论:全绿 ✅   exit=0

admin 视角实际渲染文本(实测):

平台管理 | 只读 | 本分区为只读;写操作请在平台管理台完成。 当前实例 | 运行中 | 端口 43095 · 自动重启 2 | 熔断 | 正常 | — 用户 | 4 | 待审核 1 · 已禁用 1 | 存储 | 2 | 报告每小时刷新 候选池 | 3 | 已投放插件 | 运行时 | 5 | 条目 | 打开完整管理台

已接入 npm run verify(&& node scripts/verify-platform-admin-section.mjs)⇒ 今后 UI 改动可 CI 式防回归。

9.3 一并做掉:档案 80 第 7 项 / 档案 81 §四「删 3 个跳转桩页」

  • 删 web/{desktop,plugins,skills}.html ⇒ 静态页 9 → 6 ✓;改 5 处引用(admin.html / index.html / login.html×2 / dsh.ts 注释)。verify-static.mjs 是自动发现页面的,无需改。
  • nginx alotbuy.com.conf 两个 server 块各加 3 条精确匹配 301 ⇒ 实测 /desktop.html→301 /portal.html、/plugins.html→#/plugins、/skills.html→#/skills ✓;login.html 仍 200 ✓。
  • ⚠️ 本机 nginx 由宝塔托管:systemctl reload nginx 失效,须用 nginx -s reload。

9.4 🔴 期间修掉一个由本次改名引入的真回归(如实记录)

  • 症状:admin 实例页 502,journal = plugin tree failed to load … corrupt session log。
  • 根因:会话日志是 session.jsonl.zstd(zstd 压缩)。改名只改了目录名与纯文本文件,压缩流 header 里的 cwd 仍是旧路径 ⇒ dsh 启动做一致性校验(header cwd vs 目录推导 cwd)不匹配 ⇒ 抛错 ⇒ 插件树加载失败 ⇒ 崩溃循环。
  • 修复:_fix_sesslog.cjs(node 内置 zlib.zstdDecompressSync/zstdCompressSync,22.15+)—— 解压 → 替换 → 重压 → 回读校验。26 个文件 24 个待修 → 全修完,复查 0 残留 ✓;实例恢复 200,corrupt session log 归零。
  • 📌 教训:压缩文件里的路径 grep/sed 够不到 —— 与「SQLite 改名必须带 -wal/-shm」同类。已写进项目 MEMORY.md 铁律。

9.5 期间发现的两个平台缺陷(待修)

  1. op-lock 不可用:锁根 /opt/dsh/state/.op-lock 不存在,且 scripts/op-lock.sh 自身解析 bt-server 失败 ⇒ 它报「已存在 → 停手」是假警报,无法用于互斥。
  2. agent-browser daemon 起不来(见 §9.2)—— 浏览器验收链路的唯一可用工具受阻。

9.6 尚未做

  • D / J / Q(T03 遗留)与登录/注册/门户/设置面板的体验审计(用户 18:1x 关注的第三块)。

82 · R2 管理面就地化(原生「平台管理」分区)

  • 日期:2026-09-13
  • 状态:🚧 代码完成、产物已出;待投放 + 启用 + 浏览器验收
  • 触发:档案 81 §四 R2(原「实例内弹窗 iframe」);形态经用户 2026-09-13 拍板改为原生弹窗(§9.2b)
  • 原则:只读优先(写操作回跳平台域);不改官方 dsh;不把门户 UI 复制进插件

TL;DR|① R2 的 R5 权限影响评估已在档案 81 §9.2 出齐并获批(扩大点=实例内出现可操作的管理入口 ⇒ 仅 admin 可见 + 只读 + 写操作回跳); ② 本轮把「平台管理」分区写进 @dsh-local/business-plugins 插件(原生渲染,非 iframe)—— 数据直接调平台只读 API; ③ 产物 dsh-local-business-plugins-0.2.9.tgz 已出(node --check 通过、包结构合规); ④ 未做:投放候选池 / 实例启用 / 浏览器验收(卡在需要 admin 登录态,见 §五);/admin 路由族 + 删 3 桩页 亦未做。


一、形态(与档案 81 §9.2b 一致)

维度 取值
渲染 原生渲染(复用插件自有 token --dsw-* + 06-工作台UI规范 字号阶梯),非 iframe
数据 直接调平台只读 API(跨子域 fetch + credentials: "include",门户 CORS 白名单已就绪)
范围 只读子集:实例 / 熔断 / 用户 / 存储 / 候选池 / 运行时
写操作 一律回跳平台管理台(portalHost() + "/portal.html")—— 不复制门户写 UI(否则双源维护 + 与档案 39「收窄执行面」相冲)
可见性 仅 admin:先 GET /api/auth/me 判 role === "admin",否则只渲染一行说明
落点 poc/business-plugins/lib/client.js(设置面板 settings.section,id: platform-admin, order: 102)

二、改了哪些文件

文件 改动
poc/business-plugins/lib/client.js 895 → 1083 行:① zh/en 词典各 +29 个 pa.* 键;② 新增 PaCard(指标卡)+ PlatformAdminSection;③ 新增一个 settings.section 注册(platform-admin)
poc/business-plugins/package.json 版本 0.2.8 → 0.2.9
产物 dsh-local-business-plugins-0.2.9.tgz(16,712 B;顶层仅 package/;无 .tgz/node_modules/.bak)

三、数据来源(均为平台既有路由,零新增后端)

卡片 API 权限
角色门禁 GET /api/auth/me requireAuth
当前实例 / 熔断 GET /api/dsh/status requireAuth
用户 GET /api/admin/users requireAdmin
存储 GET /api/admin/storage requireAdmin
候选池 GET /api/plugins/business requireAdmin
运行时 GET /api/admin/runtime requireAdmin

全部只读;任一失败降级为 null 并照常渲染其余卡片(不整页报错)。

四、已验证 / 未验证

项 状态 证据
语法 ✅ node --check lib/client.js 通过
包结构 ✅ 顶层仅 package/;4 条目;无违规文件;lib/client.js 在内
词条键集 ✅ zh/en 各 +29 键,键名一一对应
渲染 / 交互 / 权限门禁 ⏸ 未验证 需投放 + 启用(见 §五)

五、⛔ 未完成:投放与验收需要 admin 登录态

  • 投放走 POST /api/plugins/business(requireAdmin)⇒ 必须有 admin 的会话。
  • 平台 CLI 只有 start / bootstrap-admin / file-service,无投放命令;文档内无测试口令 ⇒ 执行会话拿不到凭据。
  • 三条可选路径(待用户定):① 用户自己在门户投放(2 分钟);② 给 admin 口令;③ 用 bootstrap-admin 建临时 admin,用完删(会动生产 auth)。

六、R2 剩余(本次未做,属同期的另一半)

  1. /admin 路由族 + 删 3 个跳转桩页(web/desktop.html / plugins.html / skills.html,各 247–265 B,title=跳转中…)—— 档案 81 §四表格口径;⚠️ 删桩页必须同时加 301 到 /admin(否则既有书签断)。删后静态页 9 → 6,需同步改 scripts/verify-static.mjs 的页数断言。
  2. 注入层 CSS 类统一为 .dshs-*(档案 81 §四:.__dsh-* / .wk-* → .dshs-*)。

七、回滚

  • 插件侧:把候选池里的 business-plugins 回落 0.2.8(旧 tgz 若已删,可从本机 git 历史取 lib/client.js 重建)。
  • 本轮改动全部在 poc/business-plugins/,未动 src/、未动官方 dsh、未动服务器 ⇒ 回滚只需还原该目录 + 重新投放。

八、口径提醒

⚠️ 不能两头都要(档案 81 §9.2b):若日后要求「弹窗里能完成全部管理动作」,那就等于把整个门户重写进插件(双源维护 + 扩大执行面)⇒ 届时应把门户收敛成 API 客户端,而不是继续复制 UI。# 82 · R2 管理面就地化(原生「平台管理」分区)

  • 日期:2026-09-13
  • 状态:🚧 代码完成、产物已出;待投放 + 启用 + 浏览器验收
  • 触发:档案 81 §四 R2(原「实例内弹窗 iframe」);形态经用户 2026-09-13 拍板改为原生弹窗(§9.2b)
  • 原则:只读优先(写操作回跳平台域);不改官方 dsh;不把门户 UI 复制进插件

TL;DR|① R2 的 R5 权限影响评估已在档案 81 §9.2 出齐并获批(扩大点=实例内出现可操作的管理入口 ⇒ 仅 admin 可见 + 只读 + 写操作回跳); ② 本轮把「平台管理」分区写进 @dsh-local/business-plugins 插件(原生渲染,非 iframe)—— 数据直接调平台只读 API; ③ 产物 dsh-local-business-plugins-0.2.9.tgz 已出(node --check 通过、包结构合规); ④ 未做:投放候选池 / 实例启用 / 浏览器验收(卡在需要 admin 登录态,见 §五);/admin 路由族 + 删 3 桩页 亦未做。


一、形态(与档案 81 §9.2b 一致)

维度 取值
渲染 原生渲染(复用插件自有 token --dsw-* + 06-工作台UI规范 字号阶梯),非 iframe
数据 直接调平台只读 API(跨子域 fetch + credentials: "include",门户 CORS 白名单已就绪)
范围 只读子集:实例 / 熔断 / 用户 / 存储 / 候选池 / 运行时
写操作 一律回跳平台管理台(portalHost() + "/portal.html")—— 不复制门户写 UI(否则双源维护 + 与档案 39「收窄执行面」相冲)
可见性 仅 admin:先 GET /api/auth/me 判 role === "admin",否则只渲染一行说明
落点 poc/business-plugins/lib/client.js(设置面板 settings.section,id: platform-admin, order: 102)

二、改了哪些文件

文件 改动
poc/business-plugins/lib/client.js 895 → 1083 行:① zh/en 词典各 +29 个 pa.* 键;② 新增 PaCard(指标卡)+ PlatformAdminSection;③ 新增一个 settings.section 注册(platform-admin)
poc/business-plugins/package.json 版本 0.2.8 → 0.2.9
产物 dsh-local-business-plugins-0.2.9.tgz(16,712 B;顶层仅 package/;无 .tgz/node_modules/.bak)

三、数据来源(均为平台既有路由,零新增后端)

卡片 API 权限
角色门禁 GET /api/auth/me requireAuth
当前实例 / 熔断 GET /api/dsh/status requireAuth
用户 GET /api/admin/users requireAdmin
存储 GET /api/admin/storage requireAdmin
候选池 GET /api/plugins/business requireAdmin
运行时 GET /api/admin/runtime requireAdmin

全部只读;任一失败降级为 null 并照常渲染其余卡片(不整页报错)。

四、已验证 / 未验证

项 状态 证据
语法 ✅ node --check lib/client.js 通过
包结构 ✅ 顶层仅 package/;4 条目;无违规文件;lib/client.js 在内
词条键集 ✅ zh/en 各 +29 键,键名一一对应
渲染 / 交互 / 权限门禁 ⏸ 未验证 需投放 + 启用(见 §五)

五、⛔ 未完成:投放与验收需要 admin 登录态

  • 投放走 POST /api/plugins/business(requireAdmin)⇒ 必须有 admin 的会话。
  • 平台 CLI 只有 start / bootstrap-admin / file-service,无投放命令;文档内无测试口令 ⇒ 执行会话拿不到凭据。
  • 三条可选路径(待用户定):① 用户自己在门户投放(2 分钟);② 给 admin 口令;③ 用 bootstrap-admin 建临时 admin,用完删(会动生产 auth)。

六、R2 剩余(本次未做,属同期的另一半)

  1. /admin 路由族 + 删 3 个跳转桩页(web/desktop.html / plugins.html / skills.html,各 247–265 B,title=跳转中…)—— 档案 81 §四表格口径;⚠️ 删桩页必须同时加 301 到 /admin(否则既有书签断)。删后静态页 9 → 6,需同步改 scripts/verify-static.mjs 的页数断言。
  2. 注入层 CSS 类统一为 .dshs-*(档案 81 §四:.__dsh-* / .wk-* → .dshs-*)。

七、回滚

  • 插件侧:把候选池里的 business-plugins 回落 0.2.8(旧 tgz 若已删,可从本机 git 历史取 lib/client.js 重建)。
  • 本轮改动全部在 poc/business-plugins/,未动 src/、未动官方 dsh、未动服务器 ⇒ 回滚只需还原该目录 + 重新投放。

八、口径提醒

⚠️ 不能两头都要(档案 81 §9.2b):若日后要求「弹窗里能完成全部管理动作」,那就等于把整个门户重写进插件(双源维护 + 扩大执行面)⇒ 届时应把门户收敛成 API 客户端,而不是继续复制 UI。


九、追加(2026-09-13 18:1x–19:2x):部署完成 + 无浏览器渲染验收通过 + 一并做掉档案 80 第 7 项

9.1 部署链路(关键:不走候选池)

@dsh-local/business-plugins 不是池内插件 —— 它由 scripts/ensure-biz-plugins.cjs 铺发:从 /opt/dsh/artifacts/ 取版本号最大的 business-plugins-*.tgz(--all 含 admin;--restart 让 bundle 生效)。

步 结果
投放产物 business-plugins-0.2.9.tgz → /opt/dsh/artifacts/(前一版为 0.2.8)
铺发 node scripts/ensure-biz-plugins.cjs --all --restart ⇒ admin 与 guest 的 profile 均 0.2.8 → 0.2.9、bundles 均含该包 ✓
磁盘层断言 两实例 node_modules/@dsh-local/business-plugins/lib/client.js 含「平台管理」× 5 ✓
实例 两实例均已重启并 running;实例页 HTTP 200 ✓

9.2 渲染验收:改用无浏览器 harness(因 agent-browser daemon 起不来)

  • ⚠️ 本机 [email protected] 的 daemon 起不来:open 挂住且零输出(--version / node -e 均正常;~/.agent-browser 里留下的 default.port 实测不通、清掉僵尸状态后仍不通)。Chrome 153 已由 agent-browser install 装好,但 daemon 不通 ⇒ 浏览器截图验收受阻(属环境问题,未解)。
  • ⚠️ 06-工作台UI规范 §7.3 的三段式在按需动态加载的 bundle 上拿不到带 rev 的完整 URL(该 bundle 不出现在实例首页 HTML 里)⇒ ②③ 段也不适用。
  • ✅ 替代做法(已沉淀为可复跑脚本):scripts/verify-platform-admin-section.mjs —— 打桩 react / react/jsx-runtime + 最小 hooks 渲染循环 + 真执行 client.js,直接断言结构与门禁。
✓ 注册了两个 settings.section  -> business-plugins, platform-admin
✓ 存在 platform-admin 分区    ✓ 其 order = 102
✓ admin:含分区标题「平台管理」  ✓ admin:6 张卡齐全  ✓ admin:含只读声明
✓ 非 admin:被门禁挡住         ✓ 非 admin:不出现任何指标卡
结论:全绿 ✅   exit=0

admin 视角实际渲染文本(实测):

平台管理 | 只读 | 本分区为只读;写操作请在平台管理台完成。 当前实例 | 运行中 | 端口 43095 · 自动重启 2 | 熔断 | 正常 | — 用户 | 4 | 待审核 1 · 已禁用 1 | 存储 | 2 | 报告每小时刷新 候选池 | 3 | 已投放插件 | 运行时 | 5 | 条目 | 打开完整管理台

已接入 npm run verify(&& node scripts/verify-platform-admin-section.mjs)⇒ 今后 UI 改动可 CI 式防回归。

9.3 一并做掉:档案 80 第 7 项 / 档案 81 §四「删 3 个跳转桩页」

  • 删 web/{desktop,plugins,skills}.html ⇒ 静态页 9 → 6 ✓;改 5 处引用(admin.html / index.html / login.html×2 / dsh.ts 注释)。verify-static.mjs 是自动发现页面的,无需改。
  • nginx alotbuy.com.conf 两个 server 块各加 3 条精确匹配 301 ⇒ 实测 /desktop.html→301 /portal.html、/plugins.html→#/plugins、/skills.html→#/skills ✓;login.html 仍 200 ✓。
  • ⚠️ 本机 nginx 由宝塔托管:systemctl reload nginx 失效,须用 nginx -s reload。

9.4 🔴 期间修掉一个由本次改名引入的真回归(如实记录)

  • 症状:admin 实例页 502,journal = plugin tree failed to load … corrupt session log。
  • 根因:会话日志是 session.jsonl.zstd(zstd 压缩)。改名只改了目录名与纯文本文件,压缩流 header 里的 cwd 仍是旧路径 ⇒ dsh 启动做一致性校验(header cwd vs 目录推导 cwd)不匹配 ⇒ 抛错 ⇒ 插件树加载失败 ⇒ 崩溃循环。
  • 修复:_fix_sesslog.cjs(node 内置 zlib.zstdDecompressSync/zstdCompressSync,22.15+)—— 解压 → 替换 → 重压 → 回读校验。26 个文件 24 个待修 → 全修完,复查 0 残留 ✓;实例恢复 200,corrupt session log 归零。
  • 📌 教训:压缩文件里的路径 grep/sed 够不到 —— 与「SQLite 改名必须带 -wal/-shm」同类。已写进项目 MEMORY.md 铁律。

9.5 期间发现的两个平台缺陷(待修)

  1. op-lock 不可用:锁根 /opt/dsh/state/.op-lock 不存在,且 scripts/op-lock.sh 自身解析 bt-server 失败 ⇒ 它报「已存在 → 停手」是假警报,无法用于互斥。
  2. agent-browser daemon 起不来(见 §9.2)—— 浏览器验收链路的唯一可用工具受阻。

9.6 尚未做

  • D / J / Q(T03 遗留)与登录/注册/门户/设置面板的体验审计(用户 18:1x 关注的第三块)。

十、追加(2026-09-13 19:3x–19:5x):从「只读」升级为「就地全量管理」(用户要求)

10.1 用户的三条要求

  1. dsh 设置里的「用户管理」改名为「用户设置」,且去掉里面的「打开管理平台」入口
  2. 「平台管理」不要再跳新页面 —— 把所有管理项都放进「系统管理」,每项点开是弹窗

10.2 落地

项 改动 产物
「用户管理」→「用户设置」 @dsh-local/portal-entry:section id: user-management → user-settings、label 改名、order 102 → 103(让位给平台管理);删除「打开管理台」按钮;内容改为「账号:<用户名> 角色:<管理员/普通用户>」+ 退出登录 portal-entry-0.5.2.tgz(已铺发到 admin+guest)
「平台管理」→「系统管理」+ 管理项 + 弹窗 @dsh-local/business-plugins:删掉 window.open(portal.html) 跳转按钮;分区改为「管理项列表」,5 项(用户管理 / 候选池 / 运行时 / 存储 / 当前实例)每项点开是原生弹窗;用户管理弹窗内可直接 通过 / 禁用 / 启用 / 删除(调平台既有 admin API,不跳门户) business-plugins-0.3.0.tgz(已铺发)

10.3 验收(npm run verify 内)

✓ 注册了两个 settings.section  -> business-plugins, platform-admin
✓ admin:含分区标题「系统管理」   ✓ admin:5 个管理项齐全
✓ admin:不再是只读(提示改为弹窗内管理)
✓ 非 admin:被门禁挡住            ✓ 非 admin:不出现任何管理项
结论:全绿 ✅

另:磁盘复核 —— 两 profile 的 business-plugins 均 0.3.0、含「系统管理」、window.open 计数 = 0(跳新页彻底移除)✓

10.4 尚未做的(下一批)

  • 弹窗内目前只有「用户管理」是可写的;候选池 / 运行时 / 存储 / 实例 三项为只读列表(写操作待补)。
  • portal-entry 源码不在仓库(只有铺发脚本 + artifacts 里的 tgz)⇒ 本次是在产物上改的。建议:把 portal-entry/business-plugins 源码纳入仓库(档案 75 · B5 的旧账)。

10.5 视觉层补齐(2026-09-13 20:1x,用户反馈「像毛坯房、参考门户样式、把 UI 规范记脑袋里」)

做法:按 06-工作台UI规范 重做视觉层(此前只做了功能骨架、无样式):

元素 采纳的规范条目 取值
管理项卡片 §4.5 .data-card r12 / 16px 18px / box-shadow: 0 1px 3px rgba(0,0,0,.08) / hover 上浮 translateY(-2px) + 蓝边 + 0 4px 12px rgba(47,111,237,.15) / transition .15s cubic-bezier(.16,1,.3,1)
卡片布局 §3 grid-template-columns: repeat(auto-fill, minmax(158px, 1fr)) + gap 12;minHeight 104px 保证等高
弹窗 §4.7 .modal / .modal-mask mask rgba(0,0,0,.35) + flex 居中;面板 r14 / 22px 26px / width 520px / max-width 92vw / 0 8px 30px;进场 paIn .18s
按钮 §4.1 .btn-sm 量级 3px 10px / r6 / 12–13px;hover 蓝边蓝字 + 淡蓝底
数值 §5 计数右对齐 + font-variant-numeric: tabular-nums
字号 §2.2 阶梯 卡片标题 15/500、说明 13/次级色、计数 17/500
动效降级 §4.5 @media (prefers-reduced-motion: reduce) 关动画与位移

色彩:继续用 dsh 官方 token --dsw-*(刻意不硬编码亮色——本 section 嵌在 dsh 设置面板内,须自动跟随 dsh 主题;硬编码会在暗色主题下瞎)。规范里的硬色值是给门户静态页的。

产物:business-plugins-0.3.1.tgz(已铺发 admin+guest);npm run verify 全绿。

⚠️ 教训(已入库):上一轮只做了功能、没做视觉就交付,被指「像毛坯房」。做页面的默认动作必须包含「查规范 → 落地 §4.5/§4.7 等具体条目」,不能等用户来提。

10.6 修复:普通用户不该看到「系统管理」(2026-09-13 20:3x,用户指出)

问题:此前只对内容做了门禁 ⇒ section 本身仍对所有人注册,普通用户在设置里能看到「系统管理」这一栏(点进去只有一行「仅管理员」)。

正解(不再注册,而非注册后藏内容):

// apply() 里先异步判角色,非 admin 干脆不注册
fetch(portalHost() + "/api/auth/me", { credentials: "include" })
  .then(r => r.ok ? r.json() : null)
  .then(d => { if (d?.user?.role !== "admin") return; ctx.slots.inject(...register...) })
  .catch(() => {})   // fail-closed:判角色失败按非 admin 处理

依据(有实证,不是猜):官方 settings 外壳的导航是这样算的 —— dsh-client-ui-settings/lib/client.js:560:const version = ctx.slots.getVersion("settings.section") ⇒ 版本变化会重算导航行 ⇒ 晚注册(异步 inject)会被正确反映 ✓。

验收(已进 npm run verify):

✓ admin 视角下注册了两个 settings.section  -> business-plugins, platform-admin
✓ 非 admin 视角下只注册 1 个分区(不含系统管理)  -> business-plugins
结论:全绿 ✅

(验收脚本原先没等异步注册 ⇒ 一并修好:apply 后 await 80ms 再断言。)

产物:business-plugins-0.3.2.tgz(已铺发 admin+guest)。

10.7 视觉层第 2 轮:「照抄门户源码」而不是「照抄规范条目」(2026-09-13 20:4x,用户第 2 次反馈)

用户原话:「点击卡片后的弹窗样式还是没变呢,说了要用之前门户的里面的对应样式」。

🔴 真因有两个(都查明并已修)

# 真因 证据
1 我上一步的改动根本没出厂 —— lib/client.js 的 mtime = 20:33,而线上最新产物 business-plugins-0.3.2.tgz 打包于 20:17 ls -la 时间戳对比;解包 0.3.2 与工作副本 diff 显示 109 行差异全在「未打包」那一侧
2 更要命:上一版只有「用户管理」1 个弹窗是门户表格,另外 4 个(候选池 / 运行时 / 存储 / 当前实例)仍是裸 div + 内联样式(padding:8px 10px; border:1px solid …; borderRadius:8px; fontSize:13px)⇒ 点开就是「毛坯房」 git diff 原文:4 个分支返回 jsxRuntime.jsx("div", { style: { display:"flex" … } }),无任何 className

⇒ 我上一轮「照抄」抄的是 06-工作台UI规范 的抽象条目(§4.5 .data-card / §4.7 .modal),而用户要的是 web/portal.html 里那套已经跑着的实际组件。 规范条目 ≠ 门户真实样式。

本轮做法:读门户源码,逐值对应

「系统管理」元素 门户来源(web/portal.html) 落地类名
卡片网格 .nav-grid(repeat(auto-fill,minmax(200px,1fr)) / gap 14px) .pa-grid
管理项卡片 .nav-card(r10 / 18px 16px / hover:蓝边 + 0 4px 12px rgba(47,111,237,.12) + 上浮 -2px) .pa-card
卡片内三行 .nav-card .ic(主色)/ .t(15-600)/ .d(12 dim) .pa-ic / .pa-t / .pa-d
卡片计数 .pg-tab .pg-cnt(12-600 胶囊 / 主色底) .pa-cnt
弹窗正文(全部 5 个) .table-wrap + table.tbl(th 灰底 8px 10px-600 / td 7px 10px / 行 hover 浅蓝 / 末行去下边框) .pa-wrap + .pa-tbl
表格空态 门户 emptyRow()(居中 + 40px 10px) .pa-tbl td.pa-empty-cell
角色徽章 .badge + 四色 .admin/.active/.pending/.disabled .pa-badge
操作按钮 .btn-sm(3px 10px / r6 / 14px;.danger 红字红边) .pa-sm / .pa-sm.danger
弹窗头 .card-h(15-600,可带 13 dim 副标题) .pa-card-h
标题 / 副标题 .page-title(20-600)/ .page-sub(13 dim) .pa-hd / .pa-sub
分组小标题 .home-section-title(13 dim 600) .pa-sec
弹窗外壳 门户没有弹窗 ⇒ 面板取 .card(r10 / 18px)+ 门户家族阴影(design.css --shadow = 0 18px 50px -18px rgba(9,24,58,.35)) .pa-overlay + .pa-modal

5 个弹窗逐个改完:

弹窗 表头 说明
用户管理 用户名 / 角色 / 操作 可写:通过 · 启用 · 禁用 · 删除(.btn-sm.danger)
候选池 插件 / 版本 只读
运行时 项目 / 版本 只读
存储 用户 / 已用(.pa-num 右对齐 tabular-nums) 只读
当前实例 项目 / 值(键值表) 只读

⚠️ 唯一的刻意差异:颜色走 dsh 官方 token --dsw-*(本 section 嵌在 dsh 设置面板内、须自动跟随 dsh 主题);门户那套 --bp-* 是给亮色静态页的硬编码。字号 / 间距 / 圆角 / 动效与门户逐值一致。

三层验收(这次不只看单测)

① 单测层(已进 npm run verify,脚本 scripts/verify-platform-admin-section.mjs 新增「结构层」断言):

✓ 首页:卡片网格取门户 .nav-grid 值
✓ 首页:卡片取门户 .nav-card 值(.pa-card)
✓ 首页:计数胶囊取门户 .pg-cnt 值(.pa-cnt)
✓ 首页:标题/副标题取门户 .page-title/.page-sub 值
✓ 5 个弹窗全部 = 门户弹窗外壳 + portal 表格 + .btn-sm  -> users/plugins/runtime/storage/instance 均通过
✓ 用户弹窗:角色用门户 .badge 四色  -> 4 枚
✓ 用户弹窗:删除按钮用门户 .btn-sm.danger
✓ 实例弹窗:键值齐全
结论:全绿 ✅

(写这套断言时踩到校验脚本自身的坑:树遍历 depth > 12 上限会把 表格>tbody>tr>td>文本 这一支截断 ⇒ 表头有、行文本丢;已放宽到 20 并加注释。属校验脚本缺陷,不是产物缺陷。)

② 服务器实装层(md5 三处一致):

dep: business-plugins-0.3.3.tgz            ← 两个 profile 都指向 0.3.3
实链: business-plugins@file+…+business-plugins-0.3.3.tgz
md5: 5800ba4f77e1c786063aed8a91f9f4b4    ← admin / guest / 本地产物 三方完全相同
旧版残留(.pa-n{|pa-go): 0

③ 端到端层(真正下发到浏览器的那份):临时会话 mksess.cjs → 取实例首页 → 解出模块 URL → 取回 bundle(用完即删临时会话):

实例首页 http=200
模块 URL: /plugins/??…,@dsh-local/business-plugins/client.js,…&rev=fd084d6aa33a
bundle http=200 bytes=4260682
  pa-empty-cell 3 处 / pa-card-h 4 处 / pa-overlay 2 处 / pa-cnt 3 处
  pa-grid 3 处 / pa-tbl 10 处 / border-radius:10px;padding:18px 16px 1 处
旧版残留:pa-go 0 / .pa-n{ 0 / 0 8px 30px rgba(0,0,0,.28) 0
清理临时会话: 1

缓存问题(这次一并确认,不是它导致的)

src/supervisor/proxy.ts:383 对 /plugins/ 与 /assets/ 统一下发 Cache-Control: no-cache(允许缓存但每次回源校验);且 dsh 的模块 URL 自带 内容 sha1 的 rev。⇒ 本轮 rev 已从旧值变为 fd084d6aa33a,用户无需清缓存 / 换无痕。

产物与部署

  • business-plugins-0.3.3.tgz(本地 dsh-local-business-plugins-0.3.3.tgz)
  • 铺发:node /opt/dshs/scripts/ensure-biz-plugins.cjs --all --restart ⇒ admin: ✓ bundles=6 / guest: ✓ bundles=7,均已停实例(下次访问自动拉起新 bundle)
  • ⚠️ 顺手清掉一个自作的地雷:打包脚本第一次因断言锚点写错(description 不以 v0.2.8 开头)在写文件前就抛错,但我已先跑了 npm pack ⇒ 生成了一个内容是新版、版本号却仍写 0.3.2 的本地 tgz。已删除该文件并改用正确锚点重新升到 0.3.3(服务器侧的 business-plugins-0.3.2.tgz 是真正的旧版,未受影响)。

🔴 教训(已入库)

「按规范条目做样式」≠「用门户已经跑着的样式」。 用户说「参考门户里的对应样式」时,正确动作是 打开 web/portal.html / admin.html 的源码,把 .nav-card / table.tbl / .badge / .btn-sm 的实际取值逐条搬过来,而不是去引规范里的抽象条目再自行演绎。另外:交付前必须自问「这份改动出厂了吗」——本轮真因 1 就是改完没打包没铺发。


十一、追加(2026-09-13 21:0x–21:3x):功能名与内容全面改为「门户 6 个功能页」(用户第 3 次反馈)

用户在铺发 0.3.3 之后当场反馈(原话): 「怎么设置系统管理里面还是老样子呢,和之前门户那个功能名称、页面样式完全不一样呢,你要不要把之前那个 portal 页面打开看看,我要点开弹窗里面展示的内容是和 portal 点击功能后那种详细的表格和功能」

11.1 先定位「还是老样子」的真因(不是没出厂)

检查 结果
线上实际装的版本 实例 profile → .dsh-stage/business-plugins-0.3.3.tgz,package.json 解析 "version": "0.3.3" ⇒ 第 2 轮确实已生效
那用户为什么说"老样子" 第 2 轮只改了「视觉层」(class / 字号 / 颜色),没动「信息架构」 —— 管理项仍是自造的 5 项只读摘要(用户管理 / 候选池 / 运行时 / 存储 / 当前实例),而门户是 6 个功能页(服务管理 / 密钥管理 / 用户管理 / 技能管理 / 插件管理 / 运行环境)。名字对不上、表对不上 ⇒ 用户一眼就看出"不一样"

⇒ 教训:说"照抄门户",只抄样式不算抄;功能名 / 表格列 / 操作按钮才是用户眼里的"是不是同一个东西"。

11.2 口径变更(推翻 §一 表里的两行)

维度 §一(初版) 本轮(现行)
范围 只读子集(实例/用户/存储/候选池/运行时) 门户 6 个功能页,同名同构
写操作 一律回跳门户管理台 就地调用平台 admin API(跨子域 + credentials:include;门户 CORS 白名单已含 GET,POST,DELETE,OPTIONS)
形态 原生弹窗(非 iframe) 不变(用户 09-13 已拍板;本轮仍不做 iframe)

⚠️ §八「口径提醒」原文(不能两头都要…届时应把门户收敛成 API 客户端)仍然成立:本轮选择了「复制 UI」这条路,代价是双源维护。为把代价压到最低,移植采用逐函数照抄并逐条注释对应关系(将来门户改了,按同名函数对照即可)。若日后要收敛,方向仍是「门户与弹窗共用一份渲染」。

11.3 落地(poc/business-plugins/lib/client.js,1624 → 2218 行)

新增 内容
PA_PAGES 6 个功能页,每页 = { icon, title, desc, sub, html(), init($, root) },其中 html() ≡ 门户 renderXxx()、init() ≡ 门户 initXxx()
PA_GROUPS 首页分组 ← 门户 renderHome() 的 sec1(服务)+ sec2(管理),顺序一致
PortalPage 页面宿主:dangerouslySetInnerHTML 注入门户原文 + useEffect 里跑门户 init($ = 弹窗子树内的局部查询器)
工具函数 pafmt({占位符})/ paesc / pafmtSize / pawhen / paemptyRow / pareadAsBase64 / parelTime / paReq / papostJson —— 均为门户同名函数移植
词典 pa.* 由 91 → 225 条(zh/en 键集一一对应,新增断言把关);弹窗内 182 条 文案逐字取自门户
CSS 门户页面级组件逐条译为 .pa-*:.card→.pa-box、.btn/.btn-primary→.pa-btn*、.page-head→.pa-phead、.pg-tabs/.pg-tab/.pg-cnt→.pa-tabs/.pa-tab/.pa-tcnt、.dsh-bar/.dot→.pa-dshbar/.pa-dot、.pathbar/.crumb→.pa-pathbar/.pa-crumb、.upload-row/.hint→.pa-row/.pa-hint、.key-row→.pa-keyrow、.wl-*→.pa-wl*、.empty→.pa-empty、.toast→.pa-toast

三处机械改写(除此外结构 / 表格列 / 文案逐字保持一致):

  1. document.getElementById(x) → $("x")(局部查询器,避免与 dsh 面板同名 id 撞车);
  2. fetch("/api/…") → paReq("/api/…")(跨子域 + credentials:"include");
  3. location.hash 路由 → 弹窗内页签状态(门户靠 hash 深链,弹窗不需要)。

弹窗尺寸(用户要求「需要多大就多大,不用做的太小」):.pa-modal.pa-wide = width:min(1440px,96vw)(对齐门户功能页 .page 的 1440)+ height:min(92vh,1040px);头固定(门户 .page-head = ← 返回 + 标题 + 副标题 + 关闭),体内部滚动。

两处对门户的有意偏离(均已在代码注释里标注):

  • 🐛 修掉门户 readAsBase64() 的缺陷:门户原文 return String(new Promise(…)).split(",")[1] ?? "" 缺 await ⇒ 恒得 "[object Promise]" ⇒ 返回空串 ⇒ 门户的「上传文件 / 上传技能 zip / 上传插件 tgz」实际传的是空数据(三个上传入口全受影响)。弹窗侧改为返回真 Promise;门户侧未动,待同修。
  • .pa-dir 补了手型 + 主色(门户的文件夹行没有任何可点提示,弹窗里若照抄会没法导航文件树)。

11.4 验收

node scripts/verify-platform-admin-section.mjs      ⇒ 全绿(0 退出码)
node --check poc/business-plugins/lib/client.js     ⇒ 通过

验收脚本本轮同步升级:新增词典键集一一对应 / 占位符键一致两条断言;断言口径从「5 项只读摘要」换成「门户 6 个功能页同名同构 + 6 个弹窗外壳 + 各页表头/按钮文本」;并新增 clsAll() —— 同时扫 React 节点与 dangerouslySetInnerHTML 里的 class(只看 React 节点会漏掉全部表格/工具条类名,这是本轮踩到的验收盲区)。

11.5 产物与铺发

  • business-plugins-0.3.4.tgz(本地 dsh-local-business-plugins-0.3.4.tgz,39,098 B;包内 4 条目:package/{package.json,lib/index.js,lib/client.js,cordis.patch.yml},无 .tgz / 无 .bak)
  • ⚠️ 打包前删掉了 lib/client.js.bak-* —— .npmignore 没有排除 .bak,留着会被打进产物
  • 铺发:ssh bt-server 'cd /opt/dshs && node scripts/ensure-biz-plugins.cjs --all --restart'(服务端脚本 md5 与本机不同,但选版逻辑一致:按 business-plugins-<ver>.tgz 前缀取最大版本)

11.6 ⚠️ 本轮发现、未动手的问题(先报告)

  1. 门户 readAsBase64() 缺 await(见 §11.3)—— 影响门户三个上传入口,属生产缺陷。修它要改 web/portal.html,不在本次要求范围 ⇒ 未动。
  2. 本档案自身严重重复:# 82 · R2 管理面就地化 标题出现 6 次,## 一–## 八 前缀块重复 6 份(1937 行里大半是重复内容,疑似历史多会话并行各自追加所致)。未做去重(档案只增不改 + 去重需逐块比对确认无独有内容,应单独立项)。

11.7 追加(21:2x):「官方推荐插件」列表拉高(用户要求)

用户原话:「系统设置 插件管理里面官方插件列表 高度可以增加,距离底部 100PX 就行」

项 改前 改后
官方插件表容器 class="pa-wrap" style="max-height:420px" class="pa-wrap pa-plist"
高度 固定 420px max(280px, min(calc(92vh - 470px), 580px))

取值依据(写进 CSS 注释,便于复核):弹窗高 = min(92vh,1040px);表上方固定消耗 ≈470px(弹窗头 + 页签 + 工具条 + 说明 + 信息行),表下方还有按钮行 + 结果区 + 内边距 ⇒ 用 calc(92vh - 470px) 反推,使列表底部距弹窗底部约 100px。

  • 下限 280px:小屏时防止被压成一条线;
  • 上限 580px:对应弹窗触顶 1040px 时的可用高度(1040 − 470 − 下方 ≈ 90 − 100 ≈ 380…560 区间,取 580 留 20px 余量)。

产物:business-plugins-0.3.5.tgz(39,544 B,包内 4 条目)。铺发同上 ⇒ admin/guest 均 0.3.5;sha256 = 1d29683770b4… 本机 = artifacts = 两实例 .dsh-stage 三方一致;实例内 lib/client.js:654 已含 .pa-plist{…}。 验收:verify-platform-admin-section.mjs 全绿(CSS 断言扩到 .pa-plist);node --check 通过;防假产物自检:源文件 21:21:41 < 产物 21:21:58 ✅。 ⚠️ 门户原值 calc(100vh - 520px) 是整页布局下的取值,弹窗内不适用 —— 别直接照抄。


修正(2026-09-14)· 本档存在严重内部重复(已体检,原文按 L5 冻结保留)

实测(python3 scripts/docs-dedupe.py "04-调整方案/82-R2管理面就地化-原生平台管理分区.md"):

项 数
文件规模 2024 行 / 89.1 KB(全库最大单篇;约定上限 30 KB)
块(按 #/##/### 切) 224 个
重复标题 22 个
冗余块 190 个(≈85%) —— 同一份「§一–§八」重复 16 次;# 82 · … 与 §九(9.1–9.6)各重复 8 次
⚠️ 内容有差异的 「八、口径提醒」两个变体(各 8 次)⇒ 不是纯复制,去重时必须两份都看

处置(零改写,遵守 L5 冻结):

  1. 原文一字未改,仅追加本小节;
  2. 生成去重视图(保留每组信息最全的一份,其余位置留一行占位注释): …/.workbuddy/cache/dedupe-view/04-调整方案__82-R2管理面就地化-原生平台管理分区.md —— 89.1 KB → 59.0 KB(省略 192 块);
  3. ⚠️ 视图仍 59 KB > 30 KB 约定 ⇒ 去重只是第一步,根治要靠拆分(把 §九 追加节与本次 R2 主体拆成两篇);此项待立项。
  4. 阅读建议:先看视图;需核对「八、口径提醒」两个变体时再回原文。

复跑体检:python3 scripts/docs-dedupe.py <本档相对路径> --view-out