Commit Graph
22 Commits
Author SHA1 Message Date
admin 452924d89c feat(config): 涉密内容外置到配置目录(档案 140)
把散落在代码里的真实部署值统一收进 config/,代码改为引用配置,
使仓库副本/开源导出不再带出生产域名、IP、内网路径与凭据。

新增 config/:platform.env.example(模板)· load.sh(shell 加载器)·
index.cjs(node 加载器)· README.md(键一览与优先级)。
真实值放 config/platform.env —— 已 .gitignore 排除,不入库、不进导出。

TS 侧新增 src/platform-paths.ts 作部署路径的唯一解析处(零副作用):
platformDir/stateDir/backupDir/artifactDir/installDir/scriptPath。
config.ts 接入这些字段;内置中继种子由生产 URL 改为空(改由
DSHS_OVERLAY_BOOTSTRAP_SEEDS 提供)。修掉 5 处硬编码绝对路径,
src/** 注释中性化 116 行/53 文件。

scripts/** 36 个内部运维脚本:真令牌/PG 口令/隧道目标/主机号/路径
一律改从配置取;web/wake.html 的注册域白名单改为运行时从
location.hostname 推导;test/** 夹具 119 行/13 文件改 RFC 2606/5737
保留值,并把「内置种子必须为空」固化为回归断言。

取证:tsc 0 错;npm test 373/375(唯一失败 lease 属既有);
全仓扫描(大小写不敏感)代码面涉密标识 = 0;已部署 47 并零回归
(/opt/dsh/* 未搬家,/var/lib/dshs/platform 未被误建)。
2026-09-19 15:12:19 +08:00
admin 9c2e7975ac 同步 docs-manifest(档案 138 收口后重算 md5) 2026-09-19 13:52:10 +08:00
admin c2b7c5ef71 平台共享模型改为「管理员逐用户授权」+ 品牌中文名改「能力网络」+ 修掉跨机模型落地/语言偏好静默失效
三条线合并入库(同一次部署批次,源码与生产此前已一致):

一、档案 138 · 平台共享模型:管理员逐用户授权(默认关闭)
  用户口径原文:「admin 设置的共享模型,需要 admin 在用户列表中开启(新增选项,默认关闭),
  用户才能在会话中使用(以及在设置的模型设置页面展示)」。
  · DB 迁移 v11:新增 users.shared_model_granted(DEFAULT 0 = 默认关闭)。
    ⚠️ 刻意**不**复用 v6 的 shared_model_enabled —— 那是用户侧偏好(用户能自己关,默认 1),
    而本需求要的是**管理员门禁**;共用一列则用户点一下就给自己授权,门禁形同不存在。
    生效 = granted ∧ enabled(server.ts#sharedLandingRows)。
  · 新路由 POST /api/admin/users/:id/models/shared(requireAdmin)+ 审计 shared_model_grant
    + **尽力而为**重启该用户实例(租约被占/实例未运行都不算失败)。
  · admin 用户列表新增「共享模型」列;用户侧 /api/me/keys 增 shared.granted / sharedModelGranted;
    插件 0.3.24:未授权时「平台共享模型」整块不渲染。

二、顺带修掉一个既有真缺陷:平台侧写用户 home 必须走 UserFs(用户卷在 worker 上)
  landModels 原先 join(owner.home_dir, …) + 本机 fs ⇒ 对「实例不在控制面本机」的用户
  读到空串(**不报错**)⇒ 模型落地一直是**静默空操作**(托管清单还被清空)
  ——即档案 87 的模型设置页对 guest 这类用户**从未生效**。
  · UserFs 新增 readHomeFile/writeHomeFile + 文件名白名单(settings.yaml / .credentials.yaml)
  · worker agent 新增 /fs/home-read /fs/home-write(只认白名单裸文件名)
  · landModels 改走 userFs(与"文件面"同一份按归属路由 ⇒ 落地与实例必然同机)
  · 同轮把 /api/me/locale(档案 102 语言偏好)也改成同一套(原先同样失效)
  · home-files.ts 抽出 backupHomeFile(备份留平台侧,命名规则逐字不变)

三、档案 139 · 品牌中文名:能力枢纽 → 能力网络(其他语言仍 CapabilityNet)
  落点四处:i18n 中文词条 / admin.html 顶栏 / favicon.svg 的 title+aria-label / design.css 注释;
  test/i18n-brand.test.mjs 期望值同步。档案 137 顶部加"后续"指针,不改历史。

验证(全部真机实测):
  · 红腿:未授权 → 106 上 guest 的 .credentials.yaml refs 变空(共享 key 被撤)
  · 绿腿:授权 → key 回来 + 托管清单恢复 ["DEEPSEEK_API_KEY"]
  · admin 列表带出 sharedModelGranted;用户侧 granted 随授权翻面(true/shared ↔ false/none)
  · 开关两次均 200(不再假失败);插件实装 0.3.24 且含 gating 字符串
  · 语言偏好:106 上 settings.yaml 出现 locale.preference=en(属主=实例属主,既有段逐字保留)
  · 本机 npm test 226 tests / 225 pass / 0 fail / 1 skipped;四个 verify 脚本全绿

部署:47 推 51 个 lib 产物、106 推 12 个(lib/ 是 gitignore ⇒ 回滚点物化在
/opt/dsh/backups/seq138b-20260919-125345/,逐文件对账 0 不一致;先 106 后 47);
插件 business-plugins 0.3.24(两机 artifacts 与本机 pack md5 一致)。
2026-09-19 13:51:01 +08:00
admin 971ccc3703 feat(auth): 注册页人机验证 + 邮箱验证码;品牌标识去 DeepSeek(附域名迁移线 序㊿ 补提交)
三条线合并入库 —— 均已完成并上线(源码与生产一致,此前只部署未入仓)。
⚠️ 其中域名迁移线为**另一会话**产出,本会话只做入库、**未复验其正确性**(它自报零回归)。

【档案 134 · 注册页人机验证 + 邮箱验证码】
- DB 迁移 v10:users.email(唯一索引 LOWER(email))+ email_codes 事件表(2 索引)
- 新增模块 src/web/{register-guard,mail,turnstile,email-code}.ts
- routes/auth.ts:新增 GET /api/auth/register/config、POST /api/auth/register/email-code;
  注册接口加人机验证与验证码校验;config.ts 新增 12 项配置(默认空 ⇒ 不配 = 老行为)
- 邮件走**可插拔驱动**(brevo/http/log),发件人 [email protected](Brevo 域名已认证 + DKIM + SPF)
- 防爆破:三层配额(邮箱 6/h、8/天;IP 20/h;全局 200/h)+ 递增冷却阶梯
  (60→60→180→300→900→1800s)+ 试错 5 次作废 + 码只存哈希 + 单次使用 + 与用户名绑定
- Turnstile 服务端校 **success + action + hostname 三项**:sitekey 是公开的,
  只校 success 时"拿我们的 sitekey 在自己站点替真人取合法 token 再打我们接口"这条路是通的
- 新增 test/register-guard.test.mjs(19 用例)

【档案 137 · 品牌标识改造 — 去 DeepSeek 图形】
- login/register/admin 页头:删 DeepSeek 鲸鱼图标 + 「DeepSeek」文字图形
  → 平台标识(中文「能力枢纽」/英语及其他语言「CapabilityNet」,走 i18n 词条 brand.name)
- portal 顶栏换图标(页面名「管理门户」保留)
- 新建 web/favicon.svg(平台自有 hub 图标,避开 DeepSeek 蓝)+ 四页 favicon 指向它
- 新增 test/i18n-brand.test.mjs(node:vm 跑真实 i18n.js,六条语言路径断言渲染结果)
- scripts/verify-static.mjs 新增 SVG 段:XML 注释不得含 ASCII 双连字符(否则整份 SVG
  解析失败、图标静默不显示 —— 实际踩到过)
- 🔴 会话页面(实例内官方 dsh 界面)的标识**按用户要求未动**(也受 R2 约束)

【档案 135/136 · 域名迁移线(另一会话产出)】
- 域名收敛为 ai1net.com;旧域 alotbuy.com 降级为 301 过渡装置
- src/net/relay/{addr-override,directory,rendezvous,switcher}.ts 种子与候选链更新;
  src/web/server.ts、src/worker/relay-tunnel.ts、scripts/verify-cluster-domain.mjs
- 档案 136 = 控制面按两台中继取并集(**已立项、未落地**)

验证(本会话两条线):新增单测 21 条全通过|全量 221 pass / 0 fail / 1 skipped|
verify-static 全合格|其余 10 个 verify 脚本全 OK|线上实测:Turnstile 假 token 403、
发码 delivered、四页 deepseek 命中 0、favicon 200。
2026-09-19 09:11:24 +08:00
admin d2ef362a98 feat(overlay): 覆盖网络线 序㊾ —— 探针观测面改「两台中继并集」(附 序㊽ 源码/文档补提交)
序㊾(本棒):
- scripts/overlay-probe.cjs:OBS-01 / OBS-08 / OBS-09 的数据源由「只读 47 中继」
  改为「按两台中继取并集」,消除 worker 归属漂移时的假红 / 假 SKIP
  · endpoints 以 network:hostId:port 为键合并,online 取「或」、localPort 取在线那一侧
  · used 按 network/hostId 去重计数(不求和,避免凭空放大在册数)
  · localPort 属中继机回环落点 ⇒ 按归属分机探活(106 侧落点由 106 机上探)
  · derived(OBS-11)保持 47 视角;阈值与判据一律未放宽
  · OBS-16 计数约束:对 47 /status 的读取仍为三次、Δ 只取 47 的 counters;
    对端 106 的采样为独立一次,落在第三次采样之后,不进 (status2, status3] 门窗口
  · 新增 --peer-status-fixture(并集的对端那一半)与「并集不可取证」强制留痕
- 交接单《覆盖网络-序45-低熵块治理-测熵与实现》§16 全节(§8 前前缀逐字未变)
- 参数表 §11.16 补记(§10 现算指纹未变,值格未动)

附(前几棒已完成并已部署、但尚未入仓的源码 / 文档):
- src/net/relay/content/*.ts、src/net/relay/index.ts、main.ts:块级寻址 C 域分离
- src/supervisor/orchestrator.ts、src/worker/agent.ts:日志采集与巡检(方案 C)
- test/overlay-content.test.mjs:随附用例(npm test = 200 pass / 0 fail / 1 skipped,Node 22)
- scripts/dshlog.mjs(跨机日志取证)、scripts/overlay-entropy.cjs(熵探针)
- dsh-server-docs/04-调整方案/129、133;INDEX.md / docs-manifest.json / 交接单 README 登记
2026-09-19 05:35:35 +08:00
admin 09ce76f3af feat(overlay): 内容块级寻址 + 实例逐步拉起 + 骨干选路 + 组密钥加密(序24–㉛ 累积同步)
代码
- 内容分发块级寻址:新增 src/net/relay/content/{chunker,store,runtime,source,peer,crypto}.ts
- 组密钥(C 档)确定性加密:AES-256-GCM,块 id β′ = sha256(密文) 前 32 hex;双 epoch 过渡窗口
- 实例生命周期:三处 teardown() 不再杀实例(local/remote/leased-spawner);启动认领 + TCP 探活判孤儿
- 骨干选路:jitter 选路 + endpoint-target;relay client/server/wire/identity/directory/rendezvous/switcher 调整
- 工作台 src/web/server.ts、src/worker/relay-tunnel.ts 装配与候选链观测

脚本与测试
- scripts/overlay-{probe,keyring,jitter}.cjs 更新
- 探针新增 OBS-21(每连接候选数)/ OBS-22(teardown 静态守卫 + 认领面)/ OBS-23(组密钥加密)
- 新增 test/{orchestrator-teardown,orchestrator-rehydrate,overlay-content,overlay-jitter}.test.mjs;relay 两例更新

文档
- 新增交接单:覆盖网络-序24-内容分发块级寻址 / 序25-实例逐步拉起 / 序26-骨干稳定选路与加密
- INDEX.md、交接单/README.md、skills/dsh-auto-handoff-chain/SKILL.md 同步

验收(零回归,2026-09-18 08:0x 复核)
- npm test           201 tests / 200 pass / 0 fail / 1 skipped
- overlay-failover-drill --scene all --table   12 PASS / 0 SKIP / 0 FAIL
- overlay-probe --table                        23 PASS / 0 SKIP / 0 FAIL (rc=0)
2026-09-18 08:08:51 +08:00
admin 04776af4b1 docs: 工作区根项目文档批量入仓(04-调整方案 113–128 / 交接单 T09–T21 / ops / archive)
起因:用户 2026-09-17 明确「所有文档都要同步,都放在开发仓库 docs 对应文件夹下」。
判据:工作区根 *.md 中在仓库(git ls-files --quotepath=false)搜不到的那些。

入仓 33 份(一律复制,工作区根原件保留不动,避免引用断链):
- 04-调整方案/113–128(16 份 · 原子占号后落盘):覆盖网络 传输方案取舍 / 应用场景与待完善清单 /
  插件化vs改内核 / 问题逐条推演 / 参数表与观测口径;会合中继拆分取证与改造方案;
  集群化改造方案 Manager-Worker;跨节点迁移与节点自举;项目代码分层范式与迭代风险评估;
  搬运与共享重建方案 guest w47→w106;方案规划方法提炼;文档无效信息审计报告;
  会话接续机制复盘与修复;会话接续规范;dsh 客户端化部署方案;dsh 桌面客户端开发方案
- 交接单/archive/交接单-已完成/T09–T21(13 份 · 覆盖网络线已完成单归档)
- ops/(2 份运行态指针:接续入口 / 接续包 · 覆盖网络线)
- archive/(2 份临时与内部简报)

已排除(无需重复入仓):覆盖网络线 10 份方案正文已入档案 103–112(文件名不同)。

登记:INDEX.md §二 新增 04-113–128 共 16 行 + §四 追加 T09–T21 说明 + 机器摘要行刷新
(⛔ 未跑 docs-index-stats.py --write:该脚本会按 \r\n 归一化全文件行尾,故改为字节级单行替换);
README.md 追加 1 条入仓指针;docs-manifest.json 复跑 scripts/docs-manifest.py 刷新。

验收:工作区根 47 份 .md —— 同名已入仓 8 / 本次内容一致 29 / 已知改名映射 10 / 未入仓 0;
git status 待提交清单只含本次新增与登记 3 件(未涉 src/ 与 relay 代码面)。
2026-09-17 18:24:19 +08:00
admin bc0dd2c96d docs(dsh-server-docs): mksess 口径校正(DB 直插→PG 直插)+ 技能 dsh-auto-handoff-chain 三处同步建立(序⑰ S1/S2)
- 02-运维手册.md:mksess 命中处补「PG 直插 + 连接串来源」+ D1 勘误指针两行(档案 77 的旧形态说明,正文不改)
- skills/dsh-change-workflow/SKILL.md(146/395/495 三行)、skills/dsh-env-bootstrap/references/常驻规则-快照.md(55 行):同口径校正
- skills/dsh-auto-handoff-chain/:新建文档库副本(SKILL.md v1.3.2 + scripts/chain_report.py),此前该技能三处同步从未建立
- README.md / INDEX.md:登记该技能(技能表 + 「什么时候查什么」+ 技能清单表)

判据:E1 = 0 行、E2 两副本 md5 全同、E3 diff -r = 0 行、E4 登记命中 README 1 / INDEX 2、镜像 47 同值
2026-09-17 17:03:34 +08:00
admin 08219c99da 接续机制修复:三级告警改为「登记一次性 automation」
- 三级(>=30 万水位)注入文案 ③ 由「告知用户请开新会话」改为「调 automation_update 登记一次性 automation(照 会话接续规范 3.2.1 模板)」,原「由用户开」降为 ④ 兜底。

- 原因:原文案使自动接续没有任何触发源(钩子不能建会话/建自动化),实测 09-16 14:32 那条一次性自动化开的会话跑了 40 次调用 / 9.37 分,而验收线是 <=10 次 / 约 1 分。

- 复盘:会话接续机制_问题复盘与修复_20260916.md(工作区根)。
2026-09-16 15:02:35 +08:00
admin 59f1a896cd chore(docs): 刷新 docs-manifest(T08 归档 + 技能 1.2.0) 2026-09-16 11:29:40 +08:00
admin 744ed98338 docs(skills,handoff): decision-method 2.7.5 / feature-first 1.7.1 / knowledge-upkeep 1.2.0(+8.6 注入预算);T08 归档 2026-09-16 11:28:53 +08:00
admin bda9b10161 chore(hooks): 输出门禁三脚本更新 + 新增技能加载闸门 skill-load-guard.py 2026-09-16 11:28:51 +08:00
admin 500011d329 docs(brief): 刷新至 09-16 —— 集群拓扑 / bwrap 逐机版本差 / 待办重写 / 归档编号至 112 2026-09-16 11:28:48 +08:00
admin 4e3a1a4a13 docs(overlay): 覆盖网络/客户端化 10 份规划转正式档案 103-112 + 登记
- 新增 04-调整方案/103-112:可行性评估 · 全球架构复盘 · 骨干层方案 ·
  百台推演 v2 · 千台全场景推演 · 游戏专项 · 游戏网络与群聊上限调研 ·
  答疑(群聊/备份/迁移/保密) · 补遗与参考方案 · 九大瓶颈落地方案
- 每份按 交接单/README.md §二 8 段改写(目标/只读前置/范围/决策点/
  步骤/验收/回滚/回报格式)+ 头部状态标注(📋 规划态 · 未实施)
- 技术内容不变:附录 A 逐字保留原文全文(仅去其一级标题),已逐份校验字节一致
- 登记:INDEX.md §二 +10 行、03-路线图与待办.md §二 +1 行
- 收尾:docs-audit.py 退出码 0(无 P0)· docs-manifest.py 已刷新
- 本轮零代码、零服务器改动;⛔ 未 push
- 占号:103-112(先原子 mkdir .lock-<NN> 再写)
2026-09-16 10:25:09 +08:00
admin cb184145e9 feat(cost): 门禁补上 Read —— 覆盖第二大输出源(用户点出「重点是把大输出去掉」)
用户纠正(2026-09-15):① 「12 万 token 就收口」**不是他定的规则**(他选的是"设会话预算"这个方向,
12 万/80 是我自己收紧的取值,未与他确认);② 「切会话」只是**缓解**,**不是重点** ——
他早在更早一轮就点明过:「跟平台参数没关系……**为什么还要在上下文中 如何才能去掉**」。

⇒ 重点 = **让大输出根本不进入历史**,唯一能做到的就是**入口拦截**。而原门禁**只管 Bash** ——
实测 `Read` 是**第二大输出源**且**完全没被覆盖**:某会话 44 次 / 累计 238 K 字符、单条最大 33 K 字符
(≈13 K token);另一会话 136 次 / 217 K 字符。

**改动**
- `bash-output-guard.py`:新增 `READ_BIG = 400 KB` + `read_too_big()`;`tool_name == 'Read'` 时,
  目标文件 > 400 KB ⇒ **deny**,文案给出两条等价做法(`Read` 带 `offset`/`limit` 分段读;
  或先 `grep -n 关键词 文件 | head -20` 定位行号再读那几行)
- `settings.json`:该 hook 的 matcher `"Bash"` → **`"Bash|Read"`**(⚠️ 配置是启动快照 ⇒ **需重启生效**)

**实测 5/5**:Read 小文件放行 | **Read 大文件拦** | Bash `cat 大文件` 仍拦 | Bash `ls -la` 仍放行 | Write 不受影响
2026-09-15 22:11:59 +08:00
admin c25609c4c1 feat(cost): 路径自检 —— hooks 指向失效 / 配置被清空时自动上报(用户选 A)
**来历(2026-09-15 实测事故)**:文档库被整目录搬到 `_中间产物_待清理/` ⇒ 宿主 hooks 仍指向旧位置
⇒ **锁闸门静默失效**;当时唯一线索是"`lock-hook.log` 今天 0 条 PreToolUse",而**没人会主动去数**。

`stop-dialog-guard.py` 新增 `path_health()`(每轮随 `UserPromptSubmit` 跑):
1. **从 `settings.json` 现读** hooks 的 command ⇒ 抽出其中的 `.py` 逐个 `os.path.exists`
   (配置里是权威指向 ⇒ 能发现"指向了不存在的文件",正是今晚那种形态)
2. **hooks 里没有任何 command 条目** ⇒ 报"可能被清空 / 被整段覆盖"(用户记忆里的真实风险)
命中即经 `UserPromptSubmit` 注入「🚨【路径自检】…请立刻上报用户」。
**fail-open**:读不到配置就直接跳过,绝不因体检本身误报。

⚠️ 设计取舍(实测发现):**没有**去做"文档库是否在预期位置"的检查 —— 新位置在**另一个盘**
(`D:/github/dsh_shenxian`),硬编码候选路径会**误报**;而检查 ① 已能覆盖同一类事故。
实测三种情形:真实环境**不报** ✓ | 指向不存在脚本**报** ✓ | hooks 被清空**报** ✓
2026-09-15 22:06:36 +08:00
admin fff2519ad3 fix(cost): journalctl 认 --since 为限流(回放里最后 1 条轻微误伤)
回放 4051 条真实命令后 soft 档剩 3 条 DENY,逐条核对:
- `ls -R $B` → 真阳性(真递归)
- `find /d/AI技能 /d/github … -maxdepth 7 -type d` → 真阳性(4 个盘符级根)
- `journalctl -u dshs --since "-2 min" --no-pager` → **轻微误伤**:`--since` 本身就是时间窗限流

⇒ 在 journalctl 规则的否定前瞻里补 `--since`(与 `-n\s*\d` / `head` 同类)。
改后 soft 档 DENY = **2 / 4051 = 0.05%**,两条均为真阳性 ⇒ **对 AI 正常会话零影响**(0 误拦)。
2026-09-15 21:21:52 +08:00
admin 88aaf98191 fix(cost): 用今日 4049 条真实命令回放,把门禁误拦从 1.63% 降到 0.07%
用户要求:「用今天其他会话的记录多测试几遍,确保不影响 AI 正常会话」。做法 = **回放机**:
从 `~/.workbuddy/projects/` 的 12 个会话转录里抽出 **4049 条真实 Bash 命令**,逐条灌进门禁比对。

**发现(数据,不是推测)**
* 旧版 soft 档 DENY **66 / 4049 = 1.63%**,其中 **62 条是 `递归 grep`** —— 而抽样 **29/29 全是窄范围**
  (单文件 / 具体目录),**0 条从根**;连 `grep -c`(只输出计数、本来只有几行)也被误伤。
* 根因还有一个正则 bug:`\bgrep\b[^|;]*-[a-zA-Z]*[rR]` 里的 `[^|;]*` 会匹配到**路径里的 `-server`**
  (`-s`+`erve`+`r`)⇒ **凡路径含 `aliyun-dsh-server` 就必命中**(这正是误拦的主要来源)。

**修法**
1. `grep -r` 规则 **core → loose**(仅 `hard` 模式拦):实测"误伤 >> 收益"——`grep -r` 是日常主力工具、几乎总是窄范围
2. 正则收紧为「**选项必须紧跟命令**」(`\bgrep\s+-[a-zA-Z]*[rR]\b` / `\bls\s+-[a-zA-Z]*R\b`),
   杜绝"路径里的 `-xxx`"被当成选项

**复测**:soft 档 DENY **3 / 4051 = 0.07%**(`ls -R` / `find <根>` / `journalctl` 无 `-n` 各 1 条),
逐条核对**全为真阳性**;hard 档 0.79%。
2026-09-15 21:21:32 +08:00
admin 3f141c7b4d fix(cost): 修门禁三处误伤 + 新增「自动发现并上报」
用户两问:① 机制会不会影响 AI 会话?② 后续能否自动发现并上报?——① 自查出**三处真误伤**并修掉,
② 新增两条自动上报。

**修误伤(都是实测出来的,不是推测)**
1. `ls -la` 被拦 —— 正则 `-[a-zA-Z]*[lR]` 里的 `l` 命中日常 `-la` ⇒ 改为**只拦 `-R`**(递归全树)
2. `cat 小文件` 被拦 —— 盲拦一切 `cat *.txt` ⇒ 改为**按目标文件大小**(`> cat_bigfile()`:>200 KB 才拦,
   取不到大小一律放行)
3. **"提到"也拦** —— 原按**整条命令文本**匹配 ⇒ `printf 'ls -laR /x'`、测试脚本、写文档全被拦(阻塞面过大)
   ⇒ 改为**按 shell 分段、只看每段开头**(`segments()` + `re.match`):
   `cd /tmp && ls -laR /x` 照样拦(第二段以 `ls` 开头),而"引号里提到"放行
   实测 8/8:`ls -la` 放行 · `ls -laR` 拦 · `cd x && ls -laR` 拦 · `cat` 小/大 分别放行/拦 ·
   引号内提到放行 · `grep -rn` 拦 · `grep -rn | head` 放行

**新增「自动发现并上报」**(用户第 2 问的落地)
- `stop-dialog-guard.py` → `guard_health()`:读 `bash-guard.log`,**同一规则重复命中 ≥3 次** ⇒
  经 `UserPromptSubmit` 主动报告「疑似误伤,不是你操作有问题」,并给出两条处置(换写法 / `off` + 上报用户)
- 两个钩子脚本仍保持**入口即留痕**(`entry|event=…`)⇒ "钩子有没有被调用"永远可判

⚠️ 副作用须知:门禁**已生效**(重启已加载)。默认 `soft` 只拦 6 类;急停 = env `DSH_OUTPUT_GUARD_OFF=1`
或 `<工作区>/.workbuddy/bash-guard-mode` 写 `off`;`hard` 才启用 `rg`/`git log`/`du·tree` 三条。
2026-09-15 21:20:02 +08:00
admin 3efd68517f chore: 并入已删除会话的在途成果(防丢失;原会话已删,未做功能验收)
**背景**:这些改动原属本工作区另外几个会话(T01/T02 等),**那些会话已被用户删除** ⇒
工作树里的成果处于"无主"状态,一次错误 checkout / 覆盖即**永久丢失** ⇒ 代入库保全。
口径遵循本项目**先例**(`39a1f2e` / `b617cdb`:**别人的活,代入库并在提交信息里注明**)。

**内容**:档案 101「能力管理」改名 + 页内 tab 分页|档案 102 语言切换搬入「用户设置」|
`07-实例UI分区登记表.md`|`scripts/find-ui*.mjs`(UI 元素定位工具)|`poc/portal-entry/`(0.5.3)|
`src/web/locale-pref.ts` + `home-files.ts`(语言偏好持久化)|`test/locale-pref.test.mjs`|
`package.json`|`BRIEF.md` / `INDEX.md` / `docs-manifest.json` / `03-路线图与待办.md` / 档案 100 增量。

**已做最小健全性检查**(⚠️ **未跑完整构建 / 单测** —— 那是原会话的验收职责,本次只求"不丢"):
- JSON 合法:`package.json` / `poc/business-plugins/package.json` / `docs-manifest.json` ✓
- 4 个 TS 文件 `{}`/`()` 配平 ✓;新增文件均非空 ✓
- 规模:13 文件改动 +340/−210,新增 12 条

**未 push**(按 §4 提交边界:用户说"提交",未说"推送")。
2026-09-15 21:17:12 +08:00
admin 03c8363960 feat(cost): 省积分机制 —— 会话预算告警 + Bash 大输出门禁
本会话实测:553 轮 × 平均 42 万 token = 2.33 亿 input,output 仅占 0.35%(286:1)。
根因 = **对话历史是 append-only**:工具输出(`function_call_result`)一旦生成就**永久留在 messages 里、
每轮全量重发**,模型无权删自己的历史 ⇒ **唯一能"去掉"的时机 = 输出被生成之前**
(平台 `contextWindow=100 万` / 压缩阈值 90% 只是放大器,不是根因)。

- `scripts/stop-dialog-guard.py`:
  ① 修 `-S -E` ⇒ stdin 回退 cp936 ⇒ 含中文 payload 解析失败导致的**静默空转**(改走 buffer 显式 UTF-8,
     读写都加固;入口即留痕;根治"日志缺失时无法区分『没被调用』与『被静默 return』")
  ② 新增 `session_budget()`:读转录 `usage.input_tokens` ⇒ 当前体量 + 累计工具调用 + **上一轮增量**
  ③ 阈值 `BUDGET_TOKENS=120000` / `BUDGET_TOOLS=80` ⇒ 超预算经 `UserPromptSubmit` 注入告警
- `scripts/bash-output-guard.py`(新):`PreToolUse(Bash)` 拦"几乎必然巨大"的 6 条读命令
  (`cat *.log/jsonl` 无管道 / `grep -r` 无管道 / `ls -laR` / `find /` / `journalctl` 无 `-n` / `dmesg` 无 `head`),
  deny 文案**必给等价限流写法**。
  **设计(用户质疑"全拦也有问题")**:⛔ **不全拦** —— 误拦挡住正事比漏拦更贵 ⇒
  默认只拦高置信度、**拿不准一律放行**、`rg`/`git log`/`du·tree` 仅 `hard` 模式拦、
  可 `off` 急停(`<工作区>/.workbuddy/bash-guard-mode`)、任何异常 **fail-open**。
  实测 8/8:soft 拦 cat/ls-lR、放行 rg/git-log/grep+head;hard 全拦;off 全放;deny JSON 正确输出。
- (`settings.json` 的 `PreToolUse` 已加 `"matcher": "Bash"` 条目 —— **该文件不在仓库内**,
  且 hooks 是**启动时快照** ⇒ **Bash 门禁需完全重启才生效**;脚本内容本身每次现读、改完即生效。)

⚠️ 记录两个已踩的坑:Python `%` 格式串里的**裸 `%` 必须写 `%%`**(否则 `TypeError` ⇒ 在 `except: pass` 里
**静默失效**,表现为"日志有 DENY 但 stdout 空"= 看起来拦了其实没生效)⇒ **hook 必须"写日志 + emit"双动作**。
2026-09-15 21:17:08 +08:00
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