minovative-mind-cli 2.5.1 → 2.6.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 +28 -25
  2. package/dist/commands/chat.js +1 -1
  3. package/dist/services/agent/inputHandler.d.ts +9 -0
  4. package/dist/services/agent/inputHandler.js +34 -0
  5. package/dist/services/agent/slashCommands.js +158 -37
  6. package/dist/services/agent/syntaxAgent.d.ts +40 -0
  7. package/dist/services/agent/syntaxAgent.js +237 -23
  8. package/dist/services/agent/toolLoop.js +10 -1
  9. package/dist/services/agent/types.d.ts +1 -0
  10. package/dist/services/agent-tools.d.ts +156 -1
  11. package/dist/services/agent-tools.js +259 -67
  12. package/dist/services/agent.d.ts +74 -0
  13. package/dist/services/agent.js +192 -30
  14. package/dist/services/ai.d.ts +5 -0
  15. package/dist/services/ai.js +80 -87
  16. package/dist/services/chatHistoryService.d.ts +11 -0
  17. package/dist/services/chatHistoryService.js +20 -1
  18. package/dist/services/contextAgent.d.ts +1 -1
  19. package/dist/services/contextAgent.js +9 -29
  20. package/dist/services/orchestration/investigationAgent.d.ts +2 -1
  21. package/dist/services/orchestration/investigationAgent.js +7 -2
  22. package/dist/services/orchestration/investigationOrchestrator.d.ts +1 -1
  23. package/dist/services/orchestration/investigationOrchestrator.js +13 -2
  24. package/dist/services/orchestration/orchestrator.js +21 -4
  25. package/dist/services/orchestration/subAgent.d.ts +2 -1
  26. package/dist/services/orchestration/subAgent.js +12 -6
  27. package/dist/services/workspaceRegistry.d.ts +7 -0
  28. package/dist/services/workspaceRegistry.js +22 -0
  29. package/dist/utils/analysisRunner.d.ts +27 -4
  30. package/dist/utils/analysisRunner.js +100 -20
  31. package/dist/utils/config.d.ts +2 -0
  32. package/dist/utils/config.js +2 -0
  33. package/dist/utils/fuzzyMatch.d.ts +32 -0
  34. package/dist/utils/fuzzyMatch.js +215 -27
  35. package/dist/utils/localSyntaxValidator.d.ts +2 -2
  36. package/dist/utils/localSyntaxValidator.js +280 -81
  37. package/dist/utils/performanceAuditor.d.ts +2 -7
  38. package/dist/utils/performanceAuditor.js +541 -89
  39. package/dist/utils/projectStorage.js +9 -0
  40. package/dist/utils/systemPrompts.d.ts +3 -2
  41. package/dist/utils/systemPrompts.js +29 -5
  42. package/oclif.manifest.json +2 -2
  43. package/package.json +1 -1
@@ -67,7 +67,7 @@ export class Orchestrator {
67
67
  this.bus = new MessageBus(workspaceRoot, conversationId);
68
68
  this.locks = new FileLockRegistry();
69
69
  let model = getGlobalActiveModel();
70
- if (model === GEMINI_MODELS.AUTO)
70
+ if (model === GEMINI_MODELS.AUTO || model.includes('claude'))
71
71
  model = GEMINI_MODELS.FLASH;
72
72
  this.pmChat = new ProxyChatSession(model, PM_SYSTEM_INSTRUCTION, [], {
73
73
  maxOutputTokens: MAX_OUTPUT_TOKENS,
@@ -109,6 +109,7 @@ export class Orchestrator {
109
109
  .join('\n');
110
110
  p.log.step(pc.magenta(`Starting Wave ${wave.depth + 1} (${wave.taskIds.length} tasks):\n${taskDescriptions}`));
111
111
  const s = p.spinner();
112
+ this.inputHandler.setSpinner(s);
112
113
  s.start(`Executing Wave ${wave.depth + 1}...`);
113
114
  const agentStatuses = new Map();
114
115
  const updateSpinner = () => {
@@ -120,6 +121,7 @@ export class Orchestrator {
120
121
  // Limit to 2 concurrent sub-agents to avoid Vertex AI RESOURCE_EXHAUSTED
121
122
  const results = [];
122
123
  const MAX_CONCURRENT = 2;
124
+ const toolLogs = [];
123
125
  for (let i = 0; i < wave.taskIds.length; i += MAX_CONCURRENT) {
124
126
  const chunk = wave.taskIds.slice(i, i + MAX_CONCURRENT);
125
127
  const wavePromises = chunk.map((taskId) => {
@@ -127,15 +129,30 @@ export class Orchestrator {
127
129
  const globalContext = `Objective:\n${objective}\n\nContext:\n${contextInjection}`;
128
130
  agentStatuses.set(taskDef.id, 'Starting...');
129
131
  updateSpinner();
132
+ const onToolCall = (msg) => {
133
+ const formattedLog = `${pc.dim(`[${taskDef.id}]`)} ${msg}`;
134
+ toolLogs.push(formattedLog);
135
+ // Keep the spinner running, just update the status message
136
+ agentStatuses.set(taskDef.id, msg);
137
+ updateSpinner();
138
+ };
130
139
  return this.dispatchAgent(taskDef, globalContext, signal, (msg) => {
131
140
  agentStatuses.set(taskDef.id, msg);
132
141
  updateSpinner();
142
+ }, onToolCall).then((res) => {
143
+ agentStatuses.set(taskDef.id, res.success ? '✅ Done' : '❌ Failed');
144
+ updateSpinner();
145
+ return res;
133
146
  });
134
147
  });
135
148
  const chunkResults = await Promise.all(wavePromises);
136
149
  results.push(...chunkResults);
137
150
  }
138
- s.stop(`Wave ${wave.depth + 1} execution finished.`);
151
+ const successful = results.filter((r) => r.success).length;
152
+ s.stop(`Wave ${wave.depth + 1} completed: ${successful}/${wave.taskIds.length} tasks succeeded`);
153
+ if (toolLogs.length > 0) {
154
+ toolLogs.forEach(log => p.log.step(log));
155
+ }
139
156
  // Post-wave evaluation
140
157
  const failedCount = results.filter((r) => !r.success).length;
141
158
  if (failedCount > 0) {
@@ -213,9 +230,9 @@ export class Orchestrator {
213
230
  /**
214
231
  * Dispatches a single sub-agent and records its result.
215
232
  */
216
- async dispatchAgent(taskDef, globalContext, signal, onProgress) {
233
+ async dispatchAgent(taskDef, globalContext, signal, onProgress, onTool) {
217
234
  return trackTask(`Sub-Agent: ${taskDef.id}`, async () => {
218
- const runner = new SubAgentRunner(taskDef.id, taskDef.intent, this.workspaceRoot, this.bus, this.locks, globalContext, onProgress);
235
+ const runner = new SubAgentRunner(taskDef.id, taskDef.intent, this.workspaceRoot, this.bus, this.locks, globalContext, onProgress, onTool);
219
236
  const result = await runner.execute(signal);
220
237
  // Clean up any stray locks if the agent crashed or stalled
221
238
  if (result.crashed) {
@@ -33,6 +33,7 @@ export declare class SubAgentRunner {
33
33
  private readonly locks;
34
34
  private readonly globalContext;
35
35
  private readonly onProgress?;
36
+ private readonly onTool?;
36
37
  private chat;
37
38
  private lastHeartbeat;
38
39
  private creditsUsed;
@@ -40,7 +41,7 @@ export declare class SubAgentRunner {
40
41
  private outputTokens;
41
42
  /** Max time without a tool call or response before the agent is considered stalled */
42
43
  static readonly STALL_TIMEOUT_MS = 300000;
43
- constructor(taskId: string, intent: string, workspaceRoot: string, bus: MessageBus, locks: FileLockRegistry, globalContext: string, onProgress?: ((msg: string) => void) | undefined);
44
+ constructor(taskId: string, intent: string, workspaceRoot: string, bus: MessageBus, locks: FileLockRegistry, globalContext: string, onProgress?: ((msg: string) => void) | undefined, onTool?: ((msg: string) => void) | undefined);
44
45
  /**
45
46
  * Constructs the base system instruction for this specific agent.
46
47
  */
@@ -9,6 +9,7 @@ import { GEMINI_MODELS, MAX_OUTPUT_TOKENS } from '../../utils/config.js';
9
9
  import { executeScopedTool, getScopedToolDeclarations } from './scopedTools.js';
10
10
  import { debugLog } from '../../utils/logger.js';
11
11
  import { runWithAgentId } from '../../utils/asyncContext.js';
12
+ import { formatToolCall } from '../agent/toolLoop.js';
12
13
  /**
13
14
  * Executes a sub-agent task with full health monitoring, tool wrapping,
14
15
  * and orchestration integration.
@@ -21,6 +22,7 @@ export class SubAgentRunner {
21
22
  locks;
22
23
  globalContext;
23
24
  onProgress;
25
+ onTool;
24
26
  chat;
25
27
  lastHeartbeat = Date.now();
26
28
  creditsUsed = 0;
@@ -28,7 +30,7 @@ export class SubAgentRunner {
28
30
  outputTokens = 0;
29
31
  /** Max time without a tool call or response before the agent is considered stalled */
30
32
  static STALL_TIMEOUT_MS = 300_000;
31
- constructor(taskId, intent, workspaceRoot, bus, locks, globalContext, onProgress) {
33
+ constructor(taskId, intent, workspaceRoot, bus, locks, globalContext, onProgress, onTool) {
32
34
  this.taskId = taskId;
33
35
  this.intent = intent;
34
36
  this.workspaceRoot = workspaceRoot;
@@ -36,6 +38,7 @@ export class SubAgentRunner {
36
38
  this.locks = locks;
37
39
  this.globalContext = globalContext;
38
40
  this.onProgress = onProgress;
41
+ this.onTool = onTool;
39
42
  let model = getGlobalActiveModel();
40
43
  if (model === GEMINI_MODELS.AUTO)
41
44
  model = GEMINI_MODELS.FLASH;
@@ -66,11 +69,11 @@ export class SubAgentRunner {
66
69
  `1. You are ONE worker in a team. Focus EXCLUSIVELY on your specific objective: "${this.intent}".\n` +
67
70
  `2. DO NOT attempt to fulfill the entire original user request in the reference context. Other agents handle other tasks.\n` +
68
71
  `3. EXECUTION WORKFLOW:\n` +
69
- ` - Step 1 (Locate): Call 'grep_search' or 'read_file' ONCE to inspect the file you need to edit.\n` +
70
- ` - Step 2 (Modify): Call 'modify_file' or 'write_file' to implement the required changes.\n` +
71
- ` - Step 3 (Conclude): Immediately STOP using tools and return a text summary of your changes.\n` +
72
- `4. Do NOT call 'grep_search' or 'run_command' repeatedly in a loop. Once you have file context or command results, proceed directly to modifying code or responding with your text summary.\n` +
73
- `5. Use 'post_message' only if you discover breaking changes affecting other agents.\n` +
72
+ ` - Step 1 (Investigate): Use 'grep_search', 'read_file', or 'list_directory' to inspect the codebase as needed.\n` +
73
+ ` - Step 2 (Execute): Use 'modify_file' or 'write_file' to implement the required changes.\n` +
74
+ ` - Step 3 (Verify): Use 'run_debug_script' or 'run_command' to test your changes if necessary.\n` +
75
+ ` - Step 4 (Conclude): Once your specific objective is fully met, stop calling tools and return a text summary of your changes.\n` +
76
+ `4. Coordinate: Use 'read_messages' to check for updates from other agents. Use 'post_message' if you discover breaking changes affecting others.\n` +
74
77
  `</critical_guidelines>`);
75
78
  }
76
79
  /**
@@ -128,6 +131,9 @@ export class SubAgentRunner {
128
131
  if (this.onProgress) {
129
132
  this.onProgress(`executing ${call.name}...`);
130
133
  }
134
+ if (this.onTool) {
135
+ this.onTool(formatToolCall(call.name, call.args));
136
+ }
131
137
  debugLog(`SubAgent [${this.taskId}]: Executing tool ${call.name}`);
132
138
  let responseData;
133
139
  try {
@@ -78,6 +78,13 @@ declare class WorkspaceRegistry {
78
78
  * @returns `true` if the workspace was found and removed, `false` otherwise.
79
79
  */
80
80
  unregister(alias: string): boolean;
81
+ /**
82
+ * Removes a registered profile and all its associated workspaces.
83
+ *
84
+ * @param profileName - The name of the profile to unregister.
85
+ * @returns `true` if the profile was found and removed, `false` otherwise.
86
+ */
87
+ unregisterProfile(profileName: string): boolean;
81
88
  /**
82
89
  * Returns all registered workspaces as an array, sorted by alias.
83
90
  */
@@ -118,6 +118,28 @@ class WorkspaceRegistry {
118
118
  }
119
119
  return existed;
120
120
  }
121
+ /**
122
+ * Removes a registered profile and all its associated workspaces.
123
+ *
124
+ * @param profileName - The name of the profile to unregister.
125
+ * @returns `true` if the profile was found and removed, `false` otherwise.
126
+ */
127
+ unregisterProfile(profileName) {
128
+ const normalizedProfile = profileName.toLowerCase().trim();
129
+ const existed = this.profiles.delete(normalizedProfile);
130
+ if (existed) {
131
+ // Find and delete all workspaces associated with this profile
132
+ for (const [alias, ws] of this.workspaces.entries()) {
133
+ if (ws.profile === normalizedProfile) {
134
+ this.workspaces.delete(alias);
135
+ debugLog(`Unregistered workspace: @${alias} (via profile removal)`);
136
+ }
137
+ }
138
+ this.saveToDisk();
139
+ debugLog(`Unregistered profile: ${normalizedProfile}`);
140
+ }
141
+ return existed;
142
+ }
121
143
  /**
122
144
  * Returns all registered workspaces as an array, sorted by alias.
123
145
  */
@@ -3,14 +3,28 @@ export interface EphemeralScriptResult {
3
3
  stderr: string;
4
4
  exitCode: number;
5
5
  }
6
- interface EphemeralScriptOptions {
7
- /** Execution timeout in milliseconds. Defaults to 10,000 (10s). */
6
+ export interface EphemeralScriptOptions {
7
+ /** Execution timeout in milliseconds. Defaults to 60,000 (60s). */
8
8
  timeoutMs?: number;
9
- /** Maximum characters to capture from stdout/stderr. Defaults to 30,000. */
9
+ /** Maximum characters to capture from stdout/stderr. Defaults to 100,000. */
10
10
  maxOutputChars?: number;
11
11
  /** AbortSignal to cancel execution. */
12
12
  abortSignal?: AbortSignal;
13
13
  }
14
+ /**
15
+ * Normalizes user/AI provided language string to a standard runtime identifier.
16
+ */
17
+ export declare function normalizeLanguage(lang: string): string;
18
+ /**
19
+ * Detects whether the workspace package.json specifies `"type": "module"`.
20
+ * Returns `'module'` or `'commonjs'`.
21
+ */
22
+ export declare function detectWorkspaceModuleType(workspaceRoot: string): Promise<'module' | 'commonjs'>;
23
+ /**
24
+ * Dynamically resolves the appropriate file extension for a script based on workspace configuration,
25
+ * target runtime language, and source code syntax analysis.
26
+ */
27
+ export declare function resolveScriptExtension(workspaceRoot: string, language: string, code: string): Promise<string>;
14
28
  /**
15
29
  * Write a disposable analysis script to a temporary file, execute it using the
16
30
  * specified language runtime, capture its output, and guarantee cleanup.
@@ -26,4 +40,13 @@ interface EphemeralScriptOptions {
26
40
  * @returns Captured stdout, stderr, and exit code.
27
41
  */
28
42
  export declare function runEphemeralScript(workspaceRoot: string, language: string, code: string, options?: EphemeralScriptOptions): Promise<EphemeralScriptResult>;
29
- export {};
43
+ /**
44
+ * Primary entry point for dynamic debug script execution.
45
+ * Accepts code and options, auto-resolving runtime language and script extension.
46
+ *
47
+ * @param workspaceRoot - Path to the root directory of the workspace.
48
+ * @param code - The debug script source code to execute.
49
+ * @param language - Optional runtime language (defaults to 'node').
50
+ * @param options - Execution options (timeoutMs, maxOutputChars, abortSignal).
51
+ */
52
+ export declare function runDebugScript(workspaceRoot: string, code: string, language?: string | EphemeralScriptOptions, options?: EphemeralScriptOptions): Promise<EphemeralScriptResult>;
@@ -5,15 +5,76 @@ import { exec } from 'node:child_process';
5
5
  import { promisify } from 'node:util';
6
6
  import { createHash } from 'node:crypto';
7
7
  const execAsync = promisify(exec);
8
- /** Map of supported language runtimes to their file extensions. */
9
- const LANGUAGE_EXTENSIONS = {
10
- node: '.js',
11
- 'ts-node': '.ts',
12
- python: '.py',
13
- bash: '.sh',
14
- go: '.go',
15
- rust: '.rs',
8
+ /** Supported language aliases map. */
9
+ const LANGUAGE_ALIASES = {
10
+ js: 'node',
11
+ javascript: 'node',
12
+ node: 'node',
13
+ ts: 'ts-node',
14
+ typescript: 'ts-node',
15
+ 'ts-node': 'ts-node',
16
+ py: 'python',
17
+ python: 'python',
18
+ sh: 'bash',
19
+ bash: 'bash',
20
+ go: 'go',
21
+ rs: 'rust',
22
+ rust: 'rust',
16
23
  };
24
+ /**
25
+ * Normalizes user/AI provided language string to a standard runtime identifier.
26
+ */
27
+ export function normalizeLanguage(lang) {
28
+ const key = lang.toLowerCase().trim();
29
+ return LANGUAGE_ALIASES[key] || key;
30
+ }
31
+ /**
32
+ * Detects whether the workspace package.json specifies `"type": "module"`.
33
+ * Returns `'module'` or `'commonjs'`.
34
+ */
35
+ export async function detectWorkspaceModuleType(workspaceRoot) {
36
+ try {
37
+ const pkgPath = path.join(workspaceRoot, 'package.json');
38
+ const content = await fs.readFile(pkgPath, 'utf-8');
39
+ const pkg = JSON.parse(content);
40
+ return pkg.type === 'module' ? 'module' : 'commonjs';
41
+ }
42
+ catch {
43
+ return 'commonjs';
44
+ }
45
+ }
46
+ /**
47
+ * Dynamically resolves the appropriate file extension for a script based on workspace configuration,
48
+ * target runtime language, and source code syntax analysis.
49
+ */
50
+ export async function resolveScriptExtension(workspaceRoot, language, code) {
51
+ const normLang = normalizeLanguage(language);
52
+ if (normLang === 'node') {
53
+ // Check for explicit CJS syntax markers
54
+ const hasCJS = new RegExp('\\b(require\\s*\\(|module\\.exports|exports\\.)').test(code);
55
+ // Check for explicit ESM syntax markers
56
+ const hasESM = new RegExp('\\b(import\\s+|import\\(|export\\s+|export\\{|export\\s+default)\\b').test(code) || new RegExp('^\\s*await\\s+', 'm').test(code);
57
+ if (hasCJS && !hasESM) {
58
+ return '.cjs';
59
+ }
60
+ if (hasESM && !hasCJS) {
61
+ return '.mjs';
62
+ }
63
+ // If ambiguous or both present, default based on workspace package.json module type
64
+ const moduleType = await detectWorkspaceModuleType(workspaceRoot);
65
+ return moduleType === 'module' ? '.mjs' : '.cjs';
66
+ }
67
+ if (normLang === 'ts-node') {
68
+ return '.ts';
69
+ }
70
+ const defaultExts = {
71
+ python: '.py',
72
+ bash: '.sh',
73
+ go: '.go',
74
+ rust: '.rs',
75
+ };
76
+ return defaultExts[normLang] || '.js';
77
+ }
17
78
  /**
18
79
  * Generates a deterministic but unique temporary file path for the analysis script.
19
80
  * Uses a content hash to prevent collisions when multiple scripts run concurrently.
@@ -27,7 +88,8 @@ function buildTempPath(code, ext) {
27
88
  * Returns null for unsupported languages.
28
89
  */
29
90
  function buildCommand(language, scriptPath) {
30
- switch (language.toLowerCase()) {
91
+ const normLang = normalizeLanguage(language);
92
+ switch (normLang) {
31
93
  case 'node':
32
94
  return `node "${scriptPath}"`;
33
95
  case 'ts-node':
@@ -40,7 +102,7 @@ function buildCommand(language, scriptPath) {
40
102
  return `go run "${scriptPath}"`;
41
103
  case 'rust': {
42
104
  const binExt = os.platform() === 'win32' ? '.exe' : '';
43
- const binPath = scriptPath.replace('.rs', binExt);
105
+ const binPath = scriptPath.replace(/\.rs$/, binExt);
44
106
  return `rustc "${scriptPath}" -o "${binPath}" && "${binPath}"`;
45
107
  }
46
108
  default:
@@ -72,24 +134,22 @@ function truncateOutput(text, max) {
72
134
  export async function runEphemeralScript(workspaceRoot, language, code, options) {
73
135
  const timeoutMs = options?.timeoutMs ?? 60_000;
74
136
  const maxOutputChars = options?.maxOutputChars ?? 100_000;
75
- const ext = LANGUAGE_EXTENSIONS[language.toLowerCase()];
76
- if (!ext) {
137
+ const normLang = normalizeLanguage(language);
138
+ const ext = await resolveScriptExtension(workspaceRoot, normLang, code);
139
+ const scriptPath = buildTempPath(code, ext);
140
+ const cmd = buildCommand(normLang, scriptPath);
141
+ if (!cmd) {
77
142
  return {
78
143
  stdout: '',
79
- stderr: `Unsupported language runtime: "${language}". Supported: ${Object.keys(LANGUAGE_EXTENSIONS).join(', ')}`,
144
+ stderr: `Unsupported language runtime: "${language}". Supported: node, ts-node, python, bash, go, rust`,
80
145
  exitCode: 1,
81
146
  };
82
147
  }
83
- const scriptPath = buildTempPath(code, ext);
84
- const cmd = buildCommand(language, scriptPath);
85
- if (!cmd) {
86
- return { stdout: '', stderr: `Failed to build command for language: ${language}`, exitCode: 1 };
87
- }
88
148
  // Collect all temp files created so we can clean them up unconditionally
89
149
  const tempFiles = [scriptPath];
90
- if (language.toLowerCase() === 'rust') {
150
+ if (normLang === 'rust') {
91
151
  const binExt = os.platform() === 'win32' ? '.exe' : '';
92
- tempFiles.push(scriptPath.replace('.rs', binExt));
152
+ tempFiles.push(scriptPath.replace(/\.rs$/, binExt));
93
153
  }
94
154
  try {
95
155
  await fs.writeFile(scriptPath, code, 'utf-8');
@@ -127,3 +187,23 @@ export async function runEphemeralScript(workspaceRoot, language, code, options)
127
187
  }
128
188
  }
129
189
  }
190
+ /**
191
+ * Primary entry point for dynamic debug script execution.
192
+ * Accepts code and options, auto-resolving runtime language and script extension.
193
+ *
194
+ * @param workspaceRoot - Path to the root directory of the workspace.
195
+ * @param code - The debug script source code to execute.
196
+ * @param language - Optional runtime language (defaults to 'node').
197
+ * @param options - Execution options (timeoutMs, maxOutputChars, abortSignal).
198
+ */
199
+ export async function runDebugScript(workspaceRoot, code, language = 'node', options) {
200
+ let lang = 'node';
201
+ let opts = options;
202
+ if (typeof language === 'string') {
203
+ lang = language;
204
+ }
205
+ else if (typeof language === 'object' && language !== null) {
206
+ opts = language;
207
+ }
208
+ return runEphemeralScript(workspaceRoot, lang, code, opts);
209
+ }
@@ -14,7 +14,9 @@ export declare const GITHUB_CLIENT_ID = "Ov23linFYFfjO3JILG7r";
14
14
  * Supported Gemini AI models.
15
15
  */
16
16
  export declare const GEMINI_MODELS: {
17
+ readonly CLAUDE_OPUS: "claude-opus-5";
17
18
  readonly PRO: "gemini-3.1-pro-preview";
19
+ readonly CLAUDE_SONNET: "claude-sonnet-5";
18
20
  readonly FLASH: "gemini-3.6-flash";
19
21
  readonly FLASH_LITE: "gemini-3.5-flash-lite";
20
22
  readonly AUTO: "auto";
@@ -14,7 +14,9 @@ export const GITHUB_CLIENT_ID = 'Ov23linFYFfjO3JILG7r';
14
14
  * Supported Gemini AI models.
15
15
  */
16
16
  export const GEMINI_MODELS = {
17
+ CLAUDE_OPUS: 'claude-opus-5',
17
18
  PRO: 'gemini-3.1-pro-preview',
19
+ CLAUDE_SONNET: 'claude-sonnet-5',
18
20
  FLASH: 'gemini-3.6-flash',
19
21
  FLASH_LITE: 'gemini-3.5-flash-lite',
20
22
  AUTO: 'auto',
@@ -1,8 +1,24 @@
1
+ import { ValidationResult } from './localSyntaxValidator.js';
1
2
  export interface MatchResult {
2
3
  start: number;
3
4
  end: number;
4
5
  strategy: string;
5
6
  }
7
+ export interface PatchBlock {
8
+ search: string;
9
+ replace: string;
10
+ }
11
+ export interface PatchApplicationResult {
12
+ success: boolean;
13
+ content: string;
14
+ appliedBlocks: number;
15
+ failedBlocks: number;
16
+ errors: string[];
17
+ syntaxValidation?: ValidationResult;
18
+ }
19
+ export interface ApplyPatchOptions {
20
+ validateSyntax?: boolean;
21
+ }
6
22
  /**
7
23
  * Trims each line, collapses multiple spaces/tabs to single space,
8
24
  * and normalizes line endings.
@@ -16,6 +32,22 @@ export declare function levenshteinSimilarity(a: string, b: string): number;
16
32
  /**
17
33
  * Finds the best match for `searchContent` inside `fileContent`.
18
34
  * Uses a pipeline of strategies: Exact -> Whitespace-normalized -> Levenshtein.
35
+ * Enforces uniqueness and higher confidence thresholds for non-unique search snippets across repetitive files.
19
36
  */
20
37
  export declare function findBestMatch(fileContent: string, searchContent: string): MatchResult | null;
21
38
  export declare function applyMatch(fileContent: string, match: MatchResult, replaceContent: string): string;
39
+ /**
40
+ * Parses differential patch block string into structured PatchBlock objects.
41
+ * Supports blocks formatted as:
42
+ * <<<<< SEARCH
43
+ * search content
44
+ * =====
45
+ * replace content
46
+ * >>>>> REPLACE
47
+ */
48
+ export declare function parsePatchBlocks(patchText: string): PatchBlock[];
49
+ /**
50
+ * Applies a sequence of search/replace patch blocks to file content
51
+ * using fuzzy matching, and validates local syntax on the result.
52
+ */
53
+ export declare function applyPatch(fileContent: string, patchTextOrBlocks: string | PatchBlock[], filePath?: string, options?: ApplyPatchOptions): PatchApplicationResult;