@epoint-testtech/ep-stage-skill 0.0.10 → 0.5.0-alpha.2
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 -223
- package/codex-skill/ep-stage/glue-generate-testcase/SKILL.md +275 -275
- 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 -95
- package/codex-skill/ep-stage/glue-run-test/SKILL.md +273 -296
- package/codex-skill/ep-stage/glue-run-test/references/ai-runtime-loop.md +30 -30
- package/codex-skill/ep-stage/glue-run-test/references/crud-pipeline.md +132 -132
- package/codex-skill/ep-stage/glue-run-test/references/gap-review-protocol.md +44 -44
- 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 +127 -166
- package/codex-skill/ep-stage/glue-run-test/scripts/generate-crud-spec.mjs +149 -149
- package/codex-skill/ep-stage/recording-to-glue/SKILL.md +28 -28
- package/codex-skill/ep-stage/scripts/validate-skill.mjs +95 -98
- package/dist/src/cli/generate-testcase.d.ts +0 -1
- package/dist/src/cli/generate-testcase.d.ts.map +1 -1
- package/dist/src/cli/generate-testcase.js +1 -6
- package/dist/src/cli/index.d.ts.map +1 -1
- package/dist/src/cli/index.js +14 -38
- package/dist/src/cli/run.d.ts +0 -2
- package/dist/src/cli/run.d.ts.map +1 -1
- package/dist/src/cli/run.js +21 -70
- package/dist/src/cli/spec.d.ts.map +1 -1
- package/dist/src/cli/spec.js +0 -9
- package/dist/src/contracts/glue-contract-v1.d.ts +0 -35
- package/dist/src/contracts/glue-contract-v1.d.ts.map +1 -1
- package/dist/src/extractors/code-list-json5.d.ts +1 -34
- package/dist/src/extractors/code-list-json5.d.ts.map +1 -1
- package/dist/src/extractors/code-list-json5.js +0 -1
- package/dist/src/extractors/html-page.d.ts +0 -9
- package/dist/src/extractors/html-page.d.ts.map +1 -1
- package/dist/src/extractors/html-page.js +2 -26
- package/dist/src/generators/agent-inferred-workflow-script.js +66 -66
- package/dist/src/generators/stage-skeleton-script.d.ts +0 -50
- package/dist/src/generators/stage-skeleton-script.d.ts.map +1 -1
- package/dist/src/generators/stage-skeleton-script.js +116 -449
- package/dist/src/runtime/ai-runtime-trace.d.ts.map +1 -1
- package/dist/src/runtime/ai-runtime-trace.js +0 -8
- package/dist/src/testcase/contract-testcase-assembler.d.ts +0 -28
- package/dist/src/testcase/contract-testcase-assembler.d.ts.map +1 -1
- package/dist/src/testcase/contract-testcase-assembler.js +75 -329
- package/dist/src/validation/contract.d.ts.map +1 -1
- package/dist/src/validation/contract.js +0 -29
- package/dist/test/cli/generate-testcase-json5.test.d.ts +2 -0
- package/dist/test/cli/generate-testcase-json5.test.d.ts.map +1 -0
- package/dist/test/cli/generate-testcase-json5.test.js +154 -0
- package/dist/test/cli/index.test.d.ts +2 -0
- package/dist/test/cli/index.test.d.ts.map +1 -0
- package/dist/test/cli/index.test.js +114 -0
- package/dist/test/cli/run.test.d.ts +2 -0
- package/dist/test/cli/run.test.d.ts.map +1 -0
- package/dist/test/cli/run.test.js +429 -0
- package/dist/test/cli/spec.test.d.ts +2 -0
- package/dist/test/cli/spec.test.d.ts.map +1 -0
- package/dist/test/cli/spec.test.js +112 -0
- package/dist/test/code-list-json5.test.d.ts +2 -0
- package/dist/test/code-list-json5.test.d.ts.map +1 -0
- package/dist/test/code-list-json5.test.js +84 -0
- package/dist/test/code-list.test.d.ts +2 -0
- package/dist/test/code-list.test.d.ts.map +1 -0
- package/dist/test/code-list.test.js +39 -0
- package/dist/test/gap-inference.test.d.ts +2 -0
- package/dist/test/gap-inference.test.d.ts.map +1 -0
- package/dist/test/gap-inference.test.js +597 -0
- package/dist/test/generalization.test.d.ts +2 -0
- package/dist/test/generalization.test.d.ts.map +1 -0
- package/dist/test/generalization.test.js +73 -0
- package/dist/test/material-inventory.test.d.ts +2 -0
- package/dist/test/material-inventory.test.d.ts.map +1 -0
- package/dist/test/material-inventory.test.js +155 -0
- package/dist/test/observable-chain.test.d.ts +2 -0
- package/dist/test/observable-chain.test.d.ts.map +1 -0
- package/dist/test/observable-chain.test.js +123 -0
- package/dist/test/page-structure.test.d.ts +2 -0
- package/dist/test/page-structure.test.d.ts.map +1 -0
- package/dist/test/page-structure.test.js +45 -0
- package/dist/test/runtime/ai-runtime-trace.test.d.ts +2 -0
- package/dist/test/runtime/ai-runtime-trace.test.d.ts.map +1 -0
- package/dist/test/runtime/ai-runtime-trace.test.js +78 -0
- package/dist/test/scenario-inference.test.d.ts +2 -0
- package/dist/test/scenario-inference.test.d.ts.map +1 -0
- package/dist/test/scenario-inference.test.js +73 -0
- package/dist/test/stage-context.test.d.ts +2 -0
- package/dist/test/stage-context.test.d.ts.map +1 -0
- package/dist/test/stage-context.test.js +395 -0
- package/dist/test/testcase/testcase-markdown.test.d.ts +2 -0
- package/dist/test/testcase/testcase-markdown.test.d.ts.map +1 -0
- package/dist/test/testcase/testcase-markdown.test.js +48 -0
- package/dist/test/testcase-generator.test.d.ts +2 -0
- package/dist/test/testcase-generator.test.d.ts.map +1 -0
- package/dist/test/testcase-generator.test.js +276 -0
- package/dist/test/testcase-skeleton.test.d.ts +2 -0
- package/dist/test/testcase-skeleton.test.d.ts.map +1 -0
- package/dist/test/testcase-skeleton.test.js +185 -0
- package/dist/test/testcase-spec-assembly.test.d.ts +2 -0
- package/dist/test/testcase-spec-assembly.test.d.ts.map +1 -0
- package/dist/test/testcase-spec-assembly.test.js +105 -0
- package/dist/test/util/credentials.test.d.ts +2 -0
- package/dist/test/util/credentials.test.d.ts.map +1 -0
- package/dist/test/util/credentials.test.js +64 -0
- package/dist/test/util/i18n-testcase.test.d.ts +2 -0
- package/dist/test/util/i18n-testcase.test.d.ts.map +1 -0
- package/dist/test/util/i18n-testcase.test.js +119 -0
- package/dist/test/util/softlink.test.d.ts +2 -0
- package/dist/test/util/softlink.test.d.ts.map +1 -0
- package/dist/test/util/softlink.test.js +82 -0
- package/dist/test/validation/contract.test.d.ts +2 -0
- package/dist/test/validation/contract.test.d.ts.map +1 -0
- package/dist/test/validation/contract.test.js +116 -0
- package/dist/test/validation/credentials.test.d.ts +2 -0
- package/dist/test/validation/credentials.test.d.ts.map +1 -0
- package/dist/test/validation/credentials.test.js +74 -0
- package/dist/test/validation/projects-index.test.d.ts +2 -0
- package/dist/test/validation/projects-index.test.d.ts.map +1 -0
- package/dist/test/validation/projects-index.test.js +48 -0
- package/dist/test/validation/testcase-v1-draft.test.d.ts +2 -0
- package/dist/test/validation/testcase-v1-draft.test.d.ts.map +1 -0
- package/dist/test/validation/testcase-v1-draft.test.js +173 -0
- package/dist/vitest.config.d.ts +3 -0
- package/dist/vitest.config.d.ts.map +1 -0
- package/dist/vitest.config.js +7 -0
- package/docs/README.md +124 -124
- 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 +19 -13
- package/codex-skill/ep-stage/glue-generate-testcase/references/testcase-tpl.md +0 -72
- package/codex-skill/ep-stage/glue-run-test/scripts/extract-page-elements-eval.mjs +0 -233
- package/codex-skill/ep-stage/page-element-scan/SKILL.md +0 -91
- package/codex-skill/ep-stage/page-element-scan/evals/evals.json +0 -37
- package/codex-skill/ep-stage/page-element-scan/evals/fixtures/sample-list-page.html +0 -85
- package/codex-skill/ep-stage/page-element-scan/references/pagination-controls.md +0 -153
- package/codex-skill/ep-stage/page-element-scan/scripts/extract-page-elements-eval.mjs +0 -233
- package/codex-skill/ep-stage/page-element-scan/scripts/extract-page-elements.mjs +0 -298
- package/codex-skill/ep-stage/page-element-scan/scripts/scan-page.mjs +0 -749
- package/dist/src/cli/probe.d.ts +0 -46
- package/dist/src/cli/probe.d.ts.map +0 -1
- package/dist/src/cli/probe.js +0 -447
- package/dist/src/cli/run-report.d.ts +0 -46
- package/dist/src/cli/run-report.d.ts.map +0 -1
- package/dist/src/cli/run-report.js +0 -331
- package/dist/src/extractors/prd-extractor.d.ts +0 -70
- package/dist/src/extractors/prd-extractor.d.ts.map +0 -1
- package/dist/src/extractors/prd-extractor.js +0 -248
- package/dist/src/testcase/button-interaction-inference.d.ts +0 -37
- package/dist/src/testcase/button-interaction-inference.d.ts.map +0 -1
- package/dist/src/testcase/button-interaction-inference.js +0 -385
- package/dist/src/testcase/prd-button-mapper.d.ts +0 -72
- package/dist/src/testcase/prd-button-mapper.d.ts.map +0 -1
- package/dist/src/testcase/prd-button-mapper.js +0 -148
- package/dist/src/testcase/testcase-v2.d.ts +0 -50
- package/dist/src/testcase/testcase-v2.d.ts.map +0 -1
- package/dist/src/testcase/testcase-v2.js +0 -1
- package/docs/mvp-usage-guide.md +0 -298
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: recording-to-glue
|
|
3
|
-
description: 使用时机:当用户讨论或规划「将录制产出的 Playwright 脚本转换为 ep-stage 胶水骨架(glue skeleton)或组件(component)候选代码」时使用。
|
|
4
|
-
version: 2026-07-05+57662df
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# ep-stage: recording-to-glue
|
|
8
|
-
|
|
9
|
-
本 skill 是一个规划中的能力入口。
|
|
10
|
-
|
|
11
|
-
## 当前状态
|
|
12
|
-
|
|
13
|
-
转换工作流在本期尚未实现。
|
|
14
|
-
|
|
15
|
-
## 预期输入(未来)
|
|
16
|
-
|
|
17
|
-
- 来自 `stage-recorder-ext` 或其他录制器的原始 Playwright 脚本。
|
|
18
|
-
- 标识页面、iframe(frame)、选择器(selector)以及用户动作意图的录制元数据。
|
|
19
|
-
|
|
20
|
-
## 预期产出(未来)
|
|
21
|
-
|
|
22
|
-
- 候选胶水骨架代码(glue skeleton code)。
|
|
23
|
-
- 候选组件动作(component actions)。
|
|
24
|
-
- 关于代码应归入骨架、组件、测试 spec,还是作为待确认槽位进入 `unresolvedSlots` / `sourceTrace` 的评审意见。
|
|
25
|
-
|
|
26
|
-
## 当前行为
|
|
27
|
-
|
|
28
|
-
当用户调用本 skill 时,应说明实现尚未开始,并提议为该转换工作流创建设计或实施计划,而不是在本期从录制产物生成生产级胶水代码。
|
|
1
|
+
---
|
|
2
|
+
name: recording-to-glue
|
|
3
|
+
description: 使用时机:当用户讨论或规划「将录制产出的 Playwright 脚本转换为 ep-stage 胶水骨架(glue skeleton)或组件(component)候选代码」时使用。
|
|
4
|
+
version: 2026-07-05+57662df
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# ep-stage: recording-to-glue
|
|
8
|
+
|
|
9
|
+
本 skill 是一个规划中的能力入口。
|
|
10
|
+
|
|
11
|
+
## 当前状态
|
|
12
|
+
|
|
13
|
+
转换工作流在本期尚未实现。
|
|
14
|
+
|
|
15
|
+
## 预期输入(未来)
|
|
16
|
+
|
|
17
|
+
- 来自 `stage-recorder-ext` 或其他录制器的原始 Playwright 脚本。
|
|
18
|
+
- 标识页面、iframe(frame)、选择器(selector)以及用户动作意图的录制元数据。
|
|
19
|
+
|
|
20
|
+
## 预期产出(未来)
|
|
21
|
+
|
|
22
|
+
- 候选胶水骨架代码(glue skeleton code)。
|
|
23
|
+
- 候选组件动作(component actions)。
|
|
24
|
+
- 关于代码应归入骨架、组件、测试 spec,还是作为待确认槽位进入 `unresolvedSlots` / `sourceTrace` 的评审意见。
|
|
25
|
+
|
|
26
|
+
## 当前行为
|
|
27
|
+
|
|
28
|
+
当用户调用本 skill 时,应说明实现尚未开始,并提议为该转换工作流创建设计或实施计划,而不是在本期从录制产物生成生产级胶水代码。
|
|
@@ -1,98 +1,95 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// validate-skill.mjs — 校验 ep-stage scope 下所有 skill 的 SKILL.md frontmatter
|
|
3
|
-
// + 双发现目录(.claude/skills / .agents/skills)symlink 指向。
|
|
4
|
-
//
|
|
5
|
-
// version 字段维护契约(REQ-VER-003):
|
|
6
|
-
// 当 SKILL.md 内容(frontmatter 或正文)发生变更时,维护者必须手动把
|
|
7
|
-
// `version:` 更新为 `YYYY-MM-DD+<7位短SHA>`,其中 <短SHA> 取当前 HEAD。
|
|
8
|
-
// 快捷生成命令:date +"%Y-%m-%d"+$(git rev-parse --short HEAD)
|
|
9
|
-
// pre-commit hook(.husky/pre-commit → check-skill-version-bump.mjs)会
|
|
10
|
-
// 自动校验:改了 SKILL.md 但没改 version 行 → 阻塞 commit。
|
|
11
|
-
import { lstatSync, readFileSync, realpathSync } from 'node:fs';
|
|
12
|
-
import path from 'node:path';
|
|
13
|
-
import { fileURLToPath } from 'node:url';
|
|
14
|
-
|
|
15
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
16
|
-
const epStageRoot = path.resolve(__dirname, '..');
|
|
17
|
-
const packageRoot = path.resolve(epStageRoot, '../..');
|
|
18
|
-
const repoRoot = path.resolve(packageRoot, '../..');
|
|
19
|
-
|
|
20
|
-
// version 值正则:YYYY-MM-DD+<7位十六进制短SHA>
|
|
21
|
-
const VERSION_PATTERN = /^\d{4}-\d{2}-\d{2}\+[0-9a-f]{7}$/;
|
|
22
|
-
|
|
23
|
-
function readFrontmatter(skillRoot) {
|
|
24
|
-
const skillPath = path.join(skillRoot, 'SKILL.md');
|
|
25
|
-
const text = readFileSync(skillPath, 'utf8');
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (
|
|
42
|
-
if (
|
|
43
|
-
if (
|
|
44
|
-
if (
|
|
45
|
-
if (!version) throw new Error(`${skillPath} version
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
if (
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
// - glue-
|
|
61
|
-
// - glue-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
{ name: 'glue-
|
|
65
|
-
{ name: 'glue-
|
|
66
|
-
{ name: '
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
//
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
path.join(repoRoot, '.
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
//
|
|
81
|
-
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
checks,
|
|
97
|
-
symlinks,
|
|
98
|
-
}, null, 2));
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// validate-skill.mjs — 校验 ep-stage scope 下所有 skill 的 SKILL.md frontmatter
|
|
3
|
+
// + 双发现目录(.claude/skills / .agents/skills)symlink 指向。
|
|
4
|
+
//
|
|
5
|
+
// version 字段维护契约(REQ-VER-003):
|
|
6
|
+
// 当 SKILL.md 内容(frontmatter 或正文)发生变更时,维护者必须手动把
|
|
7
|
+
// `version:` 更新为 `YYYY-MM-DD+<7位短SHA>`,其中 <短SHA> 取当前 HEAD。
|
|
8
|
+
// 快捷生成命令:date +"%Y-%m-%d"+$(git rev-parse --short HEAD)
|
|
9
|
+
// pre-commit hook(.husky/pre-commit → check-skill-version-bump.mjs)会
|
|
10
|
+
// 自动校验:改了 SKILL.md 但没改 version 行 → 阻塞 commit。
|
|
11
|
+
import { lstatSync, readFileSync, realpathSync } from 'node:fs';
|
|
12
|
+
import path from 'node:path';
|
|
13
|
+
import { fileURLToPath } from 'node:url';
|
|
14
|
+
|
|
15
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
16
|
+
const epStageRoot = path.resolve(__dirname, '..');
|
|
17
|
+
const packageRoot = path.resolve(epStageRoot, '../..');
|
|
18
|
+
const repoRoot = path.resolve(packageRoot, '../..');
|
|
19
|
+
|
|
20
|
+
// version 值正则:YYYY-MM-DD+<7位十六进制短SHA>
|
|
21
|
+
const VERSION_PATTERN = /^\d{4}-\d{2}-\d{2}\+[0-9a-f]{7}$/;
|
|
22
|
+
|
|
23
|
+
function readFrontmatter(skillRoot) {
|
|
24
|
+
const skillPath = path.join(skillRoot, 'SKILL.md');
|
|
25
|
+
const text = readFileSync(skillPath, 'utf8');
|
|
26
|
+
const match = text.match(/^---\n([\s\S]*?)\n---\n/);
|
|
27
|
+
if (!match) throw new Error(`${skillPath} missing YAML frontmatter`);
|
|
28
|
+
|
|
29
|
+
const frontmatter = match[1];
|
|
30
|
+
return {
|
|
31
|
+
name: frontmatter.match(/^name:\s*(.+)$/m)?.[1]?.trim(),
|
|
32
|
+
description: frontmatter.match(/^description:\s*(.+)$/m)?.[1]?.trim(),
|
|
33
|
+
version: frontmatter.match(/^\s*version:\s*["']?([^"'\n]+)["']?\s*$/m)?.[1]?.trim(),
|
|
34
|
+
skillPath,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function assertSkill(skillRoot, expectedName) {
|
|
39
|
+
const { name, description, version, skillPath } = readFrontmatter(skillRoot);
|
|
40
|
+
if (name !== expectedName) throw new Error(`Expected name ${expectedName} in ${skillPath}, got ${name ?? 'missing'}`);
|
|
41
|
+
if (!description?.startsWith('使用时机') && !description?.startsWith('Use when')) throw new Error(`${skillPath} description 必须以「使用时机」或「Use when」开头`);
|
|
42
|
+
if (description.length > 1024) throw new Error(`${skillPath} description exceeds 1024 characters`);
|
|
43
|
+
if (path.basename(skillRoot) !== name) throw new Error(`${skillPath} directory basename must match name`);
|
|
44
|
+
if (!version) throw new Error(`${skillPath} version 字段缺失;维护者改 SKILL.md 时必须同步更新 version(格式 YYYY-MM-DD+<7位短SHA>)`);
|
|
45
|
+
if (!VERSION_PATTERN.test(version)) throw new Error(`${skillPath} version 格式非法 "${version}";应为 YYYY-MM-DD+<7位短SHA>,如 2026-06-23+a9e7576`);
|
|
46
|
+
return { name, descriptionLength: description.length, version, skillRoot };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function assertSymlink(linkPath, targetPath) {
|
|
50
|
+
const linkStat = lstatSync(linkPath);
|
|
51
|
+
if (!linkStat.isSymbolicLink()) throw new Error(`${linkPath} must be a symlink`);
|
|
52
|
+
if (realpathSync(linkPath) !== realpathSync(targetPath)) {
|
|
53
|
+
throw new Error(`${linkPath} does not point at ${targetPath}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ep-stage scope 下四个 skill 的包内真相源目录。
|
|
58
|
+
// 注:Task 0.2 已 git mv 改名 3 个 skill 目录(glue-* 前缀化)。
|
|
59
|
+
// - glue-create-project:Task 2.1 已同步 SKILL.md frontmatter name → 'glue-create-project'。
|
|
60
|
+
// - glue-generate-testcase:Task 3.2 已同步 SKILL.md frontmatter name → 'glue-generate-testcase'。
|
|
61
|
+
// - glue-run-test:Task 4.3 已同步 SKILL.md frontmatter name → 'glue-run-test'。
|
|
62
|
+
const skillSources = [
|
|
63
|
+
{ name: 'glue-create-project', source: path.join(epStageRoot, 'glue-create-project') },
|
|
64
|
+
{ name: 'glue-generate-testcase', source: path.join(epStageRoot, 'glue-generate-testcase') },
|
|
65
|
+
{ name: 'glue-run-test', source: path.join(epStageRoot, 'glue-run-test') },
|
|
66
|
+
{ name: 'recording-to-glue', source: path.join(epStageRoot, 'recording-to-glue') },
|
|
67
|
+
];
|
|
68
|
+
|
|
69
|
+
// 校验每个源 skill 的 SKILL.md frontmatter。
|
|
70
|
+
const checks = skillSources.map(({ name, source }) => assertSkill(source, name));
|
|
71
|
+
|
|
72
|
+
// 发现目录:Claude Code 扫 .claude/skills/,Codex 扫 .agents/skills/。
|
|
73
|
+
// 两个工具都只扫直接子目录,每个子目录是一个 skill;用 symlink 指向包内源。
|
|
74
|
+
const discoveryDirs = [
|
|
75
|
+
path.join(repoRoot, '.claude/skills'),
|
|
76
|
+
path.join(repoRoot, '.agents/skills'),
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
// 注:symlink 名总是与包内目录 basename 一致(Phase 0 重建后)。
|
|
80
|
+
// Task 4.3 收敛后,3 个 glue-* skill 的 SKILL.md `name` 与目录 basename 完全一致;symlink 仍以 basename 为准。
|
|
81
|
+
const symlinks = [];
|
|
82
|
+
for (const dir of discoveryDirs) {
|
|
83
|
+
for (const { name, source } of skillSources) {
|
|
84
|
+
const linkName = path.basename(source);
|
|
85
|
+
assertSymlink(path.join(dir, linkName), source);
|
|
86
|
+
symlinks.push({ dir: path.relative(repoRoot, dir), name, linkName, pointsTo: path.relative(repoRoot, source) });
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
console.log(JSON.stringify({
|
|
91
|
+
ok: true,
|
|
92
|
+
packageRoot,
|
|
93
|
+
checks,
|
|
94
|
+
symlinks,
|
|
95
|
+
}, null, 2));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate-testcase.d.ts","sourceRoot":"","sources":["../../../src/cli/generate-testcase.ts"],"names":[],"mappings":"AAaA;;;;;;;GAOG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"generate-testcase.d.ts","sourceRoot":"","sources":["../../../src/cli/generate-testcase.ts"],"names":[],"mappings":"AAaA;;;;;;;GAOG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,uBAAuB,EAAE,MAAM,CAAC;IAChC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,oBAAoB,CAoB9E;AAqGD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,oBAAoB,GAAG,sBAAsB,CA8DtF"}
|
|
@@ -37,7 +37,6 @@ export function parseGenerateTestcaseArgs(argv) {
|
|
|
37
37
|
projectDir: result['project-dir'],
|
|
38
38
|
requirementDir: result['requirement-dir'],
|
|
39
39
|
directUrl: result['direct-url'],
|
|
40
|
-
sourceRoot: result['source-root'],
|
|
41
40
|
};
|
|
42
41
|
}
|
|
43
42
|
/**
|
|
@@ -145,11 +144,7 @@ export function runGenerateTestcase(args) {
|
|
|
145
144
|
if (!directUrl) {
|
|
146
145
|
throw new Error('缺少待测页面 directUrl:请在 /glue-generate-testcase 交互中提供列表页直达地址,或在 code_list.json5 的 pages[role=list].directUrl 中提供。');
|
|
147
146
|
}
|
|
148
|
-
const { contract, testcase, inferenceTrace } = assembleJson5ContractAndTestcase({
|
|
149
|
-
codeList,
|
|
150
|
-
directUrl,
|
|
151
|
-
sourceRoot: args.sourceRoot,
|
|
152
|
-
});
|
|
147
|
+
const { contract, testcase, inferenceTrace } = assembleJson5ContractAndTestcase({ codeList, directUrl });
|
|
153
148
|
if (args.projectDir) {
|
|
154
149
|
testcase.runtimeContext = {
|
|
155
150
|
testProjectDir: args.projectDir,
|
|
@@ -1 +1 @@
|
|
|
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,
|
|
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
|
@@ -34,32 +34,8 @@ export async function main(argv = process.argv) {
|
|
|
34
34
|
].join('\n'));
|
|
35
35
|
return result;
|
|
36
36
|
}
|
|
37
|
-
case 'run':
|
|
38
|
-
|
|
39
|
-
// 结果摘要回显(此前 run 静默退出,自动化无法感知成败)。
|
|
40
|
-
const lines = [
|
|
41
|
-
`spec: ${result.specPath}`,
|
|
42
|
-
`report: ${result.reportDir}`,
|
|
43
|
-
`trace: ${result.aiRuntimeTracePath}`,
|
|
44
|
-
];
|
|
45
|
-
if (result.comprehensiveReportPath) {
|
|
46
|
-
lines.push(`综合报告: ${result.comprehensiveReportPath}`);
|
|
47
|
-
}
|
|
48
|
-
if (result.repairReportPath) {
|
|
49
|
-
lines.push(`repair: ${result.repairReportPath}`);
|
|
50
|
-
}
|
|
51
|
-
if (result.credentialsNotice) {
|
|
52
|
-
lines.push(result.credentialsNotice);
|
|
53
|
-
}
|
|
54
|
-
console.log(lines.join('\n'));
|
|
55
|
-
// 执行失败(已落修补报告)以非 0 退出,对齐 skill 文档「CLI 非 0 退出 → 复述 stderr」契约;
|
|
56
|
-
// 修补流程本身不受影响,人审确认方向后重跑即可。
|
|
57
|
-
if (result.repairReportPath) {
|
|
58
|
-
console.error(`执行失败:已落修补报告 ${result.repairReportPath},待人审确认修补方向`);
|
|
59
|
-
process.exitCode = 1;
|
|
60
|
-
}
|
|
61
|
-
return result;
|
|
62
|
-
}
|
|
37
|
+
case 'run':
|
|
38
|
+
return runRun(parseRunArgs(args));
|
|
63
39
|
case undefined:
|
|
64
40
|
case '--help':
|
|
65
41
|
case '-h':
|
|
@@ -74,18 +50,18 @@ export async function main(argv = process.argv) {
|
|
|
74
50
|
* 打印 CLI help(仅 testcase / spec / run 3 子命令,无 contract)。
|
|
75
51
|
*/
|
|
76
52
|
export function printHelp() {
|
|
77
|
-
console.log(`ep-stage-skill — 胶水测试链路 CLI
|
|
78
|
-
|
|
79
|
-
用法:
|
|
80
|
-
ep-stage-skill testcase --code-list <path> --tests-dir <path> --direct-url <url> [--project-dir <path>] [--requirement-dir <path>]
|
|
81
|
-
ep-stage-skill spec --testcase <path> --out <path>
|
|
82
|
-
ep-stage-skill prepare-tasks --testcase <path>
|
|
83
|
-
ep-stage-skill run --testcase <path> [--ai-snippets <path>] [--headless false]
|
|
84
|
-
|
|
85
|
-
子命令:
|
|
86
|
-
testcase 读取 _docs/code_list.json5 + 生成 contract.json5 / testcase.json5 / inference-trace.json
|
|
87
|
-
spec 基于 testcase.json5 + contract.json5 的 glue cases 生成初始版 .spec.ts(只生成不执行)
|
|
88
|
-
prepare-tasks 组装 glue 骨架并输出 AI Runtime 任务包
|
|
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 任务包
|
|
89
65
|
run 合并 Agent 产出的 ai-snippets.json5 并执行完整 spec`);
|
|
90
66
|
}
|
|
91
67
|
/**
|
package/dist/src/cli/run.d.ts
CHANGED
|
@@ -21,7 +21,6 @@ export type RunArgs = {
|
|
|
21
21
|
* @property version - 'v1':已接入 Agent snippets 合并、spec 执行和 repair 回路。
|
|
22
22
|
* @property aiRuntimeTracePath - 落盘的 .ep-stage/ai-runtime-trace.json5(含 tasks 与 results)。
|
|
23
23
|
* @property repairReportPath - 执行失败时落盘的 repair-report.md;成功时为 undefined。
|
|
24
|
-
* @property comprehensiveReportPath - glue 风格综合报告 <reportDir>/index.html;渲染失败时为 undefined。
|
|
25
24
|
*/
|
|
26
25
|
export type RunResult = {
|
|
27
26
|
specPath: string;
|
|
@@ -30,7 +29,6 @@ export type RunResult = {
|
|
|
30
29
|
version: 'v1';
|
|
31
30
|
aiRuntimeTracePath?: string;
|
|
32
31
|
repairReportPath?: string;
|
|
33
|
-
comprehensiveReportPath?: string;
|
|
34
32
|
};
|
|
35
33
|
/**
|
|
36
34
|
* runRun 的可注入依赖(测试即契约:允许单测替换推理与执行,避免触发真机)。
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/cli/run.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAG/E,OAAO,EAML,KAAK,eAAe,EACpB,KAAK,aAAa,EACnB,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/cli/run.ts"],"names":[],"mappings":"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"}
|
package/dist/src/cli/run.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
2
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import JSON5 from 'json5';
|
|
5
5
|
import { validateTestcase } from '../validation/testcase.js';
|
|
6
6
|
import { classifyRunFailure, createInitialAiRuntimeTrace, nextRepairRound, writeAiRuntimeTrace, writeRepairReport, } from '../runtime/ai-runtime-trace.js';
|
|
7
7
|
import { runSpec } from './spec.js';
|
|
8
|
-
import { parsePlaywrightJsonResults, renderRunReportHtml } from './run-report.js';
|
|
9
8
|
/**
|
|
10
9
|
* AI 追加段分隔标记。重跑时 detect 已有标记则覆盖(保证幂等)。
|
|
11
10
|
*
|
|
@@ -115,18 +114,7 @@ export function resolveRunPaths(testcasePath) {
|
|
|
115
114
|
* @returns 命令、参数与 cwd,供 execFileSync 直接消费。
|
|
116
115
|
*/
|
|
117
116
|
export function buildPlaywrightCommand(input) {
|
|
118
|
-
|
|
119
|
-
// 的绝对路径会被误解析为无效正则。取 basename 并转义正则特殊字符,
|
|
120
|
-
// 构造 `.*<escaped-basename>` 模式,在 testDir 内稳定命中对应 spec。
|
|
121
|
-
const basename = path.basename(input.specPath);
|
|
122
|
-
const escapedBasename = basename.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
123
|
-
const specArg = `.*${escapedBasename}`;
|
|
124
|
-
// 枚举多个 reporter:list 保证控制台有可被 classifyRunFailure 消费的原生输出;
|
|
125
|
-
// json 落机器可读结果(经 PLAYWRIGHT_JSON_OUTPUT_NAME 指定文件)供 glue 风格综合报告渲染;
|
|
126
|
-
// html 与 stage-core reporter 让综合报告(playwright-report / stage-report)随 run 一并生成,
|
|
127
|
-
// 避免执行完还要手工补跑才能拿到汇总报告。CLI --reporter 会整体覆盖项目 config,
|
|
128
|
-
// 所以必须在同一条参数里显式枚举,不能只加 list。
|
|
129
|
-
const args = ['playwright', 'test', specArg, '--reporter=list,json,html,@epoint-testtech/stage-core/reporter'];
|
|
117
|
+
const args = ['playwright', 'test', input.specPath];
|
|
130
118
|
if (!input.headless) {
|
|
131
119
|
args.push('--headed');
|
|
132
120
|
}
|
|
@@ -142,21 +130,22 @@ export function buildPlaywrightCommand(input) {
|
|
|
142
130
|
*/
|
|
143
131
|
async function defaultExecuteFullSpec(input) {
|
|
144
132
|
const cmd = buildPlaywrightCommand(input);
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
133
|
+
let stdout = '';
|
|
134
|
+
let stderr = '';
|
|
135
|
+
let status = 0;
|
|
136
|
+
try {
|
|
137
|
+
stdout = execFileSync(cmd.command, cmd.args, {
|
|
138
|
+
cwd: cmd.cwd,
|
|
139
|
+
encoding: 'utf8',
|
|
140
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
const err = error;
|
|
145
|
+
stdout = err.stdout ?? '';
|
|
146
|
+
stderr = err.stderr ?? '';
|
|
147
|
+
status = err.status ?? 1;
|
|
148
|
+
}
|
|
160
149
|
return { passed: status === 0, output: `${stdout}\n${stderr}` };
|
|
161
150
|
}
|
|
162
151
|
/**
|
|
@@ -509,24 +498,17 @@ export async function runRun(args, deps) {
|
|
|
509
498
|
}
|
|
510
499
|
appendAiSnippets(paths.specPath, aiRuntimeTasks, resolvedResults);
|
|
511
500
|
writeAiRuntimeTrace(tracePath, trace);
|
|
512
|
-
// 报告目录先于执行创建:json reporter 结果文件落这里,供 glue 风格综合报告渲染。
|
|
513
|
-
const reportDir = path.join(paths.projectDir, 'e2e/glue-code-mvp/glue-report', new Date().toISOString().replace(/[:.]/g, '-'));
|
|
514
|
-
mkdirSync(reportDir, { recursive: true });
|
|
515
|
-
const resultsJsonPath = path.join(reportDir, 'playwright-results.json');
|
|
516
501
|
// 执行完整 spec。
|
|
517
502
|
const executor = deps?.executeFullSpec ?? defaultExecuteFullSpec;
|
|
518
503
|
const execution = await executor({
|
|
519
504
|
projectDir: paths.projectDir,
|
|
520
505
|
specPath: paths.specPath,
|
|
521
506
|
headless: args.headless,
|
|
522
|
-
resultsJsonPath,
|
|
523
507
|
});
|
|
524
508
|
// 失败时分类并写 repair report,停止等待人审;成功时 repairReportPath 留空。
|
|
525
509
|
let repairReportPath;
|
|
526
|
-
let failureType;
|
|
527
510
|
if (!execution.passed) {
|
|
528
511
|
const classification = classifyRunFailure(execution.output);
|
|
529
|
-
failureType = classification.failureType;
|
|
530
512
|
const round = nextRepairRound(paths.caseDir);
|
|
531
513
|
repairReportPath = writeRepairReport({
|
|
532
514
|
caseDir: paths.caseDir,
|
|
@@ -543,39 +525,9 @@ export async function runRun(args, deps) {
|
|
|
543
525
|
});
|
|
544
526
|
writeAiRuntimeTrace(tracePath, trace);
|
|
545
527
|
}
|
|
546
|
-
//
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
writeFileSync(path.join(reportDir, 'run-info.json'), `${JSON.stringify({
|
|
550
|
-
specPath: paths.specPath,
|
|
551
|
-
passed: execution.passed,
|
|
552
|
-
failureType,
|
|
553
|
-
repairReportPath,
|
|
554
|
-
executedAt: new Date().toISOString(),
|
|
555
|
-
}, null, 2)}\n`);
|
|
556
|
-
// glue 风格综合报告(index.html):数据来自 Playwright JSON 结果,
|
|
557
|
-
// 覆盖全部用例(含 AI snippet);渲染失败只降级缺省,不阻断主流程。
|
|
558
|
-
let comprehensiveReportPath;
|
|
559
|
-
try {
|
|
560
|
-
if (existsSync(resultsJsonPath)) {
|
|
561
|
-
const parsedResults = parsePlaywrightJsonResults(readFileSync(resultsJsonPath, 'utf8'));
|
|
562
|
-
const html = renderRunReportHtml({
|
|
563
|
-
suiteTitle: parsedResults.suiteTitle,
|
|
564
|
-
startedAt: parsedResults.startedAt,
|
|
565
|
-
durationMs: parsedResults.durationMs,
|
|
566
|
-
specFile: paths.specPath,
|
|
567
|
-
items: parsedResults.items,
|
|
568
|
-
aiTasks: aiRuntimeTasks.map((task) => ({ title: task.title, caseId: task.caseId })),
|
|
569
|
-
playwrightReportHref: '../../../../playwright-report/index.html',
|
|
570
|
-
stageReportHref: '../../../../stage-report/report.pdf',
|
|
571
|
-
});
|
|
572
|
-
comprehensiveReportPath = path.join(reportDir, 'index.html');
|
|
573
|
-
writeFileSync(comprehensiveReportPath, html);
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
catch {
|
|
577
|
-
comprehensiveReportPath = undefined;
|
|
578
|
-
}
|
|
528
|
+
// 报告目录。
|
|
529
|
+
const reportDir = path.join(paths.projectDir, 'e2e/glue-code-mvp/glue-report', new Date().toISOString().replace(/[:.]/g, '-'));
|
|
530
|
+
mkdirSync(reportDir, { recursive: true });
|
|
579
531
|
// credentials.json5 消费边界声明。
|
|
580
532
|
const credentialsNotice = loadCredentialsNotice(testcase, paths.testcasePath);
|
|
581
533
|
return {
|
|
@@ -585,6 +537,5 @@ export async function runRun(args, deps) {
|
|
|
585
537
|
version: 'v1',
|
|
586
538
|
aiRuntimeTracePath: tracePath,
|
|
587
539
|
repairReportPath,
|
|
588
|
-
comprehensiveReportPath,
|
|
589
540
|
};
|
|
590
541
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spec.d.ts","sourceRoot":"","sources":["../../../src/cli/spec.ts"],"names":[],"mappings":"AASA;;;;;GAKG;AACH,MAAM,MAAM,QAAQ,GAAG;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,IAAI,CAAC;CACf,CAAC;AAiCF;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,CActD;AAcD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,QAAQ,GAAG,UAAU,
|
|
1
|
+
{"version":3,"file":"spec.d.ts","sourceRoot":"","sources":["../../../src/cli/spec.ts"],"names":[],"mappings":"AASA;;;;;GAKG;AACH,MAAM,MAAM,QAAQ,GAAG;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,IAAI,CAAC;CACf,CAAC;AAiCF;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,CActD;AAcD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,QAAQ,GAAG,UAAU,CA6ClD"}
|
package/dist/src/cli/spec.js
CHANGED
|
@@ -101,7 +101,6 @@ export function runSpec(args) {
|
|
|
101
101
|
// skeletonSlots.crud 形态对齐 StageSkeletonCrudFlowSlots(见 glue-contract-v1.ts 注释)。
|
|
102
102
|
const crudSlots = contract.scenario.skeletonSlots.crud;
|
|
103
103
|
const exportSlot = contract.scenario.skeletonSlots.export;
|
|
104
|
-
const childGridSlots = (contract.scenario.skeletonSlots.childGrids ?? []);
|
|
105
104
|
const directUrl = contract.base?.navigation?.directUrl ?? '';
|
|
106
105
|
if (!directUrl) {
|
|
107
106
|
throw new Error('contract.base.navigation.directUrl 缺失。glue 主链路已切换为直达链接模式,请重跑 `/glue-generate-testcase` 补齐 --direct-url 后再生成 spec。');
|
|
@@ -119,14 +118,6 @@ export function runSpec(args) {
|
|
|
119
118
|
requirementName,
|
|
120
119
|
crudSlots,
|
|
121
120
|
exportSlot,
|
|
122
|
-
childGridSlots,
|
|
123
|
-
glueCases: (testcase.cases ?? []).map((testCase) => ({
|
|
124
|
-
caseId: testCase.caseId,
|
|
125
|
-
title: testCase.title,
|
|
126
|
-
precondition: testCase.precondition,
|
|
127
|
-
steps: testCase.steps,
|
|
128
|
-
assertion: testCase.assertion,
|
|
129
|
-
})),
|
|
130
121
|
});
|
|
131
122
|
const body = `${SKELETON_MARKER_LINE}\n${script}`;
|
|
132
123
|
mkdirSync(path.dirname(args.out), { recursive: true });
|
|
@@ -12,40 +12,6 @@
|
|
|
12
12
|
* - ai:AI Agent 推理产出
|
|
13
13
|
*/
|
|
14
14
|
export type GenerationStrategy = 'glue' | 'ai';
|
|
15
|
-
/**
|
|
16
|
-
* 子表列槽位。
|
|
17
|
-
*/
|
|
18
|
-
export type ChildGridColumnSlot = {
|
|
19
|
-
field: string;
|
|
20
|
-
label: string;
|
|
21
|
-
component: 'input' | 'listbox';
|
|
22
|
-
required: boolean;
|
|
23
|
-
modelRef?: string;
|
|
24
|
-
};
|
|
25
|
-
/**
|
|
26
|
-
* 子表槽位。
|
|
27
|
-
*/
|
|
28
|
-
export type ChildGridFlowSlot = {
|
|
29
|
-
gridId: string;
|
|
30
|
-
label: string;
|
|
31
|
-
pageRole: 'add' | 'edit';
|
|
32
|
-
editMode: 'cell_edit' | 'row_button_dialog' | 'none';
|
|
33
|
-
columns: ChildGridColumnSlot[];
|
|
34
|
-
addRowButtonLabel?: string;
|
|
35
|
-
deleteSelectedButtonLabel?: string;
|
|
36
|
-
locators: {
|
|
37
|
-
container: string;
|
|
38
|
-
addRowButton: string;
|
|
39
|
-
deleteSelectedButton: string;
|
|
40
|
-
grid: string;
|
|
41
|
-
editWrapInput: string;
|
|
42
|
-
editWrapListboxTrigger: string;
|
|
43
|
-
editWrapListboxInput: string;
|
|
44
|
-
rowCheckboxByIndex: string;
|
|
45
|
-
cellByIndexAndField: string;
|
|
46
|
-
cellValueByIndexAndField: string;
|
|
47
|
-
};
|
|
48
|
-
};
|
|
49
15
|
/**
|
|
50
16
|
* contract.json5 v1-draft 顶层类型。
|
|
51
17
|
*
|
|
@@ -85,7 +51,6 @@ export type EpStageContractV1Draft = {
|
|
|
85
51
|
label: string;
|
|
86
52
|
mode: string;
|
|
87
53
|
};
|
|
88
|
-
childGrids?: ChildGridFlowSlot[];
|
|
89
54
|
};
|
|
90
55
|
gapCandidates: Array<{
|
|
91
56
|
gapId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glue-contract-v1.d.ts","sourceRoot":"","sources":["../../../src/contracts/glue-contract-v1.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,IAAI,CAAC;AAE/C
|
|
1
|
+
{"version":3,"file":"glue-contract-v1.d.ts","sourceRoot":"","sources":["../../../src/contracts/glue-contract-v1.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,IAAI,CAAC;AAE/C;;;;;GAKG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,aAAa,EAAE,4BAA4B,CAAC;IAC5C,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE;QACJ,MAAM,EAAE;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC;QACtC,UAAU,EAAE;YAAE,SAAS,EAAE,WAAW,GAAG,MAAM,CAAC;YAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;YAAC,SAAS,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QACvF,WAAW,EAAE;YAAE,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC;KACjC,CAAC;IACF,QAAQ,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,YAAY,EAAE,KAAK,CAAC;YAClB,KAAK,EAAE,MAAM,CAAC;YACd,KAAK,EAAE,MAAM,CAAC;YACd,SAAS,EAAE,MAAM,CAAC;YAClB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;SAC1B,CAAC,CAAC;QACH,aAAa,EAAE;YAEb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YAC9B,MAAM,EAAE;gBAAE,QAAQ,EAAE,MAAM,CAAC;gBAAC,KAAK,EAAE,MAAM,CAAC;gBAAC,IAAI,EAAE,MAAM,CAAA;aAAE,CAAC;SAC3D,CAAC;QACF,aAAa,EAAE,KAAK,CAAC;YACnB,KAAK,EAAE,MAAM,CAAC;YACd,KAAK,EAAE,MAAM,CAAC;YACd,kBAAkB,EAAE,kBAAkB,CAAC;SACxC,CAAC,CAAC;KACJ,CAAC;IACF,eAAe,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACjD,CAAC"}
|