@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
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
import JSON5 from 'json5';
|
|
4
|
-
import { runProbeAndCoverage } from './probe.js';
|
|
5
5
|
import { createSoftlinkWithFallback } from '../util/softlink.js';
|
|
6
|
-
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
|
+
import { writeProjectIndex } from '../context/stage-context.js';
|
|
7
12
|
/**
|
|
8
13
|
* 解析 testcase 子命令参数。
|
|
9
14
|
*
|
|
@@ -29,169 +34,160 @@ export function parseGenerateTestcaseArgs(argv) {
|
|
|
29
34
|
return {
|
|
30
35
|
codeList: result['code-list'],
|
|
31
36
|
testsDir: result['tests-dir'],
|
|
32
|
-
scenario: result.scenario,
|
|
33
|
-
hints: result.hints,
|
|
34
37
|
projectDir: result['project-dir'],
|
|
35
38
|
requirementDir: result['requirement-dir'],
|
|
39
|
+
directUrl: result['direct-url'],
|
|
40
|
+
sourceRoot: result['source-root'],
|
|
36
41
|
};
|
|
37
42
|
}
|
|
38
43
|
/**
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* 2. ModuleHints 文件路径包含 `scenario=<value>` 字串(粗推断)
|
|
42
|
-
* 3. 默认 "crud.single-page"(与 i18n 表 / skeleton scenario 一致)
|
|
44
|
+
* 渲染 credentials.template.json5 数组内容。
|
|
45
|
+
* 每条对应一个 role,url/systemName 复用 code_list.systems[0](多系统场景由用户补齐)。
|
|
43
46
|
*
|
|
44
|
-
* @param
|
|
45
|
-
* @returns
|
|
47
|
+
* @param codeList - code_list 解析产出。
|
|
48
|
+
* @returns JSON5 字符串。
|
|
46
49
|
*/
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
+
}));
|
|
74
|
+
return `${JSON5.stringify(entries, null, 2)}\n`;
|
|
56
75
|
}
|
|
57
76
|
/**
|
|
58
|
-
*
|
|
77
|
+
* 往 projects.index.json5 对应 project 的 requirements[] 追加(去重)一条需求条目。
|
|
59
78
|
*
|
|
60
79
|
* 设计:
|
|
61
|
-
* -
|
|
62
|
-
* -
|
|
63
|
-
* -
|
|
80
|
+
* - 读 index 时同时保留 systems[](writeProjectIndex 整体覆写,丢失 systems 会丢凭据缓存);
|
|
81
|
+
* - 按 projectDir 精确匹配 project,找不到抛中文错误引导先跑 /glue-create-project;
|
|
82
|
+
* - 同 name 的 requirement 去重:存在则更新 requirementDir/testsDir/lastRunStatus,不存在则追加。
|
|
64
83
|
*
|
|
65
|
-
* @param
|
|
66
|
-
* @returns
|
|
84
|
+
* @param input - projectDir / requirementName / requirementDir / testsDir / homeDir。
|
|
85
|
+
* @returns 写入后的索引文件路径。
|
|
86
|
+
* @throws projectDir 不在 index 时抛中文错误。
|
|
67
87
|
*/
|
|
68
|
-
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
lines.push(`- ${i18nTestcase('requiredRoles')}:${testcase.requiredRoles.map((r) => r.role).join(',')}`);
|
|
77
|
-
lines.push('');
|
|
78
|
-
lines.push(`## ${i18nTestcase('coveredActions')}`);
|
|
79
|
-
if (testcase.coveredActions.length === 0)
|
|
80
|
-
lines.push('(无)');
|
|
81
|
-
for (const action of testcase.coveredActions) {
|
|
82
|
-
lines.push(`- ${action.actionId}(${action.kind})证据:${action.evidence.join(' / ')}`);
|
|
88
|
+
function appendRequirementToProjectIndex(input) {
|
|
89
|
+
const homeDir = input.homeDir ?? os.homedir();
|
|
90
|
+
const indexPath = path.join(homeDir, '.ep-stage', 'projects.index.json5');
|
|
91
|
+
let parsed;
|
|
92
|
+
if (existsSync(indexPath)) {
|
|
93
|
+
parsed = JSON5.parse(readFileSync(indexPath, 'utf8'));
|
|
94
|
+
parsed.projects = parsed.projects ?? [];
|
|
95
|
+
parsed.systems = parsed.systems ?? [];
|
|
83
96
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
if (testcase.uncoveredCandidates.length === 0)
|
|
87
|
-
lines.push('(无)');
|
|
88
|
-
for (const cand of testcase.uncoveredCandidates) {
|
|
89
|
-
lines.push(`- ${cand.actionId} ${cand.label}|状态:${i18nTestcase(cand.status)}|${i18nTestcase('requiredRole')}:${cand.requiredRole}`);
|
|
90
|
-
lines.push(` - ${i18nTestcase('businessIntent')}:${cand.businessIntent}`);
|
|
91
|
-
lines.push(` - ${i18nTestcase('assertionExpectation')}:${cand.assertionExpectation}`);
|
|
92
|
-
lines.push(` - ${i18nTestcase('evidence')}:${cand.evidence.join(' / ')}`);
|
|
97
|
+
else {
|
|
98
|
+
parsed = { projects: [], systems: [] };
|
|
93
99
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
lines.push(`- ${i18nTestcase('scenario')}:${i18nTestcase(c.scenario)}|${i18nTestcase('reviewStatus')}:${i18nTestcase(c.reviewStatus)}|${i18nTestcase('requiredRole')}:${c.requiredRole}`);
|
|
99
|
-
lines.push(`- ${i18nTestcase('evidence')}:${c.evidence.join(' / ')}`);
|
|
100
|
-
lines.push('- 步骤:');
|
|
101
|
-
for (const s of c.steps)
|
|
102
|
-
lines.push(` 1. ${s}`);
|
|
103
|
-
lines.push('- 断言:');
|
|
104
|
-
for (const a of c.assertions)
|
|
105
|
-
lines.push(` - ${a}`);
|
|
106
|
-
// 硬编码标题「未确认项」:i18nTestcase('unresolved') 返回状态值「未解决」(spec §4.6 trade-off)。
|
|
107
|
-
lines.push(`- 未确认项:${c.unresolved.length === 0 ? '(无)' : c.unresolved.join(';')}`);
|
|
108
|
-
lines.push('');
|
|
100
|
+
const targetProjectDir = path.resolve(input.projectDir);
|
|
101
|
+
const projectIdx = parsed.projects.findIndex((p) => path.resolve(p.projectDir) === targetProjectDir);
|
|
102
|
+
if (projectIdx === -1) {
|
|
103
|
+
throw new Error(`未在 ~/.ep-stage/projects.index.json5 找到 projectDir=${input.projectDir} 的 glue 项目,请先跑 /glue-create-project 创建脚手架`);
|
|
109
104
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
const baseSystem = testcase.requiredSystems[0]?.systemName ?? '';
|
|
128
|
-
const entries = testcase.requiredRoles.map((roleEntry) => ({
|
|
129
|
-
url: baseUrl,
|
|
130
|
-
username: '',
|
|
131
|
-
password: '',
|
|
132
|
-
role: roleEntry.role,
|
|
133
|
-
systemName: baseSystem,
|
|
134
|
-
}));
|
|
135
|
-
return `${JSON5.stringify(entries, null, 2)}\n`;
|
|
105
|
+
const projects = parsed.projects;
|
|
106
|
+
const project = projects[projectIdx];
|
|
107
|
+
project.requirements = project.requirements ?? [];
|
|
108
|
+
const entry = {
|
|
109
|
+
name: input.requirementName,
|
|
110
|
+
requirementDir: input.requirementDir,
|
|
111
|
+
testsDir: input.testsDir,
|
|
112
|
+
lastRunStatus: 'never',
|
|
113
|
+
};
|
|
114
|
+
const existIdx = project.requirements.findIndex((r) => r.name === entry.name);
|
|
115
|
+
if (existIdx >= 0) {
|
|
116
|
+
project.requirements[existIdx] = entry;
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
project.requirements.push(entry);
|
|
120
|
+
}
|
|
121
|
+
return writeProjectIndex({ homeDir, projects, systems: parsed.systems });
|
|
136
122
|
}
|
|
137
123
|
/**
|
|
138
|
-
* testcase 子命令主体(
|
|
124
|
+
* testcase 子命令主体(JSON5 新产线,Task 3)。
|
|
139
125
|
*
|
|
140
126
|
* 流程:
|
|
141
|
-
* 1.
|
|
142
|
-
* 2.
|
|
143
|
-
* 3.
|
|
144
|
-
* 4.
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
* 注意:contract 提取通过 probe 内部完成,不直接复用 dev/extract-contract.ts 的 CLI 入口
|
|
148
|
-
* (probe + extract-contract 共享同一组 buildCrudBusinessModuleContract + extractor 依赖,
|
|
149
|
-
* 二者各自负责自己的 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)。
|
|
150
133
|
*
|
|
151
134
|
* @param args - 已解析参数。
|
|
152
|
-
* @returns
|
|
135
|
+
* @returns 产物路径。
|
|
153
136
|
*/
|
|
154
137
|
export function runGenerateTestcase(args) {
|
|
155
|
-
|
|
138
|
+
// 路径硬校验:必须是 .json5(拒绝旧 code_list.md)。
|
|
139
|
+
assertCodeListJson5Path(args.codeList);
|
|
156
140
|
mkdirSync(args.testsDir, { recursive: true });
|
|
157
141
|
const requirementDir = args.requirementDir ?? path.dirname(args.codeList);
|
|
158
|
-
const
|
|
159
|
-
const
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
hintsPath: args.hints,
|
|
169
|
-
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,
|
|
170
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);
|
|
171
163
|
const epStageDir = path.join(args.testsDir, '.ep-stage');
|
|
172
164
|
mkdirSync(epStageDir, { recursive: true });
|
|
173
|
-
const contractPath = path.join(epStageDir, 'contract.
|
|
165
|
+
const contractPath = path.join(epStageDir, 'contract.json5');
|
|
166
|
+
const inferenceTracePath = path.join(epStageDir, 'inference-trace.json');
|
|
174
167
|
const testcasePath = path.join(args.testsDir, 'testcase.json5');
|
|
175
168
|
const testcaseMdPath = path.join(args.testsDir, 'testcase.md');
|
|
176
169
|
const credentialsTemplatePath = path.join(args.testsDir, 'credentials.template.json5');
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
writeFileSync(
|
|
180
|
-
writeFileSync(
|
|
181
|
-
writeFileSync(
|
|
182
|
-
|
|
183
|
-
createSoftlinkWithFallback(args.codeList, path.join(args.testsDir, 'code_list.
|
|
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)。
|
|
178
|
+
if (args.projectDir) {
|
|
179
|
+
appendRequirementToProjectIndex({
|
|
180
|
+
projectDir: args.projectDir,
|
|
181
|
+
requirementName: path.basename(args.testsDir),
|
|
182
|
+
requirementDir,
|
|
183
|
+
testsDir: args.testsDir,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
184
186
|
return {
|
|
185
187
|
testcasePath,
|
|
186
188
|
testcaseMdPath,
|
|
187
189
|
credentialsTemplatePath,
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
requiredSystems: testcaseV2.requiredSystems,
|
|
191
|
-
requiredRoles: testcaseV2.requiredRoles,
|
|
192
|
-
credentialsTemplatePath,
|
|
193
|
-
credentialsActualPath,
|
|
194
|
-
cachedSystemsHit: [],
|
|
195
|
-
},
|
|
190
|
+
inferenceTracePath,
|
|
191
|
+
contractPath,
|
|
196
192
|
};
|
|
197
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 调用)。
|
|
@@ -15,4 +16,12 @@ export declare function main(argv?: string[]): Promise<unknown>;
|
|
|
15
16
|
* 打印 CLI help(仅 testcase / spec / run 3 子命令,无 contract)。
|
|
16
17
|
*/
|
|
17
18
|
export declare function printHelp(): void;
|
|
19
|
+
/**
|
|
20
|
+
* 判断当前 CLI 文件是否以“直接执行”方式启动。
|
|
21
|
+
*
|
|
22
|
+
* @param importMetaUrl - 当前模块的 import.meta.url。
|
|
23
|
+
* @param argv1 - 进程入口参数,可能是 npm bin 软链路径。
|
|
24
|
+
* @returns 若当前模块就是实际执行入口则返回 true。
|
|
25
|
+
*/
|
|
26
|
+
export declare function isDirectExecution(importMetaUrl: string, argv1: string | undefined): boolean;
|
|
18
27
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/index.ts"],"names":[],"mappings":";
|
|
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,CA+B1E;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
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { realpathSync } from 'node:fs';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
2
4
|
import { parseGenerateTestcaseArgs, runGenerateTestcase } from './generate-testcase.js';
|
|
3
5
|
import { parseSpecArgs, runSpec } from './spec.js';
|
|
4
|
-
import { parseRunArgs, runRun } from './run.js';
|
|
6
|
+
import { parseRunArgs, prepareAiRuntimeTasks, runRun } from './run.js';
|
|
5
7
|
/**
|
|
6
8
|
* ep-stage-skill CLI 统一入口(REQ-CLI-02 修订):1 bin + 3 子命令。
|
|
7
9
|
*
|
|
8
10
|
* 用法:
|
|
9
|
-
* 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>]
|
|
10
12
|
* ep-stage-skill spec --testcase <p> --out <p>
|
|
11
|
-
* ep-stage-skill
|
|
13
|
+
* ep-stage-skill prepare-tasks --testcase <p>
|
|
14
|
+
* ep-stage-skill run --testcase <p> [--ai-snippets <p>] [--headless false]
|
|
12
15
|
*
|
|
13
16
|
* 无 contract 子命令(contract 提取作为 testcase 子命令内部步骤;
|
|
14
17
|
* 开发期独立调试入口为 dev/extract-contract.ts,被 pnpm generate:crud-contract 调用)。
|
|
@@ -21,6 +24,16 @@ export async function main(argv = process.argv) {
|
|
|
21
24
|
return runGenerateTestcase(parseGenerateTestcaseArgs(args));
|
|
22
25
|
case 'spec':
|
|
23
26
|
return runSpec(parseSpecArgs(args));
|
|
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
|
+
}
|
|
24
37
|
case 'run':
|
|
25
38
|
return runRun(parseRunArgs(args));
|
|
26
39
|
case undefined:
|
|
@@ -29,7 +42,7 @@ export async function main(argv = process.argv) {
|
|
|
29
42
|
printHelp();
|
|
30
43
|
return;
|
|
31
44
|
default:
|
|
32
|
-
console.error(`未知子命令: ${subcommand}。可用: testcase / spec / run`);
|
|
45
|
+
console.error(`未知子命令: ${subcommand}。可用: testcase / spec / prepare-tasks / run`);
|
|
33
46
|
process.exit(1);
|
|
34
47
|
}
|
|
35
48
|
}
|
|
@@ -37,19 +50,39 @@ export async function main(argv = process.argv) {
|
|
|
37
50
|
* 打印 CLI help(仅 testcase / spec / run 3 子命令,无 contract)。
|
|
38
51
|
*/
|
|
39
52
|
export function printHelp() {
|
|
40
|
-
console.log(`ep-stage-skill — 胶水测试链路 CLI
|
|
41
|
-
|
|
42
|
-
用法:
|
|
43
|
-
ep-stage-skill testcase --code-list <path> --tests-dir <path> [--
|
|
44
|
-
ep-stage-skill spec --testcase <path> --out <path>
|
|
45
|
-
ep-stage-skill
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
53
|
+
console.log(`ep-stage-skill — 胶水测试链路 CLI
|
|
54
|
+
|
|
55
|
+
用法:
|
|
56
|
+
ep-stage-skill testcase --code-list <path> --tests-dir <path> --direct-url <url> [--project-dir <path>] [--requirement-dir <path>]
|
|
57
|
+
ep-stage-skill spec --testcase <path> --out <path>
|
|
58
|
+
ep-stage-skill prepare-tasks --testcase <path>
|
|
59
|
+
ep-stage-skill run --testcase <path> [--ai-snippets <path>] [--headless false]
|
|
60
|
+
|
|
61
|
+
子命令:
|
|
62
|
+
testcase 读取 _docs/code_list.json5 + 生成 contract.json5 / testcase.json5 / inference-trace.json
|
|
63
|
+
spec 基于 testcase.json5 + contract.json5 的 glue cases 生成初始版 .spec.ts(只生成不执行)
|
|
64
|
+
prepare-tasks 组装 glue 骨架并输出 AI Runtime 任务包
|
|
65
|
+
run 合并 Agent 产出的 ai-snippets.json5 并执行完整 spec`);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* 判断当前 CLI 文件是否以“直接执行”方式启动。
|
|
69
|
+
*
|
|
70
|
+
* @param importMetaUrl - 当前模块的 import.meta.url。
|
|
71
|
+
* @param argv1 - 进程入口参数,可能是 npm bin 软链路径。
|
|
72
|
+
* @returns 若当前模块就是实际执行入口则返回 true。
|
|
73
|
+
*/
|
|
74
|
+
export function isDirectExecution(importMetaUrl, argv1) {
|
|
75
|
+
try {
|
|
76
|
+
if (!argv1) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
return realpathSync(fileURLToPath(importMetaUrl)) === realpathSync(argv1);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
51
84
|
}
|
|
52
85
|
// 直接执行时调用 main;作为模块 import 时由调用方决定是否执行。
|
|
53
|
-
if (import.meta.url
|
|
86
|
+
if (isDirectExecution(import.meta.url, process.argv[1])) {
|
|
54
87
|
await main();
|
|
55
88
|
}
|
package/dist/src/cli/probe.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { CrudBusinessModuleContract } from '../contracts/crud-business-module.js';
|
|
2
2
|
import type { CoverageDiffTrace } from '../contracts/observable-chain.js';
|
|
3
3
|
import type { TestcaseV2 } from '../testcase/testcase-v2.js';
|
|
4
|
+
import type { InferenceTraceV1 } from '../contracts/inference-trace.js';
|
|
4
5
|
/**
|
|
5
6
|
* probe 子模块入参(REQ-CHAIN-01)。
|
|
6
7
|
*
|
|
@@ -28,6 +29,7 @@ export type ProbeAndCoverageResult = {
|
|
|
28
29
|
contract: CrudBusinessModuleContract;
|
|
29
30
|
coverageDiff: CoverageDiffTrace;
|
|
30
31
|
testcaseV2: TestcaseV2;
|
|
32
|
+
inferenceTrace: InferenceTraceV1;
|
|
31
33
|
};
|
|
32
34
|
/**
|
|
33
35
|
* probe + coverage + testcase v2 装配的统一入口(REQ-CHAIN-01)。
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"probe.d.ts","sourceRoot":"","sources":["../../../src/cli/probe.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,0BAA0B,EAAe,MAAM,sCAAsC,CAAC;AACpG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"probe.d.ts","sourceRoot":"","sources":["../../../src/cli/probe.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,0BAA0B,EAAe,MAAM,sCAAsC,CAAC;AACpG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAI7D,OAAO,KAAK,EAAE,gBAAgB,EAAoE,MAAM,iCAAiC,CAAC;AAI1I;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,EAAE,0BAA0B,CAAC;IACrC,YAAY,EAAE,iBAAiB,CAAC;IAChC,UAAU,EAAE,UAAU,CAAC;IACvB,cAAc,EAAE,gBAAgB,CAAC;CAClC,CAAC;AAoYF;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,oBAAoB,GAAG,sBAAsB,CAuFtF"}
|