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.
Files changed (43) hide show
  1. package/README.md +27 -1
  2. package/dist/commands/chat.js +3 -1
  3. package/dist/commands/eval.d.ts +22 -0
  4. package/dist/commands/eval.js +141 -0
  5. package/dist/index.d.ts +1 -0
  6. package/dist/index.js +1 -0
  7. package/dist/services/agent/slashCommands.js +4 -2
  8. package/dist/services/agent/toolLoop.d.ts +4 -0
  9. package/dist/services/agent/toolLoop.js +61 -10
  10. package/dist/services/agent-tools.d.ts +5 -5
  11. package/dist/services/agent-tools.js +150 -11
  12. package/dist/services/contextAgent.d.ts +1 -0
  13. package/dist/services/contextAgent.js +29 -6
  14. package/dist/services/ideOptimization.d.ts +15 -0
  15. package/dist/services/ideOptimization.js +169 -0
  16. package/dist/services/metrics.d.ts +10 -0
  17. package/dist/services/metrics.js +24 -0
  18. package/dist/services/orchestration/messageBus.d.ts +81 -41
  19. package/dist/services/orchestration/messageBus.js +242 -98
  20. package/dist/services/orchestration/orchestrator.d.ts +6 -6
  21. package/dist/services/orchestration/orchestrator.js +32 -21
  22. package/dist/services/orchestration/scopedTools.d.ts +7 -1
  23. package/dist/services/orchestration/scopedTools.js +45 -9
  24. package/dist/services/orchestration/subAgent.d.ts +19 -17
  25. package/dist/services/orchestration/subAgent.js +98 -81
  26. package/dist/services/swebench/gitDiffExtractor.d.ts +57 -0
  27. package/dist/services/swebench/gitDiffExtractor.js +209 -0
  28. package/dist/services/swebench/index.d.ts +4 -0
  29. package/dist/services/swebench/index.js +4 -0
  30. package/dist/services/swebench/instanceLoader.d.ts +21 -0
  31. package/dist/services/swebench/instanceLoader.js +171 -0
  32. package/dist/services/swebench/sweBenchRunnerService.d.ts +38 -0
  33. package/dist/services/swebench/sweBenchRunnerService.js +618 -0
  34. package/dist/services/swebench/types.d.ts +167 -0
  35. package/dist/services/swebench/types.js +7 -0
  36. package/dist/services/verificationService.js +3 -0
  37. package/dist/utils/fuzzyMatch.d.ts +51 -21
  38. package/dist/utils/fuzzyMatch.js +37 -122
  39. package/dist/utils/projectStorage.js +10 -5
  40. package/dist/utils/systemPrompts.d.ts +1 -1
  41. package/dist/utils/systemPrompts.js +10 -4
  42. package/oclif.manifest.json +137 -1
  43. package/package.json +1 -1
@@ -41,7 +41,7 @@ export function getScopedToolDeclarations() {
41
41
  },
42
42
  content: {
43
43
  type: 'STRING',
44
- description: 'The semantic intent or message content',
44
+ description: 'The semantic intent or message content (concise summary, max 500 chars)',
45
45
  },
46
46
  affectedFiles: {
47
47
  type: 'ARRAY',
@@ -58,10 +58,23 @@ export function getScopedToolDeclarations() {
58
58
  },
59
59
  {
60
60
  name: 'read_messages',
61
- description: 'Fetch any new messages or activity from other agents on the bus.',
61
+ description: 'Fetch intelligent updates from other agents on the bus. Can filter by file, agent ID, or signal type.',
62
62
  parameters: {
63
63
  type: 'OBJECT',
64
- properties: {},
64
+ properties: {
65
+ file: {
66
+ type: 'STRING',
67
+ description: 'Optional: Filter updates touching a specific file path (e.g., "src/services/auth.ts")',
68
+ },
69
+ fromAgent: {
70
+ type: 'STRING',
71
+ description: 'Optional: Filter updates from a specific collaborator agent ID',
72
+ },
73
+ type: {
74
+ type: 'STRING',
75
+ description: 'Optional: Filter by signal type ("completion", "warning", "discovery", "request")',
76
+ },
77
+ },
65
78
  },
66
79
  },
67
80
  ];
@@ -80,8 +93,9 @@ export function getScopedToolDeclarations() {
80
93
  * @param locks - Shared file lock registry instance
81
94
  * @param onProgress - Callback to notify parent of sub-agent progress
82
95
  * @param options - Optional sub-path auto-focus and override configuration
96
+ * @param taskScope - Optional task scope metadata (targetFiles, dependsOn)
83
97
  */
84
- export async function executeScopedTool(name, args, workspaceRoot, agentId, bus, locks, onProgress, options) {
98
+ export async function executeScopedTool(name, args, workspaceRoot, agentId, bus, locks, onProgress, options, taskScope) {
85
99
  // Update heartbeat so the orchestrator knows we are making progress
86
100
  onProgress();
87
101
  const timestamp = Date.now();
@@ -89,23 +103,27 @@ export async function executeScopedTool(name, args, workspaceRoot, agentId, bus,
89
103
  let targetDesc = 'workspace';
90
104
  let status = 'success';
91
105
  let result = null;
92
- let resultSummary = undefined;
106
+ let resultSummary;
93
107
  try {
94
108
  // ─── Orchestration-Specific Tools ────────────────────────────────
95
109
  if (name === 'post_message') {
96
110
  const type = args.type;
111
+ let content = String(args.content || '');
112
+ if (content.length > 500) {
113
+ content = content.substring(0, 500) + '... (truncated)';
114
+ }
97
115
  const signal = {
98
116
  type,
99
117
  timestamp,
100
118
  fromAgent: agentId,
101
- content: args.content,
119
+ content,
102
120
  };
103
121
  if (type === 'discovery')
104
122
  signal.affectedFiles = args.affectedFiles || [];
105
123
  if (type === 'request')
106
124
  signal.toAgent = args.toAgent || 'all';
107
125
  if (type === 'completion')
108
- signal.summary = args.content; // map completion summary
126
+ signal.summary = content; // map completion summary
109
127
  const accepted = bus.postSignal(signal);
110
128
  if (!accepted) {
111
129
  return { error: `Message bus rejected signal. You have hit the max signal cap (${MessageBus.MAX_SIGNALS_PER_AGENT}). Stop sending signals.` };
@@ -113,7 +131,18 @@ export async function executeScopedTool(name, args, workspaceRoot, agentId, bus,
113
131
  return { success: true, message: 'Message posted to bus.' };
114
132
  }
115
133
  if (name === 'read_messages') {
116
- const unread = bus.getUnread(agentId);
134
+ const unread = bus.queryBus({
135
+ agentId,
136
+ file: args.file,
137
+ fromAgent: args.fromAgent,
138
+ type: args.type,
139
+ onlyMutations: true,
140
+ targetFiles: taskScope?.targetFiles,
141
+ dependsOn: taskScope?.dependsOn,
142
+ });
143
+ if (unread.activities.length === 0 && unread.signals.length === 0) {
144
+ return { status: 'No new peer messages or workspace mutations.' };
145
+ }
117
146
  return {
118
147
  activityLogs: MessageBus.formatActivityEntries(unread.activities),
119
148
  semanticSignals: MessageBus.formatSignals(unread.signals),
@@ -157,9 +186,16 @@ export async function executeScopedTool(name, args, workspaceRoot, agentId, bus,
157
186
  // If we got a file lock and had context from a previous writer, we should
158
187
  // inject that diff info back into the agent's tool return payload so it
159
188
  // knows someone else changed the file while it was queued.
160
- if (diffContext && typeof result === 'object') {
189
+ if (diffContext && typeof result === 'object' && result !== null) {
161
190
  result._orchestrationWarning = `NOTICE: Another agent modified this file while you were waiting. Diff context: ${diffContext}`;
162
191
  }
192
+ // In-band relevance-gated urgent signals (warnings, targeted requests, or upstream completions)
193
+ if (typeof result === 'object' && result !== null && typeof bus?.peekUrgentSignals === 'function') {
194
+ const urgentSignals = bus.peekUrgentSignals(agentId, taskScope);
195
+ if (urgentSignals && urgentSignals.length > 0) {
196
+ result._orchestrationNotice = MessageBus.formatSignals(urgentSignals);
197
+ }
198
+ }
163
199
  }
164
200
  finally {
165
201
  // Release the lock if we grabbed one
@@ -1,11 +1,12 @@
1
1
  /**
2
- * @fileoverview Sub-Agent Runner for Orchestration.
2
+ * @file Sub-Agent Runner for Orchestration.
3
3
  *
4
4
  * Implements the lifecycle, health monitoring, and tool-loop execution for a single
5
5
  * parallelized sub-agent.
6
6
  */
7
7
  import { MessageBus } from './messageBus.js';
8
8
  import { FileLockRegistry } from './fileLockRegistry.js';
9
+ import { TaskScope } from './scopedTools.js';
9
10
  /**
10
11
  * Scopes workspace file blocks within a context string by replacing full implementation
11
12
  * bodies with compact AST declaration outlines (types, classes, function signatures),
@@ -53,31 +54,20 @@ export declare class SubAgentRunner {
53
54
  private readonly globalContext;
54
55
  private readonly onProgress?;
55
56
  private readonly onTool?;
57
+ private readonly taskScope?;
58
+ /** Max time without a tool call or response before the agent is considered stalled */
59
+ static readonly STALL_TIMEOUT_MS = 300000;
56
60
  private chat;
57
- private lastHeartbeat;
58
61
  private creditsUsed;
59
62
  private inputTokens;
63
+ private lastHeartbeat;
60
64
  private outputTokens;
61
- /** Max time without a tool call or response before the agent is considered stalled */
62
- static readonly STALL_TIMEOUT_MS = 300000;
63
- constructor(taskId: string, intent: string, workspaceRoot: string, bus: MessageBus, locks: FileLockRegistry, globalContext: string, onProgress?: ((msg: string) => void) | undefined, onTool?: ((msg: string) => void) | undefined);
64
- /**
65
- * Constructs the base system instruction for this specific agent,
66
- * injecting scoped AST outlines for referenced workspace files to eliminate
67
- * multi-megabyte context bloat during parallel sub-agent execution.
68
- */
69
- private buildSystemInstruction;
70
65
  /**
71
66
  * Updates the heartbeat. Passed to `executeScopedTool` to ensure the agent
72
67
  * isn't marked as stalled while performing long-running commands.
73
68
  */
74
69
  private pingHeartbeat;
75
- /**
76
- * Executes the sub-agent with a health monitor harness.
77
- * Runs the tool loop until the model stops returning function calls,
78
- * an error occurs, or the stall timeout is hit.
79
- */
80
- execute(signal: AbortSignal): Promise<SubAgentResult>;
70
+ constructor(taskId: string, intent: string, workspaceRoot: string, bus: MessageBus, locks: FileLockRegistry, globalContext: string, onProgress?: ((msg: string) => void) | undefined, onTool?: ((msg: string) => void) | undefined, taskScope?: TaskScope | undefined);
81
71
  /**
82
72
  * Compacts older tool responses in the chat session history into concise references
83
73
  * (e.g. `[Read X lines from file.ts - tool execution completed]`), drastically reducing
@@ -87,6 +77,18 @@ export declare class SubAgentRunner {
87
77
  * @param turnsToKeep Number of recent turns to preserve in full (default: 1).
88
78
  */
89
79
  compactOlderToolResponses(turnsToKeep?: number): void;
80
+ /**
81
+ * Executes the sub-agent with a health monitor harness.
82
+ * Runs the tool loop until the model stops returning function calls,
83
+ * an error occurs, or the stall timeout is hit.
84
+ */
85
+ execute(signal: AbortSignal): Promise<SubAgentResult>;
86
+ /**
87
+ * Constructs the base system instruction for this specific agent,
88
+ * injecting scoped AST outlines for referenced workspace files to eliminate
89
+ * multi-megabyte context bloat during parallel sub-agent execution.
90
+ */
91
+ private buildSystemInstruction;
90
92
  /**
91
93
  * Accumulates token usage from the chat session.
92
94
  */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @fileoverview Sub-Agent Runner for Orchestration.
2
+ * @file Sub-Agent Runner for Orchestration.
3
3
  *
4
4
  * Implements the lifecycle, health monitoring, and tool-loop execution for a single
5
5
  * parallelized sub-agent.
@@ -64,6 +64,12 @@ function findMatchingFunctionCall(modelEntry, toolName, partIndex) {
64
64
  * @returns Compacted tool execution reference string.
65
65
  */
66
66
  export function createCompactToolReference(toolName, output, args) {
67
+ if (toolName === 'read_messages') {
68
+ return '[read_messages - peer activity reviewed]';
69
+ }
70
+ if (toolName === 'post_message') {
71
+ return '[post_message - coordination signal posted]';
72
+ }
67
73
  if (typeof output !== 'string') {
68
74
  return `[${toolName} tool execution completed]`;
69
75
  }
@@ -126,14 +132,25 @@ export class SubAgentRunner {
126
132
  globalContext;
127
133
  onProgress;
128
134
  onTool;
135
+ taskScope;
136
+ /** Max time without a tool call or response before the agent is considered stalled */
137
+ static STALL_TIMEOUT_MS = 300_000;
129
138
  chat;
130
- lastHeartbeat = Date.now();
131
139
  creditsUsed = 0;
132
140
  inputTokens = 0;
141
+ lastHeartbeat = Date.now();
133
142
  outputTokens = 0;
134
- /** Max time without a tool call or response before the agent is considered stalled */
135
- static STALL_TIMEOUT_MS = 300_000;
136
- constructor(taskId, intent, workspaceRoot, bus, locks, globalContext, onProgress, onTool) {
143
+ /**
144
+ * Updates the heartbeat. Passed to `executeScopedTool` to ensure the agent
145
+ * isn't marked as stalled while performing long-running commands.
146
+ */
147
+ pingHeartbeat = (msg) => {
148
+ this.lastHeartbeat = Date.now();
149
+ if (msg && this.onProgress) {
150
+ this.onProgress(msg);
151
+ }
152
+ };
153
+ constructor(taskId, intent, workspaceRoot, bus, locks, globalContext, onProgress, onTool, taskScope) {
137
154
  this.taskId = taskId;
138
155
  this.intent = intent;
139
156
  this.workspaceRoot = workspaceRoot;
@@ -142,6 +159,7 @@ export class SubAgentRunner {
142
159
  this.globalContext = globalContext;
143
160
  this.onProgress = onProgress;
144
161
  this.onTool = onTool;
162
+ this.taskScope = taskScope;
145
163
  let model = getGlobalActiveModel();
146
164
  if (model === GEMINI_MODELS.AUTO)
147
165
  model = GEMINI_MODELS.FLASH;
@@ -154,44 +172,56 @@ export class SubAgentRunner {
154
172
  });
155
173
  }
156
174
  /**
157
- * Constructs the base system instruction for this specific agent,
158
- * injecting scoped AST outlines for referenced workspace files to eliminate
159
- * multi-megabyte context bloat during parallel sub-agent execution.
160
- */
161
- buildSystemInstruction() {
162
- const scopedContext = scopeContext(this.globalContext);
163
- return (`<identity>\n` +
164
- `You are an autonomous Senior software developer sub-agent executing a specific portion of a larger task.\n` +
165
- `</identity>\n\n` +
166
- `<task_info>\n` +
167
- `Your task ID is: ${this.taskId}\n` +
168
- `Your objective: ${this.intent}\n` +
169
- `</task_info>\n\n` +
170
- `<reference_context>\n` +
171
- `DO NOT IMPLEMENT THIS FULL REQUEST. THIS IS JUST FOR CONTEXT.\n\n` +
172
- `${scopedContext}\n` +
173
- `</reference_context>\n\n` +
174
- `<critical_guidelines>\n` +
175
- `1. You are ONE worker in a team. Focus EXCLUSIVELY on your specific objective: "${this.intent}".\n` +
176
- `2. DO NOT attempt to fulfill the entire original user request in the reference context. Other agents handle other tasks.\n` +
177
- `3. EXECUTION WORKFLOW:\n` +
178
- ` - Step 1 (Investigate): Use 'grep_search', 'read_file', or 'list_directory' to inspect the codebase as needed.\n` +
179
- ` - Step 2 (Execute): Use 'modify_file' or 'write_file' to implement the required changes.\n` +
180
- ` - Step 3 (Verify): Use 'run_debug_script', 'run_fuzz_probe', 'check_heap_delta', 'check_behavioral_drift', or 'run_command' to test your changes if necessary.\n` +
181
- ` - Step 4 (Conclude): Once your specific objective is fully met, stop calling tools and return a text summary of your changes.\n` +
182
- `4. Coordinate: Use 'read_messages' to check for updates from other agents. Use 'post_message' if you discover breaking changes affecting others.\n` +
183
- `</critical_guidelines>`);
184
- }
185
- /**
186
- * Updates the heartbeat. Passed to `executeScopedTool` to ensure the agent
187
- * isn't marked as stalled while performing long-running commands.
175
+ * Compacts older tool responses in the chat session history into concise references
176
+ * (e.g. `[Read X lines from file.ts - tool execution completed]`), drastically reducing
177
+ * context window bloat across multi-turn sub-agent executions while preserving
178
+ * Gemini's functionCall <-> functionResponse protocol.
179
+ *
180
+ * @param turnsToKeep Number of recent turns to preserve in full (default: 1).
188
181
  */
189
- pingHeartbeat = (msg) => {
190
- this.lastHeartbeat = Date.now();
191
- if (msg && this.onProgress) {
192
- this.onProgress(msg);
182
+ compactOlderToolResponses(turnsToKeep = 1) {
183
+ const rawHistory = this.chat.getRawHistory();
184
+ // 1 turn = 1 user Content + 1 model Content pair (2 entries)
185
+ const cutoffIndex = Math.max(0, rawHistory.length - turnsToKeep * 2);
186
+ if (cutoffIndex <= 0)
187
+ return;
188
+ for (let i = 0; i < cutoffIndex; i++) {
189
+ const entry = rawHistory[i];
190
+ if (entry && entry.role === 'user' && Array.isArray(entry.parts)) {
191
+ const prevModelEntry = i > 0 ? rawHistory[i - 1] : undefined;
192
+ let funcRespIdx = 0;
193
+ for (const part of entry.parts) {
194
+ if (part && typeof part === 'object' && 'functionResponse' in part && part.functionResponse) {
195
+ const funcResp = part.functionResponse;
196
+ const toolName = funcResp.name || 'tool';
197
+ const matchingCall = findMatchingFunctionCall(prevModelEntry, toolName, funcRespIdx);
198
+ const args = matchingCall?.args;
199
+ if (funcResp.response && typeof funcResp.response === 'object') {
200
+ const respObj = funcResp.response;
201
+ if (toolName === 'read_messages') {
202
+ funcResp.response = { output: '[read_messages - peer activity reviewed]' };
203
+ }
204
+ else if (toolName === 'post_message') {
205
+ funcResp.response = { output: '[post_message - coordination signal posted]' };
206
+ }
207
+ else if (typeof respObj.output === 'string') {
208
+ respObj.output = createCompactToolReference(toolName, respObj.output, args);
209
+ }
210
+ else if (typeof respObj.result === 'string') {
211
+ respObj.result = createCompactToolReference(toolName, respObj.result, args);
212
+ }
213
+ else if (typeof respObj.output === 'object' && respObj.output !== null) {
214
+ respObj.output = createCompactToolReference(toolName, respObj.output, args);
215
+ }
216
+ }
217
+ funcRespIdx++;
218
+ }
219
+ }
220
+ }
193
221
  }
194
- };
222
+ // Also trigger proxy chat session pruning to collapse any remaining long fields
223
+ this.chat.pruneToolOutputHistory();
224
+ }
195
225
  /**
196
226
  * Executes the sub-agent with a health monitor harness.
197
227
  * Runs the tool loop until the model stops returning function calls,
@@ -243,7 +273,7 @@ export class SubAgentRunner {
243
273
  debugLog(`SubAgent [${this.taskId}]: Executing tool ${call.name}`);
244
274
  let responseData;
245
275
  try {
246
- responseData = await executeScopedTool(call.name, call.args, this.workspaceRoot, this.taskId, this.bus, this.locks, this.pingHeartbeat);
276
+ responseData = await executeScopedTool(call.name, call.args, this.workspaceRoot, this.taskId, this.bus, this.locks, this.pingHeartbeat, undefined, this.taskScope);
247
277
  }
248
278
  catch (err) {
249
279
  responseData = { error: err.message || String(err) };
@@ -309,46 +339,33 @@ export class SubAgentRunner {
309
339
  });
310
340
  }
311
341
  /**
312
- * Compacts older tool responses in the chat session history into concise references
313
- * (e.g. `[Read X lines from file.ts - tool execution completed]`), drastically reducing
314
- * context window bloat across multi-turn sub-agent executions while preserving
315
- * Gemini's functionCall <-> functionResponse protocol.
316
- *
317
- * @param turnsToKeep Number of recent turns to preserve in full (default: 1).
342
+ * Constructs the base system instruction for this specific agent,
343
+ * injecting scoped AST outlines for referenced workspace files to eliminate
344
+ * multi-megabyte context bloat during parallel sub-agent execution.
318
345
  */
319
- compactOlderToolResponses(turnsToKeep = 1) {
320
- const rawHistory = this.chat.getRawHistory();
321
- // 1 turn = 1 user Content + 1 model Content pair (2 entries)
322
- const cutoffIndex = Math.max(0, rawHistory.length - turnsToKeep * 2);
323
- if (cutoffIndex <= 0)
324
- return;
325
- for (let i = 0; i < cutoffIndex; i++) {
326
- const entry = rawHistory[i];
327
- if (entry && entry.role === 'user' && Array.isArray(entry.parts)) {
328
- const prevModelEntry = i > 0 ? rawHistory[i - 1] : undefined;
329
- let funcRespIdx = 0;
330
- for (const part of entry.parts) {
331
- if (part && typeof part === 'object' && 'functionResponse' in part && part.functionResponse) {
332
- const funcResp = part.functionResponse;
333
- const toolName = funcResp.name || 'tool';
334
- const matchingCall = findMatchingFunctionCall(prevModelEntry, toolName, funcRespIdx);
335
- const args = matchingCall?.args;
336
- if (funcResp.response && typeof funcResp.response === 'object') {
337
- const respObj = funcResp.response;
338
- if (typeof respObj.output === 'string') {
339
- respObj.output = createCompactToolReference(toolName, respObj.output, args);
340
- }
341
- if (typeof respObj.result === 'string') {
342
- respObj.result = createCompactToolReference(toolName, respObj.result, args);
343
- }
344
- }
345
- funcRespIdx++;
346
- }
347
- }
348
- }
349
- }
350
- // Also trigger proxy chat session pruning to collapse any remaining long fields
351
- this.chat.pruneToolOutputHistory();
346
+ buildSystemInstruction() {
347
+ const scopedContext = scopeContext(this.globalContext);
348
+ return (`<identity>\n` +
349
+ `You are an autonomous Senior software developer sub-agent executing a specific portion of a larger task.\n` +
350
+ `</identity>\n\n` +
351
+ `<task_info>\n` +
352
+ `Your task ID is: ${this.taskId}\n` +
353
+ `Your objective: ${this.intent}\n` +
354
+ `</task_info>\n\n` +
355
+ `<reference_context>\n` +
356
+ `DO NOT IMPLEMENT THIS FULL REQUEST. THIS IS JUST FOR CONTEXT.\n\n` +
357
+ `${scopedContext}\n` +
358
+ `</reference_context>\n\n` +
359
+ `<critical_guidelines>\n` +
360
+ `1. You are ONE worker in a team. Focus EXCLUSIVELY on your specific objective: "${this.intent}".\n` +
361
+ `2. DO NOT attempt to fulfill the entire original user request in the reference context. Other agents handle other tasks.\n` +
362
+ `3. EXECUTION WORKFLOW:\n` +
363
+ ` - Step 1 (Investigate): Use 'grep_search', 'read_file', or 'list_directory' to inspect the codebase as needed.\n` +
364
+ ` - Step 2 (Execute): Use 'modify_file' or 'write_file' to implement the required changes.\n` +
365
+ ` - Step 3 (Verify): Use 'run_debug_script', 'run_fuzz_probe', 'check_heap_delta', 'check_behavioral_drift', or 'run_command' to test your changes if necessary.\n` +
366
+ ` - Step 4 (Conclude): Once your specific objective is fully met, stop calling tools and return a text summary of your changes.\n` +
367
+ `4. Coordinate: Use 'read_messages' to check for updates from other agents. Use 'post_message' if you discover breaking changes affecting others.\n` +
368
+ `</critical_guidelines>`);
352
369
  }
353
370
  /**
354
371
  * Accumulates token usage from the chat session.
@@ -0,0 +1,57 @@
1
+ export interface DiffExtractionOptions {
2
+ baseCommit?: string;
3
+ includeUntracked?: boolean;
4
+ maxBuffer?: number;
5
+ }
6
+ /**
7
+ * Checks whether the target directory contains a valid git repository.
8
+ */
9
+ export declare function isGitRepository(workspaceDir: string): Promise<boolean>;
10
+ /**
11
+ * Gets the current HEAD commit hash of the git repository.
12
+ */
13
+ export declare function getHeadCommit(workspaceDir: string): Promise<string>;
14
+ /**
15
+ * Resets the workspace git repository to a clean state matching baseCommit or HEAD.
16
+ */
17
+ export declare function resetWorkspaceRepo(workspaceDir: string, baseCommit?: string): Promise<void>;
18
+ /**
19
+ * Extracts a unified git patch representing all modifications made by the model.
20
+ * Produces standard SWE-bench format (patch starting with `diff --git` or empty string).
21
+ */
22
+ export declare function extractGitPatch(workspaceDir: string, options?: string | DiffExtractionOptions): Promise<string>;
23
+ /**
24
+ * Normalizes git unified diff patch text:
25
+ * - Trims superfluous leading/trailing whitespace
26
+ * - Ensures empty diff returns exact empty string ""
27
+ * - Preserves trailing newline if content exists
28
+ */
29
+ export declare function normalizePatch(patch: string): string;
30
+ /**
31
+ * Validates whether a patch conforms to standard unified diff structure.
32
+ */
33
+ export declare function validatePatchFormat(patch: string): {
34
+ valid: boolean;
35
+ issues?: string[];
36
+ };
37
+ /**
38
+ * Checks out a specific base commit in the repository.
39
+ */
40
+ export declare function checkoutBaseCommit(workspaceDir: string, baseCommit: string, options?: {
41
+ fetchIfMissing?: boolean;
42
+ }): Promise<{
43
+ success: boolean;
44
+ error?: string;
45
+ }>;
46
+ /**
47
+ * Clones a repository if it doesn't already exist or ensures it is checked out.
48
+ */
49
+ export declare function cloneOrEnsureRepo(repo: string, targetDir: string, options?: {
50
+ cloneUrl?: string;
51
+ baseCommit?: string;
52
+ shallow?: boolean;
53
+ }): Promise<{
54
+ success: boolean;
55
+ repoDir: string;
56
+ error?: string;
57
+ }>;