From bc9f593a3e5becc264c293481e9f8692dea9d5eb Mon Sep 17 00:00:00 2001 From: yanghl Date: Thu, 18 Jun 2026 09:27:45 +0800 Subject: [PATCH] req-ledger: 跟踪 prototype/ 原型快照——修复 add-req 检测不到原型变动 --- README.md | 2 +- lib/req-ledger.mjs | Bin 7918 -> 10311 bytes lib/req-ledger.test.mjs | 40 ++++++++++++++++++++++++++++++++++++++-- skills/plan/add-req/SKILL.md | 12 ++++++++++-- 4 files changed, 49 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c413356..5dbda02 100644 --- a/README.md +++ b/README.md @@ -121,7 +121,7 @@ erp-workflow-plugin/ │ ├── validate-ddl.mjs # docs/03 ↔ DDL 4 维校验(替代 validate.sh) │ ├── yaml-config.mjs # config-vars.yaml 极简 YAML 读取(2 层 map + 标量) │ ├── apply-ddl.mjs # 解析 config-vars.yaml database: 段 + mysql2 apply -│ ├── req-ledger.mjs # 需求台账:docs/01 REQ + docs/08 §三 FE 内容哈希,scan/commit 识别新增/变更(add-req 用) +│ ├── req-ledger.mjs # 需求台账:docs/01 REQ + docs/08 §三 FE + prototype/ 原型快照 内容哈希,scan/commit 识别新增/变更(add-req 用) │ └── *.test.mjs # 各助手的 node:test 单测 ├── agents/ │ └── code-reviewer.md # 统一 reviewer(coding.mjs review stage 调用,phase 选维度集) diff --git a/lib/req-ledger.mjs b/lib/req-ledger.mjs index 964251c..7281e3a 100644 Binary files a/lib/req-ledger.mjs and b/lib/req-ledger.mjs differ diff --git a/lib/req-ledger.test.mjs b/lib/req-ledger.test.mjs index 87ea480..3e3304c 100644 --- a/lib/req-ledger.test.mjs +++ b/lib/req-ledger.test.mjs @@ -5,8 +5,8 @@ import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' import { - hashContent, collectReqUnits, collectFeUnits, computeUnits, - loadLedger, writeLedger, diffLedger, + hashContent, collectReqUnits, collectFeUnits, collectProtoUnit, computeUnits, + loadLedger, writeLedger, diffLedger, PROTO_UNIT_ID, } from './req-ledger.mjs' // 搭一个最小项目目录:docs/01-需求清单//{_module.md,index.md,.md} + docs/08 @@ -55,6 +55,42 @@ test('computeUnits: req + fe 合并', () => { } finally { rmSync(root, { recursive: true, force: true }) } }) +test('collectProtoUnit: 无 prototype/ → 空;有 .html → 单一 __prototype__ 单元', () => { + const root = scaffold() + try { + assert.equal(collectProtoUnit(root).size, 0) // scaffold 无 prototype/ + const protoDir = join(root, 'prototype', 'pages') + mkdirSync(protoDir, { recursive: true }) + writeFileSync(join(root, 'prototype', 'index.html'), '

首页

') + writeFileSync(join(protoDir, 'login.html'), '
登录
') + const u = collectProtoUnit(root) + assert.deepEqual([...u.keys()], [PROTO_UNIT_ID]) + assert.equal(u.get(PROTO_UNIT_ID).kind, 'proto') + } finally { rmSync(root, { recursive: true, force: true }) } +}) + +test('原型内容改动被 diff 识别为 changed(FE 行文字不变也能检测到)', () => { + const root = scaffold() + try { + writeFileSync(join(root, 'docs', '01-需求清单', 'index.md'), '# 索引\n') // 占位,无关 + mkdirSync(join(root, 'prototype'), { recursive: true }) + const proto = join(root, 'prototype', 'order.html') + writeFileSync(proto, '
订单页 v1
') + writeLedger(root, computeUnits(root)) // 建基线(含原型快照) + + // 只改原型内容,docs/08 §三 FE 行文字一字不动 + writeFileSync(proto, '
订单页 v2 改了布局
') + const diff = diffLedger(loadLedger(root), computeUnits(root)) + assert.deepEqual(diff.changed.map((x) => x.id), [PROTO_UNIT_ID]) + assert.equal(diff.changed[0].kind, 'proto') + + // 删除原型文件 → removed + rmSync(proto) + const diff2 = diffLedger(loadLedger(root), computeUnits(root)) + assert.deepEqual(diff2.removed.map((x) => x.id), [PROTO_UNIT_ID]) + } finally { rmSync(root, { recursive: true, force: true }) } +}) + test('diffLedger: 台账缺失 → 全部算 new', () => { const root = scaffold() try { diff --git a/skills/plan/add-req/SKILL.md b/skills/plan/add-req/SKILL.md index d34336c..b691acc 100644 --- a/skills/plan/add-req/SKILL.md +++ b/skills/plan/add-req/SKILL.md @@ -1,6 +1,6 @@ --- name: add-req -description: 增量需求入口——初始 Plan 完结后追加 / 修改需求时运行。基于 lib/req-ledger.mjs 内容哈希台账识别新增 / 变更的 REQ 卡片与 FE 行,只对增量做 A3-delta(写 V_n migration + 同步 docs/03,绝不改 V1)+ A5-delta(补 docs/05 端点 / docs/02 顺序 / docs/08 模块行),并作废变更单元已有的 req-done/milestone tag,使 coding.mjs Router 只重跑增量、不必整仓重跑。 +description: 增量需求入口——初始 Plan 完结后追加 / 修改需求时运行。基于 lib/req-ledger.mjs 内容哈希台账识别新增 / 变更的 REQ 卡片、FE 行与原型快照(prototype/**/*.html),只对增量做 A3-delta(写 V_n migration + 同步 docs/03,绝不改 V1)+ A5-delta(补 docs/05 端点 / docs/02 顺序 / docs/08 模块行),并作废变更单元已有的 req-done/milestone tag(原型变更则整体重跑前端阶段),使 coding.mjs Router 只重跑增量、不必整仓重跑。 user-invocable: true allowed-tools: Read Write Edit Grep Glob AskUserQuestion Bash(node *) Bash(git *) Bash(ls *) Bash(mkdir *) --- @@ -51,7 +51,9 @@ node ${CLAUDE_PLUGIN_ROOT}/lib/req-ledger.mjs scan ## 步骤 1:检测增量 -用步骤 0 已得到的 scan 输出解析 `new[]` / `changed[]` / `removed[]`(每项 `{id, kind}`,kind = `req` 后端卡片 / `fe` 前端功能行)。 +用步骤 0 已得到的 scan 输出解析 `new[]` / `changed[]` / `removed[]`(每项 `{id, kind}`,kind = `req` 后端卡片 / `fe` 前端功能行 / `proto` 原型快照——全部 `prototype/**/*.html` 聚成的单一单元,id 固定 `__prototype__`)。 + +> **原型变更(kind=proto)**:原型是前端布局/页面/交互的权威,但 FE 行只哈希行文字,改原型而 FE 行文字不变时旧台账检测不到。`__prototype__` 单元把所有原型 html 内容纳入哈希,任一原型文件改动即被识别。**老项目首次升级到带原型跟踪的台账时**,`__prototype__` 会作为 `new` 出现(无历史哈希可比)——此为基线建立,步骤 5 不作废任何 tag,步骤 6 提交后才成基线;其后再改原型才会显示为 `changed` 并触发前端重跑。 - `new` 与 `changed` 均为空 → 打印 `[add-req] 无新增 / 变更需求,无需处理。[ERP-HALT]` **停下**(不提交台账)。 - `removed` 非空 → **仅提示、不自动删**:打印 `检测到台账登记但 docs 已移除的单元:<列出>。下线需求请人工同步 docs/02/03/05 并删除对应 tag,本 skill 不自动执行删除。` 然后继续处理 new/changed(removed 不写回台账,留待人工,下次仍会提示)。 @@ -107,6 +109,11 @@ node ${CLAUDE_PLUGIN_ROOT}/lib/req-ledger.mjs scan - `git -C tag -l "req-done/"` 存在 → 删。 - 前端阶段若已 `milestone/frontend-phase` → 删该 tag,并 `Edit` `docs/08 §三` `整体里程碑:` 复位 `—`。 +- **kind=proto**(`__prototype__`,原型快照变更):原型是整个前端的权威,FE 行与具体原型文件无显式映射,且前端在 Coding 阶段本就是单一 `frontend-phase` 里程碑——故任一原型文件改动按「前端阶段需整体重跑」处理: + - 删**全部**前端功能完成 tag:`git -C tag -l "req-done/FE-*"` 列出后逐个 `git -C tag -d `(Router 据 `req-done/` 缺失把 FE 收回 `frontend-phase`,单删 milestone 不够)。 + - `milestone/frontend-phase` 存在 → `git -C tag -d milestone/frontend-phase`,并 `Edit` `docs/08 §三` `整体里程碑:` 复位 `—`。 + - (若曾开 `frontendOverlap`:同时 `git -C tag -l "fe-code-done/FE-*"` 逐个删,复位 phase1 重叠状态。缺省关时无此 tag,跳过。) + 逐条记录已删的 tag,供步骤 6 横幅汇总。 ## 步骤 6:更新台账 + git 提交全部增量产物 + 完成横幅 @@ -134,6 +141,7 @@ node ${CLAUDE_PLUGIN_ROOT}/lib/req-ledger.mjs scan 新增 REQ:<列出 id 或 无> 变更 REQ:<列出 id 或 无> 新增 FE :<列出 FE-NN 或 无> + 原型变更:<是(前端阶段整体重跑)/ 否> 新增 migration: 作废 tag:<列出已删的 req-done/* 与 milestone/* 或 无> -- libgit2 0.22.2