@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.
- package/SKILL.md +27 -27
- package/codex-skill/ep-stage/glue-create-project/SKILL.md +223 -186
- package/codex-skill/ep-stage/glue-generate-testcase/SKILL.md +275 -199
- package/codex-skill/ep-stage/glue-generate-testcase/examples/observable-testcase.json +40 -40
- package/codex-skill/ep-stage/glue-generate-testcase/references/testcase-schema.md +95 -112
- package/codex-skill/ep-stage/glue-generate-testcase/references/testcase-tpl.md +72 -0
- package/codex-skill/ep-stage/glue-run-test/SKILL.md +292 -249
- package/codex-skill/ep-stage/glue-run-test/references/ai-runtime-loop.md +30 -0
- package/codex-skill/ep-stage/glue-run-test/references/crud-pipeline.md +132 -145
- package/codex-skill/ep-stage/glue-run-test/references/gap-review-protocol.md +44 -43
- package/codex-skill/ep-stage/glue-run-test/references/harness-principles.md +46 -46
- package/codex-skill/ep-stage/glue-run-test/references/playwright-cli-odav.md +166 -0
- package/codex-skill/ep-stage/glue-run-test/scripts/extract-page-elements-eval.mjs +233 -0
- package/codex-skill/ep-stage/glue-run-test/scripts/generate-crud-spec.mjs +149 -149
- package/codex-skill/ep-stage/page-element-scan/SKILL.md +91 -0
- package/codex-skill/ep-stage/page-element-scan/evals/evals.json +37 -0
- package/codex-skill/ep-stage/page-element-scan/evals/fixtures/sample-list-page.html +85 -0
- package/codex-skill/ep-stage/page-element-scan/references/pagination-controls.md +153 -0
- package/codex-skill/ep-stage/page-element-scan/scripts/extract-page-elements-eval.mjs +233 -0
- package/codex-skill/ep-stage/page-element-scan/scripts/extract-page-elements.mjs +298 -0
- package/codex-skill/ep-stage/page-element-scan/scripts/scan-page.mjs +749 -0
- package/codex-skill/ep-stage/recording-to-glue/SKILL.md +28 -28
- package/codex-skill/ep-stage/scripts/validate-skill.mjs +98 -95
- package/dist/src/cli/generate-testcase.d.ts +18 -51
- package/dist/src/cli/generate-testcase.d.ts.map +1 -1
- package/dist/src/cli/generate-testcase.js +127 -131
- package/dist/src/cli/index.d.ts +11 -2
- package/dist/src/cli/index.d.ts.map +1 -1
- package/dist/src/cli/index.js +49 -16
- package/dist/src/cli/probe.d.ts +2 -0
- package/dist/src/cli/probe.d.ts.map +1 -1
- package/dist/src/cli/probe.js +239 -13
- package/dist/src/cli/run.d.ts +136 -29
- package/dist/src/cli/run.d.ts.map +1 -1
- package/dist/src/cli/run.js +494 -65
- package/dist/src/cli/spec.d.ts +18 -11
- package/dist/src/cli/spec.d.ts.map +1 -1
- package/dist/src/cli/spec.js +74 -20
- package/dist/src/contracts/crud-business-module.d.ts +6 -0
- package/dist/src/contracts/crud-business-module.d.ts.map +1 -1
- package/dist/src/contracts/glue-contract-v1.d.ts +98 -0
- package/dist/src/contracts/glue-contract-v1.d.ts.map +1 -0
- package/dist/src/contracts/glue-contract-v1.js +9 -0
- package/dist/src/contracts/inference-trace.d.ts +223 -0
- package/dist/src/contracts/inference-trace.d.ts.map +1 -0
- package/dist/src/contracts/inference-trace.js +12 -0
- package/dist/src/contracts/observable-chain.d.ts +4 -0
- package/dist/src/contracts/observable-chain.d.ts.map +1 -1
- package/dist/src/extractors/code-list-json5.d.ts +192 -0
- package/dist/src/extractors/code-list-json5.d.ts.map +1 -0
- package/dist/src/extractors/code-list-json5.js +91 -0
- package/dist/src/extractors/code-list.d.ts +3 -3
- package/dist/src/extractors/code-list.d.ts.map +1 -1
- package/dist/src/extractors/code-list.js +46 -11
- package/dist/src/extractors/html-page.d.ts +9 -0
- package/dist/src/extractors/html-page.d.ts.map +1 -1
- package/dist/src/extractors/html-page.js +26 -2
- package/dist/src/extractors/prd-extractor.d.ts +70 -0
- package/dist/src/extractors/prd-extractor.d.ts.map +1 -0
- package/dist/src/extractors/prd-extractor.js +248 -0
- package/dist/src/generators/agent-inferred-workflow-script.js +66 -66
- package/dist/src/generators/stage-skeleton-script.d.ts +87 -20
- package/dist/src/generators/stage-skeleton-script.d.ts.map +1 -1
- package/dist/src/generators/stage-skeleton-script.js +656 -238
- package/dist/src/index.d.ts +7 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -1
- package/dist/src/inference/module-hints-inference.d.ts +30 -0
- package/dist/src/inference/module-hints-inference.d.ts.map +1 -0
- package/dist/src/inference/module-hints-inference.js +363 -0
- package/dist/src/inference/source-analysis.d.ts +26 -0
- package/dist/src/inference/source-analysis.d.ts.map +1 -0
- package/dist/src/inference/source-analysis.js +258 -0
- package/dist/src/normalizers/crud-contract.d.ts +3 -0
- package/dist/src/normalizers/crud-contract.d.ts.map +1 -1
- package/dist/src/normalizers/crud-contract.js +3 -0
- package/dist/src/runtime/ai-runtime-trace.d.ts +88 -0
- package/dist/src/runtime/ai-runtime-trace.d.ts.map +1 -0
- package/dist/src/runtime/ai-runtime-trace.js +119 -0
- package/dist/src/testcase/button-interaction-inference.d.ts +37 -0
- package/dist/src/testcase/button-interaction-inference.d.ts.map +1 -0
- package/dist/src/testcase/button-interaction-inference.js +385 -0
- package/dist/src/testcase/contract-testcase-assembler.d.ts +44 -0
- package/dist/src/testcase/contract-testcase-assembler.d.ts.map +1 -0
- package/dist/src/testcase/contract-testcase-assembler.js +806 -0
- package/dist/src/testcase/prd-button-mapper.d.ts +72 -0
- package/dist/src/testcase/prd-button-mapper.d.ts.map +1 -0
- package/dist/src/testcase/prd-button-mapper.js +148 -0
- package/dist/src/testcase/runtime-context.d.ts +9 -0
- package/dist/src/testcase/runtime-context.d.ts.map +1 -0
- package/dist/src/testcase/runtime-context.js +1 -0
- package/dist/src/testcase/test-access.d.ts +38 -0
- package/dist/src/testcase/test-access.d.ts.map +1 -0
- package/dist/src/testcase/test-access.js +106 -0
- package/dist/src/testcase/testcase-execution-fields.d.ts +10 -0
- package/dist/src/testcase/testcase-execution-fields.d.ts.map +1 -0
- package/dist/src/testcase/testcase-execution-fields.js +1 -0
- package/dist/src/testcase/testcase-generator.d.ts.map +1 -1
- package/dist/src/testcase/testcase-generator.js +6 -0
- package/dist/src/testcase/testcase-markdown.d.ts +11 -0
- package/dist/src/testcase/testcase-markdown.d.ts.map +1 -0
- package/dist/src/testcase/testcase-markdown.js +181 -0
- package/dist/src/testcase/testcase-skeleton.d.ts +4 -0
- package/dist/src/testcase/testcase-skeleton.d.ts.map +1 -1
- package/dist/src/testcase/testcase-spec-assembly.d.ts +4 -0
- package/dist/src/testcase/testcase-spec-assembly.d.ts.map +1 -1
- package/dist/src/testcase/testcase-v1-draft.d.ts +58 -0
- package/dist/src/testcase/testcase-v1-draft.d.ts.map +1 -0
- package/dist/src/testcase/testcase-v1-draft.js +13 -0
- package/dist/src/validation/contract.d.ts +14 -0
- package/dist/src/validation/contract.d.ts.map +1 -0
- package/dist/src/validation/contract.js +132 -0
- package/dist/src/validation/credentials.d.ts +7 -2
- package/dist/src/validation/credentials.d.ts.map +1 -1
- package/dist/src/validation/credentials.js +15 -4
- package/dist/src/validation/index.d.ts +2 -0
- package/dist/src/validation/index.d.ts.map +1 -1
- package/dist/src/validation/index.js +2 -0
- package/dist/src/validation/inference-trace.d.ts +13 -0
- package/dist/src/validation/inference-trace.d.ts.map +1 -0
- package/dist/src/validation/inference-trace.js +31 -0
- package/dist/src/validation/testcase.d.ts +9 -7
- package/dist/src/validation/testcase.d.ts.map +1 -1
- package/dist/src/validation/testcase.js +181 -34
- package/docs/README.md +124 -134
- package/docs/mvp-usage-guide.md +298 -298
- package/examples/schemeresource-observable-docs/schemeresource.context.md +20 -20
- package/examples/schemeresource.module-hints.json +38 -38
- package/examples/schemeresource.observable.code_list.md +37 -37
- package/examples/zwplace-observable-docs/zwplace.context.md +16 -16
- package/examples/zwplace-placecategory-validation.json +29 -29
- package/examples/zwplace.module-hints.json +69 -69
- package/examples/zwplace.observable.code_list.md +37 -37
- package/package.json +2 -2
- package/dist/test/cli/extract-contract.test.d.ts +0 -2
- package/dist/test/cli/extract-contract.test.d.ts.map +0 -1
- package/dist/test/cli/extract-contract.test.js +0 -32
- package/dist/test/cli/generate-testcase.test.d.ts +0 -2
- package/dist/test/cli/generate-testcase.test.d.ts.map +0 -1
- package/dist/test/cli/generate-testcase.test.js +0 -130
- package/dist/test/cli/index.test.d.ts +0 -2
- package/dist/test/cli/index.test.d.ts.map +0 -1
- package/dist/test/cli/index.test.js +0 -93
- package/dist/test/cli/run.test.d.ts +0 -2
- package/dist/test/cli/run.test.d.ts.map +0 -1
- package/dist/test/cli/run.test.js +0 -149
- package/dist/test/cli/spec.test.d.ts +0 -2
- package/dist/test/cli/spec.test.d.ts.map +0 -1
- package/dist/test/cli/spec.test.js +0 -196
- package/dist/test/crud-contract.test.d.ts +0 -2
- package/dist/test/crud-contract.test.d.ts.map +0 -1
- package/dist/test/crud-contract.test.js +0 -819
- package/dist/test/gap-inference.test.d.ts +0 -2
- package/dist/test/gap-inference.test.d.ts.map +0 -1
- package/dist/test/gap-inference.test.js +0 -597
- package/dist/test/generalization.test.d.ts +0 -2
- package/dist/test/generalization.test.d.ts.map +0 -1
- package/dist/test/generalization.test.js +0 -73
- package/dist/test/material-inventory.test.d.ts +0 -2
- package/dist/test/material-inventory.test.d.ts.map +0 -1
- package/dist/test/material-inventory.test.js +0 -141
- package/dist/test/observable-chain.test.d.ts +0 -2
- package/dist/test/observable-chain.test.d.ts.map +0 -1
- package/dist/test/observable-chain.test.js +0 -123
- package/dist/test/observable-pipeline.test.d.ts +0 -2
- package/dist/test/observable-pipeline.test.d.ts.map +0 -1
- package/dist/test/observable-pipeline.test.js +0 -461
- package/dist/test/page-structure.test.d.ts +0 -2
- package/dist/test/page-structure.test.d.ts.map +0 -1
- package/dist/test/page-structure.test.js +0 -45
- package/dist/test/scenario-inference.test.d.ts +0 -2
- package/dist/test/scenario-inference.test.d.ts.map +0 -1
- package/dist/test/scenario-inference.test.js +0 -73
- package/dist/test/stage-context.test.d.ts +0 -2
- package/dist/test/stage-context.test.d.ts.map +0 -1
- package/dist/test/stage-context.test.js +0 -395
- package/dist/test/testcase-generator.test.d.ts +0 -2
- package/dist/test/testcase-generator.test.d.ts.map +0 -1
- package/dist/test/testcase-generator.test.js +0 -276
- package/dist/test/testcase-skeleton.test.d.ts +0 -2
- package/dist/test/testcase-skeleton.test.d.ts.map +0 -1
- package/dist/test/testcase-skeleton.test.js +0 -185
- package/dist/test/testcase-spec-assembly.test.d.ts +0 -2
- package/dist/test/testcase-spec-assembly.test.d.ts.map +0 -1
- package/dist/test/testcase-spec-assembly.test.js +0 -105
- package/dist/test/util/credentials.test.d.ts +0 -2
- package/dist/test/util/credentials.test.d.ts.map +0 -1
- package/dist/test/util/credentials.test.js +0 -64
- package/dist/test/util/i18n-testcase.test.d.ts +0 -2
- package/dist/test/util/i18n-testcase.test.d.ts.map +0 -1
- package/dist/test/util/i18n-testcase.test.js +0 -119
- package/dist/test/util/softlink.test.d.ts +0 -2
- package/dist/test/util/softlink.test.d.ts.map +0 -1
- package/dist/test/util/softlink.test.js +0 -82
- package/dist/test/validation/credentials.test.d.ts +0 -2
- package/dist/test/validation/credentials.test.d.ts.map +0 -1
- package/dist/test/validation/credentials.test.js +0 -72
- package/dist/test/validation/projects-index.test.d.ts +0 -2
- package/dist/test/validation/projects-index.test.d.ts.map +0 -1
- package/dist/test/validation/projects-index.test.js +0 -48
- package/dist/test/validation/testcase.test.d.ts +0 -2
- package/dist/test/validation/testcase.test.d.ts.map +0 -1
- package/dist/test/validation/testcase.test.js +0 -129
- package/dist/vitest.config.d.ts +0 -3
- package/dist/vitest.config.d.ts.map +0 -1
- package/dist/vitest.config.js +0 -7
package/dist/src/cli/probe.js
CHANGED
|
@@ -10,6 +10,8 @@ import { createSkeletonCoverage } from '../gap-planner/skeleton-coverage.js';
|
|
|
10
10
|
import { planAgentInferredWorkflows } from '../gap-planner/plan-agent-workflows.js';
|
|
11
11
|
import { summarizePageStructure } from '../capability/page-structure.js';
|
|
12
12
|
import { createCoverageDiff } from '../capability/coverage-diff.js';
|
|
13
|
+
import { buildSourceAnalysis } from '../inference/source-analysis.js';
|
|
14
|
+
import { inferModuleHintsFromMaterials } from '../inference/module-hints-inference.js';
|
|
13
15
|
/**
|
|
14
16
|
* 收集指定目录下的 HTML 物料文件。
|
|
15
17
|
*
|
|
@@ -35,23 +37,130 @@ function javaFiles(dir) {
|
|
|
35
37
|
.map((fileName) => path.join(dir, fileName));
|
|
36
38
|
}
|
|
37
39
|
/**
|
|
38
|
-
*
|
|
40
|
+
* 根据页面 ID 推断 CRUD 页面角色。
|
|
41
|
+
*
|
|
42
|
+
* @param pageId - 页面标识。
|
|
43
|
+
* @returns CRUD 页面角色。
|
|
44
|
+
*/
|
|
45
|
+
function inferCrudPageRole(pageId) {
|
|
46
|
+
if (pageId.endsWith('add'))
|
|
47
|
+
return 'add';
|
|
48
|
+
if (pageId.endsWith('edit'))
|
|
49
|
+
return 'edit';
|
|
50
|
+
if (pageId.endsWith('detail'))
|
|
51
|
+
return 'detail';
|
|
52
|
+
return 'list';
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* 将 HTML 控件类型映射为 spec.yaml 兼容的组件类型。
|
|
56
|
+
*
|
|
57
|
+
* @param controlType - HTML extractor 提取到的控件类型。
|
|
58
|
+
* @returns spec 字段组件类型。
|
|
59
|
+
*/
|
|
60
|
+
function mapHtmlControlTypeToSpecComponent(controlType) {
|
|
61
|
+
if (controlType === 'mini-combobox') {
|
|
62
|
+
return 'listbox';
|
|
63
|
+
}
|
|
64
|
+
if (controlType === 'mini-textarea') {
|
|
65
|
+
return 'textarea';
|
|
66
|
+
}
|
|
67
|
+
return 'input';
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* 在缺少 spec.yaml 时,根据 HTML 页面结构合成最小可用的 spec。
|
|
71
|
+
*
|
|
72
|
+
* 设计取舍:
|
|
73
|
+
* - searchable: 仅由列表页搜索区字段决定;
|
|
74
|
+
* - formVisible: 由 add/edit 页面字段决定;
|
|
75
|
+
* - listVisible: 优先取列表页 datagrid 列定义;
|
|
76
|
+
* - businessRules: 当前无法可靠结构化抽取,保持空数组,交给 testcase 审阅阶段。
|
|
77
|
+
*
|
|
78
|
+
* @param docsDir - 需求文档目录。
|
|
79
|
+
* @param moduleId - 模块 ID。
|
|
80
|
+
* @param codeListSummary - code_list 摘要。
|
|
81
|
+
* @param pages - 已提取的 HTML 页面集合。
|
|
82
|
+
* @returns 供 contract 正常生成使用的推理 spec。
|
|
83
|
+
*/
|
|
84
|
+
function inferSpecFromPages(docsDir, moduleId, codeListSummary, pages) {
|
|
85
|
+
const fieldMap = new Map();
|
|
86
|
+
const listPage = pages.find((page) => inferCrudPageRole(page.pageId) === 'list');
|
|
87
|
+
/**
|
|
88
|
+
* 合并同名字段的页面证据,避免列表页 / 新增页重复字段互相覆盖。
|
|
89
|
+
*
|
|
90
|
+
* @param field - 当前页面字段。
|
|
91
|
+
* @param role - 当前页面角色。
|
|
92
|
+
* @returns 无返回值。
|
|
93
|
+
*/
|
|
94
|
+
function mergeField(field, role) {
|
|
95
|
+
const existing = fieldMap.get(field.name) ?? {
|
|
96
|
+
name: field.name,
|
|
97
|
+
label: field.label,
|
|
98
|
+
component: mapHtmlControlTypeToSpecComponent(field.controlType),
|
|
99
|
+
required: field.required,
|
|
100
|
+
searchable: false,
|
|
101
|
+
listVisible: false,
|
|
102
|
+
formVisible: false,
|
|
103
|
+
length: field.maxLength,
|
|
104
|
+
};
|
|
105
|
+
existing.label ||= field.label;
|
|
106
|
+
existing.component ||= mapHtmlControlTypeToSpecComponent(field.controlType);
|
|
107
|
+
existing.required ||= field.required;
|
|
108
|
+
existing.length ??= field.maxLength;
|
|
109
|
+
if (role === 'list') {
|
|
110
|
+
existing.searchable = true;
|
|
111
|
+
}
|
|
112
|
+
if (role === 'add' || role === 'edit') {
|
|
113
|
+
existing.formVisible = true;
|
|
114
|
+
}
|
|
115
|
+
fieldMap.set(field.name, existing);
|
|
116
|
+
}
|
|
117
|
+
for (const page of pages) {
|
|
118
|
+
const role = inferCrudPageRole(page.pageId);
|
|
119
|
+
for (const field of page.fields) {
|
|
120
|
+
mergeField(field, role);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
for (const column of listPage?.grids.flatMap((grid) => grid.dataColumns) ?? []) {
|
|
124
|
+
if (!column.field) {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
const existing = fieldMap.get(column.field) ?? {
|
|
128
|
+
name: column.field,
|
|
129
|
+
label: column.headerText || column.field,
|
|
130
|
+
component: 'input',
|
|
131
|
+
required: false,
|
|
132
|
+
searchable: false,
|
|
133
|
+
listVisible: false,
|
|
134
|
+
formVisible: false,
|
|
135
|
+
};
|
|
136
|
+
existing.label ||= column.headerText || column.field;
|
|
137
|
+
existing.listVisible = true;
|
|
138
|
+
fieldMap.set(column.field, existing);
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
path: path.join(docsDir, 'spec.inferred-from-html.yaml'),
|
|
142
|
+
module: {
|
|
143
|
+
id: moduleId,
|
|
144
|
+
label: codeListSummary.moduleLabel || moduleId,
|
|
145
|
+
},
|
|
146
|
+
fields: Array.from(fieldMap.values()),
|
|
147
|
+
businessRules: [],
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* 解析 docs 目录下的 spec.yaml;缺失时根据 HTML 页面结构合成 fallback spec。
|
|
39
152
|
*
|
|
40
153
|
* @param docsDir - 需求文档目录。
|
|
41
154
|
* @param moduleId - 模块 ID。
|
|
42
155
|
* @param codeListSummary - 已解析的 code_list 摘要。
|
|
156
|
+
* @param pages - 已提取的 HTML 页面集合。
|
|
43
157
|
* @returns ExtractedSpecYaml。
|
|
44
158
|
*/
|
|
45
|
-
function resolveSpec(docsDir, moduleId, codeListSummary) {
|
|
159
|
+
function resolveSpec(docsDir, moduleId, codeListSummary, pages) {
|
|
46
160
|
const specPath = path.join(docsDir, 'spec.yaml');
|
|
47
161
|
if (existsSync(specPath))
|
|
48
162
|
return extractSpecYaml(specPath);
|
|
49
|
-
return
|
|
50
|
-
path: specPath,
|
|
51
|
-
module: { id: moduleId, label: codeListSummary.moduleLabel },
|
|
52
|
-
fields: [],
|
|
53
|
-
businessRules: [],
|
|
54
|
-
};
|
|
163
|
+
return inferSpecFromPages(docsDir, moduleId, codeListSummary, pages);
|
|
55
164
|
}
|
|
56
165
|
/**
|
|
57
166
|
* 推断 requiredRole 默认值。
|
|
@@ -173,6 +282,75 @@ function assembleTestcaseV2(input) {
|
|
|
173
282
|
},
|
|
174
283
|
};
|
|
175
284
|
}
|
|
285
|
+
/**
|
|
286
|
+
* 组装 materialInventory 章节(spec §7)。
|
|
287
|
+
*
|
|
288
|
+
* 把 probe 已解析到的 codeList / pages / actions / args 登记成可审阅的物料清单,
|
|
289
|
+
* 缺失项进 `missing` 数组。保持私有,不做跨文件抽象(Task 3 范围)。
|
|
290
|
+
*
|
|
291
|
+
* @param args - probe 入参。
|
|
292
|
+
* @param codeList - 已解析的 code_list 摘要。
|
|
293
|
+
* @param pages - 已抽取的 HTML 页面。
|
|
294
|
+
* @param actions - 已抽取的 Java Action。
|
|
295
|
+
* @returns MaterialInventoryTrace。
|
|
296
|
+
*/
|
|
297
|
+
function buildMaterialInventory(args, codeList, pages, actions) {
|
|
298
|
+
const missing = [];
|
|
299
|
+
const moduleIdSlot = { status: 'resolved', value: args.moduleId };
|
|
300
|
+
const menuSlot = codeList.menu
|
|
301
|
+
? { status: 'resolved', value: codeList.menu }
|
|
302
|
+
: (() => {
|
|
303
|
+
missing.push('menu');
|
|
304
|
+
return { status: 'missing', reason: 'code_list.md 未提供 menu' };
|
|
305
|
+
})();
|
|
306
|
+
const htmlFiles = pages.map((page) => ({
|
|
307
|
+
status: 'resolved',
|
|
308
|
+
value: page.path,
|
|
309
|
+
}));
|
|
310
|
+
const javaActionFiles = actions.map((action) => ({
|
|
311
|
+
status: 'resolved',
|
|
312
|
+
value: action.path,
|
|
313
|
+
}));
|
|
314
|
+
const docsFiles = [];
|
|
315
|
+
if (args.docsDir && existsSync(args.docsDir)) {
|
|
316
|
+
docsFiles.push({ status: 'resolved', value: args.docsDir });
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
missing.push('docsDir');
|
|
320
|
+
docsFiles.push({ status: 'missing', reason: '未提供 docsDir' });
|
|
321
|
+
}
|
|
322
|
+
return {
|
|
323
|
+
knowledgeRoot: codeList.knowledgeRoot ?? '',
|
|
324
|
+
moduleId: moduleIdSlot,
|
|
325
|
+
menu: menuSlot,
|
|
326
|
+
htmlFiles,
|
|
327
|
+
javaActionFiles,
|
|
328
|
+
docsFiles,
|
|
329
|
+
missing,
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* 把 coverageDiff(CoverageDiffTrace)映射为 InferenceTraceV1.coverageDiff 的内联形状。
|
|
334
|
+
*
|
|
335
|
+
* 映射规则(controller 裁定):
|
|
336
|
+
* - coveredActions ← coverageDiff.covered
|
|
337
|
+
* - uncoveredCandidates ← [...gapCandidates, ...partiallyCovered, ...unresolved]
|
|
338
|
+
* - needsReview ← unresolved.map(i => i.actionId)
|
|
339
|
+
*
|
|
340
|
+
* @param coverageDiff - probe 产出的 CoverageDiffTrace。
|
|
341
|
+
* @returns InferenceTraceV1.coverageDiff。
|
|
342
|
+
*/
|
|
343
|
+
function mapCoverageDiffForTrace(coverageDiff) {
|
|
344
|
+
return {
|
|
345
|
+
coveredActions: coverageDiff.covered,
|
|
346
|
+
uncoveredCandidates: [
|
|
347
|
+
...coverageDiff.gapCandidates,
|
|
348
|
+
...coverageDiff.partiallyCovered,
|
|
349
|
+
...coverageDiff.unresolved,
|
|
350
|
+
],
|
|
351
|
+
needsReview: coverageDiff.unresolved.map((item) => item.actionId),
|
|
352
|
+
};
|
|
353
|
+
}
|
|
176
354
|
/**
|
|
177
355
|
* probe + coverage + testcase v2 装配的统一入口(REQ-CHAIN-01)。
|
|
178
356
|
*
|
|
@@ -185,16 +363,43 @@ function assembleTestcaseV2(input) {
|
|
|
185
363
|
* @returns contract + coverageDiff + 装配好的 TestcaseV2。
|
|
186
364
|
*/
|
|
187
365
|
export function runProbeAndCoverage(args) {
|
|
188
|
-
const hints = args.hintsPath
|
|
189
|
-
? JSON.parse(readFileSync(args.hintsPath, 'utf8'))
|
|
190
|
-
: undefined;
|
|
191
366
|
const codeList = extractCodeListSummary(args.codeListPath);
|
|
192
367
|
const pages = htmlFiles(args.webappDir).map(extractHtmlPage);
|
|
193
368
|
const actions = javaFiles(args.javaActionsDir).map(extractJavaAction);
|
|
369
|
+
// 源分析快照(spec §7 sourceAnalysis)。
|
|
370
|
+
const sourceAnalysis = buildSourceAnalysis({
|
|
371
|
+
codeListPath: args.codeListPath,
|
|
372
|
+
docsDir: args.docsDir,
|
|
373
|
+
codeList,
|
|
374
|
+
pages,
|
|
375
|
+
actions,
|
|
376
|
+
});
|
|
377
|
+
// 显式 hints 文件 vs 推理 hints:
|
|
378
|
+
// - 有 hintsPath 时读取为 explicitHints,mode 标记 explicit_override,explicitHints 流入 builders。
|
|
379
|
+
// - 无 hintsPath 时调 inferModuleHintsFromMaterials,推理出的 hints 流入 builders(替换原 undefined)。
|
|
380
|
+
let hints;
|
|
381
|
+
let moduleHintsInference;
|
|
382
|
+
if (args.hintsPath) {
|
|
383
|
+
const explicitHints = JSON.parse(readFileSync(args.hintsPath, 'utf8'));
|
|
384
|
+
// 仍跑一次推理以记录推理过程,但 mode 标记 explicit_override,builders 用 explicitHints。
|
|
385
|
+
const inferred = inferModuleHintsFromMaterials({
|
|
386
|
+
sourceAnalysis,
|
|
387
|
+
pages,
|
|
388
|
+
actions,
|
|
389
|
+
explicitHints,
|
|
390
|
+
});
|
|
391
|
+
moduleHintsInference = { ...inferred.inference, mode: 'explicit_override' };
|
|
392
|
+
hints = explicitHints;
|
|
393
|
+
}
|
|
394
|
+
else {
|
|
395
|
+
const inferred = inferModuleHintsFromMaterials({ sourceAnalysis, pages, actions });
|
|
396
|
+
moduleHintsInference = inferred.inference;
|
|
397
|
+
hints = inferred.hints;
|
|
398
|
+
}
|
|
194
399
|
const pageStructures = pages.map(summarizePageStructure);
|
|
195
400
|
const contract = buildCrudBusinessModuleContract({
|
|
196
401
|
moduleId: args.moduleId,
|
|
197
|
-
spec: resolveSpec(args.docsDir, args.moduleId, codeList),
|
|
402
|
+
spec: resolveSpec(args.docsDir, args.moduleId, codeList, pages),
|
|
198
403
|
codeList,
|
|
199
404
|
pages,
|
|
200
405
|
actions,
|
|
@@ -217,5 +422,26 @@ export function runProbeAndCoverage(args) {
|
|
|
217
422
|
menuPath: args.menuPath ?? codeList.menu ?? '',
|
|
218
423
|
codeListPath: args.codeListPath,
|
|
219
424
|
});
|
|
220
|
-
|
|
425
|
+
// 组装 inference trace(REQ-INFER-004 / REQ-INFER-006)。
|
|
426
|
+
const materialInventory = buildMaterialInventory(args, codeList, pages, actions);
|
|
427
|
+
const reasoningSummary = {
|
|
428
|
+
conclusion: `基于 ${sourceAnalysis.mode} 源分析(置信度 ${sourceAnalysis.confidence})与 ${moduleHintsInference.mode} 槽位推理生成契约;coverageDiff unresolved ${coverageDiff.unresolved.length} 项。`,
|
|
429
|
+
confidence: sourceAnalysis.confidence,
|
|
430
|
+
risks: [
|
|
431
|
+
...sourceAnalysis.unresolved,
|
|
432
|
+
...moduleHintsInference.unresolved.map((slot) => `未解析槽位:${slot}`),
|
|
433
|
+
],
|
|
434
|
+
needsHumanReview: moduleHintsInference.unresolved.length > 0 || sourceAnalysis.confidence === 'low',
|
|
435
|
+
};
|
|
436
|
+
const inferenceTrace = {
|
|
437
|
+
schemaVersion: 'inference-trace/v1',
|
|
438
|
+
codeListPath: args.codeListPath,
|
|
439
|
+
generatedAt: new Date().toISOString(),
|
|
440
|
+
materialInventory,
|
|
441
|
+
sourceAnalysis,
|
|
442
|
+
moduleHintsInference,
|
|
443
|
+
coverageDiff: mapCoverageDiffForTrace(coverageDiff),
|
|
444
|
+
reasoningSummary,
|
|
445
|
+
};
|
|
446
|
+
return { contract, coverageDiff, testcaseV2, inferenceTrace };
|
|
221
447
|
}
|
package/dist/src/cli/run.d.ts
CHANGED
|
@@ -1,63 +1,170 @@
|
|
|
1
|
+
import type { EpStageTestcaseV1Draft } from '../testcase/testcase-v1-draft.js';
|
|
2
|
+
import { type AiRuntimeResult, type AiRuntimeTask } from '../runtime/ai-runtime-trace.js';
|
|
1
3
|
/**
|
|
2
|
-
* run 子命令参数(REQ-CHAIN-02 / REQ-SPEC-01)。
|
|
4
|
+
* run 子命令参数(REQ-CHAIN-02 / REQ-SPEC-01,新协议 v1-draft)。
|
|
3
5
|
*
|
|
4
|
-
* -
|
|
5
|
-
* - testcase:testcase.json5 路径(必填,提供 uncoveredCandidates 与 cases[].requiredRole);
|
|
6
|
+
* - testcase:testcase.json5 路径(必填,提供 uncoveredCandidates 与 generationStrategy 分桶);
|
|
6
7
|
* - headless:是否启动无头浏览器,真实业务系统通常 false;
|
|
7
|
-
* -
|
|
8
|
+
* - aiSnippets:Agent O-D-A-V 产出的 ai-snippets.json5 路径。
|
|
8
9
|
*/
|
|
9
10
|
export type RunArgs = {
|
|
10
|
-
spec: string;
|
|
11
11
|
testcase: string;
|
|
12
12
|
headless: boolean;
|
|
13
|
-
|
|
13
|
+
aiSnippets?: string;
|
|
14
14
|
};
|
|
15
15
|
/**
|
|
16
|
-
* run
|
|
16
|
+
* run 子命令产物(新协议 v1-draft)。
|
|
17
17
|
*
|
|
18
18
|
* @property specPath - 写盘后的 .spec.ts(含 AI 追加段)。
|
|
19
19
|
* @property reportDir - 本次 run 产出的报告目录。
|
|
20
|
-
* @property
|
|
21
|
-
*
|
|
20
|
+
* @property credentialsNotice - credentials.json5 消费边界声明(缺失时提示用户填充)。
|
|
21
|
+
* @property version - 'v1':已接入 Agent snippets 合并、spec 执行和 repair 回路。
|
|
22
|
+
* @property aiRuntimeTracePath - 落盘的 .ep-stage/ai-runtime-trace.json5(含 tasks 与 results)。
|
|
23
|
+
* @property repairReportPath - 执行失败时落盘的 repair-report.md;成功时为 undefined。
|
|
22
24
|
*/
|
|
23
25
|
export type RunResult = {
|
|
24
26
|
specPath: string;
|
|
25
27
|
reportDir: string;
|
|
26
|
-
|
|
28
|
+
credentialsNotice?: string;
|
|
29
|
+
version: 'v1';
|
|
30
|
+
aiRuntimeTracePath?: string;
|
|
31
|
+
repairReportPath?: string;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* runRun 的可注入依赖(测试即契约:允许单测替换推理与执行,避免触发真机)。
|
|
35
|
+
*
|
|
36
|
+
* 默认实现读取 Agent 产出的 ai-snippets.json5 并执行真实 Playwright;
|
|
37
|
+
* 测试通过该 seam 注入确定性桩。
|
|
38
|
+
*
|
|
39
|
+
* @property loadAiSnippets - 读取 Agent 产出的 resolved snippet。
|
|
40
|
+
* @property executeFullSpec - 从 projectDir 执行完整 spec,返回通过状态与输出。
|
|
41
|
+
*/
|
|
42
|
+
export type RunDeps = {
|
|
43
|
+
loadAiSnippets?: (input: {
|
|
44
|
+
snippetsPath: string;
|
|
45
|
+
testcasePath: string;
|
|
46
|
+
tasks: AiRuntimeTask[];
|
|
47
|
+
}) => AiRuntimeResult[];
|
|
48
|
+
executeFullSpec?: (input: {
|
|
49
|
+
projectDir: string;
|
|
50
|
+
specPath: string;
|
|
51
|
+
headless: boolean;
|
|
52
|
+
}) => Promise<{
|
|
53
|
+
passed: boolean;
|
|
54
|
+
output: string;
|
|
55
|
+
}>;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* 从 testcase.json5 推导 run 阶段路径。
|
|
59
|
+
*/
|
|
60
|
+
export type RunPaths = {
|
|
61
|
+
testcasePath: string;
|
|
62
|
+
caseDir: string;
|
|
63
|
+
projectDir: string;
|
|
64
|
+
specPath: string;
|
|
65
|
+
contractPath: string;
|
|
66
|
+
};
|
|
67
|
+
export type PrepareAiRuntimeTasksResult = {
|
|
68
|
+
testcasePath: string;
|
|
69
|
+
tracePath: string;
|
|
70
|
+
specPath: string;
|
|
71
|
+
taskCount: number;
|
|
72
|
+
blockedCount: number;
|
|
73
|
+
};
|
|
74
|
+
export type AiSnippetsFile = {
|
|
75
|
+
schemaVersion: 'ep-stage-ai-snippets/v1';
|
|
76
|
+
testcasePath: string;
|
|
77
|
+
generatedAt?: string;
|
|
78
|
+
results: AiRuntimeResult[];
|
|
27
79
|
};
|
|
28
80
|
/**
|
|
29
81
|
* AI 追加段分隔标记。重跑时 detect 已有标记则覆盖(保证幂等)。
|
|
82
|
+
*
|
|
83
|
+
* 注释语义:本段由 uncoveredCandidates[].generationStrategy='ai' 的候选渲染而来。
|
|
30
84
|
*/
|
|
31
|
-
export declare const AI_APPEND_MARKER = "// === AI \u94BB\u63A2\u8FFD\u52A0\uFF08\u57FA\u4E8E uncoveredCandidates[].
|
|
85
|
+
export declare const AI_APPEND_MARKER = "// === AI \u94BB\u63A2\u8FFD\u52A0\uFF08\u57FA\u4E8E uncoveredCandidates[].generationStrategy=ai\uFF09===";
|
|
32
86
|
/**
|
|
33
87
|
* 解析 run 子命令参数。
|
|
34
88
|
*
|
|
35
89
|
* @param argv - 已剥离子命令名的命令行参数。
|
|
36
90
|
* @returns RunArgs。
|
|
37
|
-
* @throws 缺少 --
|
|
91
|
+
* @throws 缺少 --testcase 或参数对非法时抛错。
|
|
38
92
|
*/
|
|
39
93
|
export declare function parseRunArgs(argv: string[]): RunArgs;
|
|
40
94
|
/**
|
|
41
|
-
*
|
|
95
|
+
* 从 testcase.json5 定位测试项目和 spec 路径。
|
|
96
|
+
*
|
|
97
|
+
* 优先消费 runtimeContext;若缺失或目录校验失败,则从 testcase 所在目录向上查找。
|
|
98
|
+
*
|
|
99
|
+
* @param testcasePath - testcase.json5 路径。
|
|
100
|
+
* @returns run 阶段消费的路径集合。
|
|
101
|
+
*/
|
|
102
|
+
export declare function resolveRunPaths(testcasePath: string): RunPaths;
|
|
103
|
+
/**
|
|
104
|
+
* 构造从项目目录执行完整 spec 的 Playwright 命令。
|
|
105
|
+
*
|
|
106
|
+
* headless=false 时追加 --headed;specPath 原样透传(绝对路径,跨目录稳定)。
|
|
107
|
+
*
|
|
108
|
+
* @param input - projectDir / specPath / headless。
|
|
109
|
+
* @returns 命令、参数与 cwd,供 execFileSync 直接消费。
|
|
110
|
+
*/
|
|
111
|
+
export declare function buildPlaywrightCommand(input: {
|
|
112
|
+
projectDir: string;
|
|
113
|
+
specPath: string;
|
|
114
|
+
headless: boolean;
|
|
115
|
+
}): {
|
|
116
|
+
command: 'npx';
|
|
117
|
+
args: string[];
|
|
118
|
+
cwd: string;
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* 读取并校验 Agent O-D-A-V 产出的 snippets。
|
|
122
|
+
*
|
|
123
|
+
* 只有 testcasePath 匹配、caseId 属于当前任务、status=resolved 且 specSnippet 非空时才可合并。
|
|
124
|
+
*
|
|
125
|
+
* @param input - snippets 路径、testcase 路径和当前 AI tasks。
|
|
126
|
+
* @returns 可合并的 AiRuntimeResult 列表。
|
|
127
|
+
*/
|
|
128
|
+
export declare function loadAiSnippets(input: {
|
|
129
|
+
snippetsPath: string;
|
|
130
|
+
testcasePath: string;
|
|
131
|
+
tasks: AiRuntimeTask[];
|
|
132
|
+
}): AiRuntimeResult[];
|
|
133
|
+
/**
|
|
134
|
+
* 从 testcase 构建 AI Runtime Task 列表。
|
|
135
|
+
*
|
|
136
|
+
* `coverageStatus='blocked'` 的候选仅保留在 testcase/审阅侧,不进入 runtime task。
|
|
137
|
+
*
|
|
138
|
+
* @param testcase - 已校验 testcase。
|
|
139
|
+
* @param paths - run 阶段解析出的路径。
|
|
140
|
+
* @returns AI Runtime Task 列表。
|
|
141
|
+
*/
|
|
142
|
+
export declare function buildAiRuntimeTasks(testcase: EpStageTestcaseV1Draft, paths: RunPaths): AiRuntimeTask[];
|
|
143
|
+
/**
|
|
144
|
+
* 生成 AI Runtime 初始任务包。
|
|
145
|
+
*
|
|
146
|
+
* 该函数只做确定性工作:定位路径、补齐 glue 骨架 spec、构建 tasks 并写 trace。
|
|
147
|
+
*
|
|
148
|
+
* @param testcasePath - testcase.json5 路径。
|
|
149
|
+
* @returns trace 路径、spec 路径和任务摘要。
|
|
150
|
+
*/
|
|
151
|
+
export declare function prepareAiRuntimeTasks(testcasePath: string): PrepareAiRuntimeTasksResult;
|
|
152
|
+
/**
|
|
153
|
+
* run 子命令主体(REQ-CHAIN-02 / REQ-SPEC-01,新协议 v1-draft)。
|
|
42
154
|
*
|
|
43
|
-
*
|
|
44
|
-
* 1.
|
|
45
|
-
* 2.
|
|
46
|
-
* 3.
|
|
47
|
-
* 4.
|
|
48
|
-
* 5.
|
|
49
|
-
* 6.
|
|
155
|
+
* 行为:
|
|
156
|
+
* 1. resolveRunPaths 定位 projectDir/specPath;spec 缺失时先跑 runSpec 组装 glue 骨架。
|
|
157
|
+
* 2. 解析 testcase,构建 aiRuntimeTasks(已过滤 coverageStatus='blocked')。
|
|
158
|
+
* 3. 读取 Agent O-D-A-V 产出的 ai-snippets.json5。
|
|
159
|
+
* 4. 若 AI tasks 未全部 resolved,则写 trace results=needs_review 并停止,避免假通过。
|
|
160
|
+
* 5. 幂等合并 specSnippet 到 spec:truncateAtMarker 后追加 marker + snippets。
|
|
161
|
+
* 6. 执行完整 spec(deps 注入或默认真实 Playwright);失败则分类、回写 trace repairRounds 并写 repair report。
|
|
50
162
|
*
|
|
51
|
-
*
|
|
52
|
-
* - 完整实现「步骤 4」(AI 追加段幂等覆盖契约);
|
|
53
|
-
* - 完整实现「步骤 5」(报告目录生成);
|
|
54
|
-
* - 步骤 1 / 2 / 3 / 6 的 Playwright runtime + AI 推理 + 索引回写在 Phase 5 真机验收阶段
|
|
55
|
-
* 迁移 run-gap-pipeline.ts 的 runtime runner 实现接入(brief 已说明 AI 推理在 Phase 5 证)。
|
|
163
|
+
* 失败时不静默改变测试意图:写 repair-report.md 等待人审确认。
|
|
56
164
|
*
|
|
57
165
|
* @param args - 已解析参数。
|
|
58
|
-
* @
|
|
59
|
-
*
|
|
60
|
-
* 而非 'v2' 是为了让下游 skill(glue-run-test 等)能区分"真 v2"与"stub 形态"。
|
|
166
|
+
* @param deps - 可选注入依赖(测试用于替换推理与执行)。
|
|
167
|
+
* @returns RunResult。
|
|
61
168
|
*/
|
|
62
|
-
export declare function runRun(args: RunArgs): Promise<RunResult>;
|
|
169
|
+
export declare function runRun(args: RunArgs, deps?: RunDeps): Promise<RunResult>;
|
|
63
170
|
//# sourceMappingURL=run.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/cli/run.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/cli/run.ts"],"names":[],"mappings":"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"}
|