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

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

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

156 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 环境引导 / 换机迁移 / 改名后的路径残留清理
> **归属**:技能 `dsh-local-env` · 详情档(主干 `../SKILL.md`)
> **本档覆盖**:原技能 `dsh-env-bootstrap` **全文**(正文 81 行 + frontmatter 变更历史)
> **provenance**:本机版(WorkBuddy 实况)
> **搬运方式**:**逐行未改**;内部附件链接已改写为 `dsh-env-bootstrap/<附件名>`(附件在本目录下)
> ⚠️ 原技能 `dsh-env-bootstrap` **已合并退役** ⇒ 见到该名按本档读。
---
# dsh-env-bootstrap — 环境引导(常驻规则的可移植化)
## 0. 为什么存在
项目规则分两层,**能力恰好互补、缺口也恰在这里**:
| 层 | 载体 | 特点 |
|---|---|---|
| **常驻层(权威)** | 工作区 `CODEBUDDY.md`(每会话自动注入 ⇒ **动作前必然生效**) | 它是**工作区文件** ⇒ **换电脑 / 换路径就没了** |
| **可移植层** | 本技能(用户级 `~/.workbuddy/skills/`) | 随技能走,但**不自动注入** |
⇒ 本技能把常驻层的关键章节做成**快照**,并提供 **校验 / 注入 / 环境自检**,让"换环境后规则还在"这件事**可执行、可验证**。
## 1. 命令(脚本 `dsh-env-bootstrap/resident-rules.py`)
```bash
S="<本技能目录>/scripts/resident-rules.py"
python3 "$S" --env-check # ① 环境自检:目录存在性 + hooks 命令里的绝对路径(失效 = 全机 Write/Edit 被拒)
python3 "$S" --check # ② ★校验:关键规则是否齐备(**默认只报**,rc=1 = 有缺失/漂移)
python3 "$S" --inject --init # ③ 注入:目标无标记块时**追加**(不动既有内容);有则在块内替换
python3 "$S" --snapshot # ④ 规则更新后,由权威 CODEBUDDY.md **重生成**技能内快照(单向)
python3 "$S" --goal <路径> # 可指定别的目标 CODEBUDDY.md
```
## 2. 换环境的正确顺序(**把"规则齐备"放在第一步**)
1. `--env-check` —— 先看路径 / hooks 是否失效(**hooks 绝对路径失配 = fail-closed:该机所有会话的 Write/Edit 全被拒**,2026-09-13 实测)
2. `--check` —— 关键规则缺失?⇒ `--inject --init` 追加标记块 ⇒ **人工去重**(块外原有内容与新块可能重复)⇒ 复跑 `--check` 直到 rc=0
3. 逐项核对快照文末的 **§待核清单**(服务器 / 备份目录 / 代码仓 / 工作区)—— **环境相关项不自动配、也不假装能配**
4. 规则更新时:改**权威** `CODEBUDDY.md` → `--snapshot` 重生成快照(**方向单向**)
## 3. 迁移 / 改名后的路径残留清理
> 本工作区已迁过 4 次(`D:\AI技能\` → `E:\ProgramData\AI技能\` → `AIProject\aliyun-dsh-server` → `AIProject\ai1net-dsh-server`),每次都留下**指向旧路径的硬编码**。以下是 2026-09-28 实测过的处理法。
### 3.1 先分类再动手 —— **⛔ 分类要细到「行」,不能只到「文件」**(2026-09-28 血的教训)
**第一层:文件分两类。**
| 类 | 判据 | 处置 |
|---|---|---|
| **活载体** | 会被**读取并据以行动**:状态脚本、规则文件头部的路径声明、可执行脚本、当前工作线入口与接续包、被规则点名为权威的文档 | **改写**为当前路径 |
| **历史档案** | 记录**过去某一棒做过什么**:`memory/` 日志 · `归档/` · `tmp/` · `交付物/` · `session-sync/` · 历史草案 / 审计报告 / 旧交接单 | **⛔ 不改写**(改了 = 伪造记录);在 `README.md` 加一句「历史文档里的旧目录名是当时事实」即可 |
**第二层(🔴 最易漏、代价最大):同一个「活载体」文件里,也有**不能改的行**。**
实测:对「活载体」做**全量替换**会改坏三类行,产出**自相矛盾或伪造**的文本:
| # | 不能改的行 | 改了会怎样(实测例) |
|---|---|---|
| ① | **「污染源」记录本身** | 某技能写「3 条接续棒的 `cwds` **写成** `…\AI技能\aliyun-dsh-server`」⇒ 替换后变成「它们写成了**正确**路径」⇒ **事故记录自毁** |
| ② | **`旧 A → 新 B` 配对里的 A 侧** | 替换把 A 也改成 B ⇒ 句子成 `新 → 新`;脚本里的 `--roots A B` 变成 `A A`(**重复参数**) |
| ③ | **会话库「分组编码名」** | `…AI技能…` → `e-ProgramData-AI技能-…`:那是**当时实际落库的名字**,换了就不是历史 |
⇒ **正确做法 = 行级白名单**:脚本按 `(文件名, 行号)` 白名单改,只纳入已逐处确认是活载体的行(默认值 / 正解字面 / 命令 / 判据 / 注释)。
⇒ **配套**:`--dry-run` 必须**逐行打印「旧 → 新」**(只打印文件+处数看不出误伤);发现误伤就补白名单,⛔ 别指望"再替换回来"。
⚠️ 最容易漏的是**状态脚本里的工作区常量** —— 它错 ⇒ 状态脚本报的是**旧工作区**(实测:报出 5 条并不存在的线),每个新会话的「第 0 步」都会被误导。**修完必须真跑一次状态脚本验收。**
⚠️ **范围别只扫工作区**:实测漏在 `E:/github`、`D:/github`、`~/.workbuddy/skills`、`C:/Users/<u>/.dsh`、`E:/dsh-worker-dev` —— 尤其 **`~/.workbuddy/skills/**` 是真正被加载的技能**,比项目内文档更该先改。
### 3.2 做法(三条硬要求)
1. **字节级替换**(`open(...,'rb')` + `bytes.replace`),⛔ 不 decode/encode ⇒ 行尾与编码零变化。实测同一批里既有 LF 也有 CRLF 文件,混在一起也不会被改坏。
2. **显式文件清单**,⛔ 不用通配符 / 全库遍历;先 `--dry-run` 打印「文件 + 处数」,人工过一遍再 `--apply`;脚本落 `tmp/`(中间产物不入库、可重跑幂等)。
3. **同一条路径有 5 种写法,必须枚举全**:`\` 与 `/` |大写盘符与 MSYS 的 `/e/…` |更早的目录名 |影子根(如 `E:\ProgramDSH\…`)|**会话库的目录编码名**(`e-ProgramData-AIProject-<旧名>` —— 改工作区名不同步它 ⇒ 分组裂开)。漏一种 = 静默残留。
### 3.3 两类「改不动」的残留(⛔ 别硬改、别猜)
- **工具家目录**(`…\.dsh\scripts\…`、`…\.dsh\temp\…` 这类):它不是本工作区的路径,**改名规则不适用**;落点不明 ⇒ **保留原样 + 上报**,⛔ 不推定。
- **同名影子树**(`E:\ProgramDSH\…` 与 `E:\ProgramData\…` 并存):会让 WorkBuddy **凭空多出一个同名会话分组**;登记自动化排期时 `cwds` 必须写**权威那份**。
- 🔴 **2026-09-28 现状**:影子树 `E:\ProgramDSH\` **已整树删除** ⇒ 本条**暂不适用**。保留作**复现判据**:一旦 `E:\` 下再出现同名镜像,立刻按本条处理(判据 = 两个根下同名子目录大部分重合、且镜像侧另有一份同名入口文件)。
### 3.4 改名必须同步的「机制层」两处(⛔ 漏了会静默失效)
工作区**改名**时,除路径字面外,这两处是**机制**,漏改的后果是「看起来正常但防线没了」:
| # | 处 | 漏改后果 | 改法 |
|---|---|---|---|
| 1 | **域锁锚点表**:`handoff-guard.sh` 的 `_ANCHOR_SEGS` / `lock-guard-hook.py` 的 `_DOMAIN_SEGS` | 锚点表里只有**旧名** ⇒ 新工作区路径**算不出域键** ⇒ 域锁**静默退化**(该拦的全放行) | 两表**同时**加新名(**旧名保留**,兼容历史路径);🔴 两侧必须**逐字一致** |
| 2 | **`preflight-lock.sh` 的剥前缀段**(`rel="${rel#*<工作区名>/}"`) | 剥不掉前缀 ⇒ 残留中间段 ⇒ 后面的**正则永不匹配** | 在既有行**之前**加一行剥新名(**顺序=先长后短**) |
⇒ 若该工作区有**多份文档库副本**,每份都要同步(实测有两份,`D:` 权威 + `E:` 旧副本)。
### 3.5 验收(三条,都可复跑)
```bash
# ① 活载体应 0 命中(命中只剩 memory/归档/tmp 等历史档案)
grep -rInE 'AIProject[\\/]<旧名>|ProgramDSH' \
state.py CODEBUDDY.md AGENTS.md README.md .workbuddy/tools docs 接续入口_*.md 接续包_*.md
# ② 真判据:状态脚本现在报的是「当前工作区的线」
<PY> state.py
# ③ 机制层两侧已同步(应各出现旧名与新名;两侧行内容须逐字一致)
grep -n '_ANCHOR_SEGS=' <DOCS>/07-scripts/handoff-guard.sh
grep -n '_DOMAIN_SEGS' <DOCS>/07-scripts/lock-guard-hook.py
```
⚠️ **验收判据要有「反向」的那一条**:① 是"旧路径没了",② 是"新路径真被读到了"。**只做 ① 会漏掉"改漏了机制层"** —— 那种情况里旧路径确实没了、状态也对,但域锁已静默失效。
## 4. 设计红线(别把它用成"第二真相源")
- **权威方向单向**:`CODEBUDDY.md` 是权威,快照是它的副本;**只允许 `--snapshot` 从权威生成副本**,⛔ 不许反向手改快照。
- **默认只报不改**(与文档库「体检只报不改」同规):`--check` **绝不**改任何文件。
- **注入只动标记块**:`<!-- BEGIN resident-rules … --> … <!-- END resident-rules -->` 之间;**首次不自动注入**(避免同一规则在两处并存)。
- **不假装能自动配环境**:环境相关项只做"存在性检查 + 待核清单"。
- ⚠️ **常驻层不可被"搬走"**:本技能**不替代** `CODEBUDDY.md` —— 规则仍必须常驻在**该环境**的 `CODEBUDDY.md`(否则"动作前必然生效"这条就断了);技能只是**把规则带过去并防丢**。
## 5. 自检(用完之后问自己)
1. 我改的是**权威**还是**快照**?(改快照 = 造漂移源)
2. `--check` 绿了吗?红的那条是**真缺失**还是我刚改错?
3. 环境相关项核对了吗(hooks 路径 / 代码仓 / 备份目录 / 工作区)?
4. 注入后有没有**人工去重**(块外原内容 vs 新块)?
5. 给用户的报告**能被扫吗**?—— 排版按 `session-mechanism §5.4`。
6. 是**迁移 / 改名**场景吗?⇒ 跑过 **§3.4 的两条验收**吗(活载体 0 命中 + 状态脚本报的是当前工作区)?
---
## 变更历史(原 frontmatter · 逐字保留)
```text
name: dsh-env-bootstrap
description: DSH 平台项目的「环境引导 / 搬迁」技能 —— 把**工作区常驻规则**(`CODEBUDDY.md` 的关键章节)带走,并在新电脑 / 新工作区路径下**校验与注入**,同时自检环境相关项(绝对路径、hooks 命令、代码仓、备份目录)。当用户说「换电脑了」「改了工作区路径」「迁移到新环境」「规则会不会丢」「新环境还没配好」时使用。
version: 1.2.0
updated_at: 2026-09-28
last_change: 2026-09-28(第 2 次)§3 大改:① §3.1 改为**两层分类** —— 新增「同一个活载体文件里也有不能改的行」三类(污染源记录本身 / `旧→新` 配对里的 A 侧 / 会话库分组编码名),并给出**行级白名单**做法(dry-run 必须逐行打印「旧→新」);② 新增 §3.4「改名必须同步的机制层两处」(域锁锚点表 `_ANCHOR_SEGS`⇄`_DOMAIN_SEGS`、`preflight-lock.sh` 剥前缀段)—— 漏改后果是**域锁静默失效**;③ §3.5 验收加第三条(机制层两侧同步)并写明「只做 ① 会漏掉改漏机制层」。依据 = 2026-09-28 覆盖 `E:/github`·`D:/github`·`~/.workbuddy/skills`·`C:/.dsh` 的实测(107 文件 / 408 处,其中约 10 处属"不能改的行")。
version_note: 此前 1.1.0(2026-09-28)新增 §3「迁移 / 改名后的路径残留清理」(活载体 vs 历史档案分类 · 字节级替换法 · 影子目录坑 · 可复跑验收)。
agent_created: true
```
---
## 变更历史(**对侧副本** frontmatter · 逐字保留 · 来自 `dsh-env-bootstrap` 的 文档库 版)
> ⚠️ 本档正文取自**另一侧**(超集);此处补上对侧副本的版本史,⛔ 以保证不丢任何事实。
```text
name: dsh-env-bootstrap
description: DSH 平台项目的「环境引导 / 搬迁」技能 —— 把**工作区常驻规则**(`CODEBUDDY.md` 的关键章节)带走,并在新电脑 / 新工作区路径下**校验与注入**,同时自检环境相关项(绝对路径、hooks 命令、代码仓、备份目录)。当用户说「换电脑了」「改了工作区路径」「迁移到新环境」「规则会不会丢」「新环境还没配好」时使用。
version: 1.0.0
updated_at: 2026-09-15
last_change: 【2026-09-22 按要求统一版本号】frontmatter `version` → `1.0.0`(原 v1.0.4);正文与历史中的版本号为当时记录,未改动。
agent_created: true
```