@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,6 @@
1
+ declare global {
2
+ var __keve_cdp_browser: import('@playwright/test').Browser | undefined;
3
+ }
4
+ export declare function getCdpBrowser(): Promise<import('@playwright/test').Browser>;
5
+ export declare function isCdpMode(): boolean;
6
+ export default function (): Promise<void>;
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.getCdpBrowser = getCdpBrowser;
37
+ exports.isCdpMode = isCdpMode;
38
+ exports.default = default_1;
39
+ const fs = __importStar(require("node:fs"));
40
+ const path = __importStar(require("node:path"));
41
+ const auth_1 = require("./auth");
42
+ async function getCdpBrowser() {
43
+ // 如果已有共享的 browser 对象,直接复用
44
+ if (globalThis.__keve_cdp_browser && globalThis.__keve_cdp_browser.isConnected()) {
45
+ return globalThis.__keve_cdp_browser;
46
+ }
47
+ const { chromium } = await Promise.resolve().then(() => __importStar(require('@playwright/test')));
48
+ let wsUrl = process.env.KEVE_CDP_WS_ENDPOINT;
49
+ // 如果只提供了 HTTP endpoint,自动获取 WebSocket URL
50
+ if (!wsUrl && process.env.KEVE_CDP_ENDPOINT) {
51
+ const httpUrl = process.env.KEVE_CDP_ENDPOINT.replace(/\/$/, '');
52
+ try {
53
+ const resp = await fetch(`${httpUrl}/json/version`);
54
+ const data = await resp.json();
55
+ wsUrl = data.webSocketDebuggerUrl;
56
+ console.log(`[keve CDP] Resolved WS endpoint: ${wsUrl}`);
57
+ }
58
+ catch (e) {
59
+ throw new Error(`Failed to resolve CDP WebSocket URL from ${httpUrl}: ${e.message}`);
60
+ }
61
+ }
62
+ if (!wsUrl)
63
+ throw new Error('No CDP endpoint configured');
64
+ const browser = await chromium.connectOverCDP(wsUrl, { timeout: 15000 });
65
+ console.log(`[keve CDP] Connected via ${wsUrl}`);
66
+ globalThis.__keve_cdp_browser = browser;
67
+ return browser;
68
+ }
69
+ function isCdpMode() {
70
+ return !!process.env.KEVE_CDP_WS_ENDPOINT || !!process.env.KEVE_CDP_ENDPOINT;
71
+ }
72
+ async function default_1() {
73
+ const projectRoot = path.resolve(process.cwd());
74
+ const storageStatePath = path.resolve(projectRoot, '.auth/storage-state.json');
75
+ const cdpEndpoint = process.env.KEVE_CDP_ENDPOINT || process.env.KEVE_CDP_WS_ENDPOINT;
76
+ if (cdpEndpoint) {
77
+ console.log(`[keve global-setup] CDP endpoint detected: ${cdpEndpoint}`);
78
+ // CDP 模式:在 global-setup 中提前连接一次,缓存 Browser 对象
79
+ try {
80
+ const browser = await getCdpBrowser();
81
+ const contexts = browser.contexts();
82
+ const pages = contexts.length > 0 ? contexts[0].pages() : [];
83
+ console.log(`[keve global-setup] CDP connected. contexts=${contexts.length}, pages=${pages.length}`);
84
+ if (pages.length > 0) {
85
+ console.log(`[keve global-setup] Existing tabs: ${pages.map(p => p.url()).join(', ')}`);
86
+ }
87
+ }
88
+ catch (e) {
89
+ console.warn(`[keve global-setup] CDP connection failed: ${e.message}`);
90
+ }
91
+ if (!fs.existsSync(storageStatePath)) {
92
+ const authDir = path.dirname(storageStatePath);
93
+ if (!fs.existsSync(authDir))
94
+ fs.mkdirSync(authDir, { recursive: true });
95
+ fs.writeFileSync(storageStatePath, JSON.stringify({ cookies: [], origins: [] }));
96
+ }
97
+ return;
98
+ }
99
+ console.log(`[keve global-setup] Acquiring fresh auth state...`);
100
+ const success = await (0, auth_1.acquireStorageState)({
101
+ logPrefix: '[keve global-setup]',
102
+ });
103
+ if (!success) {
104
+ console.warn(`[keve global-setup] Auth acquisition failed. Tests may fail due to auth issues.`);
105
+ if (!fs.existsSync(storageStatePath)) {
106
+ const authDir = path.dirname(storageStatePath);
107
+ if (!fs.existsSync(authDir))
108
+ fs.mkdirSync(authDir, { recursive: true });
109
+ fs.writeFileSync(storageStatePath, JSON.stringify({ cookies: [], origins: [] }));
110
+ console.log(`[keve global-setup] Created empty storage state → ${storageStatePath}`);
111
+ }
112
+ }
113
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * keve-aspect — Framework-internal aspect registry for keveGoal lifecycle
3
+ *
4
+ * Three phases: before → (goal body or rescue) → after
5
+ * User-invisible: aspects are registered by the framework, not by test authors.
6
+ *
7
+ * Built-in aspects:
8
+ * - screenshot-on-enter (before, order=10) — capture screenshot before goal
9
+ * - react-rescue (rescue, order=0) — Re-Act loop when fn() throws
10
+ * - expected-check (after, order=0) — verify expected state via aiAssert
11
+ * - action-log-write (after, order=10) — append to action-log.jsonl
12
+ * - learnedActions-update (after, order=20) — update in-memory cache
13
+ * - screenshot-on-fail (after, order=30) — capture screenshot on failure
14
+ */
15
+ export type AspectPhase = 'before' | 'rescue' | 'after';
16
+ export interface GoalContext {
17
+ page: import('@playwright/test').Page;
18
+ step: string;
19
+ expected: string;
20
+ precondition?: string;
21
+ order: number;
22
+ testTitle: string;
23
+ specFilePath?: string;
24
+ }
25
+ export interface GoalResult {
26
+ success: boolean;
27
+ error?: Error;
28
+ actions?: any[];
29
+ finalSnapshot?: string;
30
+ evalResult?: {
31
+ achieved: boolean;
32
+ gap: string;
33
+ nextAction: string;
34
+ fnSource?: string;
35
+ screenshotPath?: string;
36
+ snapshotPreview?: string;
37
+ };
38
+ }
39
+ export interface AspectDefinition {
40
+ name: string;
41
+ phase: AspectPhase;
42
+ order: number;
43
+ execute: (ctx: GoalContext, result?: GoalResult, error?: Error) => Promise<GoalResult | void>;
44
+ }
45
+ export declare class KeveAspectRegistry {
46
+ private aspects;
47
+ register(def: AspectDefinition): void;
48
+ unregister(name: string): void;
49
+ getByPhase(phase: AspectPhase): AspectDefinition[];
50
+ /** Run all aspects of a phase, chaining results */
51
+ runPhase(phase: AspectPhase, ctx: GoalContext, result?: GoalResult, error?: Error): Promise<GoalResult | undefined>;
52
+ }
53
+ /** Global singleton aspect registry */
54
+ export declare const keveAspect: KeveAspectRegistry;
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ /**
3
+ * keve-aspect — Framework-internal aspect registry for keveGoal lifecycle
4
+ *
5
+ * Three phases: before → (goal body or rescue) → after
6
+ * User-invisible: aspects are registered by the framework, not by test authors.
7
+ *
8
+ * Built-in aspects:
9
+ * - screenshot-on-enter (before, order=10) — capture screenshot before goal
10
+ * - react-rescue (rescue, order=0) — Re-Act loop when fn() throws
11
+ * - expected-check (after, order=0) — verify expected state via aiAssert
12
+ * - action-log-write (after, order=10) — append to action-log.jsonl
13
+ * - learnedActions-update (after, order=20) — update in-memory cache
14
+ * - screenshot-on-fail (after, order=30) — capture screenshot on failure
15
+ */
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.keveAspect = exports.KeveAspectRegistry = void 0;
18
+ class KeveAspectRegistry {
19
+ aspects = [];
20
+ register(def) {
21
+ this.aspects.push(def);
22
+ }
23
+ unregister(name) {
24
+ this.aspects = this.aspects.filter(a => a.name !== name);
25
+ }
26
+ getByPhase(phase) {
27
+ return this.aspects
28
+ .filter(a => a.phase === phase)
29
+ .sort((a, b) => a.order - b.order);
30
+ }
31
+ /** Run all aspects of a phase, chaining results */
32
+ async runPhase(phase, ctx, result, error) {
33
+ const aspects = this.getByPhase(phase);
34
+ let currentResult = result;
35
+ for (const aspect of aspects) {
36
+ try {
37
+ const aspectResult = await aspect.execute(ctx, currentResult, error);
38
+ if (aspectResult && phase === 'after') {
39
+ currentResult = aspectResult;
40
+ }
41
+ }
42
+ catch (err) {
43
+ console.warn(`[keve-aspect] ${aspect.name} failed: ${err.message}`);
44
+ // Aspects should not throw — they are framework-internal
45
+ }
46
+ }
47
+ return currentResult;
48
+ }
49
+ }
50
+ exports.KeveAspectRegistry = KeveAspectRegistry;
51
+ /** Global singleton aspect registry */
52
+ exports.keveAspect = new KeveAspectRegistry();
@@ -0,0 +1,51 @@
1
+ /**
2
+ * keve-decorators — @keveModel + @keveScene 装饰器
3
+ *
4
+ * 使用 TC39 Stage 3 装饰器 API (Playwright 1.58+ 默认支持)
5
+ *
6
+ * 执行顺序(TC39 Stage 3 规范):
7
+ * 1. Method decorator 函数调用 → 注册 addInitializer
8
+ * 2. Class decorator 函数调用 → 注册 addInitializer
9
+ * 3. Method addInitializers 执行 → @keveScene 注册场景到 WeakMap
10
+ * 4. Class addInitializer 执行 → @keveModel 读取 WeakMap 并调用 test.describe
11
+ *
12
+ * 两层装饰器 + 函数调用:
13
+ * Model (模块) → test.describe → @keveModel
14
+ * Scene (场景) → test → @keveScene (fn.toString() 捕获完整脚本)
15
+ * Goal (步骤) → 步骤元数据 → keveGoal() 函数调用(在方法体内)
16
+ */
17
+ import { type KeveGoalMeta } from './keve-registry';
18
+ /** Called by keve-test.ts to register the extended test instance */
19
+ export declare function setKeveTest(t: any): void;
20
+ /** Get the current keve test instance (extended with fixtures) */
21
+ export declare function getKeveTest(): any;
22
+ export type { KeveGoalMeta, KeveEvalMeta, ErrorCategory } from './keve-registry';
23
+ export interface KeveSceneMeta {
24
+ id: string;
25
+ description: string;
26
+ title: string;
27
+ code: string;
28
+ goals: KeveGoalMeta[];
29
+ fn: Function;
30
+ }
31
+ /**
32
+ * @keveModel(name) — Class decorator (模块层)
33
+ * Uses context.addInitializer to defer test.describe() registration
34
+ * until AFTER all @keveScene addInitializers have run.
35
+ */
36
+ export declare function keveModel(id: string, description: string): <T extends {
37
+ new (...args: any[]): {};
38
+ }>(ctor: T, context: ClassDecoratorContext) => T;
39
+ /**
40
+ * @keveScene(title) — Method decorator (场景层, static methods only)
41
+ * Captures fn.toString() as the complete scene script.
42
+ * Wraps fn with try-catch-finally to classify errors and decide skipAI.
43
+ * Registers scene metadata to both WeakMap and global Map.
44
+ *
45
+ * The wrapper preserves the original function's destructuring signature by
46
+ * extracting the parameter text from fn.toString() and constructing a wrapper
47
+ * via new Function(), so Playwright can correctly resolve fixture dependencies.
48
+ */
49
+ export declare function keveScene(id: string, description: string): (fn: Function, context: ClassMethodDecoratorContext) => Function;
50
+ /** 获取 Model 下注册的所有 Scene */
51
+ export declare function getModelScenes(ctor: Function): KeveSceneMeta[] | null;
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ /**
3
+ * keve-decorators — @keveModel + @keveScene 装饰器
4
+ *
5
+ * 使用 TC39 Stage 3 装饰器 API (Playwright 1.58+ 默认支持)
6
+ *
7
+ * 执行顺序(TC39 Stage 3 规范):
8
+ * 1. Method decorator 函数调用 → 注册 addInitializer
9
+ * 2. Class decorator 函数调用 → 注册 addInitializer
10
+ * 3. Method addInitializers 执行 → @keveScene 注册场景到 WeakMap
11
+ * 4. Class addInitializer 执行 → @keveModel 读取 WeakMap 并调用 test.describe
12
+ *
13
+ * 两层装饰器 + 函数调用:
14
+ * Model (模块) → test.describe → @keveModel
15
+ * Scene (场景) → test → @keveScene (fn.toString() 捕获完整脚本)
16
+ * Goal (步骤) → 步骤元数据 → keveGoal() 函数调用(在方法体内)
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.setKeveTest = setKeveTest;
20
+ exports.getKeveTest = getKeveTest;
21
+ exports.keveModel = keveModel;
22
+ exports.keveScene = keveScene;
23
+ exports.getModelScenes = getModelScenes;
24
+ const test_1 = require("@playwright/test");
25
+ const keve_registry_1 = require("./keve-registry");
26
+ // ─── Configurable test reference ────────────────────────────────────
27
+ // keveModel needs to call test.describe / test — but it must use the EXTENDED test
28
+ // (with keveGoal/keveAssert fixtures), not the base @playwright/test.
29
+ // keve-test.ts calls setKeveTest() after creating the extended test.
30
+ let _keveTest = test_1.test;
31
+ /** Called by keve-test.ts to register the extended test instance */
32
+ function setKeveTest(t) { _keveTest = t; }
33
+ /** Get the current keve test instance (extended with fixtures) */
34
+ function getKeveTest() { return _keveTest; }
35
+ // ─── Internal Registry (WeakMap per Model constructor) ─────────────
36
+ /** Model → Scene 列表:每个 @keveModel 类下注册的 @keveScene 列表 */
37
+ const modelScenesMap = new WeakMap();
38
+ // ─── Error Classification ──────────────────────────────────────────
39
+ // Error classification moved to keve-report.ts onTestEnd —
40
+ // onTestEnd has access to result.error and result.status, which is more reliable
41
+ // than try-catch in the decorator (async rejections, test-level timeouts can bypass decorator catch).
42
+ // ─── TC39 Stage 3 Decorators ──────────────────────────────────────
43
+ /**
44
+ * @keveModel(name) — Class decorator (模块层)
45
+ * Uses context.addInitializer to defer test.describe() registration
46
+ * until AFTER all @keveScene addInitializers have run.
47
+ */
48
+ function keveModel(id, description) {
49
+ return (ctor, context) => {
50
+ context.addInitializer(function () {
51
+ const ctor = this;
52
+ const scenes = modelScenesMap.get(ctor) || [];
53
+ _keveTest.describe(`${id}: ${description}`, () => {
54
+ for (const scene of scenes) {
55
+ _keveTest(scene.title, scene.fn);
56
+ }
57
+ });
58
+ });
59
+ return ctor;
60
+ };
61
+ }
62
+ /**
63
+ * @keveScene(title) — Method decorator (场景层, static methods only)
64
+ * Captures fn.toString() as the complete scene script.
65
+ * Wraps fn with try-catch-finally to classify errors and decide skipAI.
66
+ * Registers scene metadata to both WeakMap and global Map.
67
+ *
68
+ * The wrapper preserves the original function's destructuring signature by
69
+ * extracting the parameter text from fn.toString() and constructing a wrapper
70
+ * via new Function(), so Playwright can correctly resolve fixture dependencies.
71
+ */
72
+ function keveScene(id, description) {
73
+ return (fn, context) => {
74
+ const code = fn.toString(); // Capture original code BEFORE wrapping
75
+ const title = `${id}: ${description}`;
76
+ // Register the original function directly — Playwright resolves fixture dependencies
77
+ // by parsing fn.toString() / AST. Wrapping with new Function() breaks this resolution.
78
+ // Error classification is handled in onTestEnd (keve-report.ts), not here.
79
+ context.addInitializer(function () {
80
+ const ctor = this;
81
+ if (!modelScenesMap.has(ctor))
82
+ modelScenesMap.set(ctor, []);
83
+ const scene = { id, description, title, code, goals: [], fn };
84
+ modelScenesMap.get(ctor).push(scene);
85
+ // Register to global maps for Reporter access
86
+ keve_registry_1.sceneCodeMap.set(title, code); // Stores ORIGINAL code, not wrapped
87
+ });
88
+ return fn; // Return original function unchanged — preserves fixture parameter signature
89
+ };
90
+ }
91
+ // ─── Utility ───────────────────────────────────────────────────────
92
+ /** 获取 Model 下注册的所有 Scene */
93
+ function getModelScenes(ctor) {
94
+ return modelScenesMap.get(ctor) || null;
95
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * keve-registry — Global scene metadata registry
3
+ *
4
+ * Shared between keve-decorators (writes) and keve-report (reads).
5
+ * This module has NO dependency on @playwright/test, so the Reporter
6
+ * can import it without pulling Playwright into the report build.
7
+ */
8
+ export interface KeveGoalMeta {
9
+ precondition?: string;
10
+ step: string;
11
+ expected: string;
12
+ order: number;
13
+ }
14
+ /** 错误分类类型 */
15
+ export type ErrorCategory = 'script' | 'env' | 'assert' | 'visual' | 'text-mismatch' | 'react-fail' | 'pass' | 'unknown';
16
+ /** 场景执行后的评估元数据,由 @keveScene 装饰器写入,Reporter 读取 */
17
+ export interface KeveEvalMeta {
18
+ /** 错误分类 */
19
+ errorCategory: ErrorCategory;
20
+ /** 是否跳过 AI 评估(脚本错误时为 true) */
21
+ skipAI: boolean;
22
+ /** 原始错误信息(可选,未截断) */
23
+ errorMessage?: string;
24
+ }
25
+ /**
26
+ * 场景代码映射: scene title → scene code (fn.toString())
27
+ * Reporter 通过 sceneCodeMap.get(title) 获取场景脚本
28
+ */
29
+ export declare const sceneCodeMap: Map<string, string>;
30
+ /**
31
+ * 场景目标映射: scene title → goal metadata array
32
+ */
33
+ export declare const sceneGoalsMap: Map<string, KeveGoalMeta[]>;
34
+ /**
35
+ * 场景评估元数据映射: scene title → KeveEvalMeta
36
+ * @keveScene 装饰器在执行后写入分类结果,Reporter 在 onTestEnd 中读取
37
+ */
38
+ export declare const sceneEvalMetaMap: Map<string, KeveEvalMeta>;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ /**
3
+ * keve-registry — Global scene metadata registry
4
+ *
5
+ * Shared between keve-decorators (writes) and keve-report (reads).
6
+ * This module has NO dependency on @playwright/test, so the Reporter
7
+ * can import it without pulling Playwright into the report build.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.sceneEvalMetaMap = exports.sceneGoalsMap = exports.sceneCodeMap = void 0;
11
+ // ─── Global Registry ──────────────────────────────────────────────
12
+ /**
13
+ * 场景代码映射: scene title → scene code (fn.toString())
14
+ * Reporter 通过 sceneCodeMap.get(title) 获取场景脚本
15
+ */
16
+ exports.sceneCodeMap = new Map();
17
+ /**
18
+ * 场景目标映射: scene title → goal metadata array
19
+ */
20
+ exports.sceneGoalsMap = new Map();
21
+ /**
22
+ * 场景评估元数据映射: scene title → KeveEvalMeta
23
+ * @keveScene 装饰器在执行后写入分类结果,Reporter 在 onTestEnd 中读取
24
+ */
25
+ exports.sceneEvalMetaMap = new Map();
@@ -0,0 +1,27 @@
1
+ /**
2
+ * keve-report: Playwright Reporter that collects test execution data
3
+ *
4
+ * After EACH test completes (onTestEnd), records test result metadata
5
+ * including step results, error category, AI exploration steps, and diagnostics.
6
+ * Results are appended to confidence-data.jsonl (one line per test).
7
+ *
8
+ * After ALL tests complete (onEnd), generates report-data.json directly,
9
+ * eliminating the need for a separate `keve report` command.
10
+ *
11
+ * Usage in playwright config:
12
+ * reporter: [
13
+ * ['list'],
14
+ * ['@ks-data/keve-suite/keve-report'],
15
+ * ]
16
+ */
17
+ import type { Reporter, TestCase, TestResult, FullResult, FullConfig, Suite } from '@playwright/test/reporter';
18
+ declare class KeveReporter implements Reporter {
19
+ private outputPath;
20
+ private resultDir;
21
+ onBegin(config: FullConfig, suite: Suite): void;
22
+ private static CONFIDENCE_MAP;
23
+ onTestEnd(test: TestCase, result: TestResult): Promise<void>;
24
+ onEnd(result: FullResult): Promise<void>;
25
+ private appendRecord;
26
+ }
27
+ export default KeveReporter;