@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
@@ -0,0 +1,248 @@
1
+ /**
2
+ * PRD markdown 解析器。
3
+ *
4
+ * 职责:
5
+ * 1. 在需求目录中发现 PRD markdown 文件。
6
+ * 2. 解析 PRD 章节 4.1(功能列表)和 4.2.x(功能详细说明)。
7
+ * 3. 输出结构化的 PrdFunctionEntry[],供 testcase 装配阶段确定性使用。
8
+ *
9
+ * 设计取舍:
10
+ * - 全程使用正则/行解析,不调用 LLM,保证幂等性。
11
+ * - 只识别当前观察到的 PRD 结构(`4.1` 表格 + `4.2.x` 子章节 + 粗体字段标题)。
12
+ * - 解析失败时返回空数组并在 inferenceTrace 中记录,不阻断 pipeline。
13
+ */
14
+ import { existsSync, readdirSync, readFileSync } from 'node:fs';
15
+ import path from 'node:path';
16
+ /**
17
+ * 在目录中查找 PRD markdown 文件。
18
+ *
19
+ * 规则(满足任一即返回):
20
+ * 1. 文件名包含 `prd`(大小写不敏感)且以 `.md` 结尾。
21
+ * 2. 文件正文包含 `## 4. 功能需求` 标题。
22
+ *
23
+ * @param dir - 需求文档目录。
24
+ * @returns PRD 文件绝对路径;不存在时返回 undefined。
25
+ */
26
+ export function findPrdMarkdown(dir) {
27
+ if (!existsSync(dir)) {
28
+ return undefined;
29
+ }
30
+ const candidates = readdirSync(dir).filter((file) => file.endsWith('.md'));
31
+ for (const file of candidates) {
32
+ const fullPath = path.join(dir, file);
33
+ if (/prd/i.test(file)) {
34
+ return fullPath;
35
+ }
36
+ }
37
+ for (const file of candidates) {
38
+ const fullPath = path.join(dir, file);
39
+ const content = readFileSync(fullPath, 'utf8');
40
+ if (/##\s*4\.\s*功能需求/.test(content)) {
41
+ return fullPath;
42
+ }
43
+ }
44
+ return undefined;
45
+ }
46
+ /**
47
+ * 读取 PRD 文件并提取功能条目。
48
+ *
49
+ * @param prdPath - PRD markdown 文件绝对路径。
50
+ * @param now - 可选的解析时间戳,用于测试冻结。
51
+ * @returns PRD 提取产物。
52
+ */
53
+ export function loadPrdExtraction(prdPath, now = new Date().toISOString()) {
54
+ const markdown = readFileSync(prdPath, 'utf8');
55
+ const functions = extractPrdFunctions(markdown);
56
+ return { prdPath, functions, generatedAt: now };
57
+ }
58
+ /**
59
+ * 解析 PRD markdown 文本,提取功能列表 + 功能详细说明。
60
+ *
61
+ * @param markdown - PRD 完整 markdown 文本。
62
+ * @returns 按 PRD 顺序排列的功能条目数组。
63
+ */
64
+ export function extractPrdFunctions(markdown) {
65
+ const functionList = parseFunctionList(markdown);
66
+ const details = parseFunctionDetails(markdown);
67
+ const detailMap = new Map(details.map((d) => [d.featureId, d]));
68
+ // 以功能列表为基准顺序,合并详细说明;若详细说明缺失则使用列表中的描述兜底。
69
+ return functionList.map((listItem) => {
70
+ const detail = detailMap.get(listItem.featureId);
71
+ return {
72
+ featureId: listItem.featureId,
73
+ featureName: listItem.featureName,
74
+ featureModule: listItem.featureModule,
75
+ description: detail?.description ?? listItem.description,
76
+ inputConditions: detail?.inputConditions,
77
+ processingLogic: detail?.processingLogic ?? [],
78
+ outputResult: detail?.outputResult ?? [],
79
+ businessRules: detail?.businessRules ?? [],
80
+ constraints: detail?.constraints ?? [],
81
+ };
82
+ });
83
+ }
84
+ /**
85
+ * 解析 4.1 功能列表表格。
86
+ *
87
+ * 表格列(按当前 PRD 约定):
88
+ * | 功能模块 | 功能编号 | 功能名称 | 功能描述 | 功能类型 | ... |
89
+ */
90
+ function parseFunctionList(markdown) {
91
+ const result = [];
92
+ const sectionMatch = markdown.match(/###\s*4\.1\s*功能列表[\s\S]*?(?=###\s*4\.2|##\s+5|\n##\s)/);
93
+ if (!sectionMatch) {
94
+ return result;
95
+ }
96
+ const lines = sectionMatch[0].split('\n');
97
+ for (const line of lines) {
98
+ const trimmed = line.trim();
99
+ if (!trimmed.startsWith('|'))
100
+ continue;
101
+ if (trimmed.includes('功能编号'))
102
+ continue; // header / separator
103
+ if (/^\|\s*-+/.test(trimmed))
104
+ continue; // markdown separator
105
+ const cells = trimmed
106
+ .split('|')
107
+ .map((c) => c.trim())
108
+ .filter((c) => c.length > 0);
109
+ if (cells.length < 4)
110
+ continue;
111
+ const featureModule = cells[0];
112
+ const featureId = cells[1];
113
+ const featureName = cells[2];
114
+ const description = cells[3];
115
+ if (!/^F\d{3,}$/i.test(featureId))
116
+ continue;
117
+ result.push({ featureId: featureId.toUpperCase(), featureName, featureModule, description });
118
+ }
119
+ return result;
120
+ }
121
+ /**
122
+ * 解析 4.2.x 功能详细说明。
123
+ */
124
+ function parseFunctionDetails(markdown) {
125
+ const result = [];
126
+ // 匹配每个 4.2.x 子章节:#### 4.2.x Fxxx 功能名称
127
+ const sectionRegex = /####\s*4\.2\.(\d+)\s+((F\d{3,})\s+(.+?))\s*(?=\n)/g;
128
+ let match;
129
+ const sections = [];
130
+ while ((match = sectionRegex.exec(markdown)) !== null) {
131
+ sections.push({
132
+ start: match.index,
133
+ featureId: match[3].toUpperCase(),
134
+ featureName: match[4].trim(),
135
+ end: match.index + match[0].length,
136
+ });
137
+ }
138
+ for (let i = 0; i < sections.length; i++) {
139
+ const current = sections[i];
140
+ const nextSection = sections[i + 1];
141
+ const sectionEnd = findSectionEnd(current.end, markdown, nextSection?.start);
142
+ const sectionBody = markdown.slice(current.end, sectionEnd);
143
+ result.push(parseFunctionDetailSection(current.featureId, current.featureName, sectionBody));
144
+ }
145
+ return result;
146
+ }
147
+ /**
148
+ * 计算子章节结束位置。
149
+ *
150
+ * 结束位置取以下候选的最小值:
151
+ * 1. 下一个同层 `####` 子章节的开始位置。
152
+ * 2. 下一个更高层标题(`###` 或 `##`)的开始位置。
153
+ * 3. markdown 末尾。
154
+ */
155
+ function findSectionEnd(start, markdown, nextSectionStart) {
156
+ const nextHeadingMatch = markdown.slice(start).match(/\n#{1,3}\s/m);
157
+ const nextHeadingStart = nextHeadingMatch
158
+ ? start + nextHeadingMatch.index + 1 // +1 跳过前面的换行
159
+ : undefined;
160
+ const candidates = [nextSectionStart, nextHeadingStart].filter((n) => n !== undefined);
161
+ return candidates.length > 0 ? Math.min(...candidates) : markdown.length;
162
+ }
163
+ /**
164
+ * 解析单个 4.2.x 子章节内容。
165
+ */
166
+ function parseFunctionDetailSection(featureId, featureName, sectionBody) {
167
+ const fields = splitDetailFields(sectionBody);
168
+ return {
169
+ featureId,
170
+ featureName,
171
+ description: fields['功能描述']?.join('\n').trim() ?? '',
172
+ inputConditions: fields['输入条件']?.join('\n').trim() || undefined,
173
+ processingLogic: extractListItems(fields['处理逻辑']),
174
+ outputResult: extractListItems(fields['输出结果']),
175
+ businessRules: extractListItems(fields['业务规则']),
176
+ constraints: extractListItems(fields['约束条件']),
177
+ };
178
+ }
179
+ /**
180
+ * 按粗体字段标题把子章节内容切分成多个字段块。
181
+ *
182
+ * 字段标题形如 `**功能描述**:` 或 `**功能描述**:`(注意中文冒号)。
183
+ */
184
+ function splitDetailFields(body) {
185
+ const lines = body.split('\n');
186
+ const fields = {};
187
+ let currentField;
188
+ const fieldHeaderRegex = /^\*\*([^*]+)\*\*[::]\s*(.*)$/;
189
+ for (const rawLine of lines) {
190
+ const line = rawLine.trimEnd();
191
+ const headerMatch = line.trim().match(fieldHeaderRegex);
192
+ if (headerMatch) {
193
+ currentField = headerMatch[1].trim();
194
+ const rest = headerMatch[2].trim();
195
+ fields[currentField] = [];
196
+ if (rest) {
197
+ fields[currentField].push(rest);
198
+ }
199
+ continue;
200
+ }
201
+ if (currentField && line.trim().length > 0) {
202
+ // 跳过空行,但保留列表项和缩进内容
203
+ fields[currentField].push(line);
204
+ }
205
+ }
206
+ return fields;
207
+ }
208
+ /**
209
+ * 从字段块中提取列表项。
210
+ *
211
+ * 支持:
212
+ * - 有序列表 `1. ...`
213
+ * - 无序列表 `- ...`
214
+ * - 缩进列表(二级列表作为前一项的延续,不单独拆分)
215
+ *
216
+ * 过滤:
217
+ * - 空项
218
+ * - 纯 `--` 等表格/排版分隔符
219
+ */
220
+ function extractListItems(lines) {
221
+ if (!lines || lines.length === 0)
222
+ return [];
223
+ const items = [];
224
+ for (const rawLine of lines) {
225
+ const line = rawLine.trim();
226
+ if (line.length === 0)
227
+ continue;
228
+ if (/^-+$/.test(line))
229
+ continue; // 过滤 '--' 分隔符
230
+ const listMatch = line.match(/^(?:\d+\.|-)\s+(.+)$/);
231
+ if (listMatch) {
232
+ const content = listMatch[1].trim();
233
+ if (content)
234
+ items.push(content);
235
+ }
236
+ else if (line.startsWith('-')) {
237
+ const content = line.replace(/^-\s*/, '').trim();
238
+ if (content)
239
+ items.push(content);
240
+ }
241
+ else if (items.length > 0 && rawLine.startsWith(' ')) {
242
+ // 缩进内容追加到前一项
243
+ items[items.length - 1] += ' ' + line;
244
+ }
245
+ // 非列表行(如普通段落)忽略,避免把标题残留混入
246
+ }
247
+ return items;
248
+ }
@@ -104,20 +104,20 @@ function renderGapFindingBlock(workflow, label, assertion) {
104
104
  const kind = /暂未实现|未实现|未配置|联系管理员/.test(observed)
105
105
  ? 'feature_incomplete'
106
106
  : 'behavior_mismatch';
107
- return `
108
- gapFinding: {
109
- kind: ${singleQuoted(kind)},
110
- summary: ${singleQuoted(`运行态推理发现「${label}」未满足业务预期。`)},
111
- observed: ${singleQuoted(observed)},
107
+ return `
108
+ gapFinding: {
109
+ kind: ${singleQuoted(kind)},
110
+ summary: ${singleQuoted(`运行态推理发现「${label}」未满足业务预期。`)},
111
+ observed: ${singleQuoted(observed)},
112
112
  },`;
113
113
  }
114
114
  function renderRuntimeAwareAssertionBlock(input) {
115
115
  const exploration = input.workflow.resolvedRuntime?.exploration;
116
116
  if (!exploration) {
117
- return `
118
- await expect(${input.repoVariable}).toBeVisible();
119
- await ${input.repoVariable}.click();
120
-
117
+ return `
118
+ await expect(${input.repoVariable}).toBeVisible();
119
+ await ${input.repoVariable}.click();
120
+
121
121
  await expect(page.getByText(${singleQuoted(input.assertion)})).toBeVisible({ timeout: 30000 });`;
122
122
  }
123
123
  const confirmVariable = confirmButtonVariableName(input.label);
@@ -125,33 +125,33 @@ function renderRuntimeAwareAssertionBlock(input) {
125
125
  const actualVariable = actualFeedbackVariableName(input.label);
126
126
  const runtimeObserved = exploration.observedMessage?.replace(/\s+/g, ' ').trim() ?? '';
127
127
  const confirmBlock = exploration.confirmDialogPresent
128
- ? `
129
-
130
- const ${confirmVariable} = ${input.locatorOwner}
131
- .locator("xpath=//*[contains(@class,'mini-messagebox')]//a[normalize-space()='确定' or normalize-space()='确认']")
132
- .first();
133
- await expect(${confirmVariable}).toBeVisible({ timeout: 15000 });
128
+ ? `
129
+
130
+ const ${confirmVariable} = ${input.locatorOwner}
131
+ .locator("xpath=//*[contains(@class,'mini-messagebox')]//a[normalize-space()='确定' or normalize-space()='确认']")
132
+ .first();
133
+ await expect(${confirmVariable}).toBeVisible({ timeout: 15000 });
134
134
  await ${confirmVariable}.click();`
135
135
  : '';
136
- return `
137
- await expect(${input.repoVariable}).toBeVisible();
138
- await ${input.repoVariable}.click();${confirmBlock}
139
-
140
- const runtimeObserved反馈文案 = ${singleQuoted(runtimeObserved)};
141
- const ${feedbackVariable} = ${input.locatorOwner}.locator("xpath=//*[contains(@class,'mini-messagebox') or contains(@class,'mini-tips')]");
142
- await page.waitForTimeout(1000);
143
- const 反馈文本列表 = (await ${feedbackVariable}.allInnerTexts())
144
- .map((text) => text.replace(/\\s+/g, ' ').trim())
145
- .filter(Boolean);
146
- const ${actualVariable} =
147
- 反馈文本列表.find((text) => runtimeObserved反馈文案 && text.includes(runtimeObserved反馈文案)) ??
148
- 反馈文本列表.find((text) => text.includes(${singleQuoted(input.assertion)})) ??
149
- runtimeObserved反馈文案 ??
150
- 反馈文本列表.sort((a, b) => b.length - a.length)[0] ??
151
- '';
152
- expect(
153
- ${actualVariable}.includes(${singleQuoted(input.assertion)}),
154
- ${singleQuoted(`${input.label}未达成业务预期:期望出现「${input.assertion}」,系统实际反馈「`)} + ${actualVariable} + '」',
136
+ return `
137
+ await expect(${input.repoVariable}).toBeVisible();
138
+ await ${input.repoVariable}.click();${confirmBlock}
139
+
140
+ const runtimeObserved反馈文案 = ${singleQuoted(runtimeObserved)};
141
+ const ${feedbackVariable} = ${input.locatorOwner}.locator("xpath=//*[contains(@class,'mini-messagebox') or contains(@class,'mini-tips')]");
142
+ await page.waitForTimeout(1000);
143
+ const 反馈文本列表 = (await ${feedbackVariable}.allInnerTexts())
144
+ .map((text) => text.replace(/\\s+/g, ' ').trim())
145
+ .filter(Boolean);
146
+ const ${actualVariable} =
147
+ 反馈文本列表.find((text) => runtimeObserved反馈文案 && text.includes(runtimeObserved反馈文案)) ??
148
+ 反馈文本列表.find((text) => text.includes(${singleQuoted(input.assertion)})) ??
149
+ runtimeObserved反馈文案 ??
150
+ 反馈文本列表.sort((a, b) => b.length - a.length)[0] ??
151
+ '';
152
+ expect(
153
+ ${actualVariable}.includes(${singleQuoted(input.assertion)}),
154
+ ${singleQuoted(`${input.label}未达成业务预期:期望出现「${input.assertion}」,系统实际反馈「`)} + ${actualVariable} + '」',
155
155
  ).toBe(true);`;
156
156
  }
157
157
  export function renderAgentWorkflowTest(options) {
@@ -176,40 +176,40 @@ export function renderAgentWorkflowTest(options) {
176
176
  workflow,
177
177
  });
178
178
  const iframeSetup = iframeSrcKeyword
179
- ? `
180
- const ${frameVariable} = page.locator(${singleQuoted(`iframe[src*="${iframeSrcKeyword}"]`)}).contentFrame();
179
+ ? `
180
+ const ${frameVariable} = page.locator(${singleQuoted(`iframe[src*="${iframeSrcKeyword}"]`)}).contentFrame();
181
181
  `
182
182
  : '';
183
- return `
184
- test(${singleQuoted(title)}, async ({ page }) => {
185
- test.slow();
186
-
187
- await runRecordedWorkflow(
188
- recorder,
189
- {
190
- moduleId: ${singleQuoted(options.moduleId)},
191
- workflowId: ${singleQuoted(workflow.workflowId)},
192
- workflowKind: 'custom',
193
- workflowName: ${singleQuoted(label)},
194
- executionSource: 'agent_inferred',
195
- businessIntent: ${singleQuoted(intent)},
196
- elementActions: ${arrayLiteral(actions)},
197
- assertionExpectation: ${singleQuoted(assertion)},
198
- evidenceSources: ${arrayLiteral(evidenceSources(workflow))},
199
- evidenceRefs: ${renderEvidenceRefs(workflow)},
200
- reviewReason: ${singleQuoted(workflow.reviewReason ?? '该工作流由 gap-planner 识别为自定义业务动作。')},
201
- playwrightSuiteTitle: ${singleQuoted(options.suiteTitle)},
202
- playwrightTestTitle: ${singleQuoted(title)},
203
- ${gapFindingBlock}
204
- },
205
- async () => {
206
- await openModule(page);
207
- ${iframeSetup}
208
- const ${repoVariable} = ${locatorOwner}.locator(${locatorLiteral(locator)});
209
- ${assertionBlock}
210
- },
211
- );
212
- });
183
+ return `
184
+ test(${singleQuoted(title)}, async ({ page }) => {
185
+ test.slow();
186
+
187
+ await runRecordedWorkflow(
188
+ recorder,
189
+ {
190
+ moduleId: ${singleQuoted(options.moduleId)},
191
+ workflowId: ${singleQuoted(workflow.workflowId)},
192
+ workflowKind: 'custom',
193
+ workflowName: ${singleQuoted(label)},
194
+ executionSource: 'agent_inferred',
195
+ businessIntent: ${singleQuoted(intent)},
196
+ elementActions: ${arrayLiteral(actions)},
197
+ assertionExpectation: ${singleQuoted(assertion)},
198
+ evidenceSources: ${arrayLiteral(evidenceSources(workflow))},
199
+ evidenceRefs: ${renderEvidenceRefs(workflow)},
200
+ reviewReason: ${singleQuoted(workflow.reviewReason ?? '该工作流由 gap-planner 识别为自定义业务动作。')},
201
+ playwrightSuiteTitle: ${singleQuoted(options.suiteTitle)},
202
+ playwrightTestTitle: ${singleQuoted(title)},
203
+ ${gapFindingBlock}
204
+ },
205
+ async () => {
206
+ await openModule(page);
207
+ ${iframeSetup}
208
+ const ${repoVariable} = ${locatorOwner}.locator(${locatorLiteral(locator)});
209
+ ${assertionBlock}
210
+ },
211
+ );
212
+ });
213
213
  `;
214
214
  }
215
215
  export function appendAgentWorkflowTest(options) {
@@ -9,10 +9,14 @@
9
9
  import type { CrudBusinessModuleContract } from '../contracts/crud-business-module.js';
10
10
  export type StageSkeletonCrudDeletePolicy = 'success_delete' | 'blocked_by_business_rule';
11
11
  export type StageSkeletonCrudDataValueStrategy = 'timestamp_prefix' | 'fixed_value';
12
+ export type StageSkeletonCrudListboxValueStrategy = 'explicit' | 'first_non_placeholder';
13
+ export type StageSkeletonCrudListboxSearchAssertion = 'contains_row_anchor' | 'none';
12
14
  export type StageSkeletonCrudListboxSelectionSlot = {
13
15
  field: string;
14
16
  label: string;
15
- value: string;
17
+ value?: string;
18
+ valueStrategy?: StageSkeletonCrudListboxValueStrategy;
19
+ skipValues?: string[];
16
20
  };
17
21
  export type StageSkeletonCrudInputSearchConditionSlot = {
18
22
  component: 'input';
@@ -31,10 +35,45 @@ export type StageSkeletonCrudListboxSearchConditionSlot = {
31
35
  component: 'listbox';
32
36
  field: string;
33
37
  label: string;
34
- value: string;
38
+ value?: string;
39
+ valueStrategy?: StageSkeletonCrudListboxValueStrategy;
40
+ skipValues?: string[];
41
+ searchAssertion?: StageSkeletonCrudListboxSearchAssertion;
35
42
  createSelections?: StageSkeletonCrudListboxSelectionSlot[];
36
43
  };
37
44
  export type StageSkeletonCrudSearchConditionSlot = StageSkeletonCrudInputSearchConditionSlot | StageSkeletonCrudListboxSearchConditionSlot;
45
+ /**
46
+ * 子表列槽位(生成器层形态,与 skeleton ChildGridColumnSlot 保持一致)。
47
+ */
48
+ export type StageSkeletonChildGridColumnSlot = {
49
+ field: string;
50
+ label: string;
51
+ component: 'input' | 'listbox';
52
+ required: boolean;
53
+ modelRef?: string;
54
+ };
55
+ /**
56
+ * 子表槽位(生成器层形态,与 skeleton ChildGridFlowSlots 保持一致)。
57
+ */
58
+ export type StageSkeletonChildGridFlowSlots = {
59
+ gridId: string;
60
+ label: string;
61
+ pageRole: 'add' | 'edit';
62
+ editMode: 'cell_edit' | 'row_button_dialog' | 'none';
63
+ columns: StageSkeletonChildGridColumnSlot[];
64
+ locators: {
65
+ container: string;
66
+ addRowButton: string;
67
+ deleteSelectedButton: string;
68
+ grid: string;
69
+ editWrapInput: string;
70
+ editWrapListboxTrigger: string;
71
+ editWrapListboxInput: string;
72
+ rowCheckboxByIndex: string;
73
+ cellByIndexAndField: string;
74
+ cellValueByIndexAndField: string;
75
+ };
76
+ };
38
77
  /**
39
78
  * stage-skeleton CRUD 骨架槽位。
40
79
  *
@@ -66,18 +105,6 @@ export type StageSkeletonCrudFlowSlots = {
66
105
  blockedDeleteMessage?: string;
67
106
  };
68
107
  };
69
- /**
70
- * 生成 stage-skeleton 测试脚本的输入参数。
71
- *
72
- * @property contract CRUD 业务模块契约
73
- * @property menuNavigation 菜单路径,传给 MenuPage.navigateToMenu
74
- * @property testName 生成的测试用例名称
75
- */
76
- export type StageSkeletonScriptOptions = {
77
- contract: CrudBusinessModuleContract;
78
- menuNavigation: string;
79
- testName?: string;
80
- };
81
108
  /**
82
109
  * 将 CRUD 业务模块契约映射为 stage-skeleton 的 CrudFlowSlots。
83
110
  *
@@ -94,14 +121,54 @@ export declare function mapContractToStageSkeletonCrudSlots(contract: CrudBusine
94
121
  */
95
122
  export declare function renderStageSkeletonCrudSlots(slots: StageSkeletonCrudFlowSlots): string;
96
123
  /**
97
- * 生成动作级 CRUD + Export Playwright 测试脚本。
124
+ * 将子表槽位数组渲染为 TypeScript 对象字面量。
98
125
  *
99
- * 每个标准工作流(Create / Read / Update / Delete / Export)独立输出为
100
- * 一个 test case,使用 GlueWorkflowRecorder 记录执行报告。
101
- * 末尾保留 `// @stage-gap-append` 标记供 gap Custom test 追加。
126
+ * @param slots - 子表槽位数组
127
+ * @returns TypeScript 源码
128
+ */
129
+ export declare function renderChildGridSlots(slots: StageSkeletonChildGridFlowSlots[]): string;
130
+ /**
131
+ * fromSlots 入口生成参数(新协议,不依赖 CrudBusinessModuleContract)。
102
132
  *
103
- * @param options 生成参数
133
+ * 所有数据均来自入参:crudSlots 直接是 StageSkeletonCrudFlowSlots,
134
+ * exportSlot 是 contract.scenario.skeletonSlots.export 三元槽位,
135
+ * moduleId/moduleLabel 来自 testcase + contract.base.module,
136
+ * directUrl/primaryRole/requirementName 用于生成登录 + 直达链接进入模块的 openModule。
137
+ */
138
+ export type GenerateStageSkeletonCrudSpecFromSlotsOptions = {
139
+ moduleId: string;
140
+ moduleLabel: string;
141
+ directUrl: string;
142
+ primaryRole: string;
143
+ requirementName: string;
144
+ crudSlots: StageSkeletonCrudFlowSlots;
145
+ exportSlot: {
146
+ moduleId: string;
147
+ label: string;
148
+ mode: string;
149
+ };
150
+ childGridSlots?: StageSkeletonChildGridFlowSlots[];
151
+ };
152
+ /**
153
+ * 基于 skeletonSlots 槽位生成动作级 CRUD + Export Playwright 测试脚本(新协议 fromSlots 入口)。
154
+ *
155
+ * 与 {@link generateStageSkeletonCrudSpec} 输出同构的 spec 模板
156
+ * (test.describe / recorder / openModule / Create-Read-Update-Delete-Export),
157
+ * 但所有数据来自入参槽位,**不接收 CrudBusinessModuleContract、不 import 它、
158
+ * 不调 mapContractToStageSkeletonCrudSlots**。
159
+ *
160
+ * - crudSlots 直接调 {@link renderStageSkeletonCrudSlots}(复用现有 render)。
161
+ * - exportSlot 调 {@link renderExportSlotsFromSlot}(listIframeSrcKeyword 取自 crudSlots.frames)。
162
+ * - deletePolicy 从 crudSlots.assertions.deletePolicy 取(不再从 contract.flows.delete 推)。
163
+ *
164
+ * @param options 生成参数(全部来自 contract.skeletonSlots + testcase 导航/模块信息)
104
165
  * @returns 完整的 `.spec.ts` 源码
105
166
  */
106
- export declare function generateStageSkeletonCrudSpec(options: StageSkeletonScriptOptions): string;
167
+ export declare function generateStageSkeletonCrudSpecFromSlots(options: GenerateStageSkeletonCrudSpecFromSlotsOptions): string;
168
+ /**
169
+ * @deprecated 旧 v2 协议入口已删除(新链路改用 {@link generateStageSkeletonCrudSpecFromSlots})。
170
+ * 原实现接收 CrudBusinessModuleContract 并经 mapContractToStageSkeletonCrudSlots 映射,
171
+ * 新协议不再依赖 contract 直传,故整段移除。下方保留的 contract→slots 辅助函数
172
+ * 与 renderExportSlots(contract) 仅为历史参考,新链路不引用。
173
+ */
107
174
  //# sourceMappingURL=stage-skeleton-script.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"stage-skeleton-script.d.ts","sourceRoot":"","sources":["../../../src/generators/stage-skeleton-script.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,0BAA0B,EAAiF,MAAM,sCAAsC,CAAC;AAEtK,MAAM,MAAM,6BAA6B,GAAG,gBAAgB,GAAG,0BAA0B,CAAC;AAC1F,MAAM,MAAM,kCAAkC,GAAG,kBAAkB,GAAG,aAAa,CAAC;AAEpF,MAAM,MAAM,qCAAqC,GAAG;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,yCAAyC,GAAG;IACtD,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,kCAAkC,CAAC;IAC9C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,2CAA2C,GAAG;IACxD,SAAS,EAAE,SAAS,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,qCAAqC,EAAE,CAAC;CAC5D,CAAC;AAEF,MAAM,MAAM,oCAAoC,GAC5C,yCAAyC,GACzC,2CAA2C,CAAC;AAEhD;;;;;GAKG;AACH,MAAM,MAAM,0BAA0B,GAAG;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,oCAAoC,EAAE,CAAC;IACzD,MAAM,EAAE;QACN,oBAAoB,EAAE,MAAM,CAAC;QAC7B,mBAAmB,EAAE,MAAM,CAAC;QAC5B,oBAAoB,EAAE,MAAM,CAAC;KAC9B,CAAC;IACF,QAAQ,EAAE;QACR,YAAY,EAAE,MAAM,CAAC;QACrB,kBAAkB,CAAC,EAAE,MAAM,CAAC;QAC5B,aAAa,EAAE,MAAM,CAAC;QACtB,gBAAgB,EAAE,MAAM,CAAC;QACzB,8BAA8B,EAAE,MAAM,CAAC;QACvC,6BAA6B,EAAE,MAAM,CAAC;QACtC,cAAc,EAAE,MAAM,CAAC;QACvB,4BAA4B,EAAE,MAAM,CAAC;QACrC,gBAAgB,EAAE,MAAM,CAAC;QACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;KAC9B,CAAC;IACF,UAAU,EAAE;QACV,YAAY,EAAE,6BAA6B,CAAC;QAC5C,oBAAoB,CAAC,EAAE,MAAM,CAAC;KAC/B,CAAC;CACH,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,0BAA0B,GAAG;IACvC,QAAQ,EAAE,0BAA0B,CAAC;IACrC,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AA+QF;;;;;;GAMG;AACH,wBAAgB,mCAAmC,CAAC,QAAQ,EAAE,0BAA0B,GAAG,0BAA0B,CA0CpH;AA6DD;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,0BAA0B,GAAG,MAAM,CAwBtF;AAwBD;;;;;;;;;GASG;AACH,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,0BAA0B,GAAG,MAAM,CAoMzF"}
1
+ {"version":3,"file":"stage-skeleton-script.d.ts","sourceRoot":"","sources":["../../../src/generators/stage-skeleton-script.ts"],"names":[],"mappings":"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"}