@epoint-testtech/ep-stage-skill 0.0.4-alpha.1 → 0.0.6
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 -206
- package/codex-skill/ep-stage/glue-generate-testcase/SKILL.md +275 -274
- 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 -72
- package/codex-skill/ep-stage/glue-run-test/SKILL.md +295 -289
- 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 +17 -51
- package/dist/src/cli/generate-testcase.d.ts.map +1 -1
- package/dist/src/cli/generate-testcase.js +74 -181
- package/dist/src/cli/index.d.ts +3 -2
- package/dist/src/cli/index.d.ts.map +1 -1
- package/dist/src/cli/index.js +51 -17
- 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 +507 -65
- package/dist/src/cli/spec.d.ts +17 -13
- package/dist/src/cli/spec.d.ts.map +1 -1
- package/dist/src/cli/spec.js +59 -33
- 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/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/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 +647 -238
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -1
- 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 +1 -0
- package/dist/src/validation/index.d.ts.map +1 -1
- package/dist/src/validation/index.js +1 -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/codex-skill/ep-stage/.omc/state/sessions/d636ad35-5fc9-4d5e-85b0-2bcad7d86ee5/pre-tool-advisory-throttle.json +0 -10
- 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-inference.test.d.ts +0 -2
- package/dist/test/cli/generate-testcase-inference.test.d.ts.map +0 -1
- package/dist/test/cli/generate-testcase-inference.test.js +0 -63
- package/dist/test/cli/generate-testcase-paths.test.d.ts +0 -2
- package/dist/test/cli/generate-testcase-paths.test.d.ts.map +0 -1
- package/dist/test/cli/generate-testcase-paths.test.js +0 -165
- package/dist/test/cli/generate-testcase-requirements.test.d.ts +0 -2
- package/dist/test/cli/generate-testcase-requirements.test.d.ts.map +0 -1
- package/dist/test/cli/generate-testcase-requirements.test.js +0 -229
- 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 -113
- package/dist/test/cli/probe.test.d.ts +0 -2
- package/dist/test/cli/probe.test.d.ts.map +0 -1
- package/dist/test/cli/probe.test.js +0 -31
- 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-boundary.test.d.ts +0 -2
- package/dist/test/cli/spec-boundary.test.d.ts.map +0 -1
- package/dist/test/cli/spec-boundary.test.js +0 -198
- 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/code-list.test.d.ts +0 -2
- package/dist/test/code-list.test.d.ts.map +0 -1
- package/dist/test/code-list.test.js +0 -39
- 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 -799
- 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/inference/module-hints-inference.test.d.ts +0 -2
- package/dist/test/inference/module-hints-inference.test.d.ts.map +0 -1
- package/dist/test/inference/module-hints-inference.test.js +0 -25
- package/dist/test/inference/source-analysis.test.d.ts +0 -2
- package/dist/test/inference/source-analysis.test.d.ts.map +0 -1
- package/dist/test/inference/source-analysis.test.js +0 -23
- 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 -154
- 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 -470
- 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
|
@@ -2,12 +2,12 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
|
2
2
|
import os from 'node:os';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import JSON5 from 'json5';
|
|
5
|
-
import { runProbeAndCoverage } from './probe.js';
|
|
6
5
|
import { createSoftlinkWithFallback } from '../util/softlink.js';
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
6
|
+
import { extractCodeListJson5, assertCodeListJson5Path } from '../extractors/code-list-json5.js';
|
|
7
|
+
import { assembleJson5ContractAndTestcase } from '../testcase/contract-testcase-assembler.js';
|
|
8
|
+
import { renderUnifiedTestcaseMarkdown } from '../testcase/testcase-markdown.js';
|
|
9
|
+
import { validateContract } from '../validation/contract.js';
|
|
10
|
+
import { validateTestcase } from '../validation/testcase.js';
|
|
11
11
|
import { writeProjectIndex } from '../context/stage-context.js';
|
|
12
12
|
/**
|
|
13
13
|
* 解析 testcase 子命令参数。
|
|
@@ -34,151 +34,50 @@ export function parseGenerateTestcaseArgs(argv) {
|
|
|
34
34
|
return {
|
|
35
35
|
codeList: result['code-list'],
|
|
36
36
|
testsDir: result['tests-dir'],
|
|
37
|
-
scenario: result.scenario,
|
|
38
|
-
hints: result.hints,
|
|
39
37
|
projectDir: result['project-dir'],
|
|
40
38
|
requirementDir: result['requirement-dir'],
|
|
39
|
+
directUrl: result['direct-url'],
|
|
40
|
+
sourceRoot: result['source-root'],
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
43
|
/**
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* 2. ModuleHints 文件路径包含 `scenario=<value>` 字串(粗推断)
|
|
47
|
-
* 3. 默认 "crud.single-page"(与 i18n 表 / skeleton scenario 一致)
|
|
44
|
+
* 渲染 credentials.template.json5 数组内容。
|
|
45
|
+
* 每条对应一个 role,url/systemName 复用 code_list.systems[0](多系统场景由用户补齐)。
|
|
48
46
|
*
|
|
49
|
-
* @param
|
|
50
|
-
* @returns 决策结果。
|
|
51
|
-
*/
|
|
52
|
-
export function decideScenario(args) {
|
|
53
|
-
if (args.scenario)
|
|
54
|
-
return args.scenario;
|
|
55
|
-
if (args.hints && args.hints.includes('scenario=')) {
|
|
56
|
-
const inferred = args.hints.split('scenario=')[1]?.split(/\s|,/)[0];
|
|
57
|
-
if (inferred)
|
|
58
|
-
return inferred;
|
|
59
|
-
}
|
|
60
|
-
return 'crud.single-page';
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* 把 TestcaseV2 渲染成中文 testcase.md(REQ-UX-03)。
|
|
64
|
-
*
|
|
65
|
-
* 设计:
|
|
66
|
-
* - 字段名 / 状态值通过 i18nTestcase() 翻译;
|
|
67
|
-
* - `unresolved` 字段标题硬编码「未确认项」(i18n 表中 `unresolved` 解析为状态值「未解决」);
|
|
68
|
-
* - 每次重跑覆盖(REQ-DATA-03 由调用方 writeFileSync 触发)。
|
|
69
|
-
*
|
|
70
|
-
* @param testcase - TestcaseV2 顶层结构。
|
|
71
|
-
* @returns Markdown 文本。
|
|
72
|
-
*/
|
|
73
|
-
export function renderTestcaseMarkdown(testcase) {
|
|
74
|
-
const lines = [];
|
|
75
|
-
lines.push(`# ${testcase.moduleName} 胶水测试用例`);
|
|
76
|
-
lines.push('');
|
|
77
|
-
lines.push(`- 模块 ID:${testcase.moduleId}`);
|
|
78
|
-
lines.push(`- ${i18nTestcase('scenario')}:${i18nTestcase(testcase.scenario)}`);
|
|
79
|
-
lines.push(`- ${i18nTestcase('menuPath')}:${testcase.menuPath || '(未填写)'}`);
|
|
80
|
-
lines.push(`- ${i18nTestcase('requiredSystems')}:${testcase.requiredSystems.map((s) => s.url || '(待填写)').join(',')}`);
|
|
81
|
-
lines.push(`- ${i18nTestcase('requiredRoles')}:${testcase.requiredRoles.map((r) => r.role).join(',')}`);
|
|
82
|
-
lines.push('');
|
|
83
|
-
lines.push(`## ${i18nTestcase('coveredActions')}`);
|
|
84
|
-
if (testcase.coveredActions.length === 0)
|
|
85
|
-
lines.push('(无)');
|
|
86
|
-
for (const action of testcase.coveredActions) {
|
|
87
|
-
lines.push(`- ${action.actionId}(${action.kind})证据:${action.evidence.join(' / ')}`);
|
|
88
|
-
}
|
|
89
|
-
lines.push('');
|
|
90
|
-
lines.push(`## ${i18nTestcase('uncoveredCandidates')}`);
|
|
91
|
-
if (testcase.uncoveredCandidates.length === 0)
|
|
92
|
-
lines.push('(无)');
|
|
93
|
-
for (const cand of testcase.uncoveredCandidates) {
|
|
94
|
-
lines.push(`- ${cand.actionId} ${cand.label}|状态:${i18nTestcase(cand.status)}|${i18nTestcase('requiredRole')}:${cand.requiredRole}`);
|
|
95
|
-
lines.push(` - ${i18nTestcase('businessIntent')}:${cand.businessIntent}`);
|
|
96
|
-
lines.push(` - ${i18nTestcase('assertionExpectation')}:${cand.assertionExpectation}`);
|
|
97
|
-
lines.push(` - ${i18nTestcase('evidence')}:${cand.evidence.join(' / ')}`);
|
|
98
|
-
}
|
|
99
|
-
lines.push('');
|
|
100
|
-
lines.push('## 用例');
|
|
101
|
-
for (const c of testcase.cases) {
|
|
102
|
-
lines.push(`### ${c.title}(${i18nTestcase('caseId')}:${c.caseId})`);
|
|
103
|
-
lines.push(`- ${i18nTestcase('scenario')}:${i18nTestcase(c.scenario)}|${i18nTestcase('reviewStatus')}:${i18nTestcase(c.reviewStatus)}|${i18nTestcase('requiredRole')}:${c.requiredRole}`);
|
|
104
|
-
lines.push(`- ${i18nTestcase('evidence')}:${c.evidence.join(' / ')}`);
|
|
105
|
-
lines.push('- 步骤:');
|
|
106
|
-
for (const s of c.steps)
|
|
107
|
-
lines.push(` 1. ${s}`);
|
|
108
|
-
lines.push('- 断言:');
|
|
109
|
-
for (const a of c.assertions)
|
|
110
|
-
lines.push(` - ${a}`);
|
|
111
|
-
// 硬编码标题「未确认项」:i18nTestcase('unresolved') 返回状态值「未解决」(spec §4.6 trade-off)。
|
|
112
|
-
lines.push(`- 未确认项:${c.unresolved.length === 0 ? '(无)' : c.unresolved.join(';')}`);
|
|
113
|
-
lines.push('');
|
|
114
|
-
}
|
|
115
|
-
lines.push('## 推理摘要');
|
|
116
|
-
lines.push(testcase.reasoningSummary.conclusion);
|
|
117
|
-
lines.push('');
|
|
118
|
-
lines.push('证据链:');
|
|
119
|
-
for (const ev of testcase.reasoningSummary.evidenceChain)
|
|
120
|
-
lines.push(`- ${ev}`);
|
|
121
|
-
return `${lines.join('\n').trimEnd()}\n`;
|
|
122
|
-
}
|
|
123
|
-
/**
|
|
124
|
-
* 渲染 credentials.template.json5 数组内容。每条对应 requiredRoles[i],
|
|
125
|
-
* url/systemName 复用 requiredSystems[0](多系统场景由用户手工补齐)。
|
|
126
|
-
*
|
|
127
|
-
* @param testcase - TestcaseV2。
|
|
47
|
+
* @param codeList - code_list 解析产出。
|
|
128
48
|
* @returns JSON5 字符串。
|
|
129
49
|
*/
|
|
130
|
-
function renderCredentialsTemplate(
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
50
|
+
function renderCredentialsTemplate(codeList, directUrl) {
|
|
51
|
+
const baseSystem = codeList.systems[0]?.name ?? '';
|
|
52
|
+
// 字段命名对齐 stage-core Credential type:`url` = 登录页 URL(stage-core 消费入口,
|
|
53
|
+
// 用于 process.env.LOGIN_SYSTEM_URL);`directUrl` = 待测页面直达链接(应用侧读,
|
|
54
|
+
// 由 spec openModule 用 loginPage.gotoDirectUrl 消费)。旧 template 用 loginUrl 会
|
|
55
|
+
// 导致 stage-core loadCredentials 解析到的 credential.url=undefined、下游 goto("undefined") 失败。
|
|
56
|
+
const loginUrl = codeList.systems[0]?.defaultLoginUrl ?? '';
|
|
57
|
+
const entries = codeList.roles.length > 0
|
|
58
|
+
? codeList.roles.map((role) => ({
|
|
59
|
+
directUrl,
|
|
60
|
+
url: loginUrl,
|
|
61
|
+
systemName: role.systemName || baseSystem,
|
|
62
|
+
role: role.role,
|
|
63
|
+
username: '',
|
|
64
|
+
password: '',
|
|
65
|
+
}))
|
|
66
|
+
: (codeList.requirement?.businessRoles ?? []).map((role) => ({
|
|
67
|
+
directUrl,
|
|
68
|
+
url: loginUrl,
|
|
69
|
+
systemName: baseSystem,
|
|
70
|
+
role: role.label,
|
|
71
|
+
username: '',
|
|
72
|
+
password: '',
|
|
73
|
+
}));
|
|
140
74
|
return `${JSON5.stringify(entries, null, 2)}\n`;
|
|
141
75
|
}
|
|
142
|
-
/**
|
|
143
|
-
* 从 code_list.md 解析 testcase 子命令所需的 HTML / Action 物料目录。
|
|
144
|
-
*
|
|
145
|
-
* @param codeListPath - code_list.md 绝对路径。
|
|
146
|
-
* @returns probe 阶段所需的 webapp / java 目录。
|
|
147
|
-
* @throws 无法唯一解析 HTML 或 Action 目录时抛错。
|
|
148
|
-
*/
|
|
149
|
-
function resolveProbeInputsFromCodeList(codeListPath) {
|
|
150
|
-
const codeList = extractCodeListSummary(codeListPath);
|
|
151
|
-
const materialResult = resolveMaterialInventory({
|
|
152
|
-
codeListPath,
|
|
153
|
-
codeList,
|
|
154
|
-
debugOverrides: {},
|
|
155
|
-
});
|
|
156
|
-
if (materialResult.resolvedInputs.webappDir.status !== 'resolved') {
|
|
157
|
-
throw new Error(`code_list.md 无法唯一解析 HTML 目录:${codeListPath}`);
|
|
158
|
-
}
|
|
159
|
-
if (materialResult.resolvedInputs.javaActionsDir.status !== 'resolved') {
|
|
160
|
-
throw new Error(`code_list.md 无法唯一解析 Action 目录:${codeListPath}`);
|
|
161
|
-
}
|
|
162
|
-
return {
|
|
163
|
-
docsDir: materialResult.resolvedInputs.docsDir.status === 'resolved'
|
|
164
|
-
? materialResult.resolvedInputs.docsDir.path
|
|
165
|
-
: undefined,
|
|
166
|
-
webappDir: materialResult.resolvedInputs.webappDir.path,
|
|
167
|
-
javaActionsDir: materialResult.resolvedInputs.javaActionsDir.path,
|
|
168
|
-
hintsPath: materialResult.resolvedInputs.hintsPath.status === 'resolved'
|
|
169
|
-
? materialResult.resolvedInputs.hintsPath.path
|
|
170
|
-
: undefined,
|
|
171
|
-
moduleId: materialResult.resolvedInputs.moduleId.status === 'resolved'
|
|
172
|
-
? materialResult.resolvedInputs.moduleId.value
|
|
173
|
-
: undefined,
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
76
|
/**
|
|
177
77
|
* 往 projects.index.json5 对应 project 的 requirements[] 追加(去重)一条需求条目。
|
|
178
78
|
*
|
|
179
79
|
* 设计:
|
|
180
80
|
* - 读 index 时同时保留 systems[](writeProjectIndex 整体覆写,丢失 systems 会丢凭据缓存);
|
|
181
|
-
* - 用 JSON5.parse(readFileSync) 直接读,不复用 readProjectIndexRaw(后者未导出且丢 systems);
|
|
182
81
|
* - 按 projectDir 精确匹配 project,找不到抛中文错误引导先跑 /glue-create-project;
|
|
183
82
|
* - 同 name 的 requirement 去重:存在则更新 requirementDir/testsDir/lastRunStatus,不存在则追加。
|
|
184
83
|
*
|
|
@@ -212,7 +111,6 @@ function appendRequirementToProjectIndex(input) {
|
|
|
212
111
|
testsDir: input.testsDir,
|
|
213
112
|
lastRunStatus: 'never',
|
|
214
113
|
};
|
|
215
|
-
// 去重:同 name 存在则更新,不存在则追加。
|
|
216
114
|
const existIdx = project.requirements.findIndex((r) => r.name === entry.name);
|
|
217
115
|
if (existIdx >= 0) {
|
|
218
116
|
project.requirements[existIdx] = entry;
|
|
@@ -223,61 +121,63 @@ function appendRequirementToProjectIndex(input) {
|
|
|
223
121
|
return writeProjectIndex({ homeDir, projects, systems: parsed.systems });
|
|
224
122
|
}
|
|
225
123
|
/**
|
|
226
|
-
* testcase 子命令主体(
|
|
124
|
+
* testcase 子命令主体(JSON5 新产线,Task 3)。
|
|
227
125
|
*
|
|
228
126
|
* 流程:
|
|
229
|
-
* 1.
|
|
230
|
-
* 2.
|
|
231
|
-
* 3.
|
|
232
|
-
* 4.
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
* 注意:contract 提取通过 probe 内部完成,不直接复用 dev/extract-contract.ts 的 CLI 入口
|
|
236
|
-
* (probe + extract-contract 共享同一组 buildCrudBusinessModuleContract + extractor 依赖,
|
|
237
|
-
* 二者各自负责自己的 I/O 边界,保持职责单一)。
|
|
127
|
+
* 1. extractCodeListJson5 解析 code_list.json5;
|
|
128
|
+
* 2. assembleJson5ContractAndTestcase 装配 contract + testcase + inference-trace;
|
|
129
|
+
* 3. validateContract / validateTestcase schema 门禁;
|
|
130
|
+
* 4. 落盘 .ep-stage/contract.json5 + testcase.json5 + .ep-stage/inference-trace.json +
|
|
131
|
+
* credentials.template.json5 + testcase.md;软链 code_list.json5;
|
|
132
|
+
* 5. 可选回写 projects.index.json5(仅当显式传入 projectDir)。
|
|
238
133
|
*
|
|
239
134
|
* @param args - 已解析参数。
|
|
240
|
-
* @returns
|
|
135
|
+
* @returns 产物路径。
|
|
241
136
|
*/
|
|
242
137
|
export function runGenerateTestcase(args) {
|
|
243
|
-
|
|
138
|
+
// 路径硬校验:必须是 .json5(拒绝旧 code_list.md)。
|
|
139
|
+
assertCodeListJson5Path(args.codeList);
|
|
244
140
|
mkdirSync(args.testsDir, { recursive: true });
|
|
245
141
|
const requirementDir = args.requirementDir ?? path.dirname(args.codeList);
|
|
246
|
-
const
|
|
247
|
-
const
|
|
248
|
-
const
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
scenario,
|
|
142
|
+
const codeList = extractCodeListJson5(args.codeList);
|
|
143
|
+
const listPage = codeList.pages.find((page) => page.role === 'list');
|
|
144
|
+
const directUrl = args.directUrl ?? listPage?.directUrl;
|
|
145
|
+
if (!directUrl) {
|
|
146
|
+
throw new Error('缺少待测页面 directUrl:请在 /glue-generate-testcase 交互中提供列表页直达地址,或在 code_list.json5 的 pages[role=list].directUrl 中提供。');
|
|
147
|
+
}
|
|
148
|
+
const { contract, testcase, inferenceTrace } = assembleJson5ContractAndTestcase({
|
|
149
|
+
codeList,
|
|
150
|
+
directUrl,
|
|
151
|
+
sourceRoot: args.sourceRoot,
|
|
257
152
|
});
|
|
153
|
+
if (args.projectDir) {
|
|
154
|
+
testcase.runtimeContext = {
|
|
155
|
+
testProjectDir: args.projectDir,
|
|
156
|
+
caseDir: args.testsDir,
|
|
157
|
+
specPath: path.join(args.testsDir, 'crud.spec.ts'),
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
// schema 门禁(破旧立新,结构错直接抛)。
|
|
161
|
+
validateContract(contract);
|
|
162
|
+
validateTestcase(testcase);
|
|
258
163
|
const epStageDir = path.join(args.testsDir, '.ep-stage');
|
|
259
164
|
mkdirSync(epStageDir, { recursive: true });
|
|
260
|
-
const contractPath = path.join(epStageDir, 'contract.
|
|
165
|
+
const contractPath = path.join(epStageDir, 'contract.json5');
|
|
261
166
|
const inferenceTracePath = path.join(epStageDir, 'inference-trace.json');
|
|
262
167
|
const testcasePath = path.join(args.testsDir, 'testcase.json5');
|
|
263
168
|
const testcaseMdPath = path.join(args.testsDir, 'testcase.md');
|
|
264
169
|
const credentialsTemplatePath = path.join(args.testsDir, 'credentials.template.json5');
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
writeFileSync(
|
|
268
|
-
|
|
269
|
-
writeFileSync(
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
createSoftlinkWithFallback(args.codeList, path.join(args.testsDir, 'code_list.md'));
|
|
274
|
-
// 往 projects.index.json5 对应 project 追加(去重)一条 requirement 条目(skill Step 7)。
|
|
275
|
-
// 仅当显式传入 projectDir 时追加(skill Step 4 命令总带 --project-dir);
|
|
276
|
-
// 未传则跳过 —— 不反推 projectDir,避免非标准 testsDir 位置静默写入错误 project。
|
|
170
|
+
writeFileSync(contractPath, `${JSON5.stringify(contract, null, 2)}\n`, 'utf8');
|
|
171
|
+
writeFileSync(inferenceTracePath, `${JSON.stringify(inferenceTrace, null, 2)}\n`, 'utf8');
|
|
172
|
+
writeFileSync(testcasePath, `${JSON5.stringify(testcase, null, 2)}\n`, 'utf8');
|
|
173
|
+
writeFileSync(credentialsTemplatePath, renderCredentialsTemplate(codeList, directUrl), 'utf8');
|
|
174
|
+
writeFileSync(testcaseMdPath, renderUnifiedTestcaseMarkdown(testcase, contract), 'utf8');
|
|
175
|
+
// 软链 code_list.json5 → testsDir/code_list.json5(保留 code_list 旁路访问)。
|
|
176
|
+
createSoftlinkWithFallback(args.codeList, path.join(args.testsDir, 'code_list.json5'));
|
|
177
|
+
// 仅当显式传入 projectDir 时回写 projects.index.json5(不反推,避免静默写入错误 project)。
|
|
277
178
|
if (args.projectDir) {
|
|
278
179
|
appendRequirementToProjectIndex({
|
|
279
180
|
projectDir: args.projectDir,
|
|
280
|
-
// 需求名 = testsDir 的 basename(与 moduleId 来源一致:resolvedInputs.moduleId ?? path.basename(args.testsDir))。
|
|
281
181
|
requirementName: path.basename(args.testsDir),
|
|
282
182
|
requirementDir,
|
|
283
183
|
testsDir: args.testsDir,
|
|
@@ -288,13 +188,6 @@ export function runGenerateTestcase(args) {
|
|
|
288
188
|
testcaseMdPath,
|
|
289
189
|
credentialsTemplatePath,
|
|
290
190
|
inferenceTracePath,
|
|
291
|
-
|
|
292
|
-
scenario,
|
|
293
|
-
requiredSystems: testcaseV2.requiredSystems,
|
|
294
|
-
requiredRoles: testcaseV2.requiredRoles,
|
|
295
|
-
credentialsTemplatePath,
|
|
296
|
-
credentialsActualPath,
|
|
297
|
-
cachedSystemsHit: [],
|
|
298
|
-
},
|
|
191
|
+
contractPath,
|
|
299
192
|
};
|
|
300
193
|
}
|
package/dist/src/cli/index.d.ts
CHANGED
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
* ep-stage-skill CLI 统一入口(REQ-CLI-02 修订):1 bin + 3 子命令。
|
|
4
4
|
*
|
|
5
5
|
* 用法:
|
|
6
|
-
* ep-stage-skill testcase --code-list <p> --tests-dir <p> [--
|
|
6
|
+
* ep-stage-skill testcase --code-list <p> --tests-dir <p> --direct-url <url> [--project-dir <p>] [--requirement-dir <p>]
|
|
7
7
|
* ep-stage-skill spec --testcase <p> --out <p>
|
|
8
|
-
* ep-stage-skill
|
|
8
|
+
* ep-stage-skill prepare-tasks --testcase <p>
|
|
9
|
+
* ep-stage-skill run --testcase <p> [--ai-snippets <p>] [--headless false]
|
|
9
10
|
*
|
|
10
11
|
* 无 contract 子命令(contract 提取作为 testcase 子命令内部步骤;
|
|
11
12
|
* 开发期独立调试入口为 dev/extract-contract.ts,被 pnpm generate:crud-contract 调用)。
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/index.ts"],"names":[],"mappings":";AAOA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/index.ts"],"names":[],"mappings":";AAOA;;;;;;;;;;;GAWG;AACH,wBAAsB,IAAI,CAAC,IAAI,GAAE,MAAM,EAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,CAoD1E;AAED;;GAEG;AACH,wBAAgB,SAAS,IAAI,IAAI,CAchC;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAS3F"}
|
package/dist/src/cli/index.js
CHANGED
|
@@ -3,14 +3,15 @@ import { realpathSync } from 'node:fs';
|
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
4
|
import { parseGenerateTestcaseArgs, runGenerateTestcase } from './generate-testcase.js';
|
|
5
5
|
import { parseSpecArgs, runSpec } from './spec.js';
|
|
6
|
-
import { parseRunArgs, runRun } from './run.js';
|
|
6
|
+
import { parseRunArgs, prepareAiRuntimeTasks, runRun } from './run.js';
|
|
7
7
|
/**
|
|
8
8
|
* ep-stage-skill CLI 统一入口(REQ-CLI-02 修订):1 bin + 3 子命令。
|
|
9
9
|
*
|
|
10
10
|
* 用法:
|
|
11
|
-
* ep-stage-skill testcase --code-list <p> --tests-dir <p> [--
|
|
11
|
+
* ep-stage-skill testcase --code-list <p> --tests-dir <p> --direct-url <url> [--project-dir <p>] [--requirement-dir <p>]
|
|
12
12
|
* ep-stage-skill spec --testcase <p> --out <p>
|
|
13
|
-
* ep-stage-skill
|
|
13
|
+
* ep-stage-skill prepare-tasks --testcase <p>
|
|
14
|
+
* ep-stage-skill run --testcase <p> [--ai-snippets <p>] [--headless false]
|
|
14
15
|
*
|
|
15
16
|
* 无 contract 子命令(contract 提取作为 testcase 子命令内部步骤;
|
|
16
17
|
* 开发期独立调试入口为 dev/extract-contract.ts,被 pnpm generate:crud-contract 调用)。
|
|
@@ -23,15 +24,46 @@ export async function main(argv = process.argv) {
|
|
|
23
24
|
return runGenerateTestcase(parseGenerateTestcaseArgs(args));
|
|
24
25
|
case 'spec':
|
|
25
26
|
return runSpec(parseSpecArgs(args));
|
|
26
|
-
case '
|
|
27
|
-
|
|
27
|
+
case 'prepare-tasks': {
|
|
28
|
+
const result = prepareAiRuntimeTasks(parseRunArgs(args).testcase);
|
|
29
|
+
console.log([
|
|
30
|
+
`trace: ${result.tracePath}`,
|
|
31
|
+
`spec: ${result.specPath}`,
|
|
32
|
+
`ai tasks: ${result.taskCount}`,
|
|
33
|
+
`blocked: ${result.blockedCount}`,
|
|
34
|
+
].join('\n'));
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
case 'run': {
|
|
38
|
+
const result = await runRun(parseRunArgs(args));
|
|
39
|
+
// 结果摘要回显(此前 run 静默退出,自动化无法感知成败)。
|
|
40
|
+
const lines = [
|
|
41
|
+
`spec: ${result.specPath}`,
|
|
42
|
+
`report: ${result.reportDir}`,
|
|
43
|
+
`trace: ${result.aiRuntimeTracePath}`,
|
|
44
|
+
];
|
|
45
|
+
if (result.repairReportPath) {
|
|
46
|
+
lines.push(`repair: ${result.repairReportPath}`);
|
|
47
|
+
}
|
|
48
|
+
if (result.credentialsNotice) {
|
|
49
|
+
lines.push(result.credentialsNotice);
|
|
50
|
+
}
|
|
51
|
+
console.log(lines.join('\n'));
|
|
52
|
+
// 执行失败(已落修补报告)以非 0 退出,对齐 skill 文档「CLI 非 0 退出 → 复述 stderr」契约;
|
|
53
|
+
// 修补流程本身不受影响,人审确认方向后重跑即可。
|
|
54
|
+
if (result.repairReportPath) {
|
|
55
|
+
console.error(`执行失败:已落修补报告 ${result.repairReportPath},待人审确认修补方向`);
|
|
56
|
+
process.exitCode = 1;
|
|
57
|
+
}
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
28
60
|
case undefined:
|
|
29
61
|
case '--help':
|
|
30
62
|
case '-h':
|
|
31
63
|
printHelp();
|
|
32
64
|
return;
|
|
33
65
|
default:
|
|
34
|
-
console.error(`未知子命令: ${subcommand}。可用: testcase / spec / run`);
|
|
66
|
+
console.error(`未知子命令: ${subcommand}。可用: testcase / spec / prepare-tasks / run`);
|
|
35
67
|
process.exit(1);
|
|
36
68
|
}
|
|
37
69
|
}
|
|
@@ -39,17 +71,19 @@ export async function main(argv = process.argv) {
|
|
|
39
71
|
* 打印 CLI help(仅 testcase / spec / run 3 子命令,无 contract)。
|
|
40
72
|
*/
|
|
41
73
|
export function printHelp() {
|
|
42
|
-
console.log(`ep-stage-skill — 胶水测试链路 CLI
|
|
43
|
-
|
|
44
|
-
用法:
|
|
45
|
-
ep-stage-skill testcase --code-list <path> --tests-dir <path> [--
|
|
46
|
-
ep-stage-skill spec --testcase <path> --out <path>
|
|
47
|
-
ep-stage-skill
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
74
|
+
console.log(`ep-stage-skill — 胶水测试链路 CLI
|
|
75
|
+
|
|
76
|
+
用法:
|
|
77
|
+
ep-stage-skill testcase --code-list <path> --tests-dir <path> --direct-url <url> [--project-dir <path>] [--requirement-dir <path>]
|
|
78
|
+
ep-stage-skill spec --testcase <path> --out <path>
|
|
79
|
+
ep-stage-skill prepare-tasks --testcase <path>
|
|
80
|
+
ep-stage-skill run --testcase <path> [--ai-snippets <path>] [--headless false]
|
|
81
|
+
|
|
82
|
+
子命令:
|
|
83
|
+
testcase 读取 _docs/code_list.json5 + 生成 contract.json5 / testcase.json5 / inference-trace.json
|
|
84
|
+
spec 基于 testcase.json5 + contract.json5 的 glue cases 生成初始版 .spec.ts(只生成不执行)
|
|
85
|
+
prepare-tasks 组装 glue 骨架并输出 AI Runtime 任务包
|
|
86
|
+
run 合并 Agent 产出的 ai-snippets.json5 并执行完整 spec`);
|
|
53
87
|
}
|
|
54
88
|
/**
|
|
55
89
|
* 判断当前 CLI 文件是否以“直接执行”方式启动。
|
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
|