f08b12a46c
按「主文留头量、深规程外置」重写本仓技能,全部是逐字搬移:
搬移前断言原文每条非空行必须出现在新主文或 reference 文件里,
0 丢失才落盘;步骤编号一律不重排(正文有「第 12 步」交叉引用);
每个切点保留原小标题 + 索引(加粗引导句与步骤标题)+ 指针行。
主文变化(上限口径 = 插件写侧 65536 字节,见上一笔 skill-size 钩子):
- id-family-semantic-migration 33392 -> 10968(17%),reference 3 篇
- stale-doc-count-sweep 19811 -> 6945(11%),reference 2 篇
- mem-budget 19963 -> 13042(19%),reference 3 篇
- keil-build 12917 -> 8879(14%),reference 2 篇
- task-worktree 72601 -> 28139(42%),reference 8 篇
task-worktree 本笔同时收录另一会话已写完的 C2/D/G 三节正文——那
三处手改与我的拆分落在同一份文件改动里,不可分离;其内容同样已
随 reference/ 外置,主文只剩标题、索引与指针。
外置语料合计 122211 字节 / 30 篇:围栏数逐篇为偶,无 BOM/CR/U+FFFD。
draw-diagram 与 serial-boot-test 脚本是另一会话的在飞改动,本笔未含。
skill-size 钩子在本笔首次真跑(前一笔无 .dsh/skills 文件可触发)。
gate: pre-commit 全绿(doc-links、id-check-new、check-yaml、
skill-size、check-added-large-files);30 篇 reference 手工字节
体检 clean;skill() 逐个复载确认加载的是拆分版。
88 lines
8.1 KiB
Markdown
88 lines
8.1 KiB
Markdown
### F. 与 DSH worktree 插件(`/worktree`、模型工具 `worktree_create`)共存
|
||
|
||
本仓现在有**两套**隔离空间。别混用,也别互相回收:
|
||
|
||
| | `@task`(本 skill) | DSH worktree 插件(`dsh-task-worktree`) |
|
||
|---|---|---|
|
||
| 树在哪 | 仓库**外** `../_wt/<ID>-<slug>/` | 仓库**内** `.dsh-worktrees/worktree/<name>/` |
|
||
| 谁建 | `new <ID> <slug>`(人来敲命令) | 会话选「Worktree模式」/ 模型调 `worktree_create`(零命令) |
|
||
| 台账 | `_wt/.state/<ID>.json`(本 skill) | `.dsh-worktrees/manifest.json`(插件私有格式,别去改) |
|
||
| 分支名 | `task/<ID>-<slug>` | `worktree/<name>` |
|
||
| 共享联接 | `new` 自动建 | **建树时没有** → 要 `plugin adopt` 补 |
|
||
| 回收 | `done`(预演 / 合并 / 门禁 / 清场)或 `abort` | 用户敲 `/worktree finish\|bring-back\|remove\|prune`(模型碰不到收尾命令) |
|
||
|
||
**为什么允许它把树建在仓内**(铁律 7 的唯一例外):路径写死在插件里(`WORKTREE_NAMESPACE = worktree`
|
||
+ `<repo>/.dsh-worktrees/`),而暴露给模型的工具只有 `worktree_create` / `worktree_list` /
|
||
`worktree_status` 三个,配置面改不动。兜法三件(均已落地):
|
||
|
||
1. `.gitignore` **预置** `.dsh-worktrees/` —— 插件首次 `create` 会往 `.gitignore` 追加一模一样的字面量,
|
||
`ensureIgnored()` 见到同名规则即跳过;不预置就等于让插件在会话中途改这份受控文件(diff 里冒出
|
||
一行"不是我加的")。
|
||
2. 全库扫描的排除面登记了它:`scripts/check_doc_links.py` 的 `SKIP_PARTS`、
|
||
`tools/refgraph/gen_refgraph.py` 的 `EXCLUDE_DIRNAMES`、`scripts/check_layer_deps.py` 的 `os.walk` 兜底。
|
||
一份仓库副本被全库扫描吞进去 = 文档链接假红 + 配图生成物逐字节漂移砸在某位同事头上。
|
||
3. 联接与锁归属由本节命令接上(下面三步)。
|
||
|
||
**这棵树是不是插件的**:`git worktree list` 里路径含 `.dsh-worktrees/` 就是。`$TW list` 现在会在台账段
|
||
下面另起一段列出它们,联接列**点名缺哪一样**(`已联` / `缺 .venv` / `缺 SDL2` / `齐(实体SDL2)`)。**插件树不占
|
||
`MAX_CONCURRENT = 8` 名额**——回收不归本 skill,
|
||
硬计入只会让别人那棵关不掉的树把 `new` 挡死(`new` 会打印一行「另有 N 个插件工作树不计入上限」提醒并发代价)。
|
||
|
||
三步接上(`<name>` 可带 `worktree/` 前缀,也可多段如 `refactor/logging`):
|
||
|
||
@T3@bash
|
||
"$PY" "$TW" plugin list # 一览:分支 / 脏 / 缺哪个联接(缺项另起一行说后果)
|
||
"$PY" "$TW" plugin adopt N21-dhara-isfree # 只补缺失的 .venv 与 simulator/SDL2 联接
|
||
"$PY" "$TW" plugin unadopt N21-dhara-isfree # 只摘联接(os.rmdir),绝不动目标内容与树里文件
|
||
@T3@
|
||
|
||
- **两条联接坏了的样子完全不同**:缺 `.venv` → `ci_local.py` 的四级解释器回退**静默**落到机器级
|
||
python(无 fontTools = `generated-fresh` 假红的老根因,AGENTS.md 记着);缺 `simulator/SDL2` →
|
||
`build_sim.bat` 当场报错(`SDL2_DIR` 是裸 `set`,没有 env 逃生口)。所以列表只说「已联」不够——
|
||
它按缺的那一样分别给后果,`adopt` 没补齐也只报「还不能算就绪」,不许说「现在可以跑」。
|
||
- **adopt 只碰联接**:已联的跳过;`simulator/SDL2` 若已是实体目录只告警不动;`.dsh-worktrees/` 之外的路径
|
||
一律 exit 2(实测 `plugin adopt ".."` 被拒)——这道闸防的是把主树或 `_wt` 目录当插件树遮蔽掉真实内容。
|
||
- **锁归属现在认得出来**:`@build` 在插件树里自持自释时,持有者名从 cwd 反推成 `pw:<name>`(多段名压平成
|
||
`-`),与 `plugin adopt` 打印的那个名字逐字相同(`keil_build.py: plugin_tree_owner()` ↔
|
||
`task_worktree.py: plugin_lock_owner()`)→ `lock status` 不再一律落成 `build-cli`。
|
||
- 上台架仍须手工占锁、用同一个名:`lock acquire bench --task pw:<name> --note <说明>` →
|
||
`lock release bench --task pw:<name> --bench-pass`。插件树没有台账 → 按 B 节只 warn、锁照常放。
|
||
- **命名建议**:插件 `<name>` 沿用 `@task` 的 `<ID>-<slug>` 形态(如 `N21-dhara-isfree`),两套视图同名好对账;
|
||
但分支前缀必然不同(`worktree/` vs `task/`),别把两者说成同一个分支。
|
||
- **收尾不在这**:`done` / `abort` 拿插件树名下手只会 exit 2(这是保护,别绕过去手工 `git worktree remove`;
|
||
要拆先 `plugin unadopt` 摘联接,再由**用户** `/worktree remove`)。`/worktree bring-back` 要求主工作树干净,
|
||
本仓常有在飞改动 → 提交或 stash 由用户定。反过来插件也不会碰 `_wt/`(路径根不同,谁也删不掉谁)。
|
||
|
||
### F-1. 两条共享联接**不是同级需求**(按仓库实配定级;别答成「两个都必须」)
|
||
|
||
- **`simulator/SDL2` = 硬需求**:`simulator/CMakeLists.txt:12` 是
|
||
`set(SDL2_DIR "\${CMAKE_CURRENT_SOURCE_DIR}/SDL2/SDL2-2.32.10")`——普通 `set()`、**非 `CACHE`**,所以既没有环境变量入口、
|
||
命令行 `-DSDL2_DIR=` 也会被这个普通变量盖掉;`SDL2_INCLUDE_DIR`(:34)、`SDL2_INCLUDE_PARENT`(:70)、`SDL2_LIB_X64`(:71)、
|
||
链接目录(:180)、`SDL2.dll` 拷贝(:207)**全部从它派生**。缺它 `build_sim.bat` 当场配不出来(脚本里的 `SDL2_DIR` 同样是
|
||
裸 `set`,也没有 env 逃生口)。
|
||
- **`.venv` = 软需求**(有显式逃生门,但绕开有代价):`scripts/ci_local.py` 的解释器解析顺序(:108-:138)——
|
||
① `DTU_PRECOMMIT_PYTHON`(显式配置,指错**立即报错**、不静默降级)→ ② `sys.executable` → ③ 仓库 `.venv` →
|
||
④ `shutil.which("python")` → ⑤ `_global_python_candidates()` 的常见机器级位置。树内没有 `.venv` 时会**静默**落到机器级
|
||
解释器 → 无 fontTools → `generated-fresh` 假红(AGENTS.md 记着的老根因);可以用 `DTU_PRECOMMIT_PYTHON` 顶掉,
|
||
但要每台机器自己配——这就是它「软」的意思:有路可走,走得不爽。
|
||
|
||
结论口径:**要补就两条都补(`plugin adopt` 一次干完,成本近乎零),但「都必须」是错的**——SDL2 没有任何替代路径,
|
||
`.venv` 有 `DTU_PRECOMMIT_PYTHON` 这条门。现役命令形式仍是 `plugin list` / `plugin adopt <name>`;**不改代码、
|
||
不改 `CMakeLists.txt`**(真要给 SDL2 加 CACHE 逃生门属于改模拟器构建口径,另案 → `lvgl-simulator` skill)。
|
||
|
||
### F-2. 「DSH 都有 worktree 插件了,为什么还自持 Python 生命周期」——取证姿势与答案边界
|
||
|
||
这题不许凭印象答,口径 = **实读插件源码**:在 DSH 安装目录定位插件包(`npm root -g` → `<global>/node_modules/@deepseek-ai/dsh/`,
|
||
或读 profile 的 `dsh.profile.bundles` 找包名),**记下版本号与文件路径**,再对三个概念名逐个 grep 并**报出命中数**:
|
||
|
||
1. 独占锁 / 资源串行(`lock`、`acquire`、`release`、TTL)——插件侧**零命中**:它的模型是「一棵树一个会话」,没有跨会话排队概念。
|
||
2. 共享目录联接(`.venv`、`simulator/SDL2`、`mklink /J`、reparse point)——零命中:插件建树就是纯 `git worktree add`,
|
||
所以插件树天生缺这两条联接(定级见 F-1)。
|
||
3. 联接状态显示(三态:已联 / 缺 .venv / 缺 SDL2 / 齐(实体SDL2))——零命中。
|
||
|
||
**重叠面要说清**:两侧底层是**同一条** `git worktree add`,本 skill 没有重造「建树」;重叠只在**开**与**收**两个动作,
|
||
而插件的收(`/worktree finish|bring-back|remove|prune`)是**人类命令**、模型碰不到,也没有「合并前预演 → 并集残留审计 →
|
||
补基线 → 门禁 → 先摘联接」这条编排。本仓为什么必须自持:硬件各只有一份(一块 ST-LINK、一套 Keil 授权、一个 COM6、
|
||
一个 `192.168.1.100`)→ 要 `build` / `bench` 锁串行;SDL2 是模拟器硬依赖且无逃生门 → 要共享联接;台架 PASS 要留给
|
||
`done` 记账 → 要台账。**给不出版本号与 grep 命中数,就不要下结论。**
|