用户令逐字:「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/`)。
156 lines
12 KiB
Markdown
156 lines
12 KiB
Markdown
# 环境引导 / 换机迁移 / 改名后的路径残留清理
|
||
|
||
> **归属**:技能 `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
|
||
```
|