@kkeve/suite 0.0.1 → 0.0.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.
Files changed (152) hide show
  1. package/README.md +53 -0
  2. package/dist/bin/keve.d.ts +13 -0
  3. package/dist/bin/keve.js +164 -0
  4. package/dist/commands/auth-update.d.ts +16 -0
  5. package/dist/commands/auth-update.js +88 -0
  6. package/dist/commands/clean.d.ts +10 -0
  7. package/dist/commands/clean.js +78 -0
  8. package/dist/commands/config.d.ts +17 -0
  9. package/dist/commands/config.js +99 -0
  10. package/dist/commands/init.d.ts +15 -0
  11. package/dist/commands/init.js +292 -0
  12. package/dist/commands/report.d.ts +12 -0
  13. package/dist/commands/report.js +159 -0
  14. package/dist/commands/run.d.ts +29 -0
  15. package/dist/commands/run.js +417 -0
  16. package/dist/commands/test.d.ts +12 -0
  17. package/dist/commands/test.js +102 -0
  18. package/dist/commands/vitest.d.ts +14 -0
  19. package/dist/commands/vitest.js +166 -0
  20. package/dist/config.d.ts +109 -0
  21. package/dist/config.js +291 -0
  22. package/dist/core/action-log-writer.d.ts +47 -0
  23. package/dist/{tools/write-file.js → core/action-log-writer.js} +42 -26
  24. package/dist/core/auth.d.ts +17 -0
  25. package/dist/core/auth.js +224 -0
  26. package/dist/core/cdp-resolver.d.ts +5 -0
  27. package/dist/core/cdp-resolver.js +93 -0
  28. package/dist/core/generateReport/report.d.ts +19 -0
  29. package/dist/core/generateReport/report.js +91 -0
  30. package/dist/core/generateReport/reportData.d.ts +215 -0
  31. package/dist/core/generateReport/reportData.js +735 -0
  32. package/dist/core/global-setup.d.ts +6 -0
  33. package/dist/core/global-setup.js +113 -0
  34. package/dist/core/keve-aspect.d.ts +54 -0
  35. package/dist/core/keve-aspect.js +52 -0
  36. package/dist/core/keve-decorators.d.ts +51 -0
  37. package/dist/core/keve-decorators.js +95 -0
  38. package/dist/core/keve-registry.d.ts +38 -0
  39. package/dist/core/keve-registry.js +25 -0
  40. package/dist/core/keve-report.d.ts +27 -0
  41. package/dist/core/keve-report.js +357 -0
  42. package/dist/core/keve-test.d.ts +36 -0
  43. package/dist/core/keve-test.js +364 -0
  44. package/dist/core/learned-actions.d.ts +24 -0
  45. package/dist/core/learned-actions.js +65 -0
  46. package/dist/core/pw-config.d.ts +19 -0
  47. package/dist/core/pw-config.js +180 -0
  48. package/dist/index.d.ts +8 -23
  49. package/dist/index.js +36 -43
  50. package/dist/page-agent/agent.d.ts +129 -0
  51. package/dist/page-agent/agent.js +585 -0
  52. package/dist/page-agent/hooks.d.ts +13 -0
  53. package/dist/page-agent/hooks.js +218 -0
  54. package/dist/page-agent/tools.d.ts +29 -0
  55. package/dist/page-agent/tools.js +297 -0
  56. package/doc/README.md +124 -0
  57. package/doc/agents/keve-dev-test-agent.md +140 -0
  58. package/doc/agents/keve-test-agent.md +178 -0
  59. package/doc/asserts//346/265/213/350/257/225/345/220/204/351/230/266/346/256/265/350/257/264/346/230/216.png +0 -0
  60. package/doc/keve-agent-demo.html +370 -0
  61. package/doc/skills/keve-bddcase-gen/SKILL.md +332 -0
  62. package/doc/skills/keve-bddcase-gen/references/test-case-rules.md +91 -0
  63. package/doc/skills/keve-bddcase-gen/references/test-cases-example.md +103 -0
  64. package/doc/skills/keve-component-gen/SKILL.md +255 -0
  65. package/doc/skills/keve-component-gen/references/component-mock-strategy.md +74 -0
  66. package/doc/skills/keve-component-gen/references/component-model-template.md +98 -0
  67. package/doc/skills/keve-component-gen/references/component-test-template.md +100 -0
  68. package/doc/skills/keve-component-gen/references/vue-test-utils-guide.md +91 -0
  69. package/doc/skills/keve-e2e-gen/SKILL.md +179 -0
  70. package/doc/skills/keve-e2e-gen/references/code-analysis-guide.md +208 -0
  71. package/doc/skills/keve-e2e-gen/references/decisions.md +36 -0
  72. package/doc/skills/keve-e2e-gen/references/pom-generation-guide.md +140 -0
  73. package/doc/skills/keve-e2e-gen/references/script-generation-guide.md +236 -0
  74. package/doc/skills/keve-e2e-gen/references/test-auditor-guide.md +189 -0
  75. package/doc/skills/keve-e2e-gen/scripts/extract-components.sh +85 -0
  76. package/doc/skills/keve-e2e-gen/scripts/inject-testids.sh +95 -0
  77. package/doc/skills/keve-static-analysis/SKILL.md +362 -0
  78. package/doc/skills/keve-static-analysis/references/codegraph-analysis-guide.md +108 -0
  79. package/doc/skills/keve-static-analysis/references/git-impact-analysis.md +81 -0
  80. package/doc/skills/keve-static-analysis/references/lint-fix-guide.md +69 -0
  81. package/doc/skills/keve-static-analysis/references/runtime-risk-patterns.md +92 -0
  82. package/doc/skills/keve-static-analysis/references/security-scan-guide.md +32 -0
  83. package/doc/skills/keve-static-analysis/references/ts-error-patterns.md +98 -0
  84. package/doc/skills/keve-static-analysis/references/vue-security-guide.md +72 -0
  85. package/doc/skills/keve-test-eval/SKILL.md +78 -0
  86. package/doc/skills/keve-test-eval/references/common-fix-guide.md +166 -0
  87. package/doc/skills/keve-test-eval/references/confidence-data-guide.md +78 -0
  88. package/doc/skills/keve-test-eval/references/fix-loop-guide.md +67 -0
  89. package/doc/skills/keve-unit-gen/SKILL.md +203 -0
  90. package/doc/skills/keve-unit-gen/references/boundary-conditions.md +78 -0
  91. package/doc/skills/keve-unit-gen/references/unit-mock-strategy.md +71 -0
  92. package/doc/skills/keve-unit-gen/references/unit-test-template.md +105 -0
  93. package/package.json +47 -25
  94. package/dist/agent/factory.d.ts +0 -25
  95. package/dist/agent/factory.js +0 -99
  96. package/dist/agent/index.d.ts +0 -3
  97. package/dist/agent/index.js +0 -7
  98. package/dist/agent/loader.d.ts +0 -22
  99. package/dist/agent/loader.js +0 -117
  100. package/dist/agent/types.d.ts +0 -9
  101. package/dist/agent/types.js +0 -2
  102. package/dist/agent-loop/complete-task.d.ts +0 -28
  103. package/dist/agent-loop/complete-task.js +0 -70
  104. package/dist/agent-loop/index.d.ts +0 -16
  105. package/dist/agent-loop/index.js +0 -26
  106. package/dist/agent-loop/loop.d.ts +0 -42
  107. package/dist/agent-loop/loop.js +0 -282
  108. package/dist/agent-loop/runtime.d.ts +0 -40
  109. package/dist/agent-loop/runtime.js +0 -163
  110. package/dist/agent-loop/types.d.ts +0 -161
  111. package/dist/agent-loop/types.js +0 -105
  112. package/dist/context/index.d.ts +0 -8
  113. package/dist/context/index.js +0 -29
  114. package/dist/context/tokenCalculation.d.ts +0 -55
  115. package/dist/context/tokenCalculation.js +0 -95
  116. package/dist/context/truncation.d.ts +0 -67
  117. package/dist/context/truncation.js +0 -142
  118. package/dist/context/types.d.ts +0 -7
  119. package/dist/context/types.js +0 -27
  120. package/dist/llm/OpenAIClient.d.ts +0 -31
  121. package/dist/llm/OpenAIClient.js +0 -455
  122. package/dist/llm/constants.d.ts +0 -2
  123. package/dist/llm/constants.js +0 -6
  124. package/dist/llm/errors.d.ts +0 -25
  125. package/dist/llm/errors.js +0 -51
  126. package/dist/llm/index.d.ts +0 -49
  127. package/dist/llm/index.js +0 -158
  128. package/dist/llm/types.d.ts +0 -124
  129. package/dist/llm/types.js +0 -2
  130. package/dist/llm/utils.d.ts +0 -29
  131. package/dist/llm/utils.js +0 -284
  132. package/dist/skill/frontmatter-parser.d.ts +0 -50
  133. package/dist/skill/frontmatter-parser.js +0 -152
  134. package/dist/skill/index.d.ts +0 -12
  135. package/dist/skill/index.js +0 -17
  136. package/dist/skill/loader.d.ts +0 -96
  137. package/dist/skill/loader.js +0 -256
  138. package/dist/tools/ask-user.d.ts +0 -8
  139. package/dist/tools/ask-user.js +0 -47
  140. package/dist/tools/bash.d.ts +0 -47
  141. package/dist/tools/bash.js +0 -213
  142. package/dist/tools/edit-file.d.ts +0 -9
  143. package/dist/tools/edit-file.js +0 -76
  144. package/dist/tools/glob.d.ts +0 -8
  145. package/dist/tools/glob.js +0 -101
  146. package/dist/tools/grep.d.ts +0 -10
  147. package/dist/tools/grep.js +0 -76
  148. package/dist/tools/index.d.ts +0 -24
  149. package/dist/tools/index.js +0 -47
  150. package/dist/tools/read-files.d.ts +0 -8
  151. package/dist/tools/read-files.js +0 -81
  152. package/dist/tools/write-file.d.ts +0 -8
@@ -0,0 +1,292 @@
1
+ "use strict";
2
+ /**
3
+ * keve init - Initialize .keve/ directory and inject Skills
4
+ *
5
+ * Creates the .keve/ workspace, Playwright infrastructure,
6
+ * and copies keve skills into .codeflicker/skills/.
7
+ *
8
+ * Note: keveAssert is exported directly from @ks-data/keve-suite (import { keveAssert } from '@ks-data/keve-suite')
9
+ * — no file needs to be written to the project.
10
+ */
11
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ var desc = Object.getOwnPropertyDescriptor(m, k);
14
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
15
+ desc = { enumerable: true, get: function() { return m[k]; } };
16
+ }
17
+ Object.defineProperty(o, k2, desc);
18
+ }) : (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ o[k2] = m[k];
21
+ }));
22
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
23
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
24
+ }) : function(o, v) {
25
+ o["default"] = v;
26
+ });
27
+ var __importStar = (this && this.__importStar) || (function () {
28
+ var ownKeys = function(o) {
29
+ ownKeys = Object.getOwnPropertyNames || function (o) {
30
+ var ar = [];
31
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
32
+ return ar;
33
+ };
34
+ return ownKeys(o);
35
+ };
36
+ return function (mod) {
37
+ if (mod && mod.__esModule) return mod;
38
+ var result = {};
39
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
40
+ __setModuleDefault(result, mod);
41
+ return result;
42
+ };
43
+ })();
44
+ var __importDefault = (this && this.__importDefault) || function (mod) {
45
+ return (mod && mod.__esModule) ? mod : { "default": mod };
46
+ };
47
+ Object.defineProperty(exports, "__esModule", { value: true });
48
+ exports.init = init;
49
+ const fs = __importStar(require("node:fs"));
50
+ const os = __importStar(require("node:os"));
51
+ const path = __importStar(require("node:path"));
52
+ const chalk_1 = __importDefault(require("chalk"));
53
+ const pw_config_1 = require("../core/pw-config");
54
+ // Skills bundled in this package — copied to global ~/.codeflicker/skills/
55
+ const KEVE_SKILLS = [
56
+ 'keve-bddcase-gen',
57
+ 'keve-e2e-gen',
58
+ 'keve-test-eval',
59
+ 'keve-static-analysis',
60
+ 'keve-unit-gen',
61
+ 'keve-component-gen',
62
+ ];
63
+ // Agents bundled in this package — copied to global ~/.codeflicker/agents/
64
+ const KEVE_AGENTS = [
65
+ 'keve-test-agent',
66
+ 'keve-dev-test-agent',
67
+ ];
68
+ const KEVE_YAML_TEMPLATE = `# ━━━ 目录结构规范(Single Source of Truth)━━━━━━━━━━━━━━━━━
69
+ # 输入端 → keve_test_spec/(跨 MR 共享,项目长期资产,git tracked)
70
+ # keve.yaml ← 本文件(全局配置 + 目录约定)
71
+ # keve-test.config.ts ← Playwright 配置
72
+ # vitest.config.ts ← Vitest 配置
73
+ # e2e/poms/ ← POM 类
74
+ # e2e/locator-catalog.json ← 定位器目录
75
+ # e2e/__test__/ ← E2E 测试脚本 *.spec.ts
76
+ # component/models/ ← 组件行为模型 *.model.ts(场景+Props+断言,即组件 fixture)
77
+ # component/__test__/ ← 组件测试脚本 *.test.ts(引用 model)
78
+ # component/registry.json ← 组件注册表
79
+ # component/coverage.yaml ← 组件测试覆盖索引
80
+ # util/__test__/ ← 单元测试脚本 *.test.ts
81
+ # 输出端 → .keve/(执行产物,gitignored)
82
+ # coverage/ ← vitest --coverage 报告(HTML/JSON)
83
+ # analysis-report.yaml ← 静态分析结果
84
+ # analysis-report.html ← 静态分析可视化报告
85
+ # test-plan.yaml ← 全流程进度追踪
86
+ # MR 级模块 → .keve/{branch}/
87
+ # test-cases.yaml ← BDD 用例定义
88
+ # test-artifacts/ ← E2E 执行产物(round-N/, latest/, confidence-data.jsonl)
89
+ # {MR_ID} 替换规则:KEVE_TASK_DIR=.keve/MR123 或默认 .keve/current
90
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
91
+
92
+ project:
93
+ name: '' # 项目名称
94
+
95
+ state:
96
+ current_round: 0
97
+ # last_run_at: auto
98
+
99
+ llm:
100
+ model: app-xxx
101
+ base_url: https://xxx
102
+ # api_key: from env KEVE_LLM_API_KEY
103
+
104
+ keveAPI: https://xxx
105
+ openAPI: https://xxx
106
+
107
+ execution:
108
+ timeout_ms: 1200000
109
+ retries: 0
110
+ reporter: json
111
+ screenshot: only-on-failure
112
+ `;
113
+ const VITEST_CONFIG_TEMPLATE = `import { defineConfig } from 'vitest/config';
114
+ import vue from '@vitejs/plugin-vue';
115
+ import * as path from 'node:path';
116
+
117
+ const projectRoot = path.resolve(__dirname, '..');
118
+
119
+ // Shared resolve config — applied to all projects
120
+ const sharedResolve = {
121
+ alias: {
122
+ '@': path.resolve(projectRoot, 'src'),
123
+ '@/keve_test_spec': path.resolve(projectRoot, 'keve_test_spec'),
124
+ },
125
+ };
126
+
127
+ export default defineConfig({
128
+ plugins: [vue()],
129
+ resolve: sharedResolve,
130
+ test: {
131
+ // Multi-project: unit (node) + component (jsdom)
132
+ projects: [
133
+ {
134
+ resolve: sharedResolve,
135
+ plugins: [vue()],
136
+ test: {
137
+ name: 'unit',
138
+ environment: 'node',
139
+ include: ['keve_test_spec/util/__test__/**/*.test.ts'],
140
+ },
141
+ },
142
+ {
143
+ resolve: sharedResolve,
144
+ plugins: [vue()],
145
+ test: {
146
+ name: 'component',
147
+ environment: 'jsdom',
148
+ include: ['keve_test_spec/component/__test__/**/*.test.ts'],
149
+ setupFiles: [],
150
+ },
151
+ },
152
+ ],
153
+ coverage: {
154
+ provider: 'v8',
155
+ reporter: ['json', 'text', 'html'],
156
+ reportsDirectory: path.join(projectRoot, '.keve', 'coverage'),
157
+ include: ['src/utils/**', 'src/hooks/**', 'src/composables/**', 'src/components/**'],
158
+ },
159
+ },
160
+ });
161
+ `;
162
+ function copyDirRecursive(src, dest) {
163
+ if (!fs.existsSync(dest))
164
+ fs.mkdirSync(dest, { recursive: true });
165
+ const entries = fs.readdirSync(src, { withFileTypes: true });
166
+ for (const entry of entries) {
167
+ const srcPath = path.join(src, entry.name);
168
+ const destPath = path.join(dest, entry.name);
169
+ if (entry.isDirectory()) {
170
+ copyDirRecursive(srcPath, destPath);
171
+ }
172
+ else {
173
+ fs.copyFileSync(srcPath, destPath);
174
+ }
175
+ }
176
+ }
177
+ async function init(options) {
178
+ const cwd = process.cwd();
179
+ const keveDir = path.join(cwd, '.keve');
180
+ console.log(chalk_1.default.cyan('\n🔧 keve init\n'));
181
+ // Check if .keve already exists
182
+ if (fs.existsSync(keveDir) && !options.force) {
183
+ console.log(chalk_1.default.yellow(' ⚠ .keve/ already exists. Use --force to overwrite.'));
184
+ console.log(chalk_1.default.gray(' Existing config preserved.'));
185
+ }
186
+ // Create directories — shared modules in project root, MR-specific under .keve/
187
+ const dirs = [
188
+ keveDir,
189
+ // Shared: keve_test_spec/ (cross-MR, long-term assets)
190
+ path.join(cwd, 'keve_test_spec'),
191
+ // E2E
192
+ path.join(cwd, 'keve_test_spec', 'e2e', 'poms'),
193
+ path.join(cwd, 'keve_test_spec', 'e2e', '__test__'),
194
+ // Component
195
+ path.join(cwd, 'keve_test_spec', 'component', 'models'),
196
+ path.join(cwd, 'keve_test_spec', 'component', '__test__'),
197
+ // Unit
198
+ path.join(cwd, 'keve_test_spec', 'util', '__test__'),
199
+ ];
200
+ for (const dir of dirs) {
201
+ if (!fs.existsSync(dir)) {
202
+ fs.mkdirSync(dir, { recursive: true });
203
+ console.log(chalk_1.default.gray(` Created: ${path.relative(cwd, dir)}`));
204
+ }
205
+ else {
206
+ console.log(chalk_1.default.gray(` Exists: ${path.relative(cwd, dir)}`));
207
+ }
208
+ }
209
+ // Copy keve skills into global ~/.codeflicker/skills/
210
+ // Skills live in <package-root>/doc/skills/ (sibling of dist/)
211
+ // __dirname points to dist/commands/, so go up 2 levels to package root
212
+ const packageRoot = path.resolve(__dirname, '..', '..');
213
+ const skillsSourceDir = path.join(packageRoot, 'doc/skills');
214
+ const skillsTargetDir = path.join(cwd, '.codeflicker', 'skills');
215
+ for (const skillName of KEVE_SKILLS) {
216
+ const srcDir = path.join(skillsSourceDir, skillName);
217
+ const destDir = path.join(skillsTargetDir, skillName);
218
+ if (!fs.existsSync(srcDir)) {
219
+ console.log(chalk_1.default.yellow(` ⚠ Skill source not found: ${skillName} (skipping)`));
220
+ continue;
221
+ }
222
+ // Copy entire skill directory recursively
223
+ copyDirRecursive(srcDir, destDir);
224
+ console.log(chalk_1.default.green(` ✓ Installed Skill: ${skillName}`));
225
+ }
226
+ // Copy keve agents into global ~/.codeflicker/agents/
227
+ const agentsSourceDir = path.join(packageRoot, 'doc/agents');
228
+ const agentsTargetDir = path.join(os.homedir(), '.codeflicker', 'agents');
229
+ for (const agentName of KEVE_AGENTS) {
230
+ const srcFile = path.join(agentsSourceDir, `${agentName}.md`);
231
+ const destFile = path.join(agentsTargetDir, `${agentName}.md`);
232
+ if (!fs.existsSync(srcFile)) {
233
+ console.log(chalk_1.default.yellow(` ⚠ Agent source not found: ${agentName} (skipping)`));
234
+ continue;
235
+ }
236
+ fs.mkdirSync(agentsTargetDir, { recursive: true });
237
+ fs.copyFileSync(srcFile, destFile);
238
+ console.log(chalk_1.default.green(` ✓ Installed Agent: ${agentName}`));
239
+ }
240
+ // Write keve.yaml(with directory spec comments)
241
+ const keveYamlPath = path.join(cwd, 'keve_test_spec', 'keve.yaml');
242
+ if (!fs.existsSync(keveYamlPath) || options.force) {
243
+ fs.writeFileSync(keveYamlPath, KEVE_YAML_TEMPLATE, 'utf-8');
244
+ console.log(chalk_1.default.green(' ✓ Created keve.yaml (with directory spec)'));
245
+ }
246
+ else {
247
+ console.log(chalk_1.default.gray(' Exists: keve.yaml (preserved)'));
248
+ }
249
+ // Write Playwright config
250
+ const pwConfigPath = path.join(cwd, 'keve_test_spec', 'keve-test.config.ts');
251
+ const pwOptions = {
252
+ baseUrl: options.baseUrl || process.env.BASE_URL || process.env.PWGEN_TARGET_URL,
253
+ cdp: options.cdp,
254
+ webServer: !options.cdp,
255
+ };
256
+ if (!fs.existsSync(pwConfigPath) || options.force) {
257
+ fs.writeFileSync(pwConfigPath, (0, pw_config_1.generatePwConfig)(pwOptions), 'utf-8');
258
+ console.log(chalk_1.default.green(' ✓ Created keve-test.config.ts'));
259
+ console.log(chalk_1.default.gray(` baseURL: ${pwOptions.baseUrl || '(from env)'}`));
260
+ console.log(chalk_1.default.gray(` CDP: ${pwOptions.cdp ? 'enabled' : 'disabled'}`));
261
+ }
262
+ else {
263
+ const existingContent = fs.readFileSync(pwConfigPath, 'utf-8');
264
+ if (!existingContent.includes('keve-report') && !existingContent.includes('KeveReporter')) {
265
+ console.log(chalk_1.default.yellow(' ⚠ keve-test.config.ts exists but missing KeveReporter'));
266
+ console.log(chalk_1.default.gray(' Run: keve config --force to regenerate'));
267
+ }
268
+ else {
269
+ console.log(chalk_1.default.gray(' Exists: keve-test.config.ts (preserved)'));
270
+ }
271
+ }
272
+ // Write Vitest config
273
+ const vitestConfigPath = path.join(cwd, 'keve_test_spec', 'vitest.config.ts');
274
+ if (!fs.existsSync(vitestConfigPath) || options.force) {
275
+ fs.writeFileSync(vitestConfigPath, VITEST_CONFIG_TEMPLATE, 'utf-8');
276
+ console.log(chalk_1.default.green(' ✓ Created vitest.config.ts'));
277
+ }
278
+ else {
279
+ console.log(chalk_1.default.gray(' Exists: vitest.config.ts (preserved)'));
280
+ }
281
+ // Note: keveAssert is exported from @ks-data/keve-suite directly
282
+ // No file needs to be written — users import it:
283
+ // import { keveAssert } from '@ks-data/keve-suite';
284
+ console.log(chalk_1.default.gray(' ⓘ keveAssert available via: import { keveAssert } from "@ks-data/keve-suite"'));
285
+ console.log(chalk_1.default.green('\n ✓ keve init complete'));
286
+ console.log(chalk_1.default.gray('\n Next steps:'));
287
+ console.log(chalk_1.default.gray(' 1. keve dev-test — 静态分析 + 单测 + 组件测试(开发阶段)'));
288
+ console.log(chalk_1.default.gray(' 2. keve bddcase — 生成 BDD 测试用例'));
289
+ console.log(chalk_1.default.gray(' 3. keve e2e-gen — 生成 Playwright E2E 脚本'));
290
+ console.log(chalk_1.default.gray(' 4. keve run — 执行 E2E + 评估 + 报告'));
291
+ console.log(chalk_1.default.gray(' 5. npx playwright install — 安装 Playwright 浏览器(首次)\n'));
292
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * keve report - Generate report-data.json
3
+ *
4
+ * Usually called automatically by `keve run` after test execution.
5
+ * Only generates report-data.json — frontend Vue report page consumes this.
6
+ */
7
+ export interface ReportOptions {
8
+ results?: string;
9
+ cases?: string;
10
+ round?: string;
11
+ }
12
+ export declare function report(options: ReportOptions): Promise<void>;
@@ -0,0 +1,159 @@
1
+ "use strict";
2
+ /**
3
+ * keve report - Generate report-data.json
4
+ *
5
+ * Usually called automatically by `keve run` after test execution.
6
+ * Only generates report-data.json — frontend Vue report page consumes this.
7
+ */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
21
+ }) : function(o, v) {
22
+ o["default"] = v;
23
+ });
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ var __importDefault = (this && this.__importDefault) || function (mod) {
42
+ return (mod && mod.__esModule) ? mod : { "default": mod };
43
+ };
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.report = report;
46
+ const fs = __importStar(require("node:fs"));
47
+ const path = __importStar(require("node:path"));
48
+ const chalk_1 = __importDefault(require("chalk"));
49
+ const config_1 = require("../config");
50
+ const index_1 = require("../index");
51
+ /**
52
+ * Resolve paths for report inputs
53
+ */
54
+ function resolvePaths(options) {
55
+ const keveDir = (0, config_1.findKeveDir)();
56
+ // Determine round
57
+ let round = null;
58
+ if (options.round) {
59
+ round = parseInt(options.round, 10);
60
+ }
61
+ else if (keveDir) {
62
+ const branchDir = (0, config_1.getBranchDir)(keveDir);
63
+ const artifactsBase = branchDir ? path.join(branchDir, 'test-artifacts') : path.join(keveDir, 'test-artifacts');
64
+ if (fs.existsSync(artifactsBase)) {
65
+ const dirs = fs.readdirSync(artifactsBase)
66
+ .filter(d => d.startsWith('round-'))
67
+ .map(d => parseInt(d.replace('round-', ''), 10))
68
+ .filter(n => !isNaN(n));
69
+ if (dirs.length > 0)
70
+ round = Math.max(...dirs);
71
+ }
72
+ }
73
+ // Resolve test-results.json
74
+ let resultsPath = options.results;
75
+ if (!resultsPath && keveDir && round !== null) {
76
+ const branchDir = (0, config_1.getBranchDir)(keveDir);
77
+ const resultBase = branchDir ? path.join(branchDir, 'test-artifacts', `round-${round}`) : path.join(keveDir, 'test-artifacts', `round-${round}`);
78
+ const candidate = path.join(resultBase, 'test-results.json');
79
+ if (fs.existsSync(candidate))
80
+ resultsPath = candidate;
81
+ }
82
+ // Resolve test-cases.yaml
83
+ let casesPath = options.cases;
84
+ if (!casesPath && keveDir) {
85
+ const candidates = [
86
+ path.join(keveDir, 'test-cases.yaml'),
87
+ path.join(process.cwd(), 'keve_test_spec', 'test-cases.yaml'),
88
+ ];
89
+ for (const c of candidates) {
90
+ if (fs.existsSync(c)) {
91
+ casesPath = c;
92
+ break;
93
+ }
94
+ }
95
+ }
96
+ // Resolve confidence-data.jsonl
97
+ let confidencePath = '';
98
+ if (keveDir && round !== null) {
99
+ const branchDir = (0, config_1.getBranchDir)(keveDir);
100
+ const resultBase = branchDir ? path.join(branchDir, 'test-artifacts', `round-${round}`) : path.join(keveDir, 'test-artifacts', `round-${round}`);
101
+ const candidate = path.join(resultBase, 'confidence-data.jsonl');
102
+ if (fs.existsSync(candidate))
103
+ confidencePath = candidate;
104
+ }
105
+ return { resultsPath, casesPath, confidencePath, round, keveDir };
106
+ }
107
+ /**
108
+ * Generate report-data.json only
109
+ */
110
+ async function invokeReport(options) {
111
+ const { resultsPath, casesPath, confidencePath, keveDir } = resolvePaths(options);
112
+ if (!resultsPath || !fs.existsSync(resultsPath)) {
113
+ console.error(chalk_1.default.red(' ✗ test-results.json not found'));
114
+ console.error(chalk_1.default.gray(` Use --results to specify path`));
115
+ process.exit(1);
116
+ }
117
+ const projectRoot = keveDir || path.dirname(resultsPath);
118
+ console.log(chalk_1.default.cyan('\n📊 keve report\n'));
119
+ try {
120
+ const reportData = await (0, index_1.generateReportData)({
121
+ projectRoot,
122
+ resultsPath,
123
+ confidencePath: confidencePath || undefined,
124
+ casesPath: casesPath || undefined,
125
+ });
126
+ const roundDir = reportData.roundDir;
127
+ const latestDir = reportData.latestDir;
128
+ fs.mkdirSync(roundDir, { recursive: true });
129
+ // 只写 round-N/report-data.json
130
+ const json = JSON.stringify(reportData, null, 2);
131
+ fs.writeFileSync(path.join(roundDir, 'report-data.json'), json);
132
+ // latest → round-N symlink
133
+ try {
134
+ if (fs.existsSync(latestDir)) {
135
+ const stat = fs.lstatSync(latestDir);
136
+ if (stat.isSymbolicLink()) {
137
+ fs.unlinkSync(latestDir);
138
+ }
139
+ else {
140
+ fs.rmSync(latestDir, { recursive: true, force: true });
141
+ }
142
+ }
143
+ fs.symlinkSync(path.basename(roundDir), latestDir, 'junction');
144
+ }
145
+ catch { /* ignore latest symlink error */ }
146
+ const summaryInner = reportData.summary?.summary || reportData.summary;
147
+ console.log(chalk_1.default.green(` ✓ report-data.json generated at ${path.relative(process.cwd(), path.join(roundDir, 'report-data.json'))}`));
148
+ console.log(` Total: ${summaryInner.total} | Passed: ${summaryInner.passed} | Failed: ${summaryInner.failed}`);
149
+ }
150
+ catch (err) {
151
+ console.error(chalk_1.default.red(` ✗ Report generation failed: ${err.message}`));
152
+ if (process.env.KEVE_VERBOSE)
153
+ console.error(err);
154
+ process.exit(1);
155
+ }
156
+ }
157
+ async function report(options) {
158
+ await invokeReport(options);
159
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * keve run - Execute Playwright tests
3
+ *
4
+ * Wraps `npx playwright test` with round management and output organization.
5
+ * Does NOT hardcode reporter or resultDir — the Playwright config handles those.
6
+ * Only adds: round number management, retry-from/cases filtering, and post-run report generation.
7
+ */
8
+ export interface RunOptions {
9
+ config?: string;
10
+ round?: string;
11
+ retryFrom?: string;
12
+ cases?: string;
13
+ grep?: string;
14
+ verbose?: boolean;
15
+ }
16
+ export interface RunResult {
17
+ exitCode: number;
18
+ resultsFile: string;
19
+ resultDir: string;
20
+ taskDir: string;
21
+ round: number;
22
+ passed: number;
23
+ failed: number;
24
+ skipped: number;
25
+ }
26
+ export declare class KeveRunError extends Error {
27
+ constructor(message: string);
28
+ }
29
+ export declare function run(options: RunOptions): Promise<RunResult>;