@kkeve/suite 0.0.1 → 0.0.3

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 (153) 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 +43 -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/system_prompt.md +240 -0
  55. package/dist/page-agent/tools.d.ts +29 -0
  56. package/dist/page-agent/tools.js +297 -0
  57. package/doc/README.md +124 -0
  58. package/doc/agents/keve-dev-test-agent.md +140 -0
  59. package/doc/agents/keve-test-agent.md +178 -0
  60. 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
  61. package/doc/keve-agent-demo.html +370 -0
  62. package/doc/skills/keve-bddcase-gen/SKILL.md +332 -0
  63. package/doc/skills/keve-bddcase-gen/references/test-case-rules.md +91 -0
  64. package/doc/skills/keve-bddcase-gen/references/test-cases-example.md +103 -0
  65. package/doc/skills/keve-component-gen/SKILL.md +255 -0
  66. package/doc/skills/keve-component-gen/references/component-mock-strategy.md +74 -0
  67. package/doc/skills/keve-component-gen/references/component-model-template.md +98 -0
  68. package/doc/skills/keve-component-gen/references/component-test-template.md +100 -0
  69. package/doc/skills/keve-component-gen/references/vue-test-utils-guide.md +91 -0
  70. package/doc/skills/keve-e2e-gen/SKILL.md +179 -0
  71. package/doc/skills/keve-e2e-gen/references/code-analysis-guide.md +208 -0
  72. package/doc/skills/keve-e2e-gen/references/decisions.md +36 -0
  73. package/doc/skills/keve-e2e-gen/references/pom-generation-guide.md +140 -0
  74. package/doc/skills/keve-e2e-gen/references/script-generation-guide.md +236 -0
  75. package/doc/skills/keve-e2e-gen/references/test-auditor-guide.md +189 -0
  76. package/doc/skills/keve-e2e-gen/scripts/extract-components.sh +85 -0
  77. package/doc/skills/keve-e2e-gen/scripts/inject-testids.sh +95 -0
  78. package/doc/skills/keve-static-analysis/SKILL.md +362 -0
  79. package/doc/skills/keve-static-analysis/references/codegraph-analysis-guide.md +108 -0
  80. package/doc/skills/keve-static-analysis/references/git-impact-analysis.md +81 -0
  81. package/doc/skills/keve-static-analysis/references/lint-fix-guide.md +69 -0
  82. package/doc/skills/keve-static-analysis/references/runtime-risk-patterns.md +92 -0
  83. package/doc/skills/keve-static-analysis/references/security-scan-guide.md +32 -0
  84. package/doc/skills/keve-static-analysis/references/ts-error-patterns.md +98 -0
  85. package/doc/skills/keve-static-analysis/references/vue-security-guide.md +72 -0
  86. package/doc/skills/keve-test-eval/SKILL.md +78 -0
  87. package/doc/skills/keve-test-eval/references/common-fix-guide.md +166 -0
  88. package/doc/skills/keve-test-eval/references/confidence-data-guide.md +78 -0
  89. package/doc/skills/keve-test-eval/references/fix-loop-guide.md +67 -0
  90. package/doc/skills/keve-unit-gen/SKILL.md +203 -0
  91. package/doc/skills/keve-unit-gen/references/boundary-conditions.md +78 -0
  92. package/doc/skills/keve-unit-gen/references/unit-mock-strategy.md +71 -0
  93. package/doc/skills/keve-unit-gen/references/unit-test-template.md +105 -0
  94. package/package.json +46 -24
  95. package/dist/agent/factory.d.ts +0 -25
  96. package/dist/agent/factory.js +0 -99
  97. package/dist/agent/index.d.ts +0 -3
  98. package/dist/agent/index.js +0 -7
  99. package/dist/agent/loader.d.ts +0 -22
  100. package/dist/agent/loader.js +0 -117
  101. package/dist/agent/types.d.ts +0 -9
  102. package/dist/agent/types.js +0 -2
  103. package/dist/agent-loop/complete-task.d.ts +0 -28
  104. package/dist/agent-loop/complete-task.js +0 -70
  105. package/dist/agent-loop/index.d.ts +0 -16
  106. package/dist/agent-loop/index.js +0 -26
  107. package/dist/agent-loop/loop.d.ts +0 -42
  108. package/dist/agent-loop/loop.js +0 -282
  109. package/dist/agent-loop/runtime.d.ts +0 -40
  110. package/dist/agent-loop/runtime.js +0 -163
  111. package/dist/agent-loop/types.d.ts +0 -161
  112. package/dist/agent-loop/types.js +0 -105
  113. package/dist/context/index.d.ts +0 -8
  114. package/dist/context/index.js +0 -29
  115. package/dist/context/tokenCalculation.d.ts +0 -55
  116. package/dist/context/tokenCalculation.js +0 -95
  117. package/dist/context/truncation.d.ts +0 -67
  118. package/dist/context/truncation.js +0 -142
  119. package/dist/context/types.d.ts +0 -7
  120. package/dist/context/types.js +0 -27
  121. package/dist/llm/OpenAIClient.d.ts +0 -31
  122. package/dist/llm/OpenAIClient.js +0 -455
  123. package/dist/llm/constants.d.ts +0 -2
  124. package/dist/llm/constants.js +0 -6
  125. package/dist/llm/errors.d.ts +0 -25
  126. package/dist/llm/errors.js +0 -51
  127. package/dist/llm/index.d.ts +0 -49
  128. package/dist/llm/index.js +0 -158
  129. package/dist/llm/types.d.ts +0 -124
  130. package/dist/llm/types.js +0 -2
  131. package/dist/llm/utils.d.ts +0 -29
  132. package/dist/llm/utils.js +0 -284
  133. package/dist/skill/frontmatter-parser.d.ts +0 -50
  134. package/dist/skill/frontmatter-parser.js +0 -152
  135. package/dist/skill/index.d.ts +0 -12
  136. package/dist/skill/index.js +0 -17
  137. package/dist/skill/loader.d.ts +0 -96
  138. package/dist/skill/loader.js +0 -256
  139. package/dist/tools/ask-user.d.ts +0 -8
  140. package/dist/tools/ask-user.js +0 -47
  141. package/dist/tools/bash.d.ts +0 -47
  142. package/dist/tools/bash.js +0 -213
  143. package/dist/tools/edit-file.d.ts +0 -9
  144. package/dist/tools/edit-file.js +0 -76
  145. package/dist/tools/glob.d.ts +0 -8
  146. package/dist/tools/glob.js +0 -101
  147. package/dist/tools/grep.d.ts +0 -10
  148. package/dist/tools/grep.js +0 -76
  149. package/dist/tools/index.d.ts +0 -24
  150. package/dist/tools/index.js +0 -47
  151. package/dist/tools/read-files.d.ts +0 -8
  152. package/dist/tools/read-files.js +0 -81
  153. package/dist/tools/write-file.d.ts +0 -8
@@ -0,0 +1,166 @@
1
+ "use strict";
2
+ /**
3
+ * keve vitest - Execute Vitest unit/component tests
4
+ *
5
+ * Wraps `npx vitest` with keve-specific config and coverage support.
6
+ * Uses vitest.config.ts from keve_test_spec/ by default.
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.vitest = vitest;
46
+ const fs = __importStar(require("node:fs"));
47
+ const path = __importStar(require("node:path"));
48
+ const node_child_process_1 = require("node:child_process");
49
+ const chalk_1 = __importDefault(require("chalk"));
50
+ /**
51
+ * Walk up from __dirname to find node_modules/vitest/vitest.mjs
52
+ *
53
+ * pnpm structure:
54
+ * node_modules/.pnpm/@ks-data+keve-agent@.../node_modules/
55
+ * ├── @ks-data/keve-suite/ ← __dirname is in dist/commands/ here
56
+ * └── vitest/ ← sibling dep, walk up to find
57
+ *
58
+ * npm/node structure:
59
+ * node_modules/
60
+ * ├── @ks-data/keve-suite/ ← __dirname is in dist/commands/ here
61
+ * └── vitest/ ← sibling dep, walk up to find
62
+ */
63
+ function findVitestBinary() {
64
+ let current = __dirname;
65
+ for (let i = 0; i < 10; i++) {
66
+ const vitestBin = path.join(current, 'node_modules', 'vitest', 'vitest.mjs');
67
+ if (fs.existsSync(vitestBin)) {
68
+ return {
69
+ bin: vitestBin,
70
+ nodeModules: path.join(current, 'node_modules'),
71
+ };
72
+ }
73
+ const parent = path.dirname(current);
74
+ if (parent === current)
75
+ break; // reached filesystem root
76
+ current = parent;
77
+ }
78
+ return null;
79
+ }
80
+ /**
81
+ * Find Vitest config: keve_test_spec/vitest.config.ts by default
82
+ */
83
+ function findVitestConfig(optionsConfig) {
84
+ const cwd = process.cwd();
85
+ if (optionsConfig) {
86
+ const resolved = path.resolve(cwd, optionsConfig);
87
+ if (fs.existsSync(resolved))
88
+ return resolved;
89
+ console.error(chalk_1.default.red(` ✗ Vitest config not found: ${optionsConfig}`));
90
+ return null;
91
+ }
92
+ const configPath = path.join(cwd, 'keve_test_spec', 'vitest.config.ts');
93
+ if (fs.existsSync(configPath))
94
+ return configPath;
95
+ console.error(chalk_1.default.red(' ✗ Vitest config not found'));
96
+ console.error(chalk_1.default.gray(' Searched: keve_test_spec/vitest.config.ts'));
97
+ console.error(chalk_1.default.gray(' Run: keve init'));
98
+ return null;
99
+ }
100
+ async function vitest(options) {
101
+ const cwd = process.cwd();
102
+ const configPath = findVitestConfig(options.config);
103
+ if (!configPath) {
104
+ process.exit(1);
105
+ }
106
+ console.log(chalk_1.default.cyan('\n🧪 keve vitest\n'));
107
+ // Build vitest args
108
+ const vitestArgs = [];
109
+ // Run mode (default: single run; --watch for watch mode)
110
+ if (options.watch) {
111
+ vitestArgs.push('watch');
112
+ }
113
+ else {
114
+ vitestArgs.push('run');
115
+ }
116
+ vitestArgs.push('--config', configPath);
117
+ if (options.coverage) {
118
+ vitestArgs.push('--coverage');
119
+ }
120
+ if (options.filter) {
121
+ vitestArgs.push(options.filter);
122
+ }
123
+ if (options.verbose) {
124
+ console.log(chalk_1.default.gray(` Config: ${configPath}`));
125
+ console.log(chalk_1.default.gray(` Mode: ${options.watch ? 'watch' : 'run'}`));
126
+ console.log(chalk_1.default.gray(` Coverage: ${options.coverage ? 'enabled' : 'disabled'}`));
127
+ console.log(chalk_1.default.gray(` Filter: ${options.filter || '(all)'}`));
128
+ console.log();
129
+ }
130
+ console.log(chalk_1.default.blue(` ▶ Running Vitest tests...\n`));
131
+ // Resolve vitest binary — pnpm puts it in a sibling node_modules/
132
+ // Walk up from __dirname (dist/commands/) to find node_modules/vitest/
133
+ const vitestInfo = findVitestBinary();
134
+ if (!vitestInfo) {
135
+ console.error(chalk_1.default.red(' ✗ Vitest not found'));
136
+ console.error(chalk_1.default.yellow(' Install: pnpm add -D @ks-data/keve-suite (includes vitest)'));
137
+ process.exit(1);
138
+ }
139
+ const { bin: vitestBin, nodeModules: vitestNodeModules } = vitestInfo;
140
+ // Execute Vitest with NODE_PATH so vitest.config.ts can resolve 'vitest/config'
141
+ const exitCode = await new Promise((resolve) => {
142
+ const existingNodePath = process.env.NODE_PATH || '';
143
+ const nodePath = existingNodePath
144
+ ? `${vitestNodeModules}:${existingNodePath}`
145
+ : vitestNodeModules;
146
+ const child = (0, node_child_process_1.spawn)('node', [vitestBin, ...vitestArgs], {
147
+ cwd,
148
+ stdio: 'inherit',
149
+ env: {
150
+ ...process.env,
151
+ NODE_PATH: nodePath,
152
+ FORCE_COLOR: '1',
153
+ },
154
+ });
155
+ child.on('close', (code) => resolve(code ?? 1));
156
+ child.on('error', (err) => {
157
+ console.error(chalk_1.default.red(` ✗ Failed to start vitest: ${err.message}`));
158
+ resolve(1);
159
+ });
160
+ });
161
+ if (exitCode !== 0) {
162
+ console.log(chalk_1.default.yellow('\n ⚠ Some tests failed.'));
163
+ process.exit(exitCode);
164
+ }
165
+ console.log(chalk_1.default.green('\n ✓ All Vitest tests passed.'));
166
+ }
@@ -0,0 +1,109 @@
1
+ /**
2
+ * keve config loader - reads keve_test_spec/keve.yaml
3
+ */
4
+ export interface KeveConfig {
5
+ project: {
6
+ name: string;
7
+ prd_url?: string;
8
+ };
9
+ state: {
10
+ current_round: number;
11
+ last_run_at?: string;
12
+ };
13
+ llm: {
14
+ model: string;
15
+ base_url: string;
16
+ api_key?: string;
17
+ };
18
+ execution: {
19
+ timeout_ms: number;
20
+ retries: number;
21
+ reporter: string;
22
+ screenshot: string;
23
+ };
24
+ platform?: {
25
+ base_url?: string;
26
+ plan_id?: string | null;
27
+ teamId?: string;
28
+ };
29
+ }
30
+ /** Per-task run state — stored in .keve/{task}/run-state.yaml */
31
+ export interface RunState {
32
+ current_round: number;
33
+ last_run_at?: string;
34
+ rounds: Record<number, {
35
+ status: 'running' | 'completed' | 'failed';
36
+ started_at: string;
37
+ completed_at?: string;
38
+ passed?: number;
39
+ failed?: number;
40
+ skipped?: number;
41
+ }>;
42
+ }
43
+ /**
44
+ * Find keve_test_spec/ directory by walking up from cwd
45
+ */
46
+ export declare function findKeveDir(startDir?: string): string | null;
47
+ /**
48
+ * Load keve.yaml config
49
+ */
50
+ export declare function loadConfig(keveDir?: string | null): KeveConfig;
51
+ /**
52
+ * Save keve.yaml config
53
+ */
54
+ export declare function saveConfig(config: KeveConfig, keveDir: string): void;
55
+ /**
56
+ * Get current round number, auto-increment
57
+ */
58
+ export declare function getNextRound(keveDir: string): number;
59
+ /**
60
+ * Resolve latest round directory
61
+ */
62
+ export declare function getLatestRoundDir(keveDir: string): string | null;
63
+ /**
64
+ * Get branch-specific directory under .keve/
65
+ * Uses current git branch name to create/find .keve/{branch}/
66
+ */
67
+ export declare function getBranchDir(keveDir: string | null): string | null;
68
+ /**
69
+ * Get current git branch name
70
+ */
71
+ export declare function getCurrentBranch(): string | null;
72
+ /**
73
+ * 获取 git 用户名
74
+ */
75
+ export declare function getGitUserName(): string;
76
+ /**
77
+ * 获取 git remote origin 仓库名
78
+ */
79
+ export declare function getGitRepoName(): string;
80
+ /**
81
+ * 获取当前 git 分支名
82
+ */
83
+ export declare function getGitBranchName(): string;
84
+ /**
85
+ * Resolve task directory from KEVE_TASK_DIR env or keveDir + branch.
86
+ * Returns absolute path to the task root (e.g. .keve/mr-868-temp).
87
+ */
88
+ export declare function resolveTaskDir(keveDir: string | null): string | null;
89
+ /**
90
+ * Read run-state.yaml from task directory.
91
+ * Returns default state if file doesn't exist.
92
+ */
93
+ export declare function readRunState(taskDir: string): RunState;
94
+ /**
95
+ * Write run-state.yaml to task directory.
96
+ */
97
+ export declare function writeRunState(taskDir: string, state: RunState): void;
98
+ /**
99
+ * Get next round number and update run-state.yaml.
100
+ */
101
+ export declare function getNextRoundFromState(taskDir: string): number;
102
+ /**
103
+ * Mark a round as completed with stats.
104
+ */
105
+ export declare function completeRound(taskDir: string, round: number, stats: {
106
+ passed: number;
107
+ failed: number;
108
+ skipped: number;
109
+ }): void;
package/dist/config.js ADDED
@@ -0,0 +1,291 @@
1
+ "use strict";
2
+ /**
3
+ * keve config loader - reads keve_test_spec/keve.yaml
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.findKeveDir = findKeveDir;
40
+ exports.loadConfig = loadConfig;
41
+ exports.saveConfig = saveConfig;
42
+ exports.getNextRound = getNextRound;
43
+ exports.getLatestRoundDir = getLatestRoundDir;
44
+ exports.getBranchDir = getBranchDir;
45
+ exports.getCurrentBranch = getCurrentBranch;
46
+ exports.getGitUserName = getGitUserName;
47
+ exports.getGitRepoName = getGitRepoName;
48
+ exports.getGitBranchName = getGitBranchName;
49
+ exports.resolveTaskDir = resolveTaskDir;
50
+ exports.readRunState = readRunState;
51
+ exports.writeRunState = writeRunState;
52
+ exports.getNextRoundFromState = getNextRoundFromState;
53
+ exports.completeRound = completeRound;
54
+ const fs = __importStar(require("fs"));
55
+ const path = __importStar(require("path"));
56
+ const yaml = __importStar(require("yaml"));
57
+ const child_process_1 = require("child_process");
58
+ const DEFAULT_CONFIG = {
59
+ project: {
60
+ name: '',
61
+ },
62
+ state: {
63
+ current_round: 0,
64
+ },
65
+ llm: {
66
+ model: process.env.KEVE_LLM_MODEL || '',
67
+ base_url: process.env.KEVE_LLM_BASE_URL || process.env.KONSTRUCTOR_API_BASE || '',
68
+ api_key: process.env.KEVE_LLM_API_KEY || process.env.LLM_API_KEY || '',
69
+ },
70
+ execution: {
71
+ timeout_ms: 1200000,
72
+ retries: 0,
73
+ reporter: 'json',
74
+ screenshot: 'only-on-failure',
75
+ },
76
+ };
77
+ /**
78
+ * Find keve_test_spec/ directory by walking up from cwd
79
+ */
80
+ function findKeveDir(startDir) {
81
+ let dir = startDir || process.cwd();
82
+ for (let i = 0; i < 20; i++) {
83
+ // Prefer .keve/ directory as the canonical keve home
84
+ const dotKeve = path.join(dir, '.keve');
85
+ if (fs.existsSync(dotKeve))
86
+ return dotKeve;
87
+ // Fallback: keve_test_spec/ for legacy projects
88
+ const specDir = path.join(dir, 'keve_test_spec');
89
+ if (fs.existsSync(specDir))
90
+ return specDir;
91
+ const parent = path.dirname(dir);
92
+ if (parent === dir)
93
+ break;
94
+ dir = parent;
95
+ }
96
+ return null;
97
+ }
98
+ /**
99
+ * Load keve.yaml config
100
+ */
101
+ function loadConfig(keveDir) {
102
+ const dir = keveDir || findKeveDir();
103
+ if (!dir)
104
+ return DEFAULT_CONFIG;
105
+ const configPath = path.join(dir, 'keve.yaml');
106
+ if (!fs.existsSync(configPath))
107
+ return DEFAULT_CONFIG;
108
+ const content = fs.readFileSync(configPath, 'utf-8');
109
+ const parsed = yaml.parse(content);
110
+ return { ...DEFAULT_CONFIG, ...parsed };
111
+ }
112
+ /**
113
+ * Save keve.yaml config
114
+ */
115
+ function saveConfig(config, keveDir) {
116
+ const configPath = path.join(keveDir, 'keve.yaml');
117
+ const content = yaml.stringify(config, { lineWidth: 0 });
118
+ fs.writeFileSync(configPath, content, 'utf-8');
119
+ }
120
+ /**
121
+ * Get current round number, auto-increment
122
+ */
123
+ function getNextRound(keveDir) {
124
+ const config = loadConfig(keveDir);
125
+ const next = config.state.current_round + 1;
126
+ config.state.current_round = next;
127
+ config.state.last_run_at = new Date().toISOString();
128
+ saveConfig(config, keveDir);
129
+ return next;
130
+ }
131
+ /**
132
+ * Resolve latest round directory
133
+ */
134
+ function getLatestRoundDir(keveDir) {
135
+ const artifactsDir = path.join(keveDir, 'test-artifacts');
136
+ const latestLink = path.join(artifactsDir, 'latest');
137
+ try {
138
+ const target = fs.readlinkSync(latestLink);
139
+ return path.resolve(artifactsDir, target);
140
+ }
141
+ catch {
142
+ return null;
143
+ }
144
+ }
145
+ /**
146
+ * Get branch-specific directory under .keve/
147
+ * Uses current git branch name to create/find .keve/{branch}/
148
+ */
149
+ function getBranchDir(keveDir) {
150
+ if (!keveDir)
151
+ return null;
152
+ // Don't create branch dirs under keve_test_spec/ (legacy keveDir) — only under .keve/
153
+ if (!keveDir.endsWith(path.join('.keve')) && !keveDir.includes(`${path.sep}.keve${path.sep}`))
154
+ return null;
155
+ const branch = getCurrentBranch();
156
+ if (!branch)
157
+ return null;
158
+ const branchDir = path.join(keveDir, branch);
159
+ if (!fs.existsSync(branchDir)) {
160
+ fs.mkdirSync(branchDir, { recursive: true });
161
+ }
162
+ return branchDir;
163
+ }
164
+ /**
165
+ * Get current git branch name
166
+ */
167
+ function getCurrentBranch() {
168
+ try {
169
+ return (0, child_process_1.execSync)('git branch --show-current', { encoding: 'utf-8' }).trim();
170
+ }
171
+ catch {
172
+ return null;
173
+ }
174
+ }
175
+ /**
176
+ * 获取 git 用户名
177
+ */
178
+ function getGitUserName() {
179
+ try {
180
+ return (0, child_process_1.execSync)('git config user.name', { encoding: 'utf-8' }).trim();
181
+ }
182
+ catch {
183
+ return process.env.KEVE_USER_NAME || '';
184
+ }
185
+ }
186
+ /**
187
+ * 获取 git remote origin 仓库名
188
+ */
189
+ function getGitRepoName() {
190
+ try {
191
+ const url = (0, child_process_1.execSync)('git remote get-url origin', { encoding: 'utf-8' }).trim();
192
+ const parts = url.replace(/\.git$/, '').split('/');
193
+ return parts[parts.length - 1] || '';
194
+ }
195
+ catch {
196
+ return '';
197
+ }
198
+ }
199
+ /**
200
+ * 获取当前 git 分支名
201
+ */
202
+ function getGitBranchName() {
203
+ try {
204
+ return (0, child_process_1.execSync)('git branch --show-current', { encoding: 'utf-8' }).trim();
205
+ }
206
+ catch {
207
+ return '';
208
+ }
209
+ }
210
+ // ─── Run State (run-state.yaml) ─────────────────────────────────────────
211
+ const RUN_STATE_FILENAME = 'run-state.yaml';
212
+ /**
213
+ * Resolve task directory from KEVE_TASK_DIR env or keveDir + branch.
214
+ * Returns absolute path to the task root (e.g. .keve/mr-868-temp).
215
+ */
216
+ function resolveTaskDir(keveDir) {
217
+ if (process.env.KEVE_TASK_DIR) {
218
+ return path.resolve(process.cwd(), process.env.KEVE_TASK_DIR);
219
+ }
220
+ // Auto-detect: find branch-specific task dir under .keve/{branch}/
221
+ if (keveDir) {
222
+ const branch = getCurrentBranch();
223
+ if (branch) {
224
+ const branchDir = path.join(keveDir, branch);
225
+ if (fs.existsSync(branchDir))
226
+ return branchDir;
227
+ }
228
+ // Fallback: keveDir itself if it has run-state.yaml
229
+ if (fs.existsSync(path.join(keveDir, RUN_STATE_FILENAME)))
230
+ return keveDir;
231
+ }
232
+ return null;
233
+ }
234
+ /**
235
+ * Read run-state.yaml from task directory.
236
+ * Returns default state if file doesn't exist.
237
+ */
238
+ function readRunState(taskDir) {
239
+ const filePath = path.join(taskDir, RUN_STATE_FILENAME);
240
+ if (fs.existsSync(filePath)) {
241
+ try {
242
+ const content = fs.readFileSync(filePath, 'utf-8');
243
+ const parsed = yaml.parse(content);
244
+ return {
245
+ current_round: parsed.current_round || 0,
246
+ last_run_at: parsed.last_run_at,
247
+ rounds: parsed.rounds || {},
248
+ };
249
+ }
250
+ catch {
251
+ // Corrupted file — start fresh
252
+ }
253
+ }
254
+ return { current_round: 0, rounds: {} };
255
+ }
256
+ /**
257
+ * Write run-state.yaml to task directory.
258
+ */
259
+ function writeRunState(taskDir, state) {
260
+ const filePath = path.join(taskDir, RUN_STATE_FILENAME);
261
+ fs.writeFileSync(filePath, yaml.stringify(state), 'utf-8');
262
+ }
263
+ /**
264
+ * Get next round number and update run-state.yaml.
265
+ */
266
+ function getNextRoundFromState(taskDir) {
267
+ const state = readRunState(taskDir);
268
+ const next = state.current_round + 1;
269
+ state.current_round = next;
270
+ state.last_run_at = new Date().toISOString();
271
+ state.rounds[next] = {
272
+ status: 'running',
273
+ started_at: new Date().toISOString(),
274
+ };
275
+ writeRunState(taskDir, state);
276
+ return next;
277
+ }
278
+ /**
279
+ * Mark a round as completed with stats.
280
+ */
281
+ function completeRound(taskDir, round, stats) {
282
+ const state = readRunState(taskDir);
283
+ if (state.rounds[round]) {
284
+ state.rounds[round].status = 'completed';
285
+ state.rounds[round].completed_at = new Date().toISOString();
286
+ state.rounds[round].passed = stats.passed;
287
+ state.rounds[round].failed = stats.failed;
288
+ state.rounds[round].skipped = stats.skipped;
289
+ writeRunState(taskDir, state);
290
+ }
291
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * action-log-writer — Append action-log entries to action-log.jsonl
3
+ *
4
+ * Each line is a JSON object: { scene, step, action, source, result, timestamp }
5
+ * Used by script-refine agent to discover deterministic callbacks from Re-Act traces.
6
+ */
7
+ export interface ActionLogRecord {
8
+ scene: string;
9
+ step: string;
10
+ stepOrder: number;
11
+ action: {
12
+ tool: string;
13
+ role?: string;
14
+ name?: string;
15
+ url?: string;
16
+ text?: string;
17
+ key?: string;
18
+ direction?: string;
19
+ time?: number;
20
+ submit?: boolean;
21
+ reason?: string;
22
+ success?: boolean;
23
+ };
24
+ source: 'deterministic' | 'react' | 'evaluate';
25
+ result: 'ok' | 'error' | 'achieved' | 'not_achieved';
26
+ error?: string;
27
+ evaluation?: string;
28
+ memory?: string;
29
+ nextGoal?: string;
30
+ gap?: string;
31
+ screenshotPath?: string;
32
+ snapshotPreview?: string;
33
+ fnSource?: string;
34
+ timestamp: string;
35
+ }
36
+ export declare class ActionLogWriter {
37
+ private filePath;
38
+ constructor(taskDir?: string);
39
+ /** Append a single record */
40
+ append(record: ActionLogRecord): void;
41
+ /** Append multiple records */
42
+ appendAll(records: ActionLogRecord[]): void;
43
+ /** Read all records (for script-refine) */
44
+ readAll(): ActionLogRecord[];
45
+ /** Get file path for external consumers */
46
+ getFilePath(): string;
47
+ }
@@ -1,4 +1,10 @@
1
1
  "use strict";
2
+ /**
3
+ * action-log-writer — Append action-log entries to action-log.jsonl
4
+ *
5
+ * Each line is a JSON object: { scene, step, action, source, result, timestamp }
6
+ * Used by script-refine agent to discover deterministic callbacks from Re-Act traces.
7
+ */
2
8
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
9
  if (k2 === undefined) k2 = k;
4
10
  var desc = Object.getOwnPropertyDescriptor(m, k);
@@ -33,31 +39,41 @@ var __importStar = (this && this.__importStar) || (function () {
33
39
  };
34
40
  })();
35
41
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.writeFileTool = exports.WriteFileInputSchema = void 0;
37
- /**
38
- * write_file tool — write content to a file
39
- *
40
- * Reference: gemini-cli WriteFileTool
41
- */
42
- const fs = __importStar(require("node:fs/promises"));
42
+ exports.ActionLogWriter = void 0;
43
+ const fs = __importStar(require("node:fs"));
43
44
  const path = __importStar(require("node:path"));
44
- const v4_1 = require("zod/v4");
45
- exports.WriteFileInputSchema = v4_1.z.object({
46
- path: v4_1.z.string().describe('File path (relative to cwd or absolute)'),
47
- content: v4_1.z.string().describe('Content to write to the file'),
48
- createDirs: v4_1.z.boolean().default(true).describe('Automatically create parent directories'),
49
- });
50
- exports.writeFileTool = {
51
- name: 'write_file',
52
- description: 'Write content to a file. Overwrites if exists, creates if not. Auto-creates parent directories.',
53
- inputSchema: exports.WriteFileInputSchema,
54
- execute: async (args, context) => {
55
- const cwd = context?.cwd ?? process.cwd();
56
- const filePath = path.isAbsolute(args.path) ? args.path : path.resolve(cwd, args.path);
57
- if (args.createDirs) {
58
- await fs.mkdir(path.dirname(filePath), { recursive: true });
45
+ class ActionLogWriter {
46
+ filePath;
47
+ constructor(taskDir) {
48
+ const dir = taskDir || process.env.KEVE_TASK_DIR || '.keve';
49
+ const logDir = path.join(dir, 'test-artifacts', `round-${process.env.KEVE_ROUND || 'latest'}`);
50
+ fs.mkdirSync(logDir, { recursive: true });
51
+ this.filePath = path.join(logDir, 'action-log.jsonl');
52
+ }
53
+ /** Append a single record */
54
+ append(record) {
55
+ const line = JSON.stringify(record);
56
+ fs.appendFileSync(this.filePath, line + '\n', 'utf-8');
57
+ }
58
+ /** Append multiple records */
59
+ appendAll(records) {
60
+ for (const record of records) {
61
+ this.append(record);
59
62
  }
60
- await fs.writeFile(filePath, args.content, 'utf-8');
61
- return { ok: true, path: filePath, bytes: Buffer.byteLength(args.content, 'utf-8') };
62
- },
63
- };
63
+ }
64
+ /** Read all records (for script-refine) */
65
+ readAll() {
66
+ if (!fs.existsSync(this.filePath))
67
+ return [];
68
+ const content = fs.readFileSync(this.filePath, 'utf-8');
69
+ return content
70
+ .split('\n')
71
+ .filter(line => line.trim())
72
+ .map(line => JSON.parse(line));
73
+ }
74
+ /** Get file path for external consumers */
75
+ getFilePath() {
76
+ return this.filePath;
77
+ }
78
+ }
79
+ exports.ActionLogWriter = ActionLogWriter;