agentic-flow-kit 1.2.0 → 1.2.1
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentic-flow-kit",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "AI-Native 闭环工作流 + wiki 知识层脚手架——flow-kit init 一条命令为新项目装好 .agents 工作流引擎(阶段命令/角色契约/门禁钩子/kb 检索/看板/规则面预算)+ workflow 文档闭环 + wiki 知识库,装完自包含、零运行时依赖",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -75,7 +75,7 @@ node bin/flow-kit.mjs doctor # §6.5 delegations + §6.6 o
|
|
|
75
75
|
- 输出测试报告(通过项 / 失败项)
|
|
76
76
|
- 失败项已修复并复测通过
|
|
77
77
|
- **关单**(日常闭环点,不依赖是否上 prod):
|
|
78
|
-
- 关单前一键过门:`node .agents/scripts/verify.mjs`(npm test + check-loop
|
|
78
|
+
- 关单前一键过门:`node .agents/scripts/verify.mjs`(npm test + check-loop 固定编排,任一失败非零退出,非绿不关单);**装户仓**(根目录无 `package.json`,工程在子目录)默认 `npm test` 不可跑 → 脚本**显式跳过步骤 1 且不落测试绿凭证**(防假绿)并提示;此时按项目口径手工跑测试,或带 `--test-cmd "<项目测试命令>"` 指定(2026-10-07 papercut)
|
|
79
79
|
- 新需求:逐条勾验入口 intent「验收标准」,每条补「证据:」(例如:粘贴 CI 运行结果、UI 截图路径、或具体的 commit SHA),intent $\rightarrow$ done;同名 spec/Quick-Plan(若有)仍 approved $\rightarrow$ done。**注意:勾选但缺证据会被 check-loop 拦截(hard-block)**
|
|
80
80
|
- **approved 留痕提交**(2026-09-30 起):done 确认前确认**本次关单文档**的 approved 态已进 git 历史(越早越好——approved 后即应提交;若尚未,先补提交再 done;门为逐份校验,三件套均关单时逐份各自满足)——confirm-doc 的 done 前置门硬校验(历史未出现「状态: approved」→ 拒绝落账);done 后再提交 done 态与其余改动
|
|
81
81
|
**确认落态唯一入口**(2026-09-27 起):用户在终端跑 `node .agents/scripts/confirm-doc.mjs <path>` 键入「可以」(draft→approved / approved→done;对话内明确确认后 AI 可 `--delegated "<原话>"` 代录,台账如实记 source/quote——**逐件调用 + 逐件原话**(一次一份,build.md「逐件确认」口径;多份并录被 confirm-doc 拒绝。--delegated 每次传当次实际放行的措辞,不复用同句——复用同句使台账 quote 失去分辨力))。check-loop 15 如实口径:缺记录/指纹不配对 → hard-block 拦截;伪造台账本地不可机器防,留痕供事后对质;done 内容绑定(2026-09-28 起)——**关单编辑(勾验/回填确认结果)先于 done 确认、confirm-doc 是最后一次写入**,此后修订走 superseded 或新 intent。
|
|
@@ -10,8 +10,11 @@
|
|
|
10
10
|
// (窗口判定/门禁在消费方 confirm-doc 与 check-loop 检查 8);消费语义 = 「按门跑了 verify 且全绿」,
|
|
11
11
|
// 裸跑 npm test 不落账(对齐引导)。npm test 步骤输出从 inherit 改 pipe 捕获后回放(延迟显示,
|
|
12
12
|
// 关单场景可接受)——仅为 best-effort 抓「合计: PASS n / FAIL n」计数行,抓不到则省略计数键。
|
|
13
|
+
// 装户仓(根目录无 package.json,工程在子目录)下默认 npm test 恒 ENOENT(exit 4058)→ **显式跳过步骤 1**
|
|
14
|
+
// 且**不落测试绿凭证**(凭证语义 = 测试真跑绿,跳过即无凭证,防假绿),并提示用
|
|
15
|
+
// --test-cmd "<项目测试命令>" 指定;显式 --test-cmd 不受此判定影响(2026-10-07 papercut)。
|
|
13
16
|
// 测试:node templates/_agents/scripts/verify.test.mjs(--test-cmd 注入假命令 + CHECK_LOOP_ROOT 注入夹具,不触真实 npm test 与 workflow)
|
|
14
|
-
// 用法:node .agents/scripts/verify.mjs [--test-cmd "<shell 命令>"](--test-cmd
|
|
17
|
+
// 用法:node .agents/scripts/verify.mjs [--test-cmd "<shell 命令>"](--test-cmd 用于测试注入,或在无根 package.json 的装户仓指定项目测试命令)
|
|
15
18
|
import fs from 'node:fs';
|
|
16
19
|
import { spawnSync } from 'node:child_process';
|
|
17
20
|
import path from 'node:path';
|
|
@@ -19,19 +22,31 @@ import { fileURLToPath } from 'node:url';
|
|
|
19
22
|
|
|
20
23
|
const SCRIPT_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
21
24
|
const args = process.argv.slice(2);
|
|
22
|
-
const
|
|
25
|
+
const explicitTestCmd = args.includes('--test-cmd') ? args[args.indexOf('--test-cmd') + 1] : null;
|
|
26
|
+
const testCmd = explicitTestCmd ?? 'npm test';
|
|
23
27
|
const checkLoop = path.join(SCRIPT_DIR, 'check-loop.mjs');
|
|
24
28
|
const ROOT = process.env.CHECK_LOOP_ROOT || path.resolve(SCRIPT_DIR, '..', '..');
|
|
25
29
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
// 装户仓判定:默认命令只在**当前目录**有 package.json 时才跑(npm test 亦在该目录执行)。
|
|
31
|
+
// 跳过时后续不落测试绿凭证(见文末落账段)。
|
|
32
|
+
const hasRootPackageJson = fs.existsSync(path.join(process.cwd(), 'package.json'));
|
|
33
|
+
const skipTest = explicitTestCmd === null && !hasRootPackageJson;
|
|
34
|
+
let testStdout = '';
|
|
35
|
+
|
|
36
|
+
if (skipTest) {
|
|
37
|
+
console.log('[verify] ⏭ 1/2 跳过 npm test:当前目录无 package.json(装户仓)——请按项目口径手工跑测试,或用 --test-cmd "<项目测试命令>" 指定后重跑');
|
|
38
|
+
} else {
|
|
39
|
+
console.log(`[verify] ▶ 1/2 ${testCmd}`);
|
|
40
|
+
const t = spawnSync(testCmd, { shell: true, encoding: 'utf8', maxBuffer: 32 * 1024 * 1024 });
|
|
41
|
+
if (t.stdout) process.stdout.write(t.stdout);
|
|
42
|
+
if (t.stderr) process.stderr.write(t.stderr);
|
|
43
|
+
if (t.status !== 0) {
|
|
44
|
+
console.error(`[verify] ❌ 1/2 ${testCmd} 未通过(exit ${t.status ?? t.error?.code})——修复后重跑,非绿不关单`);
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
testStdout = String(t.stdout || '');
|
|
48
|
+
console.log('[verify] ✅ 1/2 测试通过');
|
|
33
49
|
}
|
|
34
|
-
console.log('[verify] ✅ 1/2 测试通过');
|
|
35
50
|
|
|
36
51
|
console.log('[verify] ▶ 2/2 check-loop');
|
|
37
52
|
const c = spawnSync(process.execPath, [checkLoop], { stdio: 'inherit' });
|
|
@@ -41,15 +56,20 @@ if (c.status !== 0) {
|
|
|
41
56
|
}
|
|
42
57
|
console.log('[verify] ✅ 2/2 闭环校验通过');
|
|
43
58
|
|
|
44
|
-
// 凭证落账:两步全绿才落(check-loop 红不产生凭证——凭证语义 = verify
|
|
59
|
+
// 凭证落账:两步全绿才落(check-loop 红不产生凭证——凭证语义 = verify 全绿);**步骤 1 被跳过同样不落**
|
|
60
|
+
// (测试未跑即无「测试绿」事实,落账即假绿);IO 失败出账不阻断
|
|
45
61
|
try {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
62
|
+
if (skipTest) {
|
|
63
|
+
console.log('[verify] ⚠️ 步骤 1 已跳过——本次不落测试绿凭证(凭证语义 = 测试真跑绿)');
|
|
64
|
+
} else {
|
|
65
|
+
const m = [...testStdout.matchAll(/合计: PASS (\d+) \/ FAIL (\d+)/g)].pop();
|
|
66
|
+
const entry = { ts: new Date().toISOString(), exitCode: 0, suite: 'npm test' };
|
|
67
|
+
if (m) { entry.passed = Number(m[1]); entry.failed = Number(m[2]); }
|
|
68
|
+
if (process.env.PIPELINE_RUN_ID) entry.runId = process.env.PIPELINE_RUN_ID;
|
|
69
|
+
fs.mkdirSync(path.join(ROOT, '.agents'), { recursive: true });
|
|
70
|
+
fs.appendFileSync(path.join(ROOT, '.agents', 'verifications.jsonl'), `${JSON.stringify(entry)}\n`);
|
|
71
|
+
console.log(`[verify] 🧾 测试绿凭证已落账 verifications.jsonl${entry.passed !== undefined ? `(PASS ${entry.passed} / FAIL ${entry.failed})` : ''}`);
|
|
72
|
+
}
|
|
53
73
|
} catch (e) {
|
|
54
74
|
console.error(`[verify] ⚠️ 凭证落账失败(${e.code || e.message})——不阻断,关单门前置将按无凭证告警`);
|
|
55
75
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// verify.mjs 的 fixture 测试(--test-cmd 注入假命令 + CHECK_LOOP_ROOT 注入夹具根,不触真实 npm test 与 workflow)
|
|
3
3
|
// 断言:①绿路径(假过 + 空夹具闭环)exit 0;②步骤 1 假败 exit 1 且不出全绿;
|
|
4
|
-
//
|
|
4
|
+
// ③步骤 2 配对断裂夹具 exit 1(verify 自身标记断言——孙进程 stdio inherit 输出不进本测试管道);
|
|
5
|
+
// ④⑤⑥凭证落账三态(绿落 / check-loop 红不落 / 无汇总行省略计数键);
|
|
6
|
+
// ⑦装户仓(cwd 无 package.json)未给 --test-cmd → 跳过步骤 1、不落凭证、仍跑步骤 2、exit 0。
|
|
5
7
|
// 用法:node templates/_agents/scripts/verify.test.mjs
|
|
6
8
|
import fs from 'node:fs';
|
|
7
9
|
import os from 'node:os';
|
|
@@ -116,6 +118,20 @@ const run = (argv, opts = {}) => spawnSync(process.execPath, [VERIFY, ...argv],
|
|
|
116
118
|
fs.rmSync(root, { recursive: true, force: true });
|
|
117
119
|
}
|
|
118
120
|
|
|
121
|
+
// ---- 场景 7:装户仓(cwd 无 package.json)且未给 --test-cmd → 跳过步骤 1、不落凭证、仍跑步骤 2 → exit 0 ----
|
|
122
|
+
{
|
|
123
|
+
const root = mkfix();
|
|
124
|
+
const bare = fs.mkdtempSync(path.join(os.tmpdir(), 'verify-bare-'));
|
|
125
|
+
const r = run([], { cwd: bare, env: { ...process.env, CHECK_LOOP_ROOT: root } });
|
|
126
|
+
check('场景 7:exit 0', r.status === 0, `exit=${r.status}\n${r.stdout}\n${r.stderr}`);
|
|
127
|
+
check('场景 7:步骤 1 显式跳过(⏭ 1/2)、步骤 2 通过且全绿', r.stdout.includes('⏭ 1/2') && r.stdout.includes('✅ 2/2') && r.stdout.includes('全绿'), r.stdout);
|
|
128
|
+
check('场景 7:跳过时不落测试绿凭证(防假绿)',
|
|
129
|
+
!fs.existsSync(path.join(root, '.agents', 'verifications.jsonl')) && r.stdout.includes('不落测试绿凭证'),
|
|
130
|
+
r.stdout);
|
|
131
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
132
|
+
fs.rmSync(bare, { recursive: true, force: true });
|
|
133
|
+
}
|
|
134
|
+
|
|
119
135
|
console.log(`\n合计: PASS ${pass} / FAIL ${fail}`);
|
|
120
136
|
if (fail) {
|
|
121
137
|
console.log('\n用法:node templates/_agents/scripts/verify.test.mjs');
|
|
@@ -3,22 +3,59 @@ name: verify-ui
|
|
|
3
3
|
description: 启动本地服务并用浏览器实测 UI 改动(只读验证、不留脏数据);项目无测试基建时靠实测兜底。当用户要求"实测 / UI 验证 / 浏览器验证"时使用。
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# verify-ui — UI
|
|
6
|
+
# verify-ui — UI 实测引导
|
|
7
|
+
|
|
8
|
+
无测试基建时,UI 改动必须浏览器实测。步骤:
|
|
7
9
|
|
|
8
10
|
## 1. 起服务
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
- 前端:<待填:启动命令>
|
|
12
|
+
启动命令**不写死在本文件**(本文件是 managed 件,随包升级覆盖——项目特定值写这里会丢):以 `.agents/notes/runtime-env.md`「本地端口与进程」节的记录为准;该节无记录时,先起服务并把命令补记进该文件再继续。
|
|
12
13
|
|
|
13
14
|
进程清单记进 `.agents/notes/runtime-env.md`,实测结束必须关闭。
|
|
14
15
|
|
|
15
|
-
## 2.
|
|
16
|
+
## 2. 浏览器验证
|
|
17
|
+
|
|
18
|
+
- 优先 `browser` 工具;不可用时用 `.agents/scripts/e2e/harness.mjs`(如项目已装;封装 `launch`/`seedSession`/`goto`/`hardGoto`/`clickText`/`pressKey`/`ensureClean`/`screenshot` + 网络/控制台/toast 采集器);自写脚本优先复用其常量与函数。
|
|
19
|
+
- 浏览器首选**较新的 Chromium 内核 headless**(如 Edge `--headless=new`)——旧版 Chrome 会把 antd 图标字体渲染成方框、表格 `waitFor` 超时(见下「浏览器选择」)。
|
|
20
|
+
- 登录态:先调 API 登录拿 token,注入前端约定的 localStorage 键,**并整页重载**让前端状态库重读 token(仅改 hash 的导航不重建文档,会被路由守卫弹回登录页)。
|
|
21
|
+
- 路由为 hash 模式时:`goto` 用 hash;深链接(query 变化)用 `hardGoto`(about:blank 中转强制新文档)。
|
|
22
|
+
|
|
23
|
+
## 3. 实测步骤
|
|
16
24
|
|
|
17
25
|
1. 打开目标页面,按改动点逐项操作:正常路径一条 + 失败路径一条(校验/空态/权限)。
|
|
18
26
|
2. 证据落盘:截图或关键控制台/网络报文,路径写在任务文档「验收标准」勾验项后。
|
|
19
|
-
3.
|
|
27
|
+
3. **不留脏数据**:验证产生的临时数据当场删除或还原;清理**只按本次创建的 ID 精确删除**(ID 取自网络捕获的 POST 响应),**禁止按文案/字段模糊匹配**——模糊匹配会误删用户手建数据;清理脚本一律先备份再删;不确定可回滚的操作先停下问用户。
|
|
20
28
|
|
|
21
|
-
##
|
|
29
|
+
## 4. 收尾
|
|
22
30
|
|
|
23
31
|
- 关闭本次起动的全部进程(按 §1 清单逐个停)。
|
|
24
32
|
- 结论按「页面 / 步骤 / 期望 vs 实际 / 证据」回报;发现缺陷只记录定性,不修代码(修复走 build/maintain 流程)。
|
|
33
|
+
|
|
34
|
+
## 关键坑
|
|
35
|
+
|
|
36
|
+
- API 用 **HTTP** 避开自签证书问题(HTTPS 自签证书会让浏览器/脚本报错或需额外信任配置)。
|
|
37
|
+
- MCP 报「browser is already running」是残留实例占 MCP 专用 profile 锁(`~/.cache/chrome-devtools-mcp/`),清掉对应 chrome 进程重试即可,勿误判为 MCP 不可用。
|
|
38
|
+
- 布局类修复用 `getBoundingClientRect` 程序化检测,比截图肉眼更可靠。
|
|
39
|
+
- 后台任务生命周期不可依赖(实测可长可短):长命服务一律独立进程起(如 PowerShell `Start-Process`)。
|
|
40
|
+
- 用 shell 工具起长命服务时**勿在命令末尾接管道**(`| tail` 等)——子进程继承 stdout 句柄会让命令永不返回,直到被工具超时杀掉(并可能连带杀掉服务)。
|
|
41
|
+
|
|
42
|
+
### 浏览器选择
|
|
43
|
+
|
|
44
|
+
- 旧版 Chrome(实测 83)内核太旧 → antd 图标字体全渲染成方框、表格 `waitFor` 超时。**优先较新的 Chromium 内核**(如 Edge `--headless=new`);harness 的 `CHROME` 常量按本机实际安装路径改。
|
|
45
|
+
|
|
46
|
+
### antd 交互(JS `.click()` 不够)
|
|
47
|
+
|
|
48
|
+
- 按钮文本内含空格(`确 定` / `保 存` / `取 消`)→ 匹配须去空白,勿用 `innerText === '确定'`。
|
|
49
|
+
- Select / Picker / Dropdown 的 `.click()` 打不开弹层 → 须 `Input.dispatchMouseEvent`(mousedown+mouseup 序列);普通按钮用 `clickText` 够用,弹层控件须补 `realClick`。
|
|
50
|
+
- `new KeyboardEvent('Escape')` 关不掉弹层 → 须 `Input.dispatchKeyEvent`(rawKeyDown+keyUp)。
|
|
51
|
+
- **关弹层慎用 Esc**:antd Drawer 同样响应 Esc,会连带关闭抽屉并 reset 表单(表现为「保存后列表无新行」,易误判为保存链路故障)——改点遮罩/关闭按钮。
|
|
52
|
+
- 表格行常无 `tr[data-row-key]` 属性 → 用 `.ant-table-tbody > tr.ant-table-row` + textContent 过滤业务键(如单号)定位行。
|
|
53
|
+
- 宽表 `:scroll="{x:N}"` 截图前把 `.ant-table-content` scrollLeft 置底,露出右侧列。
|
|
54
|
+
- 虚拟滚动下拉(a-select)DOM 只渲染约 10 个节点 → **勿按 DOM 节点数断言选项条数**,按接口响应条数断言。
|
|
55
|
+
|
|
56
|
+
### CDP 采集(SPA hash 导航不重建文档)
|
|
57
|
+
|
|
58
|
+
- Log/Console 采集不随导航重置 → 每次导航前重置采集器,防上一页错误泄漏成后续页面的「控制台错误」。
|
|
59
|
+
- toast 观察器须**导航前**安装;导航后装会漏首屏 toast。
|
|
60
|
+
- 首屏无 token 被路由守卫落登录页:写 localStorage 后仅 hash 变化的 `Page.navigate` 不整页重载、前端状态库仍持空 token → 须 `about:blank` 中转强制新文档,或写后 `Page.reload`。
|
|
61
|
+
- 同路由 hash query 变化不重挂载(`#/x?k=A` → `#/x?k=B`)→ 深链接用例走 `about:blank` 中转。
|