agentic-flow-kit 1.4.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/modules/hosts/claude/agents/implementer.md +5 -6
- package/modules/hosts/claude/agents/independent-reviewer.md +6 -6
- package/modules/hosts/claude/agents/ui-verifier.md +5 -5
- package/modules/hosts/claude/commands/wf-build.md +28 -21
- package/modules/hosts/claude/commands/wf-deploy.md +2 -2
- package/modules/hosts/claude/commands/wf-design.md +14 -8
- package/modules/hosts/claude/commands/wf-gate-checklist.md +8 -8
- package/modules/hosts/claude/commands/wf-maintain.md +12 -12
- package/modules/hosts/claude/commands/wf-new-task.md +11 -9
- package/modules/hosts/claude/commands/wf-pipeline-run.md +3 -3
- package/modules/hosts/claude/commands/wf-plan.md +10 -11
- package/modules/hosts/claude/commands/wf-review.md +4 -4
- package/modules/hosts/claude/commands/wf-source-sync-check.md +10 -10
- package/modules/hosts/claude/commands/wf-sync-hosts.md +9 -9
- package/modules/hosts/claude/commands/wf-test.md +5 -6
- package/modules/hosts/codex/agents/implementer.md +5 -6
- package/modules/hosts/codex/agents/independent-reviewer.md +6 -6
- package/modules/hosts/codex/agents/ui-verifier.md +5 -5
- package/modules/hosts/codex/commands/wf-build.md +28 -21
- package/modules/hosts/codex/commands/wf-deploy.md +2 -2
- package/modules/hosts/codex/commands/wf-design.md +14 -8
- package/modules/hosts/codex/commands/wf-gate-checklist.md +8 -8
- package/modules/hosts/codex/commands/wf-maintain.md +12 -12
- package/modules/hosts/codex/commands/wf-new-task.md +11 -9
- package/modules/hosts/codex/commands/wf-pipeline-run.md +3 -3
- package/modules/hosts/codex/commands/wf-plan.md +10 -11
- package/modules/hosts/codex/commands/wf-review.md +4 -4
- package/modules/hosts/codex/commands/wf-source-sync-check.md +10 -10
- package/modules/hosts/codex/commands/wf-sync-hosts.md +9 -9
- package/modules/hosts/codex/commands/wf-test.md +5 -6
- package/modules/hosts/cursor/agents/implementer.md +5 -6
- package/modules/hosts/cursor/agents/independent-reviewer.md +6 -6
- package/modules/hosts/cursor/agents/ui-verifier.md +5 -5
- package/modules/hosts/cursor/commands/wf-build.md +28 -21
- package/modules/hosts/cursor/commands/wf-deploy.md +2 -2
- package/modules/hosts/cursor/commands/wf-design.md +14 -8
- package/modules/hosts/cursor/commands/wf-gate-checklist.md +8 -8
- package/modules/hosts/cursor/commands/wf-maintain.md +12 -12
- package/modules/hosts/cursor/commands/wf-new-task.md +11 -9
- package/modules/hosts/cursor/commands/wf-pipeline-run.md +3 -3
- package/modules/hosts/cursor/commands/wf-plan.md +10 -11
- package/modules/hosts/cursor/commands/wf-review.md +4 -4
- package/modules/hosts/cursor/commands/wf-source-sync-check.md +10 -10
- package/modules/hosts/cursor/commands/wf-sync-hosts.md +9 -9
- package/modules/hosts/cursor/commands/wf-test.md +5 -6
- package/modules/hosts/omp/agents/implementer.md +5 -6
- package/modules/hosts/omp/agents/independent-reviewer.md +6 -6
- package/modules/hosts/omp/agents/ui-verifier.md +5 -5
- package/modules/hosts/opencode/agents/implementer.md +5 -6
- package/modules/hosts/opencode/agents/independent-reviewer.md +6 -6
- package/modules/hosts/opencode/agents/ui-verifier.md +5 -5
- package/modules/hosts/opencode/commands/wf-build.md +28 -21
- package/modules/hosts/opencode/commands/wf-deploy.md +2 -2
- package/modules/hosts/opencode/commands/wf-design.md +14 -8
- package/modules/hosts/opencode/commands/wf-gate-checklist.md +8 -8
- package/modules/hosts/opencode/commands/wf-maintain.md +12 -12
- package/modules/hosts/opencode/commands/wf-new-task.md +11 -9
- package/modules/hosts/opencode/commands/wf-pipeline-run.md +3 -3
- package/modules/hosts/opencode/commands/wf-plan.md +10 -11
- package/modules/hosts/opencode/commands/wf-review.md +4 -4
- package/modules/hosts/opencode/commands/wf-source-sync-check.md +10 -10
- package/modules/hosts/opencode/commands/wf-sync-hosts.md +9 -9
- package/modules/hosts/opencode/commands/wf-test.md +5 -6
- package/modules/hosts/trae/agents/implementer.md +5 -6
- package/modules/hosts/trae/agents/independent-reviewer.md +6 -6
- package/modules/hosts/trae/agents/ui-verifier.md +5 -5
- package/modules/hosts/trae/commands/wf-build.md +28 -21
- package/modules/hosts/trae/commands/wf-deploy.md +2 -2
- package/modules/hosts/trae/commands/wf-design.md +14 -8
- package/modules/hosts/trae/commands/wf-gate-checklist.md +8 -8
- package/modules/hosts/trae/commands/wf-maintain.md +12 -12
- package/modules/hosts/trae/commands/wf-new-task.md +11 -9
- package/modules/hosts/trae/commands/wf-pipeline-run.md +3 -3
- package/modules/hosts/trae/commands/wf-plan.md +10 -11
- package/modules/hosts/trae/commands/wf-review.md +4 -4
- package/modules/hosts/trae/commands/wf-source-sync-check.md +10 -10
- package/modules/hosts/trae/commands/wf-sync-hosts.md +9 -9
- package/modules/hosts/trae/commands/wf-test.md +5 -6
- package/modules/hosts/zcode/agents/implementer.md +5 -6
- package/modules/hosts/zcode/agents/independent-reviewer.md +6 -6
- package/modules/hosts/zcode/agents/ui-verifier.md +5 -5
- package/package.json +7 -2
- package/src/doctor.mjs +1 -1
- package/src/init.test.mjs +1 -1
- package/src/run-tests.mjs +15 -1
- package/src/sync-hosts.mjs +100 -62
- package/src/sync-hosts.test.mjs +43 -4
- package/src/sync.test.mjs +1 -1
- package/templates/_agents/commands/build.md +28 -21
- package/templates/_agents/commands/deploy.md +2 -2
- package/templates/_agents/commands/design.md +14 -8
- package/templates/_agents/commands/gate-checklist.md +8 -8
- package/templates/_agents/commands/maintain.md +12 -12
- package/templates/_agents/commands/new-task.md +11 -9
- package/templates/_agents/commands/pipeline-run.md +3 -3
- package/templates/_agents/commands/plan.md +10 -11
- package/templates/_agents/commands/review.md +4 -4
- package/templates/_agents/commands/source-sync-check.md +10 -10
- package/templates/_agents/commands/sync-hosts.md +9 -9
- package/templates/_agents/commands/test.md +5 -6
- package/templates/_agents/roles/implementer.md +5 -6
- package/templates/_agents/roles/independent-reviewer.md +6 -6
- package/templates/_agents/roles/ui-verifier.md +5 -5
- package/templates/_agents/scripts/agg-delegations.cjs +0 -1
- package/templates/_agents/scripts/agg-delegations.test.mjs +2 -2
- package/templates/_agents/scripts/check-hygiene.mjs +2 -2
- package/templates/_agents/scripts/check-ledger-invariant.mjs +0 -1
- package/templates/_agents/scripts/check-loop.mjs +115 -38
- package/templates/_agents/scripts/check-loop.test.mjs +67 -1
- package/templates/_agents/scripts/check-stage-index.mjs +40 -0
- package/templates/_agents/scripts/check-stage-index.test.mjs +77 -0
- package/templates/_agents/scripts/commit-check-trigger.test.mjs +0 -1
- package/templates/_agents/scripts/confirm-doc.mjs +17 -3
- package/templates/_agents/scripts/confirm-doc.test.mjs +17 -0
- package/templates/_agents/scripts/edit-face-check.mjs +107 -0
- package/templates/_agents/scripts/edit-face-check.test.mjs +98 -0
- package/templates/_agents/scripts/ensure-board.mjs +2 -2
- package/templates/_agents/scripts/fill-intent.mjs +34 -5
- package/templates/_agents/scripts/fill-intent.test.mjs +13 -0
- package/templates/_agents/scripts/fill-plan.mjs +1 -2
- package/templates/_agents/scripts/gen-wiki-board.mjs +1 -1
- package/templates/_agents/scripts/gen-workflow-dashboard.test.mjs +0 -2
- package/templates/_agents/scripts/gen-workflow-index.test.mjs +1 -1
- package/templates/_agents/scripts/gen-workflow-metrics.mjs +53 -2
- package/templates/_agents/scripts/kb-search.mjs +1 -2
- package/templates/_agents/scripts/kb-search.test.mjs +1 -1
- package/templates/_agents/scripts/pipeline-run-docs.mjs +76 -0
- package/templates/_agents/scripts/pipeline-run-run.mjs +63 -0
- package/templates/_agents/scripts/pipeline-run.mjs +8 -128
- package/templates/_agents/scripts/policy.mjs +20 -1
- package/templates/_agents/scripts/source-sync-check.mjs +2 -2
- package/templates/_agents/scripts/source-sync-check.test.mjs +1 -1
- package/templates/_agents/scripts/verify-wiki-consistency.mjs +0 -1
- package/templates/_agents/scripts/verify-wiki-consistency.test.mjs +81 -0
- package/templates/_agents/scripts/verify.test.mjs +2 -2
- package/templates/_agents/scripts/wiki-search.test.mjs +58 -0
- package/templates/_agents/scripts/workflow-board-server.test.mjs +0 -1
- package/templates/_agents/scripts/workflow-enums.test.mjs +0 -1
- package/templates/_agents/scripts-test-exempt.txt +5 -3
- package/templates/_github/workflows/kit-ci.yml +21 -1
|
@@ -13,16 +13,16 @@ description: 跨宿主适配层同步(正文段 sha 比对 + 用户拍板 +
|
|
|
13
13
|
> 比 `templates/_agents` ↔ `modules/hosts/<宿主键>/`;含 `.agents` → 装户:比 `.agents` ↔ 项目根下 `<宿主点目录>/`),
|
|
14
14
|
> 目标根取 `--dir <目录>` > 当前目录。
|
|
15
15
|
|
|
16
|
-
## 何时跑
|
|
16
|
+
## 1. 何时跑
|
|
17
17
|
|
|
18
18
|
- 改 `templates/_agents/commands/*.md` 正文后(11 个 commands 文件)
|
|
19
19
|
- 改 `templates/_agents/roles/*.md` 正文后(3 个 roles 文件)
|
|
20
20
|
- 装户跑 `flow-kit doctor` 报"跨宿主薄适配正文漂移 N 对" WARN 时
|
|
21
21
|
- 不跑:仅改 frontmatter;改 trae 钩子/规则;改包源其他文件
|
|
22
22
|
|
|
23
|
-
## 怎么跑
|
|
23
|
+
## 2. 怎么跑
|
|
24
24
|
|
|
25
|
-
### 默认 `--diff`(仅报告)
|
|
25
|
+
### 2.1 默认 `--diff`(仅报告)
|
|
26
26
|
|
|
27
27
|
```
|
|
28
28
|
node bin/flow-kit.mjs sync-hosts --diff # 包源仓(在包源根跑)
|
|
@@ -36,7 +36,7 @@ flow-kit sync-hosts --diff # 装户仓(在装户根跑;或
|
|
|
36
36
|
- **⚠️ 权威源声明但薄适配缺失** — `add-host <h>` 接管后跑 `--apply` 才会装(apply 不自动创建)
|
|
37
37
|
- **⚠️ 孤儿薄适配(权威源无对应文件)** — 历史残留或宿主特化,apply 不删
|
|
38
38
|
|
|
39
|
-
### `--apply` 单向同步
|
|
39
|
+
### 2.2 `--apply` 单向同步
|
|
40
40
|
|
|
41
41
|
```
|
|
42
42
|
node bin/flow-kit.mjs sync-hosts --apply
|
|
@@ -44,7 +44,7 @@ node bin/flow-kit.mjs sync-hosts --apply
|
|
|
44
44
|
|
|
45
45
|
按权威源正文覆盖薄适配正文段;薄适配原 frontmatter 保留(trae name: wf-X、opencode 描述、zcode/omp 中文风格各自不动)。apply 不反向同步——薄适配手改了正文也会被覆盖(这是设计选择,避免漂移方向歧义)。
|
|
46
46
|
|
|
47
|
-
### 自验
|
|
47
|
+
### 2.3 自验
|
|
48
48
|
|
|
49
49
|
```
|
|
50
50
|
npm test # 含 sync-hosts.test.mjs 8 场景
|
|
@@ -52,7 +52,7 @@ node bin/flow-kit.mjs doctor # 装户跑 §7.x PASS;包源
|
|
|
52
52
|
sh .agents/scripts/check-loop.sh # Windows 无 sh 时 doctor 已探测分流
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
## 边界(不要做)
|
|
55
|
+
## 3. 边界(不要做)
|
|
56
56
|
|
|
57
57
|
- 不要 `--apply` 反向同步(写权威源):权威源是真相,薄适配手改会被覆盖——这是设计,apply 前先看 `--diff`
|
|
58
58
|
- 不要删除孤儿薄适配:可能是宿主特化或历史残留,apply 不动
|
|
@@ -60,14 +60,14 @@ sh .agents/scripts/check-loop.sh # Windows 无 sh 时 doctor 已
|
|
|
60
60
|
- 不要把「避免与权威版本漂移」明文加回去——这是旧契约的指针风格,已被 B-b 正文副本取代
|
|
61
61
|
- 装了新宿主后跑 `--apply`:新宿主目录空白,apply 不会自动创建薄适配(薄适配须经 `add-host <h>` 接管)
|
|
62
62
|
|
|
63
|
-
## 不在本次同步范围
|
|
63
|
+
## 4. 不在本次同步范围
|
|
64
64
|
|
|
65
65
|
- trae 钩子(`modules/hosts/trae/hooks/*.cjs`)— 独立演进的工程件
|
|
66
66
|
- trae 规则(`modules/hosts/trae/rules/*.md`)— 同上
|
|
67
67
|
- 包源 .agents/scripts/*.cjs(pre-commit 等钩子)— 同步由 `flow-kit sync` 走 managed 台账负责
|
|
68
68
|
|
|
69
|
-
## 相关留痕
|
|
69
|
+
## 5. 相关留痕
|
|
70
70
|
|
|
71
71
|
- intent:`workflow/intents/2026-09-25-cross-host-sync.md`
|
|
72
72
|
- plan:`workflow/plans/2026-09-25-cross-host-sync.md`(含 B-b 方案拍板)
|
|
73
|
-
- incident:`workflow/incidents/2026-09-25-wf-runtime.md`(双源纪律教训,规范 §7.x 包源环境跳过)
|
|
73
|
+
- incident:`workflow/incidents/2026-09-25-wf-runtime.md`(双源纪律教训,规范 §7.x 包源环境跳过)
|
|
@@ -47,20 +47,19 @@ node bin/flow-kit.mjs doctor # §6.5 delegations + §6.6 o
|
|
|
47
47
|
- 复核者读入口文档(intent / incident) + spec + plan + diff,判断变更意图与风险
|
|
48
48
|
- 复核意见交用户定性(采纳 / 驳回);采纳项回 `build.md` 修改
|
|
49
49
|
|
|
50
|
-
## 子代理调用约定
|
|
50
|
+
## 5. 子代理调用约定
|
|
51
51
|
|
|
52
52
|
- 静态门不委派;UI 实测委派 `ui-verifier`(静态门通过后)、独立复核委派 `independent-reviewer`,均要求读取对应 `.agents/roles/*.md`;宿主不支持时按 frontmatter `fallback`(reviewer 必须另开新会话,不得主智能体自查冒充)。
|
|
53
53
|
- 子智能体只返回证据与结论——失败项修复仍回 `build.md`,不得在 Test 阶段顺手改代码;修复后重跑本阶段,全过后用户确认再关单。
|
|
54
54
|
|
|
55
|
-
##
|
|
55
|
+
## 6. 确认后(关单)
|
|
56
56
|
|
|
57
|
-
- 输出测试报告(通过项 / 失败项)
|
|
58
|
-
- 失败项已修复并复测通过
|
|
57
|
+
- 输出测试报告(通过项 / 失败项);失败项已修复并复测通过。
|
|
59
58
|
- **关单**(日常闭环点,不依赖是否上 prod):
|
|
60
59
|
- 关单前一键过门:`node .agents/scripts/verify.mjs --doc workflow/intents/<本单>.md`(npm test + check-loop 固定编排,任一失败非零退出,非绿不关单);**`--doc` 把测试绿凭证绑到本单**——不带它落下的绿行不给任何单背书,confirm-doc 前置与检查 8 对账只认带本单 `--doc` 的绿行(仅 v6+ 生效);**装户仓**(根目录无 `package.json`,工程在子目录)默认 `npm test` 不可跑 → 脚本**显式跳过步骤 1 且不落测试绿凭证**(防假绿)并提示;此时按项目口径手工跑测试,或带 `--test-cmd "<项目测试命令>"` 指定(2026-10-07 papercut)
|
|
61
|
-
- 新需求:逐条勾验入口 intent「验收标准」,每条补「证据:」(例如:粘贴 CI 运行结果、UI 截图路径、或具体的 commit SHA),intent
|
|
60
|
+
- 新需求:逐条勾验入口 intent「验收标准」,每条补「证据:」(例如:粘贴 CI 运行结果、UI 截图路径、或具体的 commit SHA),intent → done;同名 spec/Quick-Plan(若有)仍 approved → done。**注意:勾选但缺证据会被 check-loop 拦截(hard-block)**
|
|
62
61
|
- **approved 留痕提交**(2026-09-30 起):done 确认前确认**本次关单文档**的 approved 态已进 git 历史(越早越好——approved 后即应提交;若尚未,先补提交再 done;门为逐份校验,三件套均关单时逐份各自满足)——confirm-doc 的 done 前置门硬校验(历史未出现「状态: approved」→ 拒绝落账);done 后再提交 done 态与其余改动
|
|
63
|
-
|
|
62
|
+
- **确认落态**:唯一入口 `node .agents/scripts/confirm-doc.mjs <path>`(两形态 / 逐件+逐件原话 / done 内容绑定(关单编辑先于 done 确认、confirm-doc 是最后一次写入)/ 台账对质全口径见根 `AGENTS.md` §1.3 确认门)。
|
|
64
63
|
- 修复:防复发验证已落地,incident → closed(经确认门 confirm-doc:open→fixed / fixed→closed 两跳、无单跳;2026-09-28 起 check-loop 15 对账——关单编辑先于 closed 确认,口径同 done 内容绑定)
|
|
65
64
|
- **同族收尾**:入口置终态时,同名 plan 一并置 `done`(spec 见上条),不留 `approved` 孤儿(口径同看板「入口已 done,本 plan 未终态」告警)
|
|
66
65
|
- 主智能体自做的 L1+ 新需求在 `workflow/delegations.md`「自做任务结果表」记一行(修复类不重复记)
|
|
@@ -6,7 +6,7 @@ description: 在已批准且边界明确的工作包内实现改动或补测试
|
|
|
6
6
|
|
|
7
7
|
> 公共角色契约(本文件):`.agents/roles/implementer.md`。宿主薄适配(各宿主目录下 `agents/implementer.md`)正文段同源本文件,frontmatter 各自保留宿主特化字段(check-loop 检查项 6 按本引用校验适配层不断线)。
|
|
8
8
|
|
|
9
|
-
## 职责
|
|
9
|
+
## 1. 职责
|
|
10
10
|
|
|
11
11
|
执行已经由主智能体和用户确认、范围明确的实现任务。适用范围仅限:
|
|
12
12
|
|
|
@@ -15,7 +15,7 @@ description: 在已批准且边界明确的工作包内实现改动或补测试
|
|
|
15
15
|
- 编写或调整任务直接要求的测试
|
|
16
16
|
- 修复与任务直接相关的编译错误
|
|
17
17
|
|
|
18
|
-
## 必需输入
|
|
18
|
+
## 2. 必需输入
|
|
19
19
|
|
|
20
20
|
开始前必须获得:
|
|
21
21
|
|
|
@@ -26,7 +26,7 @@ description: 在已批准且边界明确的工作包内实现改动或补测试
|
|
|
26
26
|
|
|
27
27
|
任一输入缺失或相互冲突时,停止并向主智能体报告,不自行扩大范围。
|
|
28
28
|
|
|
29
|
-
## 行为边界
|
|
29
|
+
## 3. 行为边界
|
|
30
30
|
|
|
31
31
|
- 只修改明确授权的文件;若必须触及其他文件,先停止并说明原因。
|
|
32
32
|
- 仓库可能有其他智能体或用户同时工作;保留现有改动,不回退、不覆盖无关修改。
|
|
@@ -35,13 +35,13 @@ description: 在已批准且边界明确的工作包内实现改动或补测试
|
|
|
35
35
|
- 不执行提交、推送、发布、数据迁移或破坏性操作。
|
|
36
36
|
- 不顺手重构、格式化或清理与任务无关的代码。
|
|
37
37
|
|
|
38
|
-
## 验证
|
|
38
|
+
## 4. 验证
|
|
39
39
|
|
|
40
40
|
- 运行任务指定的最小相关检查。
|
|
41
41
|
- 检查失败时只修复由本次改动引起且仍在授权范围内的问题。
|
|
42
42
|
- 同一验证连续失败三次,或继续需要猜测需求时,停止并报告阻塞。
|
|
43
43
|
|
|
44
|
-
## 输出
|
|
44
|
+
## 5. 输出
|
|
45
45
|
|
|
46
46
|
返回给主智能体:
|
|
47
47
|
|
|
@@ -49,4 +49,3 @@ description: 在已批准且边界明确的工作包内实现改动或补测试
|
|
|
49
49
|
2. 每个文件的改动摘要
|
|
50
50
|
3. 已运行的验证及结果
|
|
51
51
|
4. 未解决的阻塞或剩余风险
|
|
52
|
-
|
|
@@ -6,11 +6,11 @@ description: 只读独立复核(spec 或实现 diff);不改动文件、不
|
|
|
6
6
|
|
|
7
7
|
> 公共角色契约(本文件):`.agents/roles/independent-reviewer.md`。宿主薄适配(各宿主目录下 `agents/independent-reviewer.md`)正文段同源本文件,frontmatter 各自保留宿主特化字段(check-loop 检查项 6 按本引用校验适配层不断线)。
|
|
8
8
|
|
|
9
|
-
## 职责
|
|
9
|
+
## 1. 职责
|
|
10
10
|
|
|
11
11
|
在独立上下文中对 spec、plan 或代码 diff 做只读复核,发现原作者可能遗漏的正确性、契约、架构、数据安全和回归风险。
|
|
12
12
|
|
|
13
|
-
## 必需输入
|
|
13
|
+
## 2. 必需输入
|
|
14
14
|
|
|
15
15
|
开始前必须获得:
|
|
16
16
|
|
|
@@ -21,7 +21,7 @@ description: 只读独立复核(spec 或实现 diff);不改动文件、不
|
|
|
21
21
|
|
|
22
22
|
输入不足以确定范围时,停止并向主智能体报告。
|
|
23
23
|
|
|
24
|
-
## 行为边界
|
|
24
|
+
## 3. 行为边界
|
|
25
25
|
|
|
26
26
|
- 只读,不修改任何仓库文件。
|
|
27
27
|
- 不替用户决定问题定性、方案取舍、合入或上线。
|
|
@@ -30,7 +30,7 @@ description: 只读独立复核(spec 或实现 diff);不改动文件、不
|
|
|
30
30
|
- 不把样式偏好、假设性风险或既有无关问题包装成缺陷。
|
|
31
31
|
- 无法验证的事项明确标为未验证,不声称已经通过。
|
|
32
32
|
|
|
33
|
-
## 复核重点
|
|
33
|
+
## 4. 复核重点
|
|
34
34
|
|
|
35
35
|
1. 实现是否满足入口文档和验收标准
|
|
36
36
|
2. 是否违反根 `AGENTS.md` 与改动域目录级 `AGENTS.md` 的架构、数据和所在域红线
|
|
@@ -38,7 +38,7 @@ description: 只读独立复核(spec 或实现 diff);不改动文件、不
|
|
|
38
38
|
4. 是否缺少能防止回归的验证
|
|
39
39
|
5. 是否存在数据丢失、安全、权限或发布风险
|
|
40
40
|
|
|
41
|
-
## 输出
|
|
41
|
+
## 5. 输出
|
|
42
42
|
|
|
43
43
|
按严重度输出问题清单:
|
|
44
44
|
|
|
@@ -46,4 +46,4 @@ description: 只读独立复核(spec 或实现 diff);不改动文件、不
|
|
|
46
46
|
- `P1`:功能错误、明确回归或违反项目硬约束
|
|
47
47
|
- `P2`:非阻断但有证据的维护性问题
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
每项必须包含:位置、问题、证据、建议。没有发现时明确输出"未发现阻断问题",并列出未验证范围。
|
|
@@ -6,11 +6,11 @@ description: 浏览器实测 UI 改动(只读验证、不留脏数据);结
|
|
|
6
6
|
|
|
7
7
|
> 公共角色契约(本文件):`.agents/roles/ui-verifier.md`。宿主薄适配(各宿主目录下 `agents/ui-verifier.md`)正文段同源本文件,frontmatter 各自保留宿主特化字段(check-loop 检查项 6 按本引用校验适配层不断线)。
|
|
8
8
|
|
|
9
|
-
## 职责
|
|
9
|
+
## 1. 职责
|
|
10
10
|
|
|
11
11
|
对已经实现的 UI 改动执行浏览器实测并收集可复核证据。只验证,不修复。
|
|
12
12
|
|
|
13
|
-
## 必需输入
|
|
13
|
+
## 2. 必需输入
|
|
14
14
|
|
|
15
15
|
开始前必须获得:
|
|
16
16
|
|
|
@@ -21,7 +21,7 @@ description: 浏览器实测 UI 改动(只读验证、不留脏数据);结
|
|
|
21
21
|
|
|
22
22
|
缺少可观察的预期结果时,停止并向主智能体报告。
|
|
23
23
|
|
|
24
|
-
## 执行
|
|
24
|
+
## 3. 执行
|
|
25
25
|
|
|
26
26
|
1. 读取项目根目录 `AGENTS.md`,以及改动域目录级 `AGENTS.md`(如有,前端改动域)。
|
|
27
27
|
2. 读取并遵循项目 UI 实测技能 `.agents/skills/verify-ui/SKILL.md`(如有)。
|
|
@@ -30,14 +30,14 @@ description: 浏览器实测 UI 改动(只读验证、不留脏数据);结
|
|
|
30
30
|
5. 收集控制台、网络请求、DOM 数据或截图等证据。
|
|
31
31
|
6. 结束时关闭本次启动的后台进程。
|
|
32
32
|
|
|
33
|
-
## 行为边界
|
|
33
|
+
## 4. 行为边界
|
|
34
34
|
|
|
35
35
|
- 不修改代码、配置、测试数据或工作流文档。
|
|
36
36
|
- 不自行修复发现的问题;将失败证据交还主智能体。
|
|
37
37
|
- 不使用生产环境或真实业务数据。
|
|
38
38
|
- 无法启动环境或完成关键路径时,报告阻塞,不把部分验证标记为通过。
|
|
39
39
|
|
|
40
|
-
## 输出
|
|
40
|
+
## 5. 输出
|
|
41
41
|
|
|
42
42
|
返回:
|
|
43
43
|
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentic-flow-kit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "AI-Native 闭环工作流 + wiki 知识层脚手架——flow-kit init 一条命令为新项目装好 .agents 工作流引擎(阶段命令/角色契约/门禁钩子/kb 检索/看板/规则面预算)+ workflow 文档闭环 + wiki 知识库,装完自包含、零运行时依赖",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "node src/run-tests.mjs",
|
|
8
|
+
"lint": "eslint .",
|
|
8
9
|
"prepack": "node -e \"require('fs').rmSync('templates/_agents/cache',{recursive:true,force:true})\" && node scripts/check-pack-eol.mjs"
|
|
9
10
|
},
|
|
10
11
|
"bin": {
|
|
@@ -41,5 +42,9 @@
|
|
|
41
42
|
"bugs": {
|
|
42
43
|
"url": "https://github.com/zerosloney/agentic-flow-kit/issues"
|
|
43
44
|
},
|
|
44
|
-
"homepage": "https://github.com/zerosloney/agentic-flow-kit#readme"
|
|
45
|
+
"homepage": "https://github.com/zerosloney/agentic-flow-kit#readme",
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@eslint/js": "^9.39.5",
|
|
48
|
+
"eslint": "^9.39.4"
|
|
49
|
+
}
|
|
45
50
|
}
|
package/src/doctor.mjs
CHANGED
|
@@ -10,7 +10,7 @@ import { isOwned, HOSTS, pickStackVars, srcTemplatePath, templateDriftOf, TEMPLA
|
|
|
10
10
|
// 宿主目录映射(与 src/profiles.mjs#HOSTS 同源:装副本目录名前缀带点)
|
|
11
11
|
const HOST_DIR = Object.fromEntries(Object.entries(HOSTS).map(([k, v]) => [k, v.dir]));
|
|
12
12
|
// 命令层薄适配宿主:[装副本目录名, 文件名前缀](单源 profiles.mjs#HOSTS.commandPrefix;与 sync-hosts pairsFor 同口径)
|
|
13
|
-
const HOST_CMD_DIR = Object.entries(HOSTS).filter(([, v]) => v.commandPrefix).map(([
|
|
13
|
+
const HOST_CMD_DIR = Object.entries(HOSTS).filter(([, v]) => v.commandPrefix).map(([, v]) => [v.dir, v.commandPrefix]);
|
|
14
14
|
|
|
15
15
|
function sh(cmd, cwd) {
|
|
16
16
|
try {
|
package/src/init.test.mjs
CHANGED
|
@@ -83,7 +83,7 @@ check('合并:原内容为空时骨架即全文', mergeAgents('', '<!-- m -->\
|
|
|
83
83
|
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'init-p1-'));
|
|
84
84
|
const pkgRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
85
85
|
const vars = { BOARD_PORT: '8933' };
|
|
86
|
-
|
|
86
|
+
renderTree(path.join(pkgRoot, 'templates'), tmp, vars, { force: true });
|
|
87
87
|
// P1-1:renderTree 落盘执行位——win32 下 statSync().mode 无 0o111 语义(恒 0666 系),
|
|
88
88
|
// 断言「writeFileSync 带 mode 参数不炸 + POSIX 语义表达」;真值在 POSIX CI 腿验证
|
|
89
89
|
const hookStat = fs.statSync(path.join(tmp, '.githooks', 'pre-commit'));
|
package/src/run-tests.mjs
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
// run-tests.mjs — 全套测试入口(npm test):CLI 单测(sync/add-host/add-gate)+ 引擎 *.test.mjs 套件。
|
|
1
|
+
// run-tests.mjs — 全套测试入口(npm test):lint 首步 + CLI 单测(sync/add-host/add-gate)+ 引擎 *.test.mjs 套件。
|
|
2
2
|
// 顺序执行、任一非零整体失败(exit 1)。check-loop 套件自 2026-09-26 check-loop-node 起为 node 实现
|
|
3
3
|
// (check-loop.test.mjs 由下方 glob 自动发现——旧 bash 特判与「无 sh 跳过」提示随迁移退役)。
|
|
4
|
+
// lint 首步(2026-10-08 engine-quality-batch):eslint 仅 devDependency(包源仓)——检测到未安装时
|
|
5
|
+
// 显式打印 skip 后继续(裸 checkout 未 npm install 场景的可诊断性;装户仓无本编排器不涉及),
|
|
6
|
+
// 已安装但报错则 fail-closed 计入失败。
|
|
4
7
|
import { spawnSync } from 'node:child_process';
|
|
5
8
|
import fs from 'node:fs';
|
|
6
9
|
import path from 'node:path';
|
|
@@ -25,6 +28,17 @@ const nodeSuites = [
|
|
|
25
28
|
];
|
|
26
29
|
|
|
27
30
|
let failed = 0;
|
|
31
|
+
|
|
32
|
+
// lint 首步:eslint 可用性探测 = require.resolve 于包源仓 node_modules(裸 checkout 解析失败 → 显式跳过)
|
|
33
|
+
console.log('\n===== lint(eslint .)=====');
|
|
34
|
+
const eslintEntry = spawnSync(process.execPath, ['-e', "require.resolve('eslint')"], { cwd: ROOT, encoding: 'utf8' });
|
|
35
|
+
if (eslintEntry.status !== 0) {
|
|
36
|
+
console.log('[lint] skipped: eslint not installed(npm install 后启用;仅包源仓场景)');
|
|
37
|
+
} else {
|
|
38
|
+
const r = spawnSync(process.execPath, [path.join(ROOT, 'node_modules/eslint/bin/eslint.js'), '.'], { cwd: ROOT, stdio: 'inherit' });
|
|
39
|
+
if (r.status !== 0) failed++;
|
|
40
|
+
}
|
|
41
|
+
|
|
28
42
|
for (const rel of nodeSuites) {
|
|
29
43
|
console.log(`\n===== ${rel} =====`);
|
|
30
44
|
const r = spawnSync(process.execPath, [path.join(ROOT, rel)], { cwd: ROOT, stdio: 'inherit' });
|
package/src/sync-hosts.mjs
CHANGED
|
@@ -47,93 +47,113 @@ function listMd(dir) {
|
|
|
47
47
|
// roles 权威源 → 全部宿主 agents 各一份
|
|
48
48
|
// hostDirOf:宿主 → 适配目录名。包源布局 = 宿主键(modules/hosts/opencode/…);装户布局 = HOSTS[h].dir
|
|
49
49
|
// (项目根下 .opencode/…,带点)——2026-10-07 sync-hosts-target-fix 加装户支持时引入。
|
|
50
|
-
|
|
50
|
+
// hostFilter(2026-10-09 sync-hosts-root-coverage):宿主级过滤(多根模式下「项目根宿主点」根只扫
|
|
51
|
+
// 实际存在 dir 的宿主——不存在=没装该宿主点,不算缺失不算漂移)。
|
|
52
|
+
function pairsFor(authRel, hostDirOf = (h) => h, hostFilter = null) {
|
|
51
53
|
const out = [];
|
|
52
54
|
const norm = authRel.split(path.sep).join('/');
|
|
55
|
+
// 条目带 h(宿主键)——faces 计数用「实际生成配对 > 0 的宿主数」(复核 P2-2:存在但空的宿主点
|
|
56
|
+
// 目录此前被计入「N 宿主」,对账面自描述轻微夸大)
|
|
53
57
|
if (norm.startsWith('commands/') && norm.endsWith('.md')) {
|
|
54
58
|
const name = norm.slice('commands/'.length, -'.md'.length);
|
|
55
59
|
for (const [h, v] of Object.entries(HOSTS)) {
|
|
56
|
-
if (
|
|
60
|
+
if (hostFilter && !hostFilter(h)) continue;
|
|
61
|
+
if (v.commandPrefix) out.push({ h, adapterRel: `${hostDirOf(h)}/commands/${v.commandPrefix}${name}.md` });
|
|
57
62
|
}
|
|
58
63
|
} else if (norm.startsWith('roles/') && norm.endsWith('.md')) {
|
|
59
64
|
const name = norm.slice('roles/'.length, -'.md'.length);
|
|
60
|
-
for (const h of Object.keys(HOSTS))
|
|
65
|
+
for (const h of Object.keys(HOSTS)) {
|
|
66
|
+
if (hostFilter && !hostFilter(h)) continue;
|
|
67
|
+
out.push({ h, adapterRel: `${hostDirOf(h)}/agents/${name}.md` });
|
|
68
|
+
}
|
|
61
69
|
}
|
|
62
70
|
return out;
|
|
63
71
|
}
|
|
64
72
|
|
|
65
73
|
// diffHosts:权威源正文段 vs 薄适配正文段的漂移分析(B-b 语义;pure function)。
|
|
66
74
|
// authorityRoot:权威源根(含 commands/ + roles/)
|
|
67
|
-
//
|
|
75
|
+
// 多根对账(2026-10-09 sync-hosts-root-coverage):adapterRoots = [{root, hostDirOf, hostFilter?, label?}]——
|
|
76
|
+
// 包源布局传两根(modules/hosts 宿主键形态 + 项目根 HOSTS.dir 形态宿主点);装户布局单根。
|
|
77
|
+
// 向后兼容:旧单根入参 adaptersRoot/hostDirOf 归一为单元素数组。
|
|
78
|
+
// 根因教训(engine-quality-round2 B1):包源布局此前只扫 modules/hosts,项目根宿主点(本仓 .zcode/)
|
|
79
|
+
// 完全不在扫描面——bb69e19「81 对全对齐」声明漏掉 .zcode 三份(独立复核 P2-3 实证)。
|
|
68
80
|
// hostDirOf:宿主 → 适配目录名(默认宿主键 = 包源布局;装户布局传 (h) => HOSTS[h].dir)
|
|
69
|
-
// 返回:{ drift, inSync, authorityMissing, adapterOrphans,
|
|
70
|
-
// drift
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
if (!fs.existsSync(authorityRoot)) return { drift: [], inSync: 0, authorityMissing: [], adapterOrphans: [], note: `权威源根不存在:${authorityRoot}` };
|
|
81
|
+
// 返回:{ drift, inSync, authorityMissing, adapterOrphans, faces }
|
|
82
|
+
// drift 条目自带 root(applyForward 按它定位适配文件);faces = 对账面自描述行(防不可解释的「N 对」)
|
|
83
|
+
export function diffHosts(opts) {
|
|
84
|
+
const authorityRoot = opts.authorityRoot;
|
|
85
|
+
const roots = opts.adapterRoots || [{ root: opts.adaptersRoot, hostDirOf: opts.hostDirOf || ((h) => h), label: null }];
|
|
86
|
+
if (!fs.existsSync(authorityRoot)) return { drift: [], inSync: 0, authorityMissing: [], adapterOrphans: [], faces: [], note: `权威源根不存在:${authorityRoot}` };
|
|
76
87
|
|
|
77
88
|
const drift = [];
|
|
89
|
+
const adapterOrphans = [];
|
|
78
90
|
let inSync = 0;
|
|
79
91
|
const adapterSeen = new Set();
|
|
80
92
|
const authorityMissing = [];
|
|
93
|
+
const faces = [];
|
|
81
94
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
95
|
+
for (const spec of roots) {
|
|
96
|
+
const { root, hostDirOf, hostFilter, label } = spec;
|
|
97
|
+
const rootHosts = new Set(); // 该根实际生成配对 > 0 的宿主(faces 计数口径,复核 P2-2)
|
|
98
|
+
// 扫权威源 commands/ + roles/
|
|
99
|
+
for (const sub of ['commands', 'roles']) {
|
|
100
|
+
const subAbs = path.join(authorityRoot, sub);
|
|
101
|
+
for (const f of listMd(subAbs)) {
|
|
102
|
+
const authRel = `${sub}/${f}`;
|
|
103
|
+
const authAbs = path.join(authorityRoot, authRel);
|
|
104
|
+
const authSha = bodySha(authAbs);
|
|
105
|
+
const pairs = pairsFor(authRel, hostDirOf, hostFilter);
|
|
106
|
+
if (pairs.length === 0) continue;
|
|
107
|
+
for (const { h, adapterRel } of pairs) {
|
|
108
|
+
rootHosts.add(h);
|
|
109
|
+
adapterSeen.add(adapterRel);
|
|
110
|
+
const adapterAbs = path.join(root, adapterRel);
|
|
111
|
+
const adapterSha = bodySha(adapterAbs);
|
|
112
|
+
if (adapterSha === null) {
|
|
113
|
+
// 未安装的宿主不算「缺失」——那是没装,不是漂移(2026-10-07:装户只装部分宿主时,
|
|
114
|
+
// 旧行为会把未装宿主的全部适配文件列成 authorityMissing,装户 --apply 恒 exit 1 且刷屏)
|
|
115
|
+
if (fs.existsSync(path.dirname(adapterAbs))) authorityMissing.push({ authRel, adapterRel });
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (authSha === adapterSha) { inSync++; continue; }
|
|
119
|
+
drift.push({ authRel, adapterRel, authSha, adapterSha, root });
|
|
100
120
|
}
|
|
101
|
-
if (authSha === adapterSha) { inSync++; continue; }
|
|
102
|
-
drift.push({ authRel, adapterRel, authSha, adapterSha });
|
|
103
121
|
}
|
|
104
122
|
}
|
|
105
|
-
}
|
|
106
123
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
+
faces.push(label ? `${label}(${rootHosts.size} 宿主)` : `${root}(${rootHosts.size} 宿主)`);
|
|
125
|
+
// 扫薄适配找孤儿(权威源无对应文件)
|
|
126
|
+
for (const h of Object.keys(HOSTS)) {
|
|
127
|
+
if (hostFilter && !hostFilter(h)) continue;
|
|
128
|
+
for (const sub of ['agents', 'commands']) {
|
|
129
|
+
const subAbs = path.join(root, hostDirOf(h), sub);
|
|
130
|
+
for (const f of listMd(subAbs)) {
|
|
131
|
+
const adapterRel = `${hostDirOf(h)}/${sub}/${f}`;
|
|
132
|
+
if (adapterSeen.has(adapterRel)) continue;
|
|
133
|
+
let authGuess;
|
|
134
|
+
const prefix = HOSTS[h] && HOSTS[h].commandPrefix;
|
|
135
|
+
if (sub === 'commands' && prefix && f.startsWith(prefix)) {
|
|
136
|
+
// 命令层薄适配带宿主 commandPrefix(2026-09-28:opencode 对齐 trae 后两宿主同口径)
|
|
137
|
+
authGuess = `commands/${f.slice(prefix.length)}`;
|
|
138
|
+
} else if (sub === 'agents') {
|
|
139
|
+
authGuess = `roles/${f}`;
|
|
140
|
+
} else {
|
|
141
|
+
authGuess = `commands/${f}`;
|
|
142
|
+
}
|
|
143
|
+
adapterOrphans.push({ adapterRel, authGuess });
|
|
124
144
|
}
|
|
125
|
-
adapterOrphans.push({ adapterRel, authGuess });
|
|
126
145
|
}
|
|
127
146
|
}
|
|
128
147
|
}
|
|
129
148
|
|
|
130
|
-
return { drift, inSync, authorityMissing, adapterOrphans };
|
|
149
|
+
return { drift, inSync, authorityMissing, adapterOrphans, faces };
|
|
131
150
|
}
|
|
132
151
|
|
|
133
152
|
// printDiff:人类可读 diff 报告(B-b 语义:正文段比对 + frontmatter 双方不动)
|
|
134
153
|
function printDiff(result) {
|
|
135
|
-
const { drift, inSync, authorityMissing, adapterOrphans, note } = result;
|
|
154
|
+
const { drift, inSync, authorityMissing, adapterOrphans, note, faces } = result;
|
|
136
155
|
if (note) console.log(`ℹ️ ${note}\n`);
|
|
156
|
+
if (faces && faces.length) console.log(` 对账面:${faces.join(' + ')}`);
|
|
137
157
|
console.log(` 正文对齐:${inSync} 对`);
|
|
138
158
|
if (authorityMissing.length) {
|
|
139
159
|
console.log(` 权威源声明但薄适配缺失(${authorityMissing.length},apply 不自动创建——薄适配须经 add-host 接管):`);
|
|
@@ -152,12 +172,13 @@ function printDiff(result) {
|
|
|
152
172
|
}
|
|
153
173
|
|
|
154
174
|
// applyForward:把权威源正文段同步到薄适配(保留薄适配原 frontmatter)
|
|
175
|
+
// 漂移条目自带 root(多根对账,2026-10-09 sync-hosts-root-coverage)——按它定位适配文件。
|
|
155
176
|
// 返回:{ synced: [{adapterRel}] }
|
|
156
|
-
function applyForward({ authorityRoot
|
|
177
|
+
function applyForward({ authorityRoot }, drift) {
|
|
157
178
|
const synced = [];
|
|
158
|
-
for (const { authRel, adapterRel } of drift) {
|
|
179
|
+
for (const { authRel, adapterRel, root } of drift) {
|
|
159
180
|
const authAbs = path.join(authorityRoot, authRel);
|
|
160
|
-
const adapterAbs = path.join(
|
|
181
|
+
const adapterAbs = path.join(root, adapterRel);
|
|
161
182
|
const authText = fs.readFileSync(authAbs, 'utf8');
|
|
162
183
|
const adapterText = fs.readFileSync(adapterAbs, 'utf8');
|
|
163
184
|
const { body } = splitFm(authText);
|
|
@@ -189,26 +210,43 @@ export function syncHosts(args, pkgRoot) {
|
|
|
189
210
|
// 解析为**包安装目录**,于是 doctor §7.x 报漂移、照提示跑 `--apply` 会去改包源仓(装户自己的适配层纹丝不动)。
|
|
190
211
|
const target = path.resolve(dir || process.cwd() || pkgRoot);
|
|
191
212
|
// 布局判定(与 doctor.checkAdapterDrift 同口径):
|
|
192
|
-
// 包源(templates/_agents 与 modules/hosts 同时存在)→ 权威源 = <target>/templates/_agents
|
|
213
|
+
// 包源(templates/_agents 与 modules/hosts 同时存在)→ 权威源 = <target>/templates/_agents
|
|
214
|
+
// 薄适配根(2026-10-09 sync-hosts-root-coverage 多根)= ① modules/hosts(宿主键形态,全宿主)
|
|
215
|
+
// + ② 项目根 HOSTS.dir 实际存在的宿主点(如本仓 .zcode/——此前不在扫描面,bb69e19「81 对全对齐」
|
|
216
|
+
// 漏掉其三份,独立复核 P2-3 实证);不存在 = 没装该宿主点,不算缺失。
|
|
193
217
|
// 装户(其余)→ 权威源 = <target>/.agents,薄适配根 = <target>(宿主目录 .opencode/.trae/… 直接位于项目根)
|
|
194
218
|
const isSourceRepo = fs.existsSync(path.join(target, 'templates', '_agents'))
|
|
195
219
|
&& fs.existsSync(path.join(target, 'modules', 'hosts'));
|
|
196
220
|
const authorityRoot = isSourceRepo ? path.join(target, 'templates', '_agents') : path.join(target, '.agents');
|
|
197
|
-
const
|
|
221
|
+
const adapterRoots = isSourceRepo
|
|
222
|
+
? [
|
|
223
|
+
{ root: path.join(target, 'modules', 'hosts'), hostDirOf: (h) => h, label: 'modules/hosts' },
|
|
224
|
+
{
|
|
225
|
+
root: target,
|
|
226
|
+
hostDirOf: (h) => (HOSTS[h] && HOSTS[h].dir) || h,
|
|
227
|
+
hostFilter: (h) => HOSTS[h] && fs.existsSync(path.join(target, HOSTS[h].dir)),
|
|
228
|
+
label: '项目根宿主点',
|
|
229
|
+
},
|
|
230
|
+
]
|
|
231
|
+
: [{
|
|
232
|
+
root: target,
|
|
233
|
+
hostDirOf: (h) => (HOSTS[h] && HOSTS[h].dir) || h,
|
|
234
|
+
hostFilter: (h) => HOSTS[h] && fs.existsSync(path.join(target, HOSTS[h].dir)),
|
|
235
|
+
label: '项目根宿主点',
|
|
236
|
+
}];
|
|
198
237
|
if (!fs.existsSync(authorityRoot)) {
|
|
199
238
|
fail(`未找到权威源目录:${authorityRoot}——目标根 ${target} 既非包源(无 templates/_agents)也非装户(无 .agents);用 --dir <项目根> 指定`);
|
|
200
239
|
}
|
|
201
240
|
const layout = isSourceRepo ? '包源' : '装户';
|
|
202
|
-
|
|
203
|
-
const hostDirOf = isSourceRepo ? (h) => h : (h) => (HOSTS[h] && HOSTS[h].dir) || h;
|
|
204
|
-
const result = diffHosts({ authorityRoot, adaptersRoot, hostDirOf });
|
|
241
|
+
const result = diffHosts({ authorityRoot, adapterRoots });
|
|
205
242
|
|
|
206
243
|
if (apply && result.drift.length > 0) {
|
|
207
|
-
const { synced } = applyForward({ authorityRoot
|
|
244
|
+
const { synced } = applyForward({ authorityRoot }, result.drift);
|
|
208
245
|
console.log(`▶ flow-kit sync-hosts --apply → ${target}(${layout}布局)`);
|
|
246
|
+
console.log(` 对账面:${result.faces.join(' + ')}`);
|
|
209
247
|
console.log(` 按权威源正文覆盖薄适配正文段 ${synced.length} 份(薄适配 frontmatter 不动):`);
|
|
210
248
|
for (const rel of synced) console.log(` - ${rel}`);
|
|
211
|
-
const after = diffHosts({ authorityRoot,
|
|
249
|
+
const after = diffHosts({ authorityRoot, adapterRoots });
|
|
212
250
|
console.log(` 同步后正文对齐:${after.inSync} 对;权威源缺失:${after.authorityMissing.length};正文漂移:${after.drift.length}`);
|
|
213
251
|
return after.drift.length === 0 && after.authorityMissing.length === 0 ? 0 : 1;
|
|
214
252
|
}
|
package/src/sync-hosts.test.mjs
CHANGED
|
@@ -149,7 +149,7 @@ syncHosts(process.argv.slice(2), root);
|
|
|
149
149
|
const r = runSyncHosts(fx, ['--diff']);
|
|
150
150
|
const out = r.stdout + r.stderr;
|
|
151
151
|
check('S5 薄适配正文手改 → 正文段漂移 1', /正文段漂移(1/.test(out), out);
|
|
152
|
-
|
|
152
|
+
runSyncHosts(fx, ['--apply']);
|
|
153
153
|
check('S5 apply 后:薄适配正文回到权威源(含「权威源正文 implementer v1」)', /权威源正文 implementer v1/.test(R(path.join(fx, 'modules/hosts/zcode/agents/implementer.md'))));
|
|
154
154
|
check('S5 apply 不污染权威源(权威源仍 v1)', !R(path.join(fx, 'templates/_agents/roles/implementer.md')).includes('薄适配手改'));
|
|
155
155
|
// apply 后再 diff 一次,diff 应显示"无漂移"
|
|
@@ -164,7 +164,7 @@ syncHosts(process.argv.slice(2), root);
|
|
|
164
164
|
const r = runSyncHosts(fx, ['--diff']);
|
|
165
165
|
const out = r.stdout + r.stderr;
|
|
166
166
|
check('S6 薄适配缺失 → authorityMissing 列', /权威源声明但薄适配缺失(/.test(out) && out.includes('opencode/commands/wf-build.md'), out);
|
|
167
|
-
|
|
167
|
+
runSyncHosts(fx, ['--apply']);
|
|
168
168
|
check('S6 apply 不自动创建薄适配(仍缺失)', !fs.existsSync(path.join(fx, 'modules/hosts/opencode/commands/wf-build.md')));
|
|
169
169
|
}
|
|
170
170
|
|
|
@@ -174,7 +174,7 @@ syncHosts(process.argv.slice(2), root);
|
|
|
174
174
|
const r = runSyncHosts(fx, ['--json']);
|
|
175
175
|
const out = r.stdout + r.stderr;
|
|
176
176
|
let parsed = null;
|
|
177
|
-
try { parsed = JSON.parse(out); } catch {}
|
|
177
|
+
try { parsed = JSON.parse(out); } catch { /* 非 JSON 输出时 parsed 保持 null */ }
|
|
178
178
|
check('S7 --json 输出可解析', parsed && typeof parsed === 'object' && Array.isArray(parsed.drift));
|
|
179
179
|
check('S7 --json 含 inSync = 17', parsed && parsed.inSync === 17, parsed ? JSON.stringify({ inSync: parsed && parsed.inSync, missing: parsed && parsed.authorityMissing }) : 'null');
|
|
180
180
|
}
|
|
@@ -188,7 +188,7 @@ syncHosts(process.argv.slice(2), root);
|
|
|
188
188
|
check('S8 孤儿薄适配 → adapterOrphans 列', /孤儿薄适配(/.test(out) && out.includes('opencode/commands/orphan.md'), out);
|
|
189
189
|
check('S8 opencode 孤儿带 wf- 前缀 → 反推权威源去掉前缀', out.includes('opencode/commands/wf-legacy.md(推测权威源:commands/legacy.md)'), out);
|
|
190
190
|
check('S8 opencode 孤儿不带前缀 → 原样反推 commands/<file>', out.includes('opencode/commands/orphan.md(推测权威源:commands/orphan.md)'), out);
|
|
191
|
-
|
|
191
|
+
runSyncHosts(fx, ['--apply']);
|
|
192
192
|
check('S8 apply 不删孤儿薄适配', fs.existsSync(path.join(fx, 'modules/hosts/opencode/commands/orphan.md')) && fs.existsSync(path.join(fx, 'modules/hosts/opencode/commands/wf-legacy.md')));
|
|
193
193
|
}
|
|
194
194
|
|
|
@@ -237,5 +237,44 @@ syncHosts(process.argv.slice(2), root);
|
|
|
237
237
|
check('实仓薄适配无缺失无正文漂移', r.authorityMissing.length === 0 && r.drift.length === 0, `missing=${r.authorityMissing.length} drift=${r.drift.length} ${sample}`);
|
|
238
238
|
}
|
|
239
239
|
|
|
240
|
+
// ============ 场景 10-12:包源布局多根对账(2026-10-09 sync-hosts-root-coverage,B1)============
|
|
241
|
+
// 根因教训(bb69e19「81 对全对齐」漏 .zcode 三份,独立复核 P2-3):包源布局此前只扫 modules/hosts,
|
|
242
|
+
// 项目根 HOSTS.dir 形态宿主点(本仓 .zcode/)不在扫描面。三场景钉住:漂移可检出 / apply 可修复且
|
|
243
|
+
// frontmatter 保留 / 对账面自描述行在案。
|
|
244
|
+
{
|
|
245
|
+
// S10:包源 fixture + 项目根 .zcode/agents 漂移(正文旧 + frontmatter zcode 风格)→ --diff 报漂移
|
|
246
|
+
const fx = mkFixture();
|
|
247
|
+
W(path.join(fx, '.zcode/agents/implementer.md'),
|
|
248
|
+
`---\nname: implementer\ndescription: zcode 本仓风格\n---\n\n# Implementer · v0\n\n旧版正文 implementer v0\n`);
|
|
249
|
+
const r = runSyncHosts(fx, ['--diff']);
|
|
250
|
+
const out = r.stdout + r.stderr;
|
|
251
|
+
check('S10 项目根宿主点漂移:--diff 报 .zcode/agents/implementer.md',
|
|
252
|
+
out.includes('.zcode/agents/implementer.md') && /正文段漂移/.test(out), out.slice(0, 600));
|
|
253
|
+
check('S10 对账面自描述:含「项目根宿主点(1 宿主)」', /对账面:.*项目根宿主点(1 宿主)/.test(out), out.split('\n').slice(0, 4).join('\n'));
|
|
254
|
+
|
|
255
|
+
// S11:--apply 修复项目根漂移——正文覆盖为权威源、frontmatter 保留、漂移归零
|
|
256
|
+
const r2 = runSyncHosts(fx, ['--apply']);
|
|
257
|
+
const out2 = r2.stdout + r2.stderr;
|
|
258
|
+
const synced = /- \.zcode\/agents\/implementer\.md/.test(out2);
|
|
259
|
+
const fixed = R(path.join(fx, '.zcode/agents/implementer.md'));
|
|
260
|
+
check('S11 --apply 同步清单含 .zcode 条目', synced, out2.slice(0, 500));
|
|
261
|
+
check('S11 --apply 正文覆盖 + frontmatter 保留',
|
|
262
|
+
fixed.includes('权威源正文 implementer v1') && fixed.includes('description: zcode 本仓风格'),
|
|
263
|
+
fixed.slice(0, 200));
|
|
264
|
+
check('S11 --apply 后漂移归零', /正文漂移:\s*0/.test(out2), out2.slice(-300));
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
{
|
|
268
|
+
// S12:装户布局 faces 自描述(回归钉住——装户单根 label=项目根宿主点,行为不变)
|
|
269
|
+
const fx = fs.mkdtempSync(path.join(os.tmpdir(), 'fk-synchosts-adopter-'));
|
|
270
|
+
W(path.join(fx, '.agents/roles/implementer.md'),
|
|
271
|
+
`---\ndescription: Implementer 角色契约\n---\n\n# Implementer · v1\n\n权威源正文 implementer v1\n`);
|
|
272
|
+
W(path.join(fx, '.zcode/agents/implementer.md'),
|
|
273
|
+
`---\nname: implementer\ndescription: zcode\n---\n\n# Implementer · v1\n\n权威源正文 implementer v1\n`);
|
|
274
|
+
const r = runSyncHostsByCwd(fx, ['--diff']);
|
|
275
|
+
const out = r.stdout + r.stderr;
|
|
276
|
+
check('S12 装户布局:faces 单根自描述 + 对齐 1 对', /对账面:项目根宿主点(1 宿主)/.test(out) && /正文对齐:\s*1\s*对/.test(out), out.slice(0, 400));
|
|
277
|
+
}
|
|
278
|
+
|
|
240
279
|
console.log(`\n合计: PASS ${pass} / FAIL ${failCount}`);
|
|
241
280
|
process.exit(failCount ? 1 : 0);
|
package/src/sync.test.mjs
CHANGED
|
@@ -39,7 +39,7 @@ function mkFixture() {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
// ---- v1 安装态(managed 台账与盘面对应 v1 渲染产物)----
|
|
42
|
-
function mkTarget(
|
|
42
|
+
function mkTarget(_fixtureRoot) {
|
|
43
43
|
const t = fs.mkdtempSync(path.join(os.tmpdir(), 'fk-target-'));
|
|
44
44
|
const files = {
|
|
45
45
|
'.agents/scripts/keep.txt': 'keep v2\n',
|