@epoint-testtech/ep-stage-skill 0.0.4-alpha.0 → 0.0.5

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.
Files changed (206) hide show
  1. package/SKILL.md +27 -27
  2. package/codex-skill/ep-stage/glue-create-project/SKILL.md +223 -186
  3. package/codex-skill/ep-stage/glue-generate-testcase/SKILL.md +275 -199
  4. package/codex-skill/ep-stage/glue-generate-testcase/examples/observable-testcase.json +40 -40
  5. package/codex-skill/ep-stage/glue-generate-testcase/references/testcase-schema.md +95 -112
  6. package/codex-skill/ep-stage/glue-generate-testcase/references/testcase-tpl.md +72 -0
  7. package/codex-skill/ep-stage/glue-run-test/SKILL.md +292 -249
  8. package/codex-skill/ep-stage/glue-run-test/references/ai-runtime-loop.md +30 -0
  9. package/codex-skill/ep-stage/glue-run-test/references/crud-pipeline.md +132 -145
  10. package/codex-skill/ep-stage/glue-run-test/references/gap-review-protocol.md +44 -43
  11. package/codex-skill/ep-stage/glue-run-test/references/harness-principles.md +46 -46
  12. package/codex-skill/ep-stage/glue-run-test/references/playwright-cli-odav.md +166 -0
  13. package/codex-skill/ep-stage/glue-run-test/scripts/extract-page-elements-eval.mjs +233 -0
  14. package/codex-skill/ep-stage/glue-run-test/scripts/generate-crud-spec.mjs +149 -149
  15. package/codex-skill/ep-stage/page-element-scan/SKILL.md +91 -0
  16. package/codex-skill/ep-stage/page-element-scan/evals/evals.json +37 -0
  17. package/codex-skill/ep-stage/page-element-scan/evals/fixtures/sample-list-page.html +85 -0
  18. package/codex-skill/ep-stage/page-element-scan/references/pagination-controls.md +153 -0
  19. package/codex-skill/ep-stage/page-element-scan/scripts/extract-page-elements-eval.mjs +233 -0
  20. package/codex-skill/ep-stage/page-element-scan/scripts/extract-page-elements.mjs +298 -0
  21. package/codex-skill/ep-stage/page-element-scan/scripts/scan-page.mjs +749 -0
  22. package/codex-skill/ep-stage/recording-to-glue/SKILL.md +28 -28
  23. package/codex-skill/ep-stage/scripts/validate-skill.mjs +98 -95
  24. package/dist/src/cli/generate-testcase.d.ts +18 -51
  25. package/dist/src/cli/generate-testcase.d.ts.map +1 -1
  26. package/dist/src/cli/generate-testcase.js +127 -131
  27. package/dist/src/cli/index.d.ts +11 -2
  28. package/dist/src/cli/index.d.ts.map +1 -1
  29. package/dist/src/cli/index.js +49 -16
  30. package/dist/src/cli/probe.d.ts +2 -0
  31. package/dist/src/cli/probe.d.ts.map +1 -1
  32. package/dist/src/cli/probe.js +239 -13
  33. package/dist/src/cli/run.d.ts +136 -29
  34. package/dist/src/cli/run.d.ts.map +1 -1
  35. package/dist/src/cli/run.js +494 -65
  36. package/dist/src/cli/spec.d.ts +18 -11
  37. package/dist/src/cli/spec.d.ts.map +1 -1
  38. package/dist/src/cli/spec.js +74 -20
  39. package/dist/src/contracts/crud-business-module.d.ts +6 -0
  40. package/dist/src/contracts/crud-business-module.d.ts.map +1 -1
  41. package/dist/src/contracts/glue-contract-v1.d.ts +98 -0
  42. package/dist/src/contracts/glue-contract-v1.d.ts.map +1 -0
  43. package/dist/src/contracts/glue-contract-v1.js +9 -0
  44. package/dist/src/contracts/inference-trace.d.ts +223 -0
  45. package/dist/src/contracts/inference-trace.d.ts.map +1 -0
  46. package/dist/src/contracts/inference-trace.js +12 -0
  47. package/dist/src/contracts/observable-chain.d.ts +4 -0
  48. package/dist/src/contracts/observable-chain.d.ts.map +1 -1
  49. package/dist/src/extractors/code-list-json5.d.ts +192 -0
  50. package/dist/src/extractors/code-list-json5.d.ts.map +1 -0
  51. package/dist/src/extractors/code-list-json5.js +91 -0
  52. package/dist/src/extractors/code-list.d.ts +3 -3
  53. package/dist/src/extractors/code-list.d.ts.map +1 -1
  54. package/dist/src/extractors/code-list.js +46 -11
  55. package/dist/src/extractors/html-page.d.ts +9 -0
  56. package/dist/src/extractors/html-page.d.ts.map +1 -1
  57. package/dist/src/extractors/html-page.js +26 -2
  58. package/dist/src/extractors/prd-extractor.d.ts +70 -0
  59. package/dist/src/extractors/prd-extractor.d.ts.map +1 -0
  60. package/dist/src/extractors/prd-extractor.js +248 -0
  61. package/dist/src/generators/agent-inferred-workflow-script.js +66 -66
  62. package/dist/src/generators/stage-skeleton-script.d.ts +87 -20
  63. package/dist/src/generators/stage-skeleton-script.d.ts.map +1 -1
  64. package/dist/src/generators/stage-skeleton-script.js +656 -238
  65. package/dist/src/index.d.ts +7 -2
  66. package/dist/src/index.d.ts.map +1 -1
  67. package/dist/src/index.js +3 -1
  68. package/dist/src/inference/module-hints-inference.d.ts +30 -0
  69. package/dist/src/inference/module-hints-inference.d.ts.map +1 -0
  70. package/dist/src/inference/module-hints-inference.js +363 -0
  71. package/dist/src/inference/source-analysis.d.ts +26 -0
  72. package/dist/src/inference/source-analysis.d.ts.map +1 -0
  73. package/dist/src/inference/source-analysis.js +258 -0
  74. package/dist/src/normalizers/crud-contract.d.ts +3 -0
  75. package/dist/src/normalizers/crud-contract.d.ts.map +1 -1
  76. package/dist/src/normalizers/crud-contract.js +3 -0
  77. package/dist/src/runtime/ai-runtime-trace.d.ts +88 -0
  78. package/dist/src/runtime/ai-runtime-trace.d.ts.map +1 -0
  79. package/dist/src/runtime/ai-runtime-trace.js +119 -0
  80. package/dist/src/testcase/button-interaction-inference.d.ts +37 -0
  81. package/dist/src/testcase/button-interaction-inference.d.ts.map +1 -0
  82. package/dist/src/testcase/button-interaction-inference.js +385 -0
  83. package/dist/src/testcase/contract-testcase-assembler.d.ts +44 -0
  84. package/dist/src/testcase/contract-testcase-assembler.d.ts.map +1 -0
  85. package/dist/src/testcase/contract-testcase-assembler.js +806 -0
  86. package/dist/src/testcase/prd-button-mapper.d.ts +72 -0
  87. package/dist/src/testcase/prd-button-mapper.d.ts.map +1 -0
  88. package/dist/src/testcase/prd-button-mapper.js +148 -0
  89. package/dist/src/testcase/runtime-context.d.ts +9 -0
  90. package/dist/src/testcase/runtime-context.d.ts.map +1 -0
  91. package/dist/src/testcase/runtime-context.js +1 -0
  92. package/dist/src/testcase/test-access.d.ts +38 -0
  93. package/dist/src/testcase/test-access.d.ts.map +1 -0
  94. package/dist/src/testcase/test-access.js +106 -0
  95. package/dist/src/testcase/testcase-execution-fields.d.ts +10 -0
  96. package/dist/src/testcase/testcase-execution-fields.d.ts.map +1 -0
  97. package/dist/src/testcase/testcase-execution-fields.js +1 -0
  98. package/dist/src/testcase/testcase-generator.d.ts.map +1 -1
  99. package/dist/src/testcase/testcase-generator.js +6 -0
  100. package/dist/src/testcase/testcase-markdown.d.ts +11 -0
  101. package/dist/src/testcase/testcase-markdown.d.ts.map +1 -0
  102. package/dist/src/testcase/testcase-markdown.js +181 -0
  103. package/dist/src/testcase/testcase-skeleton.d.ts +4 -0
  104. package/dist/src/testcase/testcase-skeleton.d.ts.map +1 -1
  105. package/dist/src/testcase/testcase-spec-assembly.d.ts +4 -0
  106. package/dist/src/testcase/testcase-spec-assembly.d.ts.map +1 -1
  107. package/dist/src/testcase/testcase-v1-draft.d.ts +58 -0
  108. package/dist/src/testcase/testcase-v1-draft.d.ts.map +1 -0
  109. package/dist/src/testcase/testcase-v1-draft.js +13 -0
  110. package/dist/src/validation/contract.d.ts +14 -0
  111. package/dist/src/validation/contract.d.ts.map +1 -0
  112. package/dist/src/validation/contract.js +132 -0
  113. package/dist/src/validation/credentials.d.ts +7 -2
  114. package/dist/src/validation/credentials.d.ts.map +1 -1
  115. package/dist/src/validation/credentials.js +15 -4
  116. package/dist/src/validation/index.d.ts +2 -0
  117. package/dist/src/validation/index.d.ts.map +1 -1
  118. package/dist/src/validation/index.js +2 -0
  119. package/dist/src/validation/inference-trace.d.ts +13 -0
  120. package/dist/src/validation/inference-trace.d.ts.map +1 -0
  121. package/dist/src/validation/inference-trace.js +31 -0
  122. package/dist/src/validation/testcase.d.ts +9 -7
  123. package/dist/src/validation/testcase.d.ts.map +1 -1
  124. package/dist/src/validation/testcase.js +181 -34
  125. package/docs/README.md +124 -134
  126. package/docs/mvp-usage-guide.md +298 -298
  127. package/examples/schemeresource-observable-docs/schemeresource.context.md +20 -20
  128. package/examples/schemeresource.module-hints.json +38 -38
  129. package/examples/schemeresource.observable.code_list.md +37 -37
  130. package/examples/zwplace-observable-docs/zwplace.context.md +16 -16
  131. package/examples/zwplace-placecategory-validation.json +29 -29
  132. package/examples/zwplace.module-hints.json +69 -69
  133. package/examples/zwplace.observable.code_list.md +37 -37
  134. package/package.json +2 -2
  135. package/dist/test/cli/extract-contract.test.d.ts +0 -2
  136. package/dist/test/cli/extract-contract.test.d.ts.map +0 -1
  137. package/dist/test/cli/extract-contract.test.js +0 -32
  138. package/dist/test/cli/generate-testcase.test.d.ts +0 -2
  139. package/dist/test/cli/generate-testcase.test.d.ts.map +0 -1
  140. package/dist/test/cli/generate-testcase.test.js +0 -130
  141. package/dist/test/cli/index.test.d.ts +0 -2
  142. package/dist/test/cli/index.test.d.ts.map +0 -1
  143. package/dist/test/cli/index.test.js +0 -93
  144. package/dist/test/cli/run.test.d.ts +0 -2
  145. package/dist/test/cli/run.test.d.ts.map +0 -1
  146. package/dist/test/cli/run.test.js +0 -149
  147. package/dist/test/cli/spec.test.d.ts +0 -2
  148. package/dist/test/cli/spec.test.d.ts.map +0 -1
  149. package/dist/test/cli/spec.test.js +0 -196
  150. package/dist/test/crud-contract.test.d.ts +0 -2
  151. package/dist/test/crud-contract.test.d.ts.map +0 -1
  152. package/dist/test/crud-contract.test.js +0 -819
  153. package/dist/test/gap-inference.test.d.ts +0 -2
  154. package/dist/test/gap-inference.test.d.ts.map +0 -1
  155. package/dist/test/gap-inference.test.js +0 -597
  156. package/dist/test/generalization.test.d.ts +0 -2
  157. package/dist/test/generalization.test.d.ts.map +0 -1
  158. package/dist/test/generalization.test.js +0 -73
  159. package/dist/test/material-inventory.test.d.ts +0 -2
  160. package/dist/test/material-inventory.test.d.ts.map +0 -1
  161. package/dist/test/material-inventory.test.js +0 -141
  162. package/dist/test/observable-chain.test.d.ts +0 -2
  163. package/dist/test/observable-chain.test.d.ts.map +0 -1
  164. package/dist/test/observable-chain.test.js +0 -123
  165. package/dist/test/observable-pipeline.test.d.ts +0 -2
  166. package/dist/test/observable-pipeline.test.d.ts.map +0 -1
  167. package/dist/test/observable-pipeline.test.js +0 -461
  168. package/dist/test/page-structure.test.d.ts +0 -2
  169. package/dist/test/page-structure.test.d.ts.map +0 -1
  170. package/dist/test/page-structure.test.js +0 -45
  171. package/dist/test/scenario-inference.test.d.ts +0 -2
  172. package/dist/test/scenario-inference.test.d.ts.map +0 -1
  173. package/dist/test/scenario-inference.test.js +0 -73
  174. package/dist/test/stage-context.test.d.ts +0 -2
  175. package/dist/test/stage-context.test.d.ts.map +0 -1
  176. package/dist/test/stage-context.test.js +0 -395
  177. package/dist/test/testcase-generator.test.d.ts +0 -2
  178. package/dist/test/testcase-generator.test.d.ts.map +0 -1
  179. package/dist/test/testcase-generator.test.js +0 -276
  180. package/dist/test/testcase-skeleton.test.d.ts +0 -2
  181. package/dist/test/testcase-skeleton.test.d.ts.map +0 -1
  182. package/dist/test/testcase-skeleton.test.js +0 -185
  183. package/dist/test/testcase-spec-assembly.test.d.ts +0 -2
  184. package/dist/test/testcase-spec-assembly.test.d.ts.map +0 -1
  185. package/dist/test/testcase-spec-assembly.test.js +0 -105
  186. package/dist/test/util/credentials.test.d.ts +0 -2
  187. package/dist/test/util/credentials.test.d.ts.map +0 -1
  188. package/dist/test/util/credentials.test.js +0 -64
  189. package/dist/test/util/i18n-testcase.test.d.ts +0 -2
  190. package/dist/test/util/i18n-testcase.test.d.ts.map +0 -1
  191. package/dist/test/util/i18n-testcase.test.js +0 -119
  192. package/dist/test/util/softlink.test.d.ts +0 -2
  193. package/dist/test/util/softlink.test.d.ts.map +0 -1
  194. package/dist/test/util/softlink.test.js +0 -82
  195. package/dist/test/validation/credentials.test.d.ts +0 -2
  196. package/dist/test/validation/credentials.test.d.ts.map +0 -1
  197. package/dist/test/validation/credentials.test.js +0 -72
  198. package/dist/test/validation/projects-index.test.d.ts +0 -2
  199. package/dist/test/validation/projects-index.test.d.ts.map +0 -1
  200. package/dist/test/validation/projects-index.test.js +0 -48
  201. package/dist/test/validation/testcase.test.d.ts +0 -2
  202. package/dist/test/validation/testcase.test.d.ts.map +0 -1
  203. package/dist/test/validation/testcase.test.js +0 -129
  204. package/dist/vitest.config.d.ts +0 -3
  205. package/dist/vitest.config.d.ts.map +0 -1
  206. package/dist/vitest.config.js +0 -7
@@ -1,249 +1,292 @@
1
- ---
2
- name: glue-run-test
3
- description: 使用时机:当用户对某需求要「跑测试 / 验证 / 端到端执行 / 跑胶水测试 / 看报告」或显式触发 `/glue-run-test <需求目录>` 时使用。本 skill 包装 `@epoint-testtech/ep-stage-skill` CLI 的 `spec` + `run` 双子命令,做 spec 组装与 Playwright 执行 + AI 钻探追加。
4
- version: 2026-06-25+79c305a
5
- argument-hint: "<需求目录绝对/相对路径>"
6
- compatibility: 需要由 stage-create 生成的 glue 模式 Playwright 项目 + 已审过的 `<需求名>/testcase.json5` (v2) + 填好的 `<需求名>/credentials.json5`。
7
- metadata:
8
- source-package: "@epoint-testtech/ep-stage-skill"
9
- contract: "crud-business-module/v1"
10
- ---
11
-
12
- # ep-stage: glue-run-test
13
-
14
- 本 skill 引导 Agent **包装** `@epoint-testtech/ep-stage-skill` CLI `spec` + `run` 双子命令,不重新实现 spec 组装、Playwright 执行或 AI 推理。CLI 内部完成:v1 初始版 spec 生成(spec 子命令)+ 凭据数组加载 + 多角色登录切换 + Playwright 执行 + uncoveredCandidates 中 `planned` 项 AI 钻探追加 + v2 追加版 spec 写回 + 报告生成 + 项目索引回写(run 子命令)。skill 负责:路径解析、反查项目脚手架、缺前置数据引导、任务清单打印、报告路径回显。用户视角全中文,不暴露 CLI 名称。
15
-
16
- > **钻探已前置**:上游钻探 + contract 提取 + coverage 分析 + uncoveredCandidates 推断由 `/glue-generate-testcase` 阶段完成(REQ-CHAIN-01)。本 skill 只消费 testcase v2 + contract.json,不再自行钻探(REQ-CHAIN-02)。
17
- >
18
- > **spec 双生命周期**(REQ-SPEC-01):spec 子命令只产 **v1 初始版**(只含 coveredActions 胶水部分,顶部 `// === 胶水模式生成 ===`),不执行;run 子命令跑 v1 + AI 钻探 uncoveredCandidates → 追加 **v2 追加版**(底部 `// === AI 钻探追加 ===`)。重跑 run 检测已有追加段则**覆盖**,不保留旧追加。
19
-
20
- ## 1. 自然语言映射
21
-
22
- ```text
23
- /glue-run-test /abs/path/.../014-测试需求10-20260622 # 绝对路径
24
- /glue-run-test ../knowledge-project/.../014-测试需求10-20260622 # 相对路径
25
- /glue-run-test # 无参数 问需求目录
26
- ```
27
-
28
- skill 把入参 `path.resolve` 绝对化,`path.basename` 取「需求名」。projectDir 不接受参数,全部从 `~/.ep-stage/projects.index.json5` 反查最新 `mode: 'glue'` 条目(多条 AskUserQuestion 让用户挑);索引缺失走引导场景 A。
29
-
30
- ## 2. Agent 执行剧本(8 步任务清单协议)
31
-
32
- **任务清单协议(REQ-UX-01)**:load 后**立即**打印初始任务清单(Step 0);每完成一步输出单行 `✅ 第 N 步 — <中文名> 已完成,进入第 N+1 步 — <下一中文名>...`;Step 8 输出全勾选终态清单 + 摘要(spec 路径 + 报告路径 + lastRunStatus)。
33
-
34
- ### Step 0 — 打印任务清单
35
-
36
- ```markdown
37
- 📋 **执行胶水测试任务清单**
38
-
39
- - [ ] 第 1 步 — 解析需求路径并反查项目脚手架
40
- - [ ] 2 校验 testcase.json5 输入
41
- - [ ] 第 3 步 — 校验 credentials.json5 凭据
42
- - [ ] 4 步 — 调用 spec 组装 CLI(只生成 v1 不执行)
43
- - [ ] 第 5 步 — 调用 run 执行与 AI 推理 CLI(产 v2)
44
- - [ ] 6 步 — 收集报告产物
45
- - [ ] 第 7 步 — 写入运行状态到项目索引
46
- - [ ] 8 步 — 输出执行摘要
47
- ```
48
-
49
- ### Step 1 — 解析需求路径并反查项目脚手架(缺 → 引导 A)
50
-
51
- - 从用户消息 / args 抽取需求目录路径,绝对化 + basename。入参缺失 → free text 询问"请给我需求目录的绝对或相对路径"。
52
- - 读 `~/.ep-stage/projects.index.json5`:文件不存在 / 无 glue 条目 → **引导场景 A**:中文提示"未发现胶水测试脚手架。请先跑 `/glue-create-project <项目名>` 创建脚手架后再回来",退出不调 CLI。多条匹配 → AskUserQuestion 挑 projectDir。
53
- - 中文复述识别结果:"已识别:需求目录 = `<abs>`,需求名 = `<basename>`,项目目录 = `<projectDir>`"。
54
-
55
- ### Step 2 — 校验 testcase.json5 输入(缺 → 引导 B)
56
-
57
- 校验 `<projectDir>/src/tests/<需求名>/testcase.json5` 是否存在 + `schemaVersion: "v2"`。
58
-
59
- 缺失 / schema v2 **引导场景 B**,AskUserQuestion 三选一:
60
-
61
- 1. **跑 `/glue-generate-testcase <需求目录>`**:先生成用例,回头再跑 run。
62
- 2. **跳过用例直接组装**(不推荐):警告"无 testcase spec 只能生成空胶水骨架,钻探追加无法启动",确认后继续。
63
- 3. **取消**:直接退出,不调 CLI。
64
-
65
- ### Step 3 校验 credentials.json5 凭据(缺 引导 C)
66
-
67
- 校验 `<projectDir>/src/tests/<需求名>/credentials.json5` 存在 + 数组至少 1 条 + 每条 `url / username / password` 非空(参 §4.3)。
68
-
69
- 缺失 / 字段空 → **引导场景 C**,先读 `~/.ep-stage/projects.index.json5` 的 `systems[].credentialsCache`,按 testcase.json5 `requiredSystems[].url` 比对算 `cachedSystemsHit`。AskUserQuestion 三选一:
70
-
71
- 1. **从全局缓存复用**(仅 `cachedSystemsHit` 非空时显示):列出命中的 url + 已缓存角色,自动拼出 credentials.json5(缺失角色用占位符保留)。
72
- 2. **现在补**:skill 顺序问每条角色的 URL / username / password / systemName(free text),直接写 `<需求名>/credentials.json5`,**回写**全局 `systems[].credentialsCache`(按 url 归并,跨需求复用)。
73
- 3. **取消**:直接退出,不调 CLI。
74
-
75
- ### Step 4 调用 spec 组装 CLI(只生成 v1 不执行)
76
-
77
- 固定命令形式(不 which、不扫 monorepo、不 cd、**不喂 stdin**):
78
-
79
- ```bash
80
- npx -y @epoint-testtech/ep-stage-skill@latest spec \
81
- --testcase <projectDir>/src/tests/<需求名>/testcase.json5 \
82
- --out <projectDir>/src/tests/<需求名>/crud.spec.ts
83
- ```
84
-
85
- CLI 内部:读 testcase v2 + `.ep-stage/contract.json` 基于 `coveredActions` + `cases[]` 生成 **v1 初始版** `crud.spec.ts`(顶部注释 `// === 胶水模式生成 ===`,引用 `../../skeletons` 相对路径,只覆盖 coveredActions 胶水部分,不执行 Playwright)。CLI 非 0 退出 → 复述 stderr,不进 Step 5。
86
-
87
- ### Step 5 — 调用 run 执行与 AI 推理 CLI(产 v2)
88
-
89
- 固定命令形式:
90
-
91
- ```bash
92
- npx -y @epoint-testtech/ep-stage-skill@latest run \
93
- --spec <projectDir>/src/tests/<需求名>/crud.spec.ts \
94
- --testcase <projectDir>/src/tests/<需求名>/testcase.json5 \
95
- --headless false
96
- ```
97
-
98
- CLI 内部全链路(详见 references/crud-pipeline.md「执行 + AI 推理追加」):
99
-
100
- 1. 读 `<需求名>/credentials.json5`(数组形态多角色)+ testcase.json5(v2)。
101
- 2. **多角色登录**:通过 `@epoint-testtech/stage-core.loadCredentials(path, role?)` 按 `cases[].requiredRole` / `uncoveredCandidates[].requiredRole` 检索对应角色,启动 `LoginPage`。
102
- 3. **跑 v1 胶水部分**:执行 spec 顶部 `// === 胶水模式生成 ===` 区段所有 `test(...)` block。
103
- 4. **AI 钻探追加**:对 `uncoveredCandidates[].status === 'planned'` 项,按 `requiredRole` 切登录 → 页面浏览补 spec(`businessIntent` / `assertionExpectation` / `label` 驱动 test 标题与断言)→ **追加到 spec 底部**产 v2(注释 `// === AI 钻探追加 ===`)。
104
- 5. **重跑覆盖**:检测到分段标记则**覆盖**追加段(v2 v2'),不保留旧追加。
105
- 6. 写报告到 `e2e/glue-code-mvp/glue-report/<run-timestamp>/`。
106
-
107
- CLI 非 0 退出 → 复述 stderr,按 §4 报告。
108
-
109
- > **凭据通路**:skill 自身**不调** `loadCredentials`;该工具由 CLI run 子命令生成的 Playwright spec 内部 import `@epoint-testtech/stage-core`。skill 只校验 credentials.json5 + 引导补齐,不解析凭据明文。
110
-
111
- ### Step 6 — 收集报告产物
112
-
113
- CLI 退出后用 `ls` / `Read` 校验 §3 验证清单。报告目录缺失视为整体失败,按 §4 报告。
114
-
115
- ### Step 7 — 写入运行状态到项目索引
116
-
117
- CLI run 子命令已在 `~/.ep-stage/projects.index.json5` 回写:
118
-
119
- - `projects[].requirements[<i>].lastRunAt` / `lastRunStatus`(`passed` / `failed` / `partial`)
120
- - `systems[].credentialsCache`(按 url 归并本次 credentials.json5 用到的角色凭据)
121
-
122
- skill 校验:本需求条目存在;`lastRunAt` 是本次时间戳;`lastRunStatus` `never`。缺时由 skill 补写。
123
-
124
- ### Step 8输出执行摘要
125
-
126
- 打印全勾选终态清单 + §5 完成提示(含 spec 路径 + 报告路径 + `lastRunStatus` + Playwright HTML 报告打开指令 + 重跑提示)。
127
-
128
- ## 3. 验证清单
129
-
130
- | 路径 | 说明 |
131
- |-----------------------------------------------------------------|-----------------------------------------------------|
132
- | `<projectDir>/src/tests/<需求名>/crud.spec.ts` | v1 或 v2(含 `// === 胶水模式生成 ===` + 可选 `// === AI 钻探追加 ===` 分段)|
133
- | `<projectDir>/src/tests/<需求名>/testcase.json5` | 必须存在 + `schemaVersion: "v2"` |
134
- | `<projectDir>/src/tests/<需求名>/credentials.json5` | 必须存在 + 数组 ≥ 1 条 + 必填字段非空 |
135
- | `<projectDir>/src/tests/<需求名>/.ep-stage/contract.json` | 由 testcase 阶段产,run 阶段只读不写 |
136
- | `e2e/glue-code-mvp/glue-report/<run-timestamp>/` | run 子命令产;含执行摘要 + Playwright trace 引用 |
137
- | `~/.ep-stage/projects.index.json5` | 已更新 `lastRunAt / lastRunStatus + systems[].credentialsCache` |
138
-
139
- ## 4. 错误处理
140
-
141
- 失败归类与详细排障路径见 `references/crud-pipeline.md`「失败归类」节。本 skill 高频呈现:
142
-
143
- | 触发时机 | Agent 中文呈现 + 建议 |
144
- |---------------------------|-----------------------------------------------------------|
145
- | 引导 A(缺脚手架) | 中文提示+退出,引导先跑 `/glue-create-project <项目名>` |
146
- | 引导 B(缺 testcase) | AskUserQuestion 三选一:跑 testcase / 强组装 / 取消 |
147
- | 引导 C(缺凭据) | AskUserQuestion 三选一:缓存复用 / 现在补 / 取消 |
148
- | spec 子命令 exit ≠ 0 | 复述 stderr 中文转述,不进 Step 5 |
149
- | run 子命令 exit ≠ 0 | 复述 stderr;归类参 references/crud-pipeline.md 失败归类 |
150
- | Playwright 业务失败 | 报告 `lastRunStatus: failed`,提示打开 HTML 报告人审 |
151
- | `coveredActions` 为空 | 阻断 spec 子命令;提示用户回 `/glue-generate-testcase` 补齐 |
152
- | 用户中途取消 | AskUserQuestion 阶段说「算了/取消」立即终止;CLI 启动后等其退出再复述 |
153
-
154
- ## 5. 完成提示
155
-
156
- Step 8 全部通过后,按以下中文格式呈现(不要用 success/done/passed):
157
-
158
- > ✅ 胶水测试执行完成
159
- >
160
- > 需求:`<需求名>`/项目:`<projectDir>`
161
- > Spec:`<projectDir>/src/tests/<需求名>/crud.spec.ts`(v2 胶水 + AI 钻探追加)
162
- > 报告目录:`e2e/glue-code-mvp/glue-report/<run-timestamp>/`
163
- > Playwright HTML:`npx playwright show-report --config <projectDir>/playwright.config.ts`
164
- > 运行状态:`lastRunStatus = <passed/failed/partial>`(已回写 `~/.ep-stage/projects.index.json5`)
165
- >
166
- > 下一步:① 失败用例打开 HTML 报告看 trace;② 调整 testcase.json5 / ModuleHints 后重跑 `/glue-run-test <需求目录>`;③ 研发回归独立执行 `cd <projectDir> && npx playwright test src/tests/<需求名>/crud.spec.ts`(**跑文件当前内容**,v1/v2 行为见 §6)
167
-
168
- **失败时不要发完成提示**:§3 验证项任一缺失或 CLI 非 0 退出 → 按 §4 报告,不允许混合"执行完成"字样。
169
-
170
- ## 6. spec 双向执行路径与生命周期(REQ-SPEC-01)
171
-
172
- 生成的 `crud.spec.ts` 是 standard Playwright spec,可被 2 条路径执行;文件有 v1 / v2 两个生命周期:
173
-
174
- | 状态 | 文件内容 | 由谁产 | 何时存在 |
175
- |---|---|---|---|
176
- | **v1 初始版** | 仅 coveredActions 胶水部分(顶部 `// === 胶水模式生成 ===`) | `spec` 子命令 | 跑过 spec 但未跑过 run |
177
- | **v2 追加版** | v1 + AI 钻探追加(底部 `// === AI 钻探追加 ===`) | `run` 子命令 | 跑过 run 后;重跑覆盖追加段 |
178
-
179
- - **路径 ①(本 skill 标准链路)**:spec → run 子命令 → AI 推理追加产 v2。
180
- - **路径 ②(研发回归独立执行)**:`cd <projectDir> && npx playwright test src/tests/<需求名>/crud.spec.ts` 纯文件 IO 跑当前内容,不区分 v1/v2,不修改文件。
181
-
182
- **测试资产自包含原则**(v1/v2 都成立):spec 用相对路径 `import { CrudPage } from '../../skeletons/...'`;凭据由同需求目录 `credentials.json5` 加载(通过 stage-core `loadCredentials`),不依赖任何 ep-stage runtime 状态;研发人员把整个 `<需求名>/` 目录拷到任意环境都能跑(含填好的 credentials.json5)。
183
-
184
- ## 7. 真实系统 E2E 运行约束
185
-
186
- - **禁止** `--headless true` 跑真实业务系统 E2E。本 skill 调用 run 子命令固定 `--headless false`。
187
- - 真实系统验证**必须有人在场观察**页面行为、弹窗、登录状态和业务副作用;无人工观察的无头回放不算当前阶段验收证据。
188
- - `--headless true` 仅允许用于本地结构调试,不作为真实系统验收方式。
189
- - 观察结论须与 `glue-report/<run-timestamp>/` + Playwright HTML 报告交叉核对后才作为验收证据。
190
-
191
- ## 8. 内嵌数据契约范例
192
-
193
- `<需求名>/credentials.json5`(数组形态,REQ-ENV-02;详见 spec §4.3):
194
-
195
- ```json5
196
- // 单系统单角色(zwplace 最常见)
197
- [ { url: "http://192.168.x.x:8100/.../login", username: "admin", password: "..." } ]
198
-
199
- // 多系统多角色(StageZhgd 类业务)
200
- [
201
- { url: "http://sys1/login", username: "atjsdw...", password: "Epoint@2021", role: "建设单位", systemName: "建设单位办公系统" },
202
- { url: "http://sys1/login", username: "atsgdw...", password: "Epoint@2021", role: "施工单位", systemName: "建设单位办公系统" },
203
- { url: "http://sys2/login", username: "...", password: "...", role: "审批员", systemName: "审批端" }
204
- ]
205
- ```
206
-
207
- 字段约束:必填 `url / username / password`;可选 `role / systemName`;数组至少 1 条;同 `(url, role)` 组合唯一;文件 gitignore。
208
-
209
- `~/.ep-stage/projects.index.json5`(run 阶段回写 `requirements[].lastRun*` + `systems[].credentialsCache`):
210
-
211
- ```json5
212
- {
213
- projects: [{
214
- projectName: "...", projectDir: "...", mode: "glue", stageCreateVersion: "0.0.4-alpha.0",
215
- requirements: [{
216
- name: "014-测试需求10-20260622",
217
- requirementDir: "/abs/.../014-测试需求10-20260622",
218
- testsDir: "<projectDir>/src/tests/014-测试需求10-20260622",
219
- lastRunAt: "2026-06-25T10:00:00Z", // run 回写
220
- lastRunStatus: "passed" // passed | failed | partial | never;run 回写
221
- }]
222
- }],
223
- systems: [{
224
- url: "http://192.168.x.x:8100/.../login",
225
- knownRoles: ["建设单位", "施工单位"],
226
- credentialsCache: { "建设单位": { username: "...", password: "...", lastUsed: "..." } } // run 回写
227
- }]
228
- }
229
- ```
230
-
231
- ## 9. 引导场景
232
-
233
- - **A(缺脚手架)**:Step 1 反查 projects.index.json5 无 glue 条目 → 提示先跑 `/glue-create-project` 退出。
234
- - **B(缺 testcase)**:Step 2 缺失 / schema 非 v2 → AskUserQuestion 三选一(跑 testcase / 强组装 / 取消)。
235
- - **C(缺凭据)**:Step 3 字段空 → AskUserQuestion 三选一(缓存复用 / 现在补 / 取消,含 `cachedSystemsHit` 命中提示)。
236
- - **D(缺 code_list.md)**:归 `/glue-generate-testcase` 处理(钻探前置)。
237
-
238
- ## 10. 按需加载
239
-
240
- - CRUD 组装 pipeline + 验证命令 + **失败归类**:`references/crud-pipeline.md`
241
- - harness 治理原则:`references/harness-principles.md`;gap 评审协议:`references/gap-review-protocol.md`
242
-
243
- ## 11. 关键约束
244
-
245
- - 钻探前置:本 skill 不再实现 contract 提取 / coverage 分析 / uncoveredCandidates 推断;这些在 `/glue-generate-testcase` 完成。
246
- - spec 子命令**只生成不执行**(REQ-SPEC-01);Playwright 执行只走 run 子命令 ① 或研发独立 ②。
247
- - run 子命令仅对 `uncoveredCandidates[].status === 'planned'` 项 AI 推理;`candidate` / `unresolved` 项不得盲目追加 spec(gap 评审协议)。
248
- - AI 推理阶段不修改 `cases[].businessIntent` / `assertionExpectation`,也不改 `src/skeletons/*.ts`。
249
- - 用户视角始终全中文;业务断言、selector、iframe 关键字、按钮文案均由骨架 + `ModuleHints` 决策,skill / spec 不发明。
1
+ ---
2
+ name: glue-run-test
3
+ description: 使用时机:当用户对某需求要「跑测试 / 验证 / 端到端执行 / 跑胶水测试 / 看报告」或显式触发 `/glue-run-test <testcase.json5路径>` 时使用。
4
+ version: 2026-08-12+925f4c4
5
+ argument-hint: "<testcase.json5绝对/相对路径>"
6
+ compatibility: 需要由 stage-create 生成的 glue 模式 Playwright 项目 + 已审过的 `testcase.json5` + 同目录 `credentials.json5`。
7
+ metadata:
8
+ source-package: "@epoint-testtech/ep-stage-skill"
9
+ contract: "crud-business-module/v1"
10
+ ---
11
+
12
+ # ep-stage: glue-run-test
13
+
14
+ 本 skill 编排 `@epoint-testtech/ep-stage-skill` CLI Agent Runtime。分工固定:
15
+
16
+ 1. 用户入口只收 `/glue-run-test <testcase.json5路径>`。
17
+ 2. CLI `prepare-tasks` 只做确定性工作:定位项目、补组装 glue 骨架、生成 `.ep-stage/ai-runtime-trace.json5` 任务包。
18
+ 3. Agent 读取 trace tasks,使用 playwright-cli 观察和操作真实页面,按 O-D-A-V 产出 `.ep-stage/ai-snippets.json5`。
19
+ 4. CLI `run` 只读取 Agent 产出的 resolved snippets,幂等追加到 `AI_APPEND_MARKER` 后并执行完整 spec。
20
+ 5. 缺少真实 resolved snippet 时,CLI 只写 `needs_review` trace,不追加占位代码、不执行 Playwright,避免假通过。
21
+ 6. 失败时写 `.ep-stage/repair-runs/<round>/repair-report.md` 并回写 trace.repairRounds,等待人审确认修补方向。
22
+
23
+ skill 负责:路径解析、必要前置校验、任务清单打印、结果回显。用户视角全中文,不暴露 CLI 名称。
24
+
25
+ > 钻探已前置:上游钻探、contract 提取、coverage 分析、`uncoveredCandidates` 推断由 `/glue-generate-testcase` 完成。本 skill 只消费 `testcase.json5` 和 `.ep-stage/contract.json5`,不再自行钻探,不读取 `inference-trace.json`,也不对 contract 缺失槽位二次猜测。
26
+ >
27
+ > 修补边界:run 失败时先落 repair-report.md,等待用户确认修补方向后再重跑。不静默削弱断言、不改变 testcase 意图。重跑读取更新后的 spec/testcase 重新进入状态机。
28
+ >
29
+ > 详细状态机和修补边界见 references/ai-runtime-loop.md。
30
+
31
+ ## 1. 自然语言映射
32
+
33
+ ```text
34
+ /glue-run-test /abs/path/.../src/tests/014-测试需求10-20260622/testcase.json5
35
+ /glue-run-test ../glue-project/src/tests/014-测试需求10-20260622/testcase.json5
36
+ /glue-run-test # 无参数 → 问 testcase.json5 路径
37
+ /glue-run-test /abs/path/.../testcase.json5 --debug # 调试模式 → 跑本地 ep-stage-skill dist
38
+ ```
39
+
40
+ > `--debug` flag:正常调用走远程 `npx @epoint-testtech/ep-stage-skill@latest`。开发期想测试未发布的本地代码时传 `--debug`,skill Step 4/Step 6 都改用 `node <repo>/packages/ep-stage-skill/dist/src/cli/index.js`:先跑 `prepare-tasks --testcase ...`,Agent 产出 `ai-snippets.json5` 后再跑 `run --testcase ... --ai-snippets ...`。前提:cwd 在 ep-stage monorepo 内(向上能找到 `pnpm-workspace.yaml`);找不到时直接 exit 1 报错,不静默 fallback 到 npx。
41
+
42
+ skill 把入参 `path.resolve` 绝对化,直接消费 `testcase.json5`。用户心智只保留这一个入口,不要求先显式跑 `spec` 再跑 `run`。
43
+
44
+ ## 2. Agent 执行剧本(7 步任务清单协议)
45
+
46
+ **任务清单协议(REQ-UX-01)**:load 后**最先**单行展示技能版本(取本 SKILL.md frontmatter `version` 字段),格式 `技能版本:glue-run-test <version>`;随后**立即**打印初始任务清单(Step 0);每完成一步输出单行 `第 N 步 — <中文名> 已完成,进入第 N+1 步 — <下一中文名>...`;Step 7 输出全勾选终态清单 + 摘要(spec 路径 + trace 路径 + 报告路径)。
47
+
48
+ ### Step 0 — 打印任务清单
49
+
50
+ ```markdown
51
+ **执行胶水测试任务清单**
52
+
53
+ - [ ] 1 解析 testcase.json5 路径并定位测试项目
54
+ - [ ] 第 2 步 — 校验 testcase.json5 输入
55
+ - [ ] 第 3 步 — 校验 credentials.json5 凭据
56
+ - [ ] 第 4 步 — 调用 prepare-tasks 输出 AI 任务包
57
+ - [ ] 5 步 — Agent 使用 playwright-cli 完成 O-D-A-V 并写 ai-snippets.json5
58
+ - [ ] 第 6 步 — 调用 run CLI 合并 snippet 并执行完整 spec
59
+ - [ ] 7 收集 spec、trace 与报告产物并输出摘要
60
+ ```
61
+
62
+ ### Step 1 解析 testcase.json5 路径并定位测试项目
63
+
64
+ - 从用户消息 / args 抽取 `testcase.json5` 路径,绝对化。入参缺失 → free text 询问"请给我 testcase.json5 的绝对或相对路径"。
65
+ - 优先读取 `testcase.json5.runtimeContext.testProjectDir / specPath`;若缺失或校验失败,再从 testcase 所在目录向上查找 `package.json + playwright.config.ts + src/skeletons`。
66
+ - 中文复述识别结果:"已识别:testcase.json5 = `<abs>`,项目目录 = `<projectDir>`,spec = `<specPath>`"。
67
+
68
+ ### Step 2 — 校验 testcase.json5 输入(缺 → 引导 B)
69
+
70
+ 校验 `<projectDir>/src/tests/<需求名>/testcase.json5` 是否存在,且 `schemaVersion` 字段存在且合法。
71
+
72
+ 缺失 / schema 不合法 引导场景 B,AskUserQuestion 三选一:
73
+
74
+ 1. 跑 `/glue-generate-testcase <code_list.json5路径>`:先生成用例,回头再跑 run。
75
+ 2. 跳过用例直接组装(不推荐):警告"无 testcase run 内部也无法自动补出有效 glue 骨架",确认后继续。
76
+ 3. 取消:直接退出,不调 CLI。
77
+
78
+ ### Step 3 — 校验 credentials.json5 凭据(缺 → 引导 C)
79
+
80
+ 校验 `<projectDir>/src/tests/<需求名>/credentials.json5` 存在,数组至少 1 条,且每条 `url / username / password` 非空。
81
+
82
+ 缺失 / 字段空 → 引导场景 C,先读 `~/.ep-stage/projects.index.json5` 的 `systems[].credentialsCache`,按 `url` 比对算 `cachedSystemsHit`。AskUserQuestion 三选一:
83
+
84
+ 1. 从全局缓存复用(仅 `cachedSystemsHit` 非空时显示):列出命中的 url + 已缓存角色,自动拼出 `credentials.json5`(缺失角色用占位符保留)。
85
+ 2. 现在补:skill 顺序问每条角色的 URL / username / password / systemName(free text),直接写 `<需求名>/credentials.json5`。
86
+ 3. 取消:直接退出,不调 CLI。
87
+
88
+ ### Step 4 — 调用 prepare-tasks 输出 AI 任务包
89
+
90
+ 固定流程:不 which、不扫 monorepo、不 cd、不喂 stdin。用户入口仍只保留 `/glue-run-test <testcase.json5路径>`,但内部先调用 CLI `prepare-tasks`。
91
+
92
+ 正常模式:
93
+
94
+ ```bash
95
+ npx -y @epoint-testtech/ep-stage-skill@latest prepare-tasks \
96
+ --testcase <projectDir>/src/tests/<需求名>/testcase.json5
97
+ ```
98
+
99
+ 调试模式:
100
+
101
+ ```bash
102
+ D="$PWD"; REPO=""
103
+ while [ "$D" != "/" ]; do
104
+ if [ -f "$D/pnpm-workspace.yaml" ] && [ -f "$D/packages/ep-stage-skill/dist/src/cli/index.js" ]; then
105
+ REPO="$D"; break
106
+ fi
107
+ D="$(dirname "$D")"
108
+ done
109
+ [ -z "$REPO" ] && { echo "错误:--debug 但找不到本地 monorepo"; exit 1; }
110
+ echo "调试模式:本地 $REPO/packages/ep-stage-skill/dist/src/cli/index.js"
111
+ node "$REPO/packages/ep-stage-skill/dist/src/cli/index.js" prepare-tasks \
112
+ --testcase <projectDir>/src/tests/<需求名>/testcase.json5
113
+ ```
114
+
115
+ CLI prepare-tasks 行为:
116
+
117
+ 1. 解析 `runtimeContext` 或向上查找测试项目;若 `crud.spec.ts` 不存在,先自动补跑 `spec` 生成 glue 骨架。
118
+ 2. 构建 AI Runtime Tasks:取 `uncoveredCandidates` 中 `generationStrategy="ai"` 且 `coverageStatus!="blocked"` 的候选;`blocked` 候选不进入后续步骤。
119
+ 3. 写 `<caseDir>/.ep-stage/ai-runtime-trace.json5`:`tasks` 就绪,`results` 为空。
120
+ 4. 输出 trace 路径、spec 路径、AI task 数量和 blocked 数量。
121
+
122
+ CLI 0 退出 复述 stderr,不进 Step 5。
123
+
124
+ ### Step 5Agent 使用 playwright-cli 完成 O-D-A-V 并写 ai-snippets.json5
125
+
126
+ 读取 `<caseDir>/.ep-stage/ai-runtime-trace.json5` `tasks[]`。若任务数为 0,写一个空结果包:
127
+
128
+ ```json5
129
+ {
130
+ schemaVersion: 'ep-stage-ai-snippets/v1',
131
+ testcasePath: '<testcase.json5绝对路径>',
132
+ generatedAt: '<ISO时间>',
133
+ results: [],
134
+ }
135
+ ```
136
+
137
+ 若存在任务,先跑 `which playwright-cli` 校验本机已安装官方 CLI(v0.1.15+ 起支持 coding agent one-shot 子命令 + daemon session 模型)。缺失 → 整包 `needs_review` 后退出。可用则读 `docs/00-memory/dev-rules.md`,再按 `references/playwright-cli-odav.md` 执行:
138
+
139
+ 1. 生成一个命名 session:`SESSION="<moduleId>-$(date +%Y%m%d%H%M%S)"`,后续所有子命令都传 `-s=$SESSION`(daemon 保持浏览器 + cookies + localStorage 跨命令)。
140
+ 2. 从 `testcase.json5.testAccess.requiredRoles[0]` 取 primary role,从 `credentials.json5` 匹配该角色的 `loginUrl / username / password`。跑 `playwright-cli -s=$SESSION open <loginUrl> --headed`(**必须 `--headed`**,人工旁观 O-D-A-V 过程;不允许无头默认,避免运行态钻探变成无监督黑盒)→ `snapshot` 读 accessibility tree yml 拿 refs → `fill <userRef> <username>` / `fill <passRef> <password>` / `click <loginRef>` → 再 `snapshot` 验证登录成功。可选 `state-save <caseDir>/.ep-stage/auth.json` 便于跨 session 复用。
141
+ 3. `playwright-cli -s=$SESSION goto <contract.base.navigation.directUrl>` 直达列表页 → `snapshot` 观察 iframe 与初始 DOM。
142
+ 4. **初始元素扫描(page-element-scan 内核)**:在列表页加载完成后,用 `playwright-cli run-code` 将 `extract-page-elements-eval.mjs` 函数体注入主 frame 执行,拿到当前页元素清单落袋 `<caseDir>/.ep-stage/elementmap.json`(`{ title, scannedAt, elements[] }` 原始格式,grid 条目保留 `columns`/`rowActions` 供字段→列号映射)。后续 O-D-A-V 推理时 Agent 优先查此 map,snapshot refs 仅用于验证动作已生效。**不写 trace 根级**——`run` 子命令回写 trace 时全量覆盖,Agent 侧写入的自定义字段会被冲掉。
143
+ ```bash
144
+ CODE=$(cat <技能目录>/scripts/extract-page-elements-eval.mjs)
145
+ playwright-cli -s=$SESSION run-code "async page => page.evaluate(() => { $CODE; return JSON.stringify(extractPageElements()); })"
146
+ ```
147
+ > 注意:必须用 `run-code "async page => page.evaluate(...)"` 而不是 `eval`。`eval` 参数会被 CLI 包裹成 `() => (参数)`,文件内顶层语句(function 声明、`;` 分隔)会导致 `Passed function is not well-serializable!`;`run-code` 接收 `page => expr` 形式的 Node 侧函数,`page.evaluate` 回调体内可以安全包含完整脚本。
148
+ 首次扫描只扫主 frame(不含弹窗 iframe),避免误扫登录残留。
149
+ 5. 对每条 task O-D-A-V:
150
+ - **Observe**:`snapshot` 观察当前页面/iframe 结构,读 refs。
151
+ - **Decide**:推理下一步动作,查 `elementmap.json` `label locator` 找稳定定位符。
152
+ - **Act**:执行 `click <ref>` / `fill <ref> <text>` / `select <ref> <val>`。
153
+ - **补扫(Act 之后、Verify 之前)**:用 `run-code` 遍历 `page.frames()` 对所有 frame(含弹窗 iframe)分别注入执行,将新出现的元素按 `type|label|locator` 去重合并到 `.ep-stage/elementmap.json`。这一步确保弹窗/子表等动态创建的元素被捕获,供后续 task 直接查表使用,无需重复触发。注意 `extractAllFramesElementMap()` 依赖子 frame 也注入了同名函数,直接在主 frame eval 调用它扫不到子 frame;正确做法是 Node 侧遍历 frame:
154
+ ```bash
155
+ CODE=$(cat <技能目录>/scripts/extract-page-elements-eval.mjs)
156
+ playwright-cli -s=$SESSION run-code "async page => { const map = {}; for (const f of page.frames()) { try { const r = await f.evaluate(() => { $CODE; return extractPageElements(); }); r.elements.forEach(e => { if (e.label && (!map[e.label] || e.visible)) map[e.label] = { locator: e.locator, controlType: e.controlType, visible: e.visible }; }); } catch (_) {} } return JSON.stringify(map); }"
157
+ ```
158
+ - **Verify**:二次 snapshot 或 `eval "<js>"` 验证动作已生效并抽取断言值。
159
+ **refs 每次 snapshot 后重新编号,禁止跨 snapshot 缓存。**
160
+ 6. Agent 按 `dev-rules.md` 把观察 + 动作原料改写为符合本项目规范的 `test()` snippet(`repo*` 前缀、锚点作用域、复用 crud.spec.ts 已声明的 `directListUrl / credentialsPath / primaryRole / crudSlots / exportSlots` 常量,不重复声明)。
161
+ 7. 写 `<caseDir>/.ep-stage/ai-snippets.json5`,格式 `{ schemaVersion, testcasePath, generatedAt, results }`;每条 result 的 `evidence` 保留 `source: 'playwright-cli'` + snapshot yml 路径,支撑可观测性 gate。**specSnippet 值必须是合法 JSON5 字符串(单/双引号 + 转义),禁止反引号模板字符串**——JSON5 不支持 `` ` ``,run 解析即崩;建议用脚本 `JSON.stringify` 生成文件而非手写。
162
+ 8. 全部 task 完成后跑 `playwright-cli -s=$SESSION close` 释放 session(异常时 `playwright-cli kill-all` 兜底)。
163
+
164
+ 宿主 Agent `playwright-cli`、目标系统网络不可达、testcase 信息不足或断言无法确认时,不强造 snippet;对应 result 标 `needs_review`,并在 observation/evidence 中写明原因。
165
+
166
+ ### Step 6 调用 run CLI 合并 snippet 并执行完整 spec
167
+
168
+ 正常模式:
169
+
170
+ ```bash
171
+ npx -y @epoint-testtech/ep-stage-skill@latest run \
172
+ --testcase <projectDir>/src/tests/<需求名>/testcase.json5 \
173
+ --ai-snippets <projectDir>/src/tests/<需求名>/.ep-stage/ai-snippets.json5 \
174
+ --headless false
175
+ ```
176
+
177
+ 调试模式:
178
+
179
+ ```bash
180
+ node "$REPO/packages/ep-stage-skill/dist/src/cli/index.js" run \
181
+ --testcase <projectDir>/src/tests/<需求名>/testcase.json5 \
182
+ --ai-snippets <projectDir>/src/tests/<需求名>/.ep-stage/ai-snippets.json5 \
183
+ --headless false
184
+ ```
185
+
186
+ CLI run 行为:
187
+
188
+ 1. 读取 ai-snippets.json5;只合并 `status="resolved"` `specSnippet` 非空、caseId 属于当前 tasks 的结果。
189
+ 2. 若存在 AI tasks 但缺少完整 resolved snippet,写 trace `needs_review` 后停止,不追加占位代码、不执行 Playwright
190
+ 3. 若 snippets 完整,定位 `AI_APPEND_MARKER` 截断旧追加段,按任务顺序追加 snippets。
191
+ 4. 从 `projectDir` 跑 `npx playwright test <specPath>`,`headless=false` 时带 `--headed`。
192
+ 5. 失败时归类并写 `.ep-stage/repair-runs/<round>/repair-report.md`,同时回写 `trace.repairRounds`。
193
+
194
+ CLI 非 0 退出 → 复述 stderr,不进 Step 7。
195
+
196
+ ### Step 7 — 收集 spec、trace 与报告产物并输出摘要
197
+
198
+ 用 `ls` / `Read` 校验 §3 验证清单。成功信号:
199
+
200
+ - `crud.spec.ts` 已存在;若原先缺失,说明 prepare-tasks 已自动补组装。
201
+ - `ai-runtime-trace.json5` 已落盘且含 tasks + results;若 results `needs_review`,按原因提示继续 Agent O-D-A-V。
202
+ - `ai-snippets.json5` 已落盘;resolved 结果已合并到 spec,needs_review 结果不会合并。
203
+ - 报告目录已创建。
204
+ - 成功路径不落 repair report;若失败,`.ep-stage/repair-runs/<round>/repair-report.md` 存在,按 §4 引导人审确认修补方向。
205
+ - 若 CLI 返回 `credentialsNotice`,按原文回显给用户。
206
+
207
+ ## 3. 验证清单
208
+
209
+ | 路径 | 说明 |
210
+ |---|---|
211
+ | `<projectDir>/src/tests/<需求名>/crud.spec.ts` | prepare-tasks 自动补组装 glue 骨架;run 在 `AI_APPEND_MARKER` 后合并 Agent snippet(幂等) |
212
+ | `<projectDir>/src/tests/<需求名>/testcase.json5` | 必须存在 + `schemaVersion` 合法 |
213
+ | `<projectDir>/src/tests/<需求名>/credentials.json5` | 必须存在 + 数组 ≥ 1 条 + 必填字段非空 |
214
+ | `<projectDir>/src/tests/<需求名>/.ep-stage/contract.json5` | testcase 阶段产,run 阶段只读不写 |
215
+ | `<projectDir>/src/tests/<需求名>/.ep-stage/ai-runtime-trace.json5` | prepare-tasks 先写 tasks;run 回写 results / repairRounds |
216
+ | `<projectDir>/src/tests/<需求名>/.ep-stage/elementmap.json` | Agent O-D-A-V 落的页面控件定位清单(含 grid columns);run 不触碰 |
217
+ | `<projectDir>/src/tests/<需求名>/.ep-stage/repair-runs/<round>/repair-report.md` | 失败时才产;含失败分类与摘要,待人审确认 |
218
+ | `e2e/glue-code-mvp/glue-report/<run-timestamp>/` | run 子命令产;执行结果账本目录 |
219
+
220
+ ## 4. 错误处理
221
+
222
+ | 触发时机 | Agent 中文呈现 + 建议 |
223
+ |---|---|
224
+ | 引导 A(缺脚手架) | 中文提示+退出,引导先跑 `/glue-create-project <项目名>` |
225
+ | 引导 B(缺 testcase) | AskUserQuestion 三选一:跑 testcase / 强组装 / 取消(schema 不合法归入此类) |
226
+ | 引导 C(缺凭据) | AskUserQuestion 三选一:缓存复用 / 现在补 / 取消 |
227
+ | prepare-tasks / run 子命令 exit ≠ 0 | 复述 stderr;若缺 spec,也可能是 prepare-tasks 自动补跑 spec 失败 |
228
+ | glue cases 为空 | 阻断 prepare-tasks 内部 spec 组装;提示用户回 `/glue-generate-testcase` 补齐 |
229
+ | Playwright 执行失败 | 回显 `repairReportPath` 与失败分类;建议用户确认修补方向后重跑 `/glue-run-test <testcase.json5路径>`,不静默改 testcase |
230
+ | 用户中途取消 | AskUserQuestion 阶段说「算了/取消」立即终止;CLI 启动后等其退出再复述 |
231
+
232
+ ## 5. 完成提示
233
+
234
+ Step 7 全部通过后,按以下中文格式呈现:
235
+
236
+ > 胶水测试执行完成
237
+ >
238
+ > 需求:`<需求名>`/项目:`<projectDir>`
239
+ > Spec:`<projectDir>/src/tests/<需求名>/crud.spec.ts`(glue 骨架 + Agent snippet 合并)
240
+ > AI Runtime Trace:`<projectDir>/src/tests/<需求名>/.ep-stage/ai-runtime-trace.json5`
241
+ > 报告目录:`e2e/glue-code-mvp/glue-report/<run-timestamp>/`
242
+ > 运行版本:`version = v1`
243
+ >
244
+ > 下一步:① 调整 `testcase.json5` / `contract.json5` 后重跑 `/glue-run-test <testcase.json5路径>`;② 失败时查看 repair-report.md 确认修补方向后再重跑。
245
+
246
+ 失败时不要发完成提示:Playwright 失败已落 repair-report.md,按 §4 引导人审确认修补方向,不允许混合"执行完成"字样。
247
+
248
+ ## 6. 产物生命周期
249
+
250
+ | 层 | 文件内容 | 由谁产 |
251
+ |---|---|---|
252
+ | glue 骨架 | 顶部 `// === 胶水模式生成 ===`,只含 glue cases | `spec` 子命令,或 `prepare-tasks` 内部自动补跑 |
253
+ | AI 推理结果 | `.ep-stage/ai-snippets.json5`,由 Agent Runtime O-D-A-V 产出 | Agent + playwright-cli |
254
+ | AI snippet 追加 | `AI_APPEND_MARKER` 后的 snippet,由 run 子命令按 ai-snippets.json5 合并 | `run` 子命令 |
255
+ | trace | `.ep-stage/ai-runtime-trace.json5`,prepare-tasks 写 tasks,run 回写 results / repairRounds(全量覆盖,不保留 Agent 自定义字段) | `prepare-tasks` + `run` 子命令 |
256
+ | elementMap | `.ep-stage/elementmap.json`,Agent O-D-A-V 落的控件定位清单(初始扫描 + 补扫合并,grid 保留 columns) | Agent + playwright-cli |
257
+ | repair report | `.ep-stage/repair-runs/<round>/repair-report.md`,失败分类 + 摘要 | `run` 子命令(仅失败) |
258
+
259
+ 重跑幂等:AI 追加段在 `AI_APPEND_MARKER` 处截断旧段后重新追加,不堆积。
260
+
261
+ ## 7. 内嵌数据契约范例
262
+
263
+ `<需求名>/credentials.json5`:
264
+
265
+ ```json5
266
+ [ { url: "<请填登录页 URL>", username: "<请填>", password: "<请填>", role: "业务管理员" } ]
267
+ ```
268
+
269
+ 字段约束:必填 `url / username / password`;可选 `role / systemName`;数组至少 1 条;同 `(url, role)` 组合唯一;文件 gitignore。
270
+
271
+ ## 8. 引导场景
272
+
273
+ - A(缺脚手架):Step 1 反查 projects.index.json5 无 glue 条目 → 提示先跑 `/glue-create-project` 退出。
274
+ - B(缺 testcase):Step 2 缺失 / schema 不合法 → AskUserQuestion 三选一(跑 testcase / 强组装 / 取消)。
275
+ - C(缺凭据):Step 3 字段空 → AskUserQuestion 三选一(缓存复用 / 现在补 / 取消)。
276
+ - D(缺 code_list.json5):归 `/glue-generate-testcase` 处理。
277
+
278
+ ## 9. 按需加载
279
+
280
+ - AI Runtime Loop 状态机与修补边界:`references/ai-runtime-loop.md`
281
+ - CRUD 组装 pipeline + 失败归类:`references/crud-pipeline.md`
282
+ - harness 治理原则:`references/harness-principles.md`
283
+ - gap 评审协议:`references/gap-review-protocol.md`
284
+
285
+ ## 10. 关键约束
286
+
287
+ - 钻探前置:本 skill 不再实现 contract 提取、coverage 分析、`uncoveredCandidates` 推断;这些在 `/glue-generate-testcase` 完成。
288
+ - 当前用户入口只保留 `/glue-run-test <testcase.json5路径>`;不要要求用户先显式跑 `spec`。
289
+ - Agent 对 AI 用例执行受控运行态推理并写 ai-snippets.json5;run 子命令只合并 resolved snippet 后执行完整 spec;失败时先落 repair-report.md 等待确认,不静默改变 testcase 意图。
290
+ - `coverageStatus="blocked"` 的候选不进入 AI Runtime Task、不写 trace、不进 spec 追加段。
291
+ - spec / run 都不得对 contract 缺失槽位二次猜测。
292
+ - 用户视角始终全中文;业务断言、selector、iframe 关键字、按钮文案均由骨架 + `contract.json5` 的 `scenario.skeletonSlots` 决策,skill 不发明。
@@ -0,0 +1,30 @@
1
+ # AI Runtime Loop
2
+
3
+ glue-run-test 对 `generationStrategy=ai` 的用例采用受控运行态推理。
4
+
5
+ 状态机:
6
+
7
+ ```text
8
+ prepare_tasks_cli
9
+ -> agent_infer_ai_snippets
10
+ -> compose_full_spec_cli
11
+ -> run_full_spec
12
+ -> classify_result
13
+ -> passed: final_report
14
+ -> failed: write_repair_report
15
+ -> wait_human_direction
16
+ -> repair_spec
17
+ -> rerun
18
+ ```
19
+
20
+ Agent 可以读取 trace tasks,并使用 playwright-cli 观察页面、iframe、弹窗、提示和网络反馈;CLI 不做业务推理。Agent 不能新增测试范围、反刷 code_list.json5、静默改 testcase.json5 或绕开 docs/00-memory/dev-rules.md。
21
+
22
+ 失败后第一版只落:
23
+
24
+ ```text
25
+ .ep-stage/ai-runtime-trace.json5
26
+ .ep-stage/ai-snippets.json5
27
+ .ep-stage/repair-runs/<round>/repair-report.md
28
+ ```
29
+
30
+ 修补 loop 不设固定轮数上限,每轮失败先落袋、人审纠偏,再修补重跑。退出条件:用户停止、同类失败无新证据、环境不可达、权限不足、数据不足、需要改变测试意图、真实业务不满足预期。