minovative-mind-cli 2.11.5 → 2.13.0
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/README.md +27 -1
- package/dist/commands/chat.js +3 -1
- package/dist/commands/eval.d.ts +22 -0
- package/dist/commands/eval.js +141 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/services/agent/slashCommands.js +4 -2
- package/dist/services/agent/toolLoop.d.ts +4 -0
- package/dist/services/agent/toolLoop.js +61 -10
- package/dist/services/agent-tools.d.ts +5 -5
- package/dist/services/agent-tools.js +150 -11
- package/dist/services/contextAgent.d.ts +1 -0
- package/dist/services/contextAgent.js +29 -6
- package/dist/services/ideOptimization.d.ts +15 -0
- package/dist/services/ideOptimization.js +169 -0
- package/dist/services/metrics.d.ts +10 -0
- package/dist/services/metrics.js +24 -0
- package/dist/services/orchestration/messageBus.d.ts +81 -41
- package/dist/services/orchestration/messageBus.js +242 -98
- package/dist/services/orchestration/orchestrator.d.ts +6 -6
- package/dist/services/orchestration/orchestrator.js +32 -21
- package/dist/services/orchestration/scopedTools.d.ts +7 -1
- package/dist/services/orchestration/scopedTools.js +45 -9
- package/dist/services/orchestration/subAgent.d.ts +19 -17
- package/dist/services/orchestration/subAgent.js +98 -81
- package/dist/services/swebench/gitDiffExtractor.d.ts +57 -0
- package/dist/services/swebench/gitDiffExtractor.js +209 -0
- package/dist/services/swebench/index.d.ts +4 -0
- package/dist/services/swebench/index.js +4 -0
- package/dist/services/swebench/instanceLoader.d.ts +21 -0
- package/dist/services/swebench/instanceLoader.js +171 -0
- package/dist/services/swebench/sweBenchRunnerService.d.ts +38 -0
- package/dist/services/swebench/sweBenchRunnerService.js +618 -0
- package/dist/services/swebench/types.d.ts +167 -0
- package/dist/services/swebench/types.js +7 -0
- package/dist/services/verificationService.js +3 -0
- package/dist/utils/fuzzyMatch.d.ts +51 -21
- package/dist/utils/fuzzyMatch.js +37 -122
- package/dist/utils/projectStorage.js +10 -5
- package/dist/utils/systemPrompts.d.ts +1 -1
- package/dist/utils/systemPrompts.js +10 -4
- package/oclif.manifest.json +137 -1
- package/package.json +1 -1
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
3
|
+
import * as fs from 'node:fs';
|
|
4
|
+
import * as path from 'node:path';
|
|
5
|
+
const execFileAsync = promisify(execFile);
|
|
6
|
+
/**
|
|
7
|
+
* Safely executes a git command in the target workspace directory.
|
|
8
|
+
*/
|
|
9
|
+
async function runGit(args, cwd, maxBuffer = 20 * 1024 * 1024) {
|
|
10
|
+
try {
|
|
11
|
+
const { stdout, stderr } = await execFileAsync('git', args, {
|
|
12
|
+
cwd,
|
|
13
|
+
maxBuffer,
|
|
14
|
+
encoding: 'utf-8',
|
|
15
|
+
env: {
|
|
16
|
+
...process.env,
|
|
17
|
+
GIT_PAGER: 'cat',
|
|
18
|
+
GIT_TERMINAL_PROMPT: '0',
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
return { stdout, stderr };
|
|
22
|
+
}
|
|
23
|
+
catch (err) {
|
|
24
|
+
const execErr = err;
|
|
25
|
+
throw new Error(`Git command failed: git ${args.join(' ')} (in ${cwd})\n${execErr.stderr || execErr.message}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Checks whether the target directory contains a valid git repository.
|
|
30
|
+
*/
|
|
31
|
+
export async function isGitRepository(workspaceDir) {
|
|
32
|
+
try {
|
|
33
|
+
const gitDir = path.join(workspaceDir, '.git');
|
|
34
|
+
if (!fs.existsSync(gitDir)) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
const { stdout } = await runGit(['rev-parse', '--is-inside-work-tree'], workspaceDir);
|
|
38
|
+
return stdout.trim() === 'true';
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Gets the current HEAD commit hash of the git repository.
|
|
46
|
+
*/
|
|
47
|
+
export async function getHeadCommit(workspaceDir) {
|
|
48
|
+
const { stdout } = await runGit(['rev-parse', 'HEAD'], workspaceDir);
|
|
49
|
+
return stdout.trim();
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Resets the workspace git repository to a clean state matching baseCommit or HEAD.
|
|
53
|
+
*/
|
|
54
|
+
export async function resetWorkspaceRepo(workspaceDir, baseCommit) {
|
|
55
|
+
const isRepo = await isGitRepository(workspaceDir);
|
|
56
|
+
if (!isRepo) {
|
|
57
|
+
throw new Error(`Directory is not a git repository: ${workspaceDir}`);
|
|
58
|
+
}
|
|
59
|
+
if (baseCommit) {
|
|
60
|
+
await runGit(['checkout', baseCommit, '--force'], workspaceDir);
|
|
61
|
+
await runGit(['reset', '--hard', baseCommit], workspaceDir);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
await runGit(['reset', '--hard', 'HEAD'], workspaceDir);
|
|
65
|
+
}
|
|
66
|
+
// Clean untracked files and directories
|
|
67
|
+
await runGit(['clean', '-fdx'], workspaceDir);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Extracts a unified git patch representing all modifications made by the model.
|
|
71
|
+
* Produces standard SWE-bench format (patch starting with `diff --git` or empty string).
|
|
72
|
+
*/
|
|
73
|
+
export async function extractGitPatch(workspaceDir, options = {}) {
|
|
74
|
+
const opts = typeof options === 'string' ? { baseCommit: options } : options;
|
|
75
|
+
const isRepo = await isGitRepository(workspaceDir);
|
|
76
|
+
if (!isRepo) {
|
|
77
|
+
throw new Error(`Cannot extract patch: Directory is not a git repository (${workspaceDir})`);
|
|
78
|
+
}
|
|
79
|
+
const maxBuffer = opts.maxBuffer ?? 20 * 1024 * 1024;
|
|
80
|
+
// Include untracked files in the git index as intent-to-add so git diff includes newly created files
|
|
81
|
+
if (opts.includeUntracked !== false) {
|
|
82
|
+
try {
|
|
83
|
+
await runGit(['add', '-N', '.'], workspaceDir, maxBuffer);
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
// Intent-to-add might fail on locked files or non-standard repos; continue anyway
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
let patch = '';
|
|
90
|
+
if (opts.baseCommit) {
|
|
91
|
+
try {
|
|
92
|
+
const { stdout } = await runGit(['diff', '--binary', opts.baseCommit, '--'], workspaceDir, maxBuffer);
|
|
93
|
+
patch = stdout;
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
// Fallback without --binary
|
|
97
|
+
const { stdout } = await runGit(['diff', opts.baseCommit, '--'], workspaceDir, maxBuffer);
|
|
98
|
+
patch = stdout;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
// If no base commit is specified, diff against HEAD
|
|
103
|
+
const { stdout } = await runGit(['diff', '--binary', 'HEAD', '--'], workspaceDir, maxBuffer);
|
|
104
|
+
patch = stdout;
|
|
105
|
+
}
|
|
106
|
+
return normalizePatch(patch);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Normalizes git unified diff patch text:
|
|
110
|
+
* - Trims superfluous leading/trailing whitespace
|
|
111
|
+
* - Ensures empty diff returns exact empty string ""
|
|
112
|
+
* - Preserves trailing newline if content exists
|
|
113
|
+
*/
|
|
114
|
+
export function normalizePatch(patch) {
|
|
115
|
+
if (!patch || patch.trim().length === 0) {
|
|
116
|
+
return '';
|
|
117
|
+
}
|
|
118
|
+
const trimmed = patch.trimEnd();
|
|
119
|
+
if (trimmed.length === 0) {
|
|
120
|
+
return '';
|
|
121
|
+
}
|
|
122
|
+
return trimmed + '\n';
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Validates whether a patch conforms to standard unified diff structure.
|
|
126
|
+
*/
|
|
127
|
+
export function validatePatchFormat(patch) {
|
|
128
|
+
if (!patch || patch.trim().length === 0) {
|
|
129
|
+
return { valid: true };
|
|
130
|
+
}
|
|
131
|
+
const issues = [];
|
|
132
|
+
const hasDiffHeader = /^diff --git a\/.+ b\/.+$/m.test(patch);
|
|
133
|
+
const hasFileHeader = /^--- (a\/.+|\/dev\/null)$/m.test(patch) && /^\+\+\+ (b\/.+|\/dev\/null)$/m.test(patch);
|
|
134
|
+
const hasHunkHeader = /^@@ -\d+(,\d+)? \+\d+(,\d+)? @@/m.test(patch);
|
|
135
|
+
if (!hasDiffHeader) {
|
|
136
|
+
issues.push('Missing "diff --git a/... b/..." header');
|
|
137
|
+
}
|
|
138
|
+
if (!hasFileHeader) {
|
|
139
|
+
issues.push('Missing "--- a/..." and "+++ b/..." unified diff headers');
|
|
140
|
+
}
|
|
141
|
+
if (!hasHunkHeader) {
|
|
142
|
+
issues.push('Missing "@@ ... @@" hunk header');
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
valid: issues.length === 0,
|
|
146
|
+
issues: issues.length > 0 ? issues : undefined,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Checks out a specific base commit in the repository.
|
|
151
|
+
*/
|
|
152
|
+
export async function checkoutBaseCommit(workspaceDir, baseCommit, options) {
|
|
153
|
+
const isRepo = await isGitRepository(workspaceDir);
|
|
154
|
+
if (!isRepo) {
|
|
155
|
+
return { success: false, error: `Directory ${workspaceDir} is not a valid git repository.` };
|
|
156
|
+
}
|
|
157
|
+
try {
|
|
158
|
+
await runGit(['checkout', '-f', baseCommit], workspaceDir);
|
|
159
|
+
return { success: true };
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
if (options?.fetchIfMissing) {
|
|
163
|
+
try {
|
|
164
|
+
await runGit(['fetch', 'origin', baseCommit], workspaceDir);
|
|
165
|
+
await runGit(['checkout', '-f', baseCommit], workspaceDir);
|
|
166
|
+
return { success: true };
|
|
167
|
+
}
|
|
168
|
+
catch (fetchErr) {
|
|
169
|
+
return { success: false, error: `Failed to checkout base commit ${baseCommit}: ${fetchErr?.message || err?.message}` };
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return { success: false, error: `Failed to checkout base commit ${baseCommit}: ${err?.message || String(err)}` };
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Clones a repository if it doesn't already exist or ensures it is checked out.
|
|
177
|
+
*/
|
|
178
|
+
export async function cloneOrEnsureRepo(repo, targetDir, options) {
|
|
179
|
+
const isRepo = await isGitRepository(targetDir);
|
|
180
|
+
if (isRepo) {
|
|
181
|
+
if (options?.baseCommit) {
|
|
182
|
+
const checkoutRes = await checkoutBaseCommit(targetDir, options.baseCommit, { fetchIfMissing: true });
|
|
183
|
+
if (!checkoutRes.success) {
|
|
184
|
+
return { success: false, repoDir: targetDir, error: checkoutRes.error };
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return { success: true, repoDir: targetDir };
|
|
188
|
+
}
|
|
189
|
+
try {
|
|
190
|
+
await fs.promises.mkdir(path.dirname(targetDir), { recursive: true });
|
|
191
|
+
const url = options?.cloneUrl || `https://github.com/${repo}.git`;
|
|
192
|
+
const cloneArgs = ['clone'];
|
|
193
|
+
if (options?.shallow) {
|
|
194
|
+
cloneArgs.push('--depth', '1');
|
|
195
|
+
}
|
|
196
|
+
cloneArgs.push(url, targetDir);
|
|
197
|
+
await runGit(cloneArgs, path.dirname(targetDir));
|
|
198
|
+
if (options?.baseCommit) {
|
|
199
|
+
const checkoutRes = await checkoutBaseCommit(targetDir, options.baseCommit, { fetchIfMissing: true });
|
|
200
|
+
if (!checkoutRes.success) {
|
|
201
|
+
return { success: false, repoDir: targetDir, error: checkoutRes.error };
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return { success: true, repoDir: targetDir };
|
|
205
|
+
}
|
|
206
|
+
catch (err) {
|
|
207
|
+
return { success: false, repoDir: targetDir, error: `Failed to clone repository ${repo}: ${err?.message || String(err)}` };
|
|
208
|
+
}
|
|
209
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { SWEBenchInstance, SWEBenchPrediction, InstanceFilterOptions } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Loads SWE-bench instances from a JSON or JSONL file.
|
|
4
|
+
*/
|
|
5
|
+
export declare function loadInstancesFromFile(filePath: string, filterOptions?: InstanceFilterOptions): Promise<SWEBenchInstance[]>;
|
|
6
|
+
/**
|
|
7
|
+
* Applies filtering, pagination, and deterministic shuffling to an array of instances.
|
|
8
|
+
*/
|
|
9
|
+
export declare function filterInstances(instances: SWEBenchInstance[], options?: InstanceFilterOptions): SWEBenchInstance[];
|
|
10
|
+
/**
|
|
11
|
+
* Parses a SWE-bench predictions JSONL file into an array of predictions.
|
|
12
|
+
*/
|
|
13
|
+
export declare function parsePredictions(predictionsPath: string): Promise<SWEBenchPrediction[]>;
|
|
14
|
+
/**
|
|
15
|
+
* Saves a list of SWE-bench predictions to a JSONL file.
|
|
16
|
+
*/
|
|
17
|
+
export declare function savePredictions(predictions: SWEBenchPrediction[], outputPath: string): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Appends a single prediction object to a JSONL file immediately.
|
|
20
|
+
*/
|
|
21
|
+
export declare function appendPrediction(prediction: SWEBenchPrediction, outputPath: string): Promise<void>;
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import * as readline from 'node:readline';
|
|
4
|
+
/**
|
|
5
|
+
* Loads SWE-bench instances from a JSON or JSONL file.
|
|
6
|
+
*/
|
|
7
|
+
export async function loadInstancesFromFile(filePath, filterOptions = {}) {
|
|
8
|
+
const resolvedPath = path.resolve(filePath);
|
|
9
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
10
|
+
throw new Error(`Failed to load instances: file not found at ${resolvedPath}`);
|
|
11
|
+
}
|
|
12
|
+
const ext = path.extname(resolvedPath).toLowerCase();
|
|
13
|
+
let instances = [];
|
|
14
|
+
try {
|
|
15
|
+
if (ext === '.jsonl') {
|
|
16
|
+
instances = await loadJsonlInstances(resolvedPath);
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
instances = await loadJsonInstances(resolvedPath);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
throw new Error(`Failed to load instances from ${resolvedPath}: ${err?.message || String(err)}`);
|
|
24
|
+
}
|
|
25
|
+
return filterInstances(instances, filterOptions);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Loads instances from a JSON file.
|
|
29
|
+
*/
|
|
30
|
+
async function loadJsonInstances(filePath) {
|
|
31
|
+
const content = await fs.promises.readFile(filePath, 'utf-8');
|
|
32
|
+
const parsed = JSON.parse(content);
|
|
33
|
+
if (Array.isArray(parsed)) {
|
|
34
|
+
return parsed;
|
|
35
|
+
}
|
|
36
|
+
if (parsed && typeof parsed === 'object') {
|
|
37
|
+
if (Array.isArray(parsed.instances)) {
|
|
38
|
+
return parsed.instances;
|
|
39
|
+
}
|
|
40
|
+
if (Array.isArray(parsed.data)) {
|
|
41
|
+
return parsed.data;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
throw new Error(`Unrecognized JSON format in ${filePath}. Expected an array or { instances: [...] }`);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Loads instances from a JSONL file line-by-line.
|
|
48
|
+
*/
|
|
49
|
+
async function loadJsonlInstances(filePath) {
|
|
50
|
+
const instances = [];
|
|
51
|
+
const fileStream = fs.createReadStream(filePath, { encoding: 'utf-8' });
|
|
52
|
+
const rl = readline.createInterface({
|
|
53
|
+
input: fileStream,
|
|
54
|
+
crlfDelay: Infinity,
|
|
55
|
+
});
|
|
56
|
+
let lineNum = 0;
|
|
57
|
+
for await (const line of rl) {
|
|
58
|
+
lineNum++;
|
|
59
|
+
const trimmed = line.trim();
|
|
60
|
+
if (!trimmed || trimmed.startsWith('#') || trimmed.startsWith('//')) {
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
const parsed = JSON.parse(trimmed);
|
|
65
|
+
if (parsed && typeof parsed === 'object' && parsed.instance_id) {
|
|
66
|
+
instances.push(parsed);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
71
|
+
throw new Error(`Failed to parse line ${lineNum} in JSONL ${filePath}: ${msg}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return instances;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Applies filtering, pagination, and deterministic shuffling to an array of instances.
|
|
78
|
+
*/
|
|
79
|
+
export function filterInstances(instances, options = {}) {
|
|
80
|
+
let result = [...instances];
|
|
81
|
+
if (options.repo) {
|
|
82
|
+
const targetRepo = options.repo.toLowerCase();
|
|
83
|
+
result = result.filter((inst) => inst.repo && inst.repo.toLowerCase().includes(targetRepo));
|
|
84
|
+
}
|
|
85
|
+
if (options.instanceIds && options.instanceIds.length > 0) {
|
|
86
|
+
const idSet = new Set(options.instanceIds);
|
|
87
|
+
result = result.filter((inst) => idSet.has(inst.instance_id));
|
|
88
|
+
}
|
|
89
|
+
if (options.shuffle) {
|
|
90
|
+
result = pseudoShuffle(result, options.seed ?? 42);
|
|
91
|
+
}
|
|
92
|
+
if (typeof options.offset === 'number' && options.offset > 0) {
|
|
93
|
+
result = result.slice(options.offset);
|
|
94
|
+
}
|
|
95
|
+
if (typeof options.limit === 'number' && options.limit > 0) {
|
|
96
|
+
result = result.slice(0, options.limit);
|
|
97
|
+
}
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Deterministic pseudo-random shuffle (Fisher-Yates) using a simple LCG algorithm.
|
|
102
|
+
*/
|
|
103
|
+
function pseudoShuffle(items, seed) {
|
|
104
|
+
const array = [...items];
|
|
105
|
+
let currentSeed = seed;
|
|
106
|
+
const random = () => {
|
|
107
|
+
currentSeed = (currentSeed * 9301 + 49297) % 233280;
|
|
108
|
+
return currentSeed / 233280;
|
|
109
|
+
};
|
|
110
|
+
for (let i = array.length - 1; i > 0; i--) {
|
|
111
|
+
const j = Math.floor(random() * (i + 1));
|
|
112
|
+
const temp = array[i];
|
|
113
|
+
array[i] = array[j];
|
|
114
|
+
array[j] = temp;
|
|
115
|
+
}
|
|
116
|
+
return array;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Parses a SWE-bench predictions JSONL file into an array of predictions.
|
|
120
|
+
*/
|
|
121
|
+
export async function parsePredictions(predictionsPath) {
|
|
122
|
+
const resolvedPath = path.resolve(predictionsPath);
|
|
123
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
124
|
+
return [];
|
|
125
|
+
}
|
|
126
|
+
const predictions = [];
|
|
127
|
+
const fileStream = fs.createReadStream(resolvedPath, { encoding: 'utf-8' });
|
|
128
|
+
const rl = readline.createInterface({
|
|
129
|
+
input: fileStream,
|
|
130
|
+
crlfDelay: Infinity,
|
|
131
|
+
});
|
|
132
|
+
for await (const line of rl) {
|
|
133
|
+
const trimmed = line.trim();
|
|
134
|
+
if (!trimmed)
|
|
135
|
+
continue;
|
|
136
|
+
try {
|
|
137
|
+
const parsed = JSON.parse(trimmed);
|
|
138
|
+
if (parsed && parsed.instance_id) {
|
|
139
|
+
predictions.push(parsed);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// Skip malformed individual prediction lines
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return predictions;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Saves a list of SWE-bench predictions to a JSONL file.
|
|
150
|
+
*/
|
|
151
|
+
export async function savePredictions(predictions, outputPath) {
|
|
152
|
+
const resolvedPath = path.resolve(outputPath);
|
|
153
|
+
const dir = path.dirname(resolvedPath);
|
|
154
|
+
if (!fs.existsSync(dir)) {
|
|
155
|
+
await fs.promises.mkdir(dir, { recursive: true });
|
|
156
|
+
}
|
|
157
|
+
const lines = predictions.map((pred) => JSON.stringify(pred)).join('\n') + (predictions.length > 0 ? '\n' : '');
|
|
158
|
+
await fs.promises.writeFile(resolvedPath, lines, 'utf-8');
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Appends a single prediction object to a JSONL file immediately.
|
|
162
|
+
*/
|
|
163
|
+
export async function appendPrediction(prediction, outputPath) {
|
|
164
|
+
const resolvedPath = path.resolve(outputPath);
|
|
165
|
+
const dir = path.dirname(resolvedPath);
|
|
166
|
+
if (!fs.existsSync(dir)) {
|
|
167
|
+
await fs.promises.mkdir(dir, { recursive: true });
|
|
168
|
+
}
|
|
169
|
+
const line = JSON.stringify(prediction) + '\n';
|
|
170
|
+
await fs.promises.appendFile(resolvedPath, line, 'utf-8');
|
|
171
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { SWEBenchInstance, SWEBenchInstanceResult, SWEBenchEvaluationOptions, SWEBenchEvaluationSummary, SWEBenchEvaluationMetrics, RunInstanceOptions } from './types.js';
|
|
2
|
+
export declare const DEFAULT_MODEL_NAME = "minovative-mind-agent";
|
|
3
|
+
export declare const DEFAULT_TIMEOUT_MS: number;
|
|
4
|
+
/**
|
|
5
|
+
* Formats a SWE-bench instance into a comprehensive problem prompt for the agent.
|
|
6
|
+
*/
|
|
7
|
+
export declare function buildInstancePrompt(instance: SWEBenchInstance): string;
|
|
8
|
+
/**
|
|
9
|
+
* Resolves the workspace directory for an instance based on configuration.
|
|
10
|
+
*/
|
|
11
|
+
export declare function resolveInstanceWorkspaceDir(instance: SWEBenchInstance, options?: {
|
|
12
|
+
workspacesBaseDir?: string;
|
|
13
|
+
workspaceDirMap?: Record<string, string>;
|
|
14
|
+
defaultDir?: string;
|
|
15
|
+
autoCloneRepos?: boolean;
|
|
16
|
+
}): string;
|
|
17
|
+
/**
|
|
18
|
+
* Executes the mmcli agent loop on a single SWE-bench instance and extracts the resulting patch.
|
|
19
|
+
*/
|
|
20
|
+
export declare function runSWEBenchInstance(instance: SWEBenchInstance, options?: RunInstanceOptions): Promise<SWEBenchInstanceResult>;
|
|
21
|
+
/**
|
|
22
|
+
* Runs evaluation across a suite of SWE-bench instances.
|
|
23
|
+
*/
|
|
24
|
+
export declare function runSWEBenchEvaluation(options: SWEBenchEvaluationOptions): Promise<SWEBenchEvaluationSummary>;
|
|
25
|
+
/**
|
|
26
|
+
* Computes aggregate metrics across SWE-bench evaluation results including token usage,
|
|
27
|
+
* repository pass rates, diff sizes, and timing statistics.
|
|
28
|
+
*/
|
|
29
|
+
export declare function calculateEvaluationMetrics(results: SWEBenchInstanceResult[], totalDurationMs: number, modelName?: string): SWEBenchEvaluationMetrics;
|
|
30
|
+
/**
|
|
31
|
+
* Saves a structured, public-ready evaluation report JSON file containing summary statistics,
|
|
32
|
+
* token economics, repository breakdown, and individual instance outcomes.
|
|
33
|
+
*/
|
|
34
|
+
export declare function saveEvaluationReport(summary: SWEBenchEvaluationSummary, reportPath: string): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Formats a clean, high-impact ASCII terminal summary dashboard for SWE-bench evaluation runs.
|
|
37
|
+
*/
|
|
38
|
+
export declare function formatEvaluationReportSummary(summary: SWEBenchEvaluationSummary): string;
|