Browse Source

Remove code for old diff strategies (#2262)

Matt Rubens 9 months ago
parent
commit
3f5f8bb81f

+ 2 - 3
src/core/diff/DiffStrategy.ts

@@ -1,7 +1,6 @@
 import type { DiffStrategy } from "./types"
-import { NewUnifiedDiffStrategy } from "./strategies/new-unified"
 import { MultiSearchReplaceDiffStrategy } from "./strategies/multi-search-replace"
-import { EXPERIMENT_IDS, ExperimentId } from "../../shared/experiments"
+import { ExperimentId } from "../../shared/experiments"
 
 export type { DiffStrategy }
 
@@ -11,7 +10,7 @@ export type { DiffStrategy }
  * @returns The appropriate diff strategy for the model
  */
 
-export type DiffStrategyName = "unified" | "multi-search-and-replace"
+export type DiffStrategyName = "multi-search-and-replace"
 
 type GetDiffStrategyOptions = {
 	model: string

+ 0 - 738
src/core/diff/strategies/__tests__/new-unified.test.ts

@@ -1,738 +0,0 @@
-import { NewUnifiedDiffStrategy } from "../new-unified"
-
-describe("main", () => {
-	let strategy: NewUnifiedDiffStrategy
-
-	beforeEach(() => {
-		strategy = new NewUnifiedDiffStrategy(0.97)
-	})
-
-	describe("constructor", () => {
-		it("should use default confidence threshold when not provided", () => {
-			const defaultStrategy = new NewUnifiedDiffStrategy()
-			expect(defaultStrategy["confidenceThreshold"]).toBe(1)
-		})
-
-		it("should use provided confidence threshold", () => {
-			const customStrategy = new NewUnifiedDiffStrategy(0.85)
-			expect(customStrategy["confidenceThreshold"]).toBe(0.85)
-		})
-
-		it("should enforce minimum confidence threshold", () => {
-			const lowStrategy = new NewUnifiedDiffStrategy(0.7) // Below minimum of 0.8
-			expect(lowStrategy["confidenceThreshold"]).toBe(0.8)
-		})
-	})
-
-	describe("getToolDescription", () => {
-		it("should return tool description with correct cwd", () => {
-			const cwd = "/test/path"
-			const description = strategy.getToolDescription({ cwd })
-
-			expect(description).toContain("apply_diff Tool - Generate Precise Code Changes")
-			expect(description).toContain(cwd)
-			expect(description).toContain("Step-by-Step Instructions")
-			expect(description).toContain("Requirements")
-			expect(description).toContain("Examples")
-			expect(description).toContain("Parameters:")
-		})
-	})
-
-	it("should apply simple diff correctly", async () => {
-		const original = `line1
-line2
-line3`
-
-		const diff = `--- a/file.txt
-+++ b/file.txt
-@@ ... @@
- line1
-+new line
- line2
--line3
-+modified line3`
-
-		const result = await strategy.applyDiff(original, diff)
-		expect(result.success).toBe(true)
-		if (result.success) {
-			expect(result.content).toBe(`line1
-new line
-line2
-modified line3`)
-		}
-	})
-
-	it("should handle multiple hunks", async () => {
-		const original = `line1
-line2
-line3
-line4
-line5`
-
-		const diff = `--- a/file.txt
-+++ b/file.txt
-@@ ... @@
- line1
-+new line
- line2
--line3
-+modified line3
-@@ ... @@
- line4
--line5
-+modified line5
-+new line at end`
-
-		const result = await strategy.applyDiff(original, diff)
-		expect(result.success).toBe(true)
-		if (result.success) {
-			expect(result.content).toBe(`line1
-new line
-line2
-modified line3
-line4
-modified line5
-new line at end`)
-		}
-	})
-
-	it("should handle complex large", async () => {
-		const original = `line1
-line2
-line3
-line4
-line5
-line6
-line7
-line8
-line9
-line10`
-
-		const diff = `--- a/file.txt
-+++ b/file.txt
-@@ ... @@
- line1
-+header line
-+another header
- line2
--line3
--line4
-+modified line3
-+modified line4
-+extra line
-@@ ... @@
- line6
-+middle section
- line7
--line8
-+changed line8
-+bonus line
-@@ ... @@
- line9
--line10
-+final line
-+very last line`
-
-		const result = await strategy.applyDiff(original, diff)
-		expect(result.success).toBe(true)
-		if (result.success) {
-			expect(result.content).toBe(`line1
-header line
-another header
-line2
-modified line3
-modified line4
-extra line
-line5
-line6
-middle section
-line7
-changed line8
-bonus line
-line9
-final line
-very last line`)
-		}
-	})
-
-	it("should handle indentation changes", async () => {
-		const original = `first line
-  indented line
-    double indented line
-  back to single indent
-no indent
-  indented again
-    double indent again
-      triple indent
-  back to single
-last line`
-
-		const diff = `--- original
-+++ modified
-@@ ... @@
- first line
-   indented line
-+	tab indented line
-+  new indented line
-     double indented line
-   back to single indent
- no indent
-   indented again
-     double indent again
--      triple indent
-+      hi there mate
-   back to single
- last line`
-
-		const expected = `first line
-  indented line
-	tab indented line
-  new indented line
-    double indented line
-  back to single indent
-no indent
-  indented again
-    double indent again
-      hi there mate
-  back to single
-last line`
-
-		const result = await strategy.applyDiff(original, diff)
-		expect(result.success).toBe(true)
-		if (result.success) {
-			expect(result.content).toBe(expected)
-		}
-	})
-
-	it("should handle high level edits", async () => {
-		const original = `def factorial(n):
-    if n == 0:
-        return 1
-    else:
-        return n * factorial(n-1)`
-		const diff = `@@ ... @@
--def factorial(n):
--    if n == 0:
--        return 1
--    else:
--        return n * factorial(n-1)
-+def factorial(number):
-+    if number == 0:
-+        return 1
-+    else:
-+        return number * factorial(number-1)`
-
-		const expected = `def factorial(number):
-    if number == 0:
-        return 1
-    else:
-        return number * factorial(number-1)`
-
-		const result = await strategy.applyDiff(original, diff)
-		expect(result.success).toBe(true)
-		if (result.success) {
-			expect(result.content).toBe(expected)
-		}
-	})
-
-	it("it should handle very complex edits", async () => {
-		const original = `//Initialize the array that will hold the primes
-var primeArray = [];
-/*Write a function that checks for primeness and
- pushes those values to t*he array*/
-function PrimeCheck(candidate){
-  isPrime = true;
-  for(var i = 2; i < candidate && isPrime; i++){
-    if(candidate%i === 0){
-      isPrime = false;
-    } else {
-      isPrime = true;
-    }
-  }
-  if(isPrime){
-    primeArray.push(candidate);
-  }
-  return primeArray;
-}
-/*Write the code that runs the above until the
- l ength of the array equa*ls the number of primes
- desired*/
-
-var numPrimes = prompt("How many primes?");
-
-//Display the finished array of primes
-
-//for loop starting at 2 as that is the lowest prime number keep going until the array is as long as we requested
-for (var i = 2; primeArray.length < numPrimes; i++) {
-  PrimeCheck(i); //
-}
-console.log(primeArray);
-`
-
-		const diff = `--- test_diff.js
-+++ test_diff.js
-@@ ... @@
--//Initialize the array that will hold the primes
- var primeArray = [];
--/*Write a function that checks for primeness and
-- pushes those values to t*he array*/
- function PrimeCheck(candidate){
-   isPrime = true;
-   for(var i = 2; i < candidate && isPrime; i++){
-@@ ... @@
-   return primeArray;
- }
--/*Write the code that runs the above until the
--  l ength of the array equa*ls the number of primes
--  desired*/
- 
- var numPrimes = prompt("How many primes?");
- 
--//Display the finished array of primes
--
--//for loop starting at 2 as that is the lowest prime number keep going until the array is as long as we requested
- for (var i = 2; primeArray.length < numPrimes; i++) {
--  PrimeCheck(i); //
-+  PrimeCheck(i);
- }
- console.log(primeArray);`
-
-		const expected = `var primeArray = [];
-function PrimeCheck(candidate){
-  isPrime = true;
-  for(var i = 2; i < candidate && isPrime; i++){
-    if(candidate%i === 0){
-      isPrime = false;
-    } else {
-      isPrime = true;
-    }
-  }
-  if(isPrime){
-    primeArray.push(candidate);
-  }
-  return primeArray;
-}
-
-var numPrimes = prompt("How many primes?");
-
-for (var i = 2; primeArray.length < numPrimes; i++) {
-  PrimeCheck(i);
-}
-console.log(primeArray);
-`
-
-		const result = await strategy.applyDiff(original, diff)
-		expect(result.success).toBe(true)
-		if (result.success) {
-			expect(result.content).toBe(expected)
-		}
-	})
-
-	describe("error handling and edge cases", () => {
-		it("should reject completely invalid diff format", async () => {
-			const original = "line1\nline2\nline3"
-			const invalidDiff = "this is not a diff at all"
-
-			const result = await strategy.applyDiff(original, invalidDiff)
-			expect(result.success).toBe(false)
-		})
-
-		it("should reject diff with invalid hunk format", async () => {
-			const original = "line1\nline2\nline3"
-			const invalidHunkDiff = `--- a/file.txt
-+++ b/file.txt
-invalid hunk header
- line1
--line2
-+new line`
-
-			const result = await strategy.applyDiff(original, invalidHunkDiff)
-			expect(result.success).toBe(false)
-		})
-
-		it("should fail when diff tries to modify non-existent content", async () => {
-			const original = "line1\nline2\nline3"
-			const nonMatchingDiff = `--- a/file.txt
-+++ b/file.txt
-@@ ... @@
- line1
--nonexistent line
-+new line
- line3`
-
-			const result = await strategy.applyDiff(original, nonMatchingDiff)
-			expect(result.success).toBe(false)
-		})
-
-		it("should handle overlapping hunks", async () => {
-			const original = `line1
-line2
-line3
-line4
-line5`
-			const overlappingDiff = `--- a/file.txt
-+++ b/file.txt
-@@ ... @@
- line1
- line2
--line3
-+modified3
- line4
-@@ ... @@
- line2
--line3
--line4
-+modified3and4
- line5`
-
-			const result = await strategy.applyDiff(original, overlappingDiff)
-			expect(result.success).toBe(false)
-		})
-
-		it("should handle empty lines modifications", async () => {
-			const original = `line1
-
-line3
-
-line5`
-			const emptyLinesDiff = `--- a/file.txt
-+++ b/file.txt
-@@ ... @@
- line1
-
--line3
-+line3modified
-
- line5`
-
-			const result = await strategy.applyDiff(original, emptyLinesDiff)
-			expect(result.success).toBe(true)
-			if (result.success) {
-				expect(result.content).toBe(`line1
-
-line3modified
-
-line5`)
-			}
-		})
-
-		it("should handle mixed line endings in diff", async () => {
-			const original = "line1\r\nline2\nline3\r\n"
-			const mixedEndingsDiff = `--- a/file.txt
-+++ b/file.txt
-@@ ... @@
- line1\r
--line2
-+modified2\r
- line3`
-
-			const result = await strategy.applyDiff(original, mixedEndingsDiff)
-			expect(result.success).toBe(true)
-			if (result.success) {
-				expect(result.content).toBe("line1\r\nmodified2\r\nline3\r\n")
-			}
-		})
-
-		it("should handle partial line modifications", async () => {
-			const original = "const value = oldValue + 123;"
-			const partialDiff = `--- a/file.txt
-+++ b/file.txt
-@@ ... @@
--const value = oldValue + 123;
-+const value = newValue + 123;`
-
-			const result = await strategy.applyDiff(original, partialDiff)
-			expect(result.success).toBe(true)
-			if (result.success) {
-				expect(result.content).toBe("const value = newValue + 123;")
-			}
-		})
-
-		it("should handle slightly malformed but recoverable diff", async () => {
-			const original = "line1\nline2\nline3"
-			// Missing space after --- and +++
-			const slightlyBadDiff = `---a/file.txt
-+++b/file.txt
-@@ ... @@
- line1
--line2
-+new line
- line3`
-
-			const result = await strategy.applyDiff(original, slightlyBadDiff)
-			expect(result.success).toBe(true)
-			if (result.success) {
-				expect(result.content).toBe("line1\nnew line\nline3")
-			}
-		})
-	})
-
-	describe("similar code sections", () => {
-		it("should correctly modify the right section when similar code exists", async () => {
-			const original = `function add(a, b) {
-  return a + b;
-}
-
-function subtract(a, b) {
-  return a - b;
-}
-
-function multiply(a, b) {
-  return a + b;  // Bug here
-}`
-
-			const diff = `--- a/math.js
-+++ b/math.js
-@@ ... @@
- function multiply(a, b) {
--  return a + b;  // Bug here
-+  return a * b;
- }`
-
-			const result = await strategy.applyDiff(original, diff)
-			expect(result.success).toBe(true)
-			if (result.success) {
-				expect(result.content).toBe(`function add(a, b) {
-  return a + b;
-}
-
-function subtract(a, b) {
-  return a - b;
-}
-
-function multiply(a, b) {
-  return a * b;
-}`)
-			}
-		})
-
-		it("should handle multiple similar sections with correct context", async () => {
-			const original = `if (condition) {
-  doSomething();
-  doSomething();
-  doSomething();
-}
-
-if (otherCondition) {
-  doSomething();
-  doSomething();
-  doSomething();
-}`
-
-			const diff = `--- a/file.js
-+++ b/file.js
-@@ ... @@
- if (otherCondition) {
-   doSomething();
--  doSomething();
-+  doSomethingElse();
-   doSomething();
- }`
-
-			const result = await strategy.applyDiff(original, diff)
-			expect(result.success).toBe(true)
-			if (result.success) {
-				expect(result.content).toBe(`if (condition) {
-  doSomething();
-  doSomething();
-  doSomething();
-}
-
-if (otherCondition) {
-  doSomething();
-  doSomethingElse();
-  doSomething();
-}`)
-			}
-		})
-	})
-
-	describe("hunk splitting", () => {
-		it("should handle large diffs with multiple non-contiguous changes", async () => {
-			const original = `import { readFile } from 'fs';
-import { join } from 'path';
-import { Logger } from './logger';
-
-const logger = new Logger();
-
-async function processFile(filePath: string) {
-  try {
-    const data = await readFile(filePath, 'utf8');
-    logger.info('File read successfully');
-    return data;
-  } catch (error) {
-    logger.error('Failed to read file:', error);
-    throw error;
-  }
-}
-
-function validateInput(input: string): boolean {
-  if (!input) {
-    logger.warn('Empty input received');
-    return false;
-  }
-  return input.length > 0;
-}
-
-async function writeOutput(data: string) {
-  logger.info('Processing output');
-  // TODO: Implement output writing
-  return Promise.resolve();
-}
-
-function parseConfig(configPath: string) {
-  logger.debug('Reading config from:', configPath);
-  // Basic config parsing
-  return {
-    enabled: true,
-    maxRetries: 3
-  };
-}
-
-export {
-  processFile,
-  validateInput,
-  writeOutput,
-  parseConfig
-};`
-
-			const diff = `--- a/file.ts
-+++ b/file.ts
-@@ ... @@
--import { readFile } from 'fs';
-+import { readFile, writeFile } from 'fs';
- import { join } from 'path';
--import { Logger } from './logger';
-+import { Logger } from './utils/logger';
-+import { Config } from './types';
- 
--const logger = new Logger();
-+const logger = new Logger('FileProcessor');
- 
- async function processFile(filePath: string) {
-   try {
-     const data = await readFile(filePath, 'utf8');
--    logger.info('File read successfully');
-+    logger.info(\`File \${filePath} read successfully\`);
-     return data;
-   } catch (error) {
--    logger.error('Failed to read file:', error);
-+    logger.error(\`Failed to read file \${filePath}:\`, error);
-     throw error;
-   }
- }
- 
- function validateInput(input: string): boolean {
-   if (!input) {
--    logger.warn('Empty input received');
-+    logger.warn('Validation failed: Empty input received');
-     return false;
-   }
--  return input.length > 0;
-+  return input.trim().length > 0;
- }
- 
--async function writeOutput(data: string) {
--  logger.info('Processing output');
--  // TODO: Implement output writing
--  return Promise.resolve();
-+async function writeOutput(data: string, outputPath: string) {
-+  try {
-+    await writeFile(outputPath, data, 'utf8');
-+    logger.info(\`Output written to \${outputPath}\`);
-+  } catch (error) {
-+    logger.error(\`Failed to write output to \${outputPath}:\`, error);
-+    throw error;
-+  }
- }
- 
--function parseConfig(configPath: string) {
--  logger.debug('Reading config from:', configPath);
--  // Basic config parsing
--  return {
--    enabled: true,
--    maxRetries: 3
--  };
-+async function parseConfig(configPath: string): Promise<Config> {
-+  try {
-+    const configData = await readFile(configPath, 'utf8');
-+    logger.debug(\`Reading config from \${configPath}\`);
-+    return JSON.parse(configData);
-+  } catch (error) {
-+    logger.error(\`Failed to parse config from \${configPath}:\`, error);
-+    throw error;
-+  }
- }
- 
- export {
-   processFile,
-   validateInput,
-   writeOutput,
--  parseConfig
-+  parseConfig,
-+  type Config
- };`
-
-			const expected = `import { readFile, writeFile } from 'fs';
-import { join } from 'path';
-import { Logger } from './utils/logger';
-import { Config } from './types';
-
-const logger = new Logger('FileProcessor');
-
-async function processFile(filePath: string) {
-  try {
-    const data = await readFile(filePath, 'utf8');
-    logger.info(\`File \${filePath} read successfully\`);
-    return data;
-  } catch (error) {
-    logger.error(\`Failed to read file \${filePath}:\`, error);
-    throw error;
-  }
-}
-
-function validateInput(input: string): boolean {
-  if (!input) {
-    logger.warn('Validation failed: Empty input received');
-    return false;
-  }
-  return input.trim().length > 0;
-}
-
-async function writeOutput(data: string, outputPath: string) {
-  try {
-    await writeFile(outputPath, data, 'utf8');
-    logger.info(\`Output written to \${outputPath}\`);
-  } catch (error) {
-    logger.error(\`Failed to write output to \${outputPath}:\`, error);
-    throw error;
-  }
-}
-
-async function parseConfig(configPath: string): Promise<Config> {
-  try {
-    const configData = await readFile(configPath, 'utf8');
-    logger.debug(\`Reading config from \${configPath}\`);
-    return JSON.parse(configData);
-  } catch (error) {
-    logger.error(\`Failed to parse config from \${configPath}:\`, error);
-    throw error;
-  }
-}
-
-export {
-  processFile,
-  validateInput,
-  writeOutput,
-  parseConfig,
-  type Config
-};`
-
-			const result = await strategy.applyDiff(original, diff)
-			expect(result.success).toBe(true)
-			if (result.success) {
-				expect(result.content).toBe(expected)
-			}
-		})
-	})
-})

+ 0 - 228
src/core/diff/strategies/__tests__/unified.test.ts

@@ -1,228 +0,0 @@
-import { UnifiedDiffStrategy } from "../unified"
-
-describe("UnifiedDiffStrategy", () => {
-	let strategy: UnifiedDiffStrategy
-
-	beforeEach(() => {
-		strategy = new UnifiedDiffStrategy()
-	})
-
-	describe("getToolDescription", () => {
-		it("should return tool description with correct cwd", () => {
-			const cwd = "/test/path"
-			const description = strategy.getToolDescription({ cwd })
-
-			expect(description).toContain("apply_diff")
-			expect(description).toContain(cwd)
-			expect(description).toContain("Parameters:")
-			expect(description).toContain("Format Requirements:")
-		})
-	})
-
-	describe("applyDiff", () => {
-		it("should successfully apply a function modification diff", async () => {
-			const originalContent = `import { Logger } from '../logger';
-
-function calculateTotal(items: number[]): number {
-  return items.reduce((sum, item) => {
-    return sum + item;
-  }, 0);
-}
-
-export { calculateTotal };`
-
-			const diffContent = `--- src/utils/helper.ts
-+++ src/utils/helper.ts
-@@ -1,9 +1,10 @@
- import { Logger } from '../logger';
- 
- function calculateTotal(items: number[]): number {
--  return items.reduce((sum, item) => {
--    return sum + item;
-+  const total = items.reduce((sum, item) => {
-+    return sum + item * 1.1;  // Add 10% markup
-   }, 0);
-+  return Math.round(total * 100) / 100;  // Round to 2 decimal places
- }
- 
- export { calculateTotal };`
-
-			const expected = `import { Logger } from '../logger';
-
-function calculateTotal(items: number[]): number {
-  const total = items.reduce((sum, item) => {
-    return sum + item * 1.1;  // Add 10% markup
-  }, 0);
-  return Math.round(total * 100) / 100;  // Round to 2 decimal places
-}
-
-export { calculateTotal };`
-
-			const result = await strategy.applyDiff(originalContent, diffContent)
-			expect(result.success).toBe(true)
-			if (result.success) {
-				expect(result.content).toBe(expected)
-			}
-		})
-
-		it("should successfully apply a diff adding a new method", async () => {
-			const originalContent = `class Calculator {
-  add(a: number, b: number): number {
-    return a + b;
-  }
-}`
-
-			const diffContent = `--- src/Calculator.ts
-+++ src/Calculator.ts
-@@ -1,5 +1,9 @@
- class Calculator {
-   add(a: number, b: number): number {
-     return a + b;
-   }
-+
-+  multiply(a: number, b: number): number {
-+    return a * b;
-+  }
- }`
-
-			const expected = `class Calculator {
-  add(a: number, b: number): number {
-    return a + b;
-  }
-
-  multiply(a: number, b: number): number {
-    return a * b;
-  }
-}`
-
-			const result = await strategy.applyDiff(originalContent, diffContent)
-			expect(result.success).toBe(true)
-			if (result.success) {
-				expect(result.content).toBe(expected)
-			}
-		})
-
-		it("should successfully apply a diff modifying imports", async () => {
-			const originalContent = `import { useState } from 'react';
-import { Button } from './components';
-
-function App() {
-  const [count, setCount] = useState(0);
-  return <Button onClick={() => setCount(count + 1)}>{count}</Button>;
-}`
-
-			const diffContent = `--- src/App.tsx
-+++ src/App.tsx
-@@ -1,7 +1,8 @@
--import { useState } from 'react';
-+import { useState, useEffect } from 'react';
- import { Button } from './components';
- 
- function App() {
-   const [count, setCount] = useState(0);
-+  useEffect(() => { document.title = \`Count: \${count}\` }, [count]);
-   return <Button onClick={() => setCount(count + 1)}>{count}</Button>;
- }`
-
-			const expected = `import { useState, useEffect } from 'react';
-import { Button } from './components';
-
-function App() {
-  const [count, setCount] = useState(0);
-  useEffect(() => { document.title = \`Count: \${count}\` }, [count]);
-  return <Button onClick={() => setCount(count + 1)}>{count}</Button>;
-}`
-
-			const result = await strategy.applyDiff(originalContent, diffContent)
-			expect(result.success).toBe(true)
-			if (result.success) {
-				expect(result.content).toBe(expected)
-			}
-		})
-
-		it("should successfully apply a diff with multiple hunks", async () => {
-			const originalContent = `import { readFile, writeFile } from 'fs';
-
-function processFile(path: string) {
-  readFile(path, 'utf8', (err, data) => {
-    if (err) throw err;
-    const processed = data.toUpperCase();
-    writeFile(path, processed, (err) => {
-      if (err) throw err;
-    });
-  });
-}
-
-export { processFile };`
-
-			const diffContent = `--- src/file-processor.ts
-+++ src/file-processor.ts
-@@ -1,12 +1,14 @@
--import { readFile, writeFile } from 'fs';
-+import { promises as fs } from 'fs';
-+import { join } from 'path';
- 
--function processFile(path: string) {
--  readFile(path, 'utf8', (err, data) => {
--    if (err) throw err;
-+async function processFile(path: string) {
-+  try {
-+    const data = await fs.readFile(join(__dirname, path), 'utf8');
-     const processed = data.toUpperCase();
--    writeFile(path, processed, (err) => {
--      if (err) throw err;
--    });
--  });
-+    await fs.writeFile(join(__dirname, path), processed);
-+  } catch (error) {
-+    console.error('Failed to process file:', error);
-+    throw error;
-+  }
- }
- 
- export { processFile };`
-
-			const expected = `import { promises as fs } from 'fs';
-import { join } from 'path';
-
-async function processFile(path: string) {
-  try {
-    const data = await fs.readFile(join(__dirname, path), 'utf8');
-    const processed = data.toUpperCase();
-    await fs.writeFile(join(__dirname, path), processed);
-  } catch (error) {
-    console.error('Failed to process file:', error);
-    throw error;
-  }
-}
-
-export { processFile };`
-
-			const result = await strategy.applyDiff(originalContent, diffContent)
-			expect(result.success).toBe(true)
-			if (result.success) {
-				expect(result.content).toBe(expected)
-			}
-		})
-
-		it("should handle empty original content", async () => {
-			const originalContent = ""
-			const diffContent = `--- empty.ts
-+++ empty.ts
-@@ -0,0 +1,3 @@
-+export function greet(name: string): string {
-+  return \`Hello, \${name}!\`;
-+}`
-
-			const expected = `export function greet(name: string): string {
-  return \`Hello, \${name}!\`;
-}\n`
-
-			const result = await strategy.applyDiff(originalContent, diffContent)
-			expect(result.success).toBe(true)
-			if (result.success) {
-				expect(result.content).toBe(expected)
-			}
-		})
-	})
-})

+ 0 - 295
src/core/diff/strategies/new-unified/__tests__/edit-strategies.test.ts

@@ -1,295 +0,0 @@
-import { applyContextMatching, applyDMP, applyGitFallback } from "../edit-strategies"
-import { Hunk } from "../types"
-
-const testCases = [
-	{
-		name: "should return original content if no match is found",
-		hunk: {
-			changes: [
-				{ type: "context", content: "line1" },
-				{ type: "add", content: "line2" },
-			],
-		} as Hunk,
-		content: ["line1", "line3"],
-		matchPosition: -1,
-		expected: {
-			confidence: 0,
-			result: ["line1", "line3"],
-		},
-		expectedResult: "line1\nline3",
-		strategies: ["context", "dmp"],
-	},
-	{
-		name: "should apply a simple add change",
-		hunk: {
-			changes: [
-				{ type: "context", content: "line1" },
-				{ type: "add", content: "line2" },
-			],
-		} as Hunk,
-		content: ["line1", "line3"],
-		matchPosition: 0,
-		expected: {
-			confidence: 1,
-			result: ["line1", "line2", "line3"],
-		},
-		expectedResult: "line1\nline2\nline3",
-		strategies: ["context", "dmp"],
-	},
-	{
-		name: "should apply a simple remove change",
-		hunk: {
-			changes: [
-				{ type: "context", content: "line1" },
-				{ type: "remove", content: "line2" },
-			],
-		} as Hunk,
-		content: ["line1", "line2", "line3"],
-		matchPosition: 0,
-		expected: {
-			confidence: 1,
-			result: ["line1", "line3"],
-		},
-		expectedResult: "line1\nline3",
-		strategies: ["context", "dmp"],
-	},
-	{
-		name: "should apply a simple context change",
-		hunk: {
-			changes: [{ type: "context", content: "line1" }],
-		} as Hunk,
-		content: ["line1", "line2", "line3"],
-		matchPosition: 0,
-		expected: {
-			confidence: 1,
-			result: ["line1", "line2", "line3"],
-		},
-		expectedResult: "line1\nline2\nline3",
-		strategies: ["context", "dmp"],
-	},
-	{
-		name: "should apply a multi-line add change",
-		hunk: {
-			changes: [
-				{ type: "context", content: "line1" },
-				{ type: "add", content: "line2\nline3" },
-			],
-		} as Hunk,
-		content: ["line1", "line4"],
-		matchPosition: 0,
-		expected: {
-			confidence: 1,
-			result: ["line1", "line2\nline3", "line4"],
-		},
-		expectedResult: "line1\nline2\nline3\nline4",
-		strategies: ["context", "dmp"],
-	},
-	{
-		name: "should apply a multi-line remove change",
-		hunk: {
-			changes: [
-				{ type: "context", content: "line1" },
-				{ type: "remove", content: "line2\nline3" },
-			],
-		} as Hunk,
-		content: ["line1", "line2", "line3", "line4"],
-		matchPosition: 0,
-		expected: {
-			confidence: 1,
-			result: ["line1", "line4"],
-		},
-		expectedResult: "line1\nline4",
-		strategies: ["context", "dmp"],
-	},
-	{
-		name: "should apply a multi-line context change",
-		hunk: {
-			changes: [
-				{ type: "context", content: "line1" },
-				{ type: "context", content: "line2\nline3" },
-			],
-		} as Hunk,
-		content: ["line1", "line2", "line3", "line4"],
-		matchPosition: 0,
-		expected: {
-			confidence: 1,
-			result: ["line1", "line2\nline3", "line4"],
-		},
-		expectedResult: "line1\nline2\nline3\nline4",
-		strategies: ["context", "dmp"],
-	},
-	{
-		name: "should apply a change with indentation",
-		hunk: {
-			changes: [
-				{ type: "context", content: "  line1" },
-				{ type: "add", content: "    line2" },
-			],
-		} as Hunk,
-		content: ["  line1", "  line3"],
-		matchPosition: 0,
-		expected: {
-			confidence: 1,
-			result: ["  line1", "    line2", "  line3"],
-		},
-		expectedResult: "  line1\n    line2\n  line3",
-		strategies: ["context", "dmp"],
-	},
-	{
-		name: "should apply a change with mixed indentation",
-		hunk: {
-			changes: [
-				{ type: "context", content: "\tline1" },
-				{ type: "add", content: "  line2" },
-			],
-		} as Hunk,
-		content: ["\tline1", "  line3"],
-		matchPosition: 0,
-		expected: {
-			confidence: 1,
-			result: ["\tline1", "  line2", "  line3"],
-		},
-		expectedResult: "\tline1\n  line2\n  line3",
-		strategies: ["context", "dmp"],
-	},
-	{
-		name: "should apply a change with mixed indentation and multi-line",
-		hunk: {
-			changes: [
-				{ type: "context", content: "  line1" },
-				{ type: "add", content: "\tline2\n    line3" },
-			],
-		} as Hunk,
-		content: ["  line1", "  line4"],
-		matchPosition: 0,
-		expected: {
-			confidence: 1,
-			result: ["  line1", "\tline2\n    line3", "  line4"],
-		},
-		expectedResult: "  line1\n\tline2\n    line3\n  line4",
-		strategies: ["context", "dmp"],
-	},
-	{
-		name: "should apply a complex change with mixed indentation and multi-line",
-		hunk: {
-			changes: [
-				{ type: "context", content: "  line1" },
-				{ type: "remove", content: "    line2" },
-				{ type: "add", content: "\tline3\n      line4" },
-				{ type: "context", content: "  line5" },
-			],
-		} as Hunk,
-		content: ["  line1", "    line2", "  line5", "  line6"],
-		matchPosition: 0,
-		expected: {
-			confidence: 1,
-			result: ["  line1", "\tline3\n      line4", "  line5", "  line6"],
-		},
-		expectedResult: "  line1\n\tline3\n      line4\n  line5\n  line6",
-		strategies: ["context", "dmp"],
-	},
-	{
-		name: "should apply a complex change with mixed indentation and multi-line and context",
-		hunk: {
-			changes: [
-				{ type: "context", content: "  line1" },
-				{ type: "remove", content: "    line2" },
-				{ type: "add", content: "\tline3\n      line4" },
-				{ type: "context", content: "  line5" },
-				{ type: "context", content: "  line6" },
-			],
-		} as Hunk,
-		content: ["  line1", "    line2", "  line5", "  line6", "  line7"],
-		matchPosition: 0,
-		expected: {
-			confidence: 1,
-			result: ["  line1", "\tline3\n      line4", "  line5", "  line6", "  line7"],
-		},
-		expectedResult: "  line1\n\tline3\n      line4\n  line5\n  line6\n  line7",
-		strategies: ["context", "dmp"],
-	},
-	{
-		name: "should apply a complex change with mixed indentation and multi-line and context and a different match position",
-		hunk: {
-			changes: [
-				{ type: "context", content: "  line1" },
-				{ type: "remove", content: "    line2" },
-				{ type: "add", content: "\tline3\n      line4" },
-				{ type: "context", content: "  line5" },
-				{ type: "context", content: "  line6" },
-			],
-		} as Hunk,
-		content: ["  line0", "  line1", "    line2", "  line5", "  line6", "  line7"],
-		matchPosition: 1,
-		expected: {
-			confidence: 1,
-			result: ["  line0", "  line1", "\tline3\n      line4", "  line5", "  line6", "  line7"],
-		},
-		expectedResult: "  line0\n  line1\n\tline3\n      line4\n  line5\n  line6\n  line7",
-		strategies: ["context", "dmp"],
-	},
-]
-
-describe("applyContextMatching", () => {
-	testCases.forEach(({ name, hunk, content, matchPosition, expected, strategies, expectedResult }) => {
-		if (!strategies?.includes("context")) {
-			return
-		}
-		it(name, () => {
-			const result = applyContextMatching(hunk, content, matchPosition)
-			expect(result.result.join("\n")).toEqual(expectedResult)
-			expect(result.confidence).toBeGreaterThanOrEqual(expected.confidence)
-			expect(result.strategy).toBe("context")
-		})
-	})
-})
-
-describe("applyDMP", () => {
-	testCases.forEach(({ name, hunk, content, matchPosition, expected, strategies, expectedResult }) => {
-		if (!strategies?.includes("dmp")) {
-			return
-		}
-		it(name, () => {
-			const result = applyDMP(hunk, content, matchPosition)
-			expect(result.result.join("\n")).toEqual(expectedResult)
-			expect(result.confidence).toBeGreaterThanOrEqual(expected.confidence)
-			expect(result.strategy).toBe("dmp")
-		})
-	})
-})
-
-describe("applyGitFallback", () => {
-	it("should successfully apply changes using git operations", async () => {
-		const hunk = {
-			changes: [
-				{ type: "context", content: "line1", indent: "" },
-				{ type: "remove", content: "line2", indent: "" },
-				{ type: "add", content: "new line2", indent: "" },
-				{ type: "context", content: "line3", indent: "" },
-			],
-		} as Hunk
-
-		const content = ["line1", "line2", "line3"]
-		const result = await applyGitFallback(hunk, content)
-
-		expect(result.result.join("\n")).toEqual("line1\nnew line2\nline3")
-		expect(result.confidence).toBe(1)
-		expect(result.strategy).toBe("git-fallback")
-	})
-
-	it("should return original content with 0 confidence when changes cannot be applied", async () => {
-		const hunk = {
-			changes: [
-				{ type: "context", content: "nonexistent", indent: "" },
-				{ type: "add", content: "new line", indent: "" },
-			],
-		} as Hunk
-
-		const content = ["line1", "line2", "line3"]
-		const result = await applyGitFallback(hunk, content)
-
-		expect(result.result).toEqual(content)
-		expect(result.confidence).toBe(0)
-		expect(result.strategy).toBe("git-fallback")
-	})
-})

+ 0 - 262
src/core/diff/strategies/new-unified/__tests__/search-strategies.test.ts

@@ -1,262 +0,0 @@
-import { findAnchorMatch, findExactMatch, findSimilarityMatch, findLevenshteinMatch } from "../search-strategies"
-
-type SearchStrategy = (
-	searchStr: string,
-	content: string[],
-	startIndex?: number,
-) => {
-	index: number
-	confidence: number
-	strategy: string
-}
-
-const testCases = [
-	{
-		name: "should return no match if the search string is not found",
-		searchStr: "not found",
-		content: ["line1", "line2", "line3"],
-		expected: { index: -1, confidence: 0 },
-		strategies: ["exact", "similarity", "levenshtein"],
-	},
-	{
-		name: "should return a match if the search string is found",
-		searchStr: "line2",
-		content: ["line1", "line2", "line3"],
-		expected: { index: 1, confidence: 1 },
-		strategies: ["exact", "similarity", "levenshtein"],
-	},
-	{
-		name: "should return a match with correct index when startIndex is provided",
-		searchStr: "line3",
-		content: ["line1", "line2", "line3", "line4", "line3"],
-		startIndex: 3,
-		expected: { index: 4, confidence: 1 },
-		strategies: ["exact", "similarity", "levenshtein"],
-	},
-	{
-		name: "should return a match even if there are more lines in content",
-		searchStr: "line2",
-		content: ["line1", "line2", "line3", "line4", "line5"],
-		expected: { index: 1, confidence: 1 },
-		strategies: ["exact", "similarity", "levenshtein"],
-	},
-	{
-		name: "should return a match even if the search string is at the beginning of the content",
-		searchStr: "line1",
-		content: ["line1", "line2", "line3"],
-		expected: { index: 0, confidence: 1 },
-		strategies: ["exact", "similarity", "levenshtein"],
-	},
-	{
-		name: "should return a match even if the search string is at the end of the content",
-		searchStr: "line3",
-		content: ["line1", "line2", "line3"],
-		expected: { index: 2, confidence: 1 },
-		strategies: ["exact", "similarity", "levenshtein"],
-	},
-	{
-		name: "should return a match for a multi-line search string",
-		searchStr: "line2\nline3",
-		content: ["line1", "line2", "line3", "line4"],
-		expected: { index: 1, confidence: 1 },
-		strategies: ["exact", "similarity", "levenshtein"],
-	},
-	{
-		name: "should return no match if a multi-line search string is not found",
-		searchStr: "line2\nline4",
-		content: ["line1", "line2", "line3", "line4"],
-		expected: { index: -1, confidence: 0 },
-		strategies: ["exact", "similarity"],
-	},
-	{
-		name: "should return a match with indentation",
-		searchStr: "  line2",
-		content: ["line1", "  line2", "line3"],
-		expected: { index: 1, confidence: 1 },
-		strategies: ["exact", "similarity", "levenshtein"],
-	},
-	{
-		name: "should return a match with more complex indentation",
-		searchStr: "    line3",
-		content: ["  line1", "    line2", "    line3", "  line4"],
-		expected: { index: 2, confidence: 1 },
-		strategies: ["exact", "similarity", "levenshtein"],
-	},
-	{
-		name: "should return a match with mixed indentation",
-		searchStr: "\tline2",
-		content: ["  line1", "\tline2", "    line3"],
-		expected: { index: 1, confidence: 1 },
-		strategies: ["exact", "similarity", "levenshtein"],
-	},
-	{
-		name: "should return a match with mixed indentation and multi-line",
-		searchStr: "  line2\n\tline3",
-		content: ["line1", "  line2", "\tline3", "    line4"],
-		expected: { index: 1, confidence: 1 },
-		strategies: ["exact", "similarity", "levenshtein"],
-	},
-	{
-		name: "should return no match if mixed indentation and multi-line is not found",
-		searchStr: "  line2\n    line4",
-		content: ["line1", "  line2", "\tline3", "    line4"],
-		expected: { index: -1, confidence: 0 },
-		strategies: ["exact", "similarity"],
-	},
-	{
-		name: "should return a match with leading and trailing spaces",
-		searchStr: "  line2  ",
-		content: ["line1", "  line2  ", "line3"],
-		expected: { index: 1, confidence: 1 },
-		strategies: ["exact", "similarity", "levenshtein"],
-	},
-	{
-		name: "should return a match with leading and trailing tabs",
-		searchStr: "\tline2\t",
-		content: ["line1", "\tline2\t", "line3"],
-		expected: { index: 1, confidence: 1 },
-		strategies: ["exact", "similarity", "levenshtein"],
-	},
-	{
-		name: "should return a match with mixed leading and trailing spaces and tabs",
-		searchStr: " \tline2\t ",
-		content: ["line1", " \tline2\t ", "line3"],
-		expected: { index: 1, confidence: 1 },
-		strategies: ["exact", "similarity", "levenshtein"],
-	},
-	{
-		name: "should return a match with mixed leading and trailing spaces and tabs and multi-line",
-		searchStr: " \tline2\t \n  line3  ",
-		content: ["line1", " \tline2\t ", "  line3  ", "line4"],
-		expected: { index: 1, confidence: 1 },
-		strategies: ["exact", "similarity", "levenshtein"],
-	},
-	{
-		name: "should return no match if mixed leading and trailing spaces and tabs and multi-line is not found",
-		searchStr: " \tline2\t \n  line4  ",
-		content: ["line1", " \tline2\t ", "  line3  ", "line4"],
-		expected: { index: -1, confidence: 0 },
-		strategies: ["exact", "similarity"],
-	},
-]
-
-describe("findExactMatch", () => {
-	testCases.forEach(({ name, searchStr, content, startIndex, expected, strategies }) => {
-		if (!strategies?.includes("exact")) {
-			return
-		}
-		it(name, () => {
-			const result = findExactMatch(searchStr, content, startIndex)
-			expect(result.index).toBe(expected.index)
-			expect(result.confidence).toBeGreaterThanOrEqual(expected.confidence)
-			expect(result.strategy).toMatch(/exact(-overlapping)?/)
-		})
-	})
-})
-
-describe("findAnchorMatch", () => {
-	const anchorTestCases = [
-		{
-			name: "should return no match if no anchors are found",
-			searchStr: "   \n   \n   ",
-			content: ["line1", "line2", "line3"],
-			expected: { index: -1, confidence: 0 },
-		},
-		{
-			name: "should return no match if anchor positions cannot be validated",
-			searchStr: "unique line\ncontext line 1\ncontext line 2",
-			content: [
-				"different line 1",
-				"different line 2",
-				"different line 3",
-				"another unique line",
-				"context line 1",
-				"context line 2",
-			],
-			expected: { index: -1, confidence: 0 },
-		},
-		{
-			name: "should return a match if anchor positions can be validated",
-			searchStr: "unique line\ncontext line 1\ncontext line 2",
-			content: ["line1", "line2", "unique line", "context line 1", "context line 2", "line 6"],
-			expected: { index: 2, confidence: 1 },
-		},
-		{
-			name: "should return a match with correct index when startIndex is provided",
-			searchStr: "unique line\ncontext line 1\ncontext line 2",
-			content: ["line1", "line2", "line3", "unique line", "context line 1", "context line 2", "line 7"],
-			startIndex: 3,
-			expected: { index: 3, confidence: 1 },
-		},
-		{
-			name: "should return a match even if there are more lines in content",
-			searchStr: "unique line\ncontext line 1\ncontext line 2",
-			content: [
-				"line1",
-				"line2",
-				"unique line",
-				"context line 1",
-				"context line 2",
-				"line 6",
-				"extra line 1",
-				"extra line 2",
-			],
-			expected: { index: 2, confidence: 1 },
-		},
-		{
-			name: "should return a match even if the anchor is at the beginning of the content",
-			searchStr: "unique line\ncontext line 1\ncontext line 2",
-			content: ["unique line", "context line 1", "context line 2", "line 6"],
-			expected: { index: 0, confidence: 1 },
-		},
-		{
-			name: "should return a match even if the anchor is at the end of the content",
-			searchStr: "unique line\ncontext line 1\ncontext line 2",
-			content: ["line1", "line2", "unique line", "context line 1", "context line 2"],
-			expected: { index: 2, confidence: 1 },
-		},
-		{
-			name: "should return no match if no valid anchor is found",
-			searchStr: "non-unique line\ncontext line 1\ncontext line 2",
-			content: ["line1", "line2", "non-unique line", "context line 1", "context line 2", "non-unique line"],
-			expected: { index: -1, confidence: 0 },
-		},
-	]
-
-	anchorTestCases.forEach(({ name, searchStr, content, startIndex, expected }) => {
-		it(name, () => {
-			const result = findAnchorMatch(searchStr, content, startIndex)
-			expect(result.index).toBe(expected.index)
-			expect(result.confidence).toBeGreaterThanOrEqual(expected.confidence)
-			expect(result.strategy).toBe("anchor")
-		})
-	})
-})
-
-describe("findSimilarityMatch", () => {
-	testCases.forEach(({ name, searchStr, content, startIndex, expected, strategies }) => {
-		if (!strategies?.includes("similarity")) {
-			return
-		}
-		it(name, () => {
-			const result = findSimilarityMatch(searchStr, content, startIndex)
-			expect(result.index).toBe(expected.index)
-			expect(result.confidence).toBeGreaterThanOrEqual(expected.confidence)
-			expect(result.strategy).toBe("similarity")
-		})
-	})
-})
-
-describe("findLevenshteinMatch", () => {
-	testCases.forEach(({ name, searchStr, content, startIndex, expected, strategies }) => {
-		if (!strategies?.includes("levenshtein")) {
-			return
-		}
-		it(name, () => {
-			const result = findLevenshteinMatch(searchStr, content, startIndex)
-			expect(result.index).toBe(expected.index)
-			expect(result.confidence).toBeGreaterThanOrEqual(expected.confidence)
-			expect(result.strategy).toBe("levenshtein")
-		})
-	})
-})

+ 0 - 306
src/core/diff/strategies/new-unified/edit-strategies.ts

@@ -1,306 +0,0 @@
-import { diff_match_patch } from "diff-match-patch"
-import { EditResult, Hunk } from "./types"
-import { getDMPSimilarity, validateEditResult } from "./search-strategies"
-import * as path from "path"
-import simpleGit, { SimpleGit } from "simple-git"
-import * as tmp from "tmp"
-import * as fs from "fs"
-
-// Helper function to infer indentation - simplified version
-function inferIndentation(line: string, contextLines: string[], previousIndent: string = ""): string {
-	// If the line has explicit indentation in the change, use it exactly
-	const lineMatch = line.match(/^(\s+)/)
-	if (lineMatch) {
-		return lineMatch[1]
-	}
-
-	// If we have context lines, use the indentation from the first context line
-	const contextLine = contextLines[0]
-	if (contextLine) {
-		const contextMatch = contextLine.match(/^(\s+)/)
-		if (contextMatch) {
-			return contextMatch[1]
-		}
-	}
-
-	// Fallback to previous indent
-	return previousIndent
-}
-
-// Context matching edit strategy
-export function applyContextMatching(hunk: Hunk, content: string[], matchPosition: number): EditResult {
-	if (matchPosition === -1) {
-		return { confidence: 0, result: content, strategy: "context" }
-	}
-
-	const newResult = [...content.slice(0, matchPosition)]
-	let sourceIndex = matchPosition
-
-	for (const change of hunk.changes) {
-		if (change.type === "context") {
-			// Use the original line from content if available
-			if (sourceIndex < content.length) {
-				newResult.push(content[sourceIndex])
-			} else {
-				const line = change.indent ? change.indent + change.content : change.content
-				newResult.push(line)
-			}
-			sourceIndex++
-		} else if (change.type === "add") {
-			// Use exactly the indentation from the change
-			const baseIndent = change.indent || ""
-
-			// Handle multi-line additions
-			const lines = change.content.split("\n").map((line) => {
-				// If the line already has indentation, preserve it relative to the base indent
-				const lineIndentMatch = line.match(/^(\s*)(.*)/)
-				if (lineIndentMatch) {
-					const [, lineIndent, content] = lineIndentMatch
-					// Only add base indent if the line doesn't already have it
-					return lineIndent ? line : baseIndent + content
-				}
-				return baseIndent + line
-			})
-
-			newResult.push(...lines)
-		} else if (change.type === "remove") {
-			// Handle multi-line removes by incrementing sourceIndex for each line
-			const removedLines = change.content.split("\n").length
-			sourceIndex += removedLines
-		}
-	}
-
-	// Append remaining content
-	newResult.push(...content.slice(sourceIndex))
-
-	// Calculate confidence based on the actual changes
-	const afterText = newResult.slice(matchPosition, newResult.length - (content.length - sourceIndex)).join("\n")
-
-	const confidence = validateEditResult(hunk, afterText)
-
-	return {
-		confidence,
-		result: newResult,
-		strategy: "context",
-	}
-}
-
-// DMP edit strategy
-export function applyDMP(hunk: Hunk, content: string[], matchPosition: number): EditResult {
-	if (matchPosition === -1) {
-		return { confidence: 0, result: content, strategy: "dmp" }
-	}
-
-	const dmp = new diff_match_patch()
-
-	// Calculate total lines in before block accounting for multi-line content
-	const beforeLineCount = hunk.changes
-		.filter((change) => change.type === "context" || change.type === "remove")
-		.reduce((count, change) => count + change.content.split("\n").length, 0)
-
-	// Build BEFORE block (context + removals)
-	const beforeLines = hunk.changes
-		.filter((change) => change.type === "context" || change.type === "remove")
-		.map((change) => {
-			if (change.originalLine) {
-				return change.originalLine
-			}
-			return change.indent ? change.indent + change.content : change.content
-		})
-
-	// Build AFTER block (context + additions)
-	const afterLines = hunk.changes
-		.filter((change) => change.type === "context" || change.type === "add")
-		.map((change) => {
-			if (change.originalLine) {
-				return change.originalLine
-			}
-			return change.indent ? change.indent + change.content : change.content
-		})
-
-	// Convert to text with proper line endings
-	const beforeText = beforeLines.join("\n")
-	const afterText = afterLines.join("\n")
-
-	// Create and apply patch
-	const patch = dmp.patch_make(beforeText, afterText)
-	const targetText = content.slice(matchPosition, matchPosition + beforeLineCount).join("\n")
-	const [patchedText] = dmp.patch_apply(patch, targetText)
-
-	// Split result and preserve line endings
-	const patchedLines = patchedText.split("\n")
-
-	// Construct final result
-	const newResult = [
-		...content.slice(0, matchPosition),
-		...patchedLines,
-		...content.slice(matchPosition + beforeLineCount),
-	]
-
-	const confidence = validateEditResult(hunk, patchedText)
-
-	return {
-		confidence,
-		result: newResult,
-		strategy: "dmp",
-	}
-}
-
-// Git fallback strategy that works with full content
-export async function applyGitFallback(hunk: Hunk, content: string[]): Promise<EditResult> {
-	let tmpDir: tmp.DirResult | undefined
-
-	try {
-		tmpDir = tmp.dirSync({ unsafeCleanup: true })
-		const git: SimpleGit = simpleGit(tmpDir.name)
-
-		await git.init()
-		await git.addConfig("user.name", "Temp")
-		await git.addConfig("user.email", "[email protected]")
-		// Prevent Git from automatically converting line endings
-		await git.addConfig("core.autocrlf", "false")
-
-		const filePath = path.join(tmpDir.name, "file.txt")
-
-		const searchLines = hunk.changes
-			.filter((change) => change.type === "context" || change.type === "remove")
-			.map((change) => change.originalLine || change.indent + change.content)
-
-		const replaceLines = hunk.changes
-			.filter((change) => change.type === "context" || change.type === "add")
-			.map((change) => change.originalLine || change.indent + change.content)
-
-		// Ensure consistent line endings (LF only) in all text operations
-		const searchText = searchLines.join("\n")
-		const replaceText = replaceLines.join("\n")
-		const originalText = content.join("\n")
-
-		try {
-			fs.writeFileSync(filePath, originalText)
-			await git.add("file.txt")
-			const originalCommit = await git.commit("original")
-			console.log("Strategy 1 - Original commit:", originalCommit.commit)
-
-			fs.writeFileSync(filePath, searchText)
-			await git.add("file.txt")
-			const searchCommit1 = await git.commit("search")
-			console.log("Strategy 1 - Search commit:", searchCommit1.commit)
-
-			fs.writeFileSync(filePath, replaceText)
-			await git.add("file.txt")
-			const replaceCommit = await git.commit("replace")
-			console.log("Strategy 1 - Replace commit:", replaceCommit.commit)
-
-			console.log("Strategy 1 - Attempting checkout of:", originalCommit.commit)
-			await git.raw(["checkout", originalCommit.commit])
-			try {
-				console.log("Strategy 1 - Attempting cherry-pick of:", replaceCommit.commit)
-				await git.raw(["cherry-pick", "--minimal", replaceCommit.commit])
-
-				const newText = fs.readFileSync(filePath, "utf-8")
-				// Normalize line endings to LF before splitting
-				const normalizedText = newText.replace(/\r\n/g, "\n")
-				const newLines = normalizedText.split("\n")
-				return {
-					confidence: 1,
-					result: newLines,
-					strategy: "git-fallback",
-				}
-			} catch (cherryPickError) {
-				console.error("Strategy 1 failed with merge conflict")
-			}
-		} catch (error) {
-			console.error("Strategy 1 failed:", error)
-		}
-
-		try {
-			await git.init()
-			await git.addConfig("user.name", "Temp")
-			await git.addConfig("user.email", "[email protected]")
-			// Prevent Git from automatically converting line endings
-			await git.addConfig("core.autocrlf", "false")
-
-			fs.writeFileSync(filePath, searchText)
-			await git.add("file.txt")
-			const searchCommit = await git.commit("search")
-			const searchHash = searchCommit.commit.replace(/^HEAD /, "")
-			console.log("Strategy 2 - Search commit:", searchHash)
-
-			fs.writeFileSync(filePath, replaceText)
-			await git.add("file.txt")
-			const replaceCommit = await git.commit("replace")
-			const replaceHash = replaceCommit.commit.replace(/^HEAD /, "")
-			console.log("Strategy 2 - Replace commit:", replaceHash)
-
-			console.log("Strategy 2 - Attempting checkout of:", searchHash)
-			await git.raw(["checkout", searchHash])
-			fs.writeFileSync(filePath, originalText)
-			await git.add("file.txt")
-			const originalCommit2 = await git.commit("original")
-			console.log("Strategy 2 - Original commit:", originalCommit2.commit)
-
-			try {
-				console.log("Strategy 2 - Attempting cherry-pick of:", replaceHash)
-				await git.raw(["cherry-pick", "--minimal", replaceHash])
-
-				const newText = fs.readFileSync(filePath, "utf-8")
-				// Normalize line endings to LF before splitting
-				const normalizedText = newText.replace(/\r\n/g, "\n")
-				const newLines = normalizedText.split("\n")
-				return {
-					confidence: 1,
-					result: newLines,
-					strategy: "git-fallback",
-				}
-			} catch (cherryPickError) {
-				console.error("Strategy 2 failed with merge conflict")
-			}
-		} catch (error) {
-			console.error("Strategy 2 failed:", error)
-		}
-
-		console.error("Git fallback failed")
-		return { confidence: 0, result: content, strategy: "git-fallback" }
-	} catch (error) {
-		console.error("Git fallback strategy failed:", error)
-		return { confidence: 0, result: content, strategy: "git-fallback" }
-	} finally {
-		if (tmpDir) {
-			tmpDir.removeCallback()
-		}
-	}
-}
-
-// Main edit function that tries strategies sequentially
-export async function applyEdit(
-	hunk: Hunk,
-	content: string[],
-	matchPosition: number,
-	confidence: number,
-	confidenceThreshold: number = 0.97,
-): Promise<EditResult> {
-	// Don't attempt regular edits if confidence is too low
-	if (confidence < confidenceThreshold) {
-		console.log(
-			`Search confidence (${confidence}) below minimum threshold (${confidenceThreshold}), trying git fallback...`,
-		)
-		return applyGitFallback(hunk, content)
-	}
-
-	// Try each strategy in sequence until one succeeds
-	const strategies = [
-		{ name: "dmp", apply: () => applyDMP(hunk, content, matchPosition) },
-		{ name: "context", apply: () => applyContextMatching(hunk, content, matchPosition) },
-		{ name: "git-fallback", apply: () => applyGitFallback(hunk, content) },
-	]
-
-	// Try strategies sequentially until one succeeds
-	for (const strategy of strategies) {
-		const result = await strategy.apply()
-		if (result.confidence >= confidenceThreshold) {
-			return result
-		}
-	}
-
-	return { confidence: 0, result: content, strategy: "none" }
-}

+ 0 - 354
src/core/diff/strategies/new-unified/index.ts

@@ -1,354 +0,0 @@
-import { Diff, Hunk, Change } from "./types"
-import { findBestMatch, prepareSearchString } from "./search-strategies"
-import { applyEdit } from "./edit-strategies"
-import { DiffResult, DiffStrategy } from "../../types"
-
-export class NewUnifiedDiffStrategy implements DiffStrategy {
-	private readonly confidenceThreshold: number
-
-	getName(): string {
-		return "NewUnified"
-	}
-
-	constructor(confidenceThreshold: number = 1) {
-		this.confidenceThreshold = Math.max(confidenceThreshold, 0.8)
-	}
-
-	private parseUnifiedDiff(diff: string): Diff {
-		const MAX_CONTEXT_LINES = 6 // Number of context lines to keep before/after changes
-		const lines = diff.split("\n")
-		const hunks: Hunk[] = []
-		let currentHunk: Hunk | null = null
-
-		let i = 0
-		while (i < lines.length && !lines[i].startsWith("@@")) {
-			i++
-		}
-
-		for (; i < lines.length; i++) {
-			const line = lines[i]
-
-			if (line.startsWith("@@")) {
-				if (
-					currentHunk &&
-					currentHunk.changes.length > 0 &&
-					currentHunk.changes.some((change) => change.type === "add" || change.type === "remove")
-				) {
-					const changes = currentHunk.changes
-					let startIdx = 0
-					let endIdx = changes.length - 1
-
-					for (let j = 0; j < changes.length; j++) {
-						if (changes[j].type !== "context") {
-							startIdx = Math.max(0, j - MAX_CONTEXT_LINES)
-							break
-						}
-					}
-
-					for (let j = changes.length - 1; j >= 0; j--) {
-						if (changes[j].type !== "context") {
-							endIdx = Math.min(changes.length - 1, j + MAX_CONTEXT_LINES)
-							break
-						}
-					}
-
-					currentHunk.changes = changes.slice(startIdx, endIdx + 1)
-					hunks.push(currentHunk)
-				}
-				currentHunk = { changes: [] }
-				continue
-			}
-
-			if (!currentHunk) {
-				continue
-			}
-
-			const content = line.slice(1)
-			const indentMatch = content.match(/^(\s*)/)
-			const indent = indentMatch ? indentMatch[0] : ""
-			const trimmedContent = content.slice(indent.length)
-
-			if (line.startsWith(" ")) {
-				currentHunk.changes.push({
-					type: "context",
-					content: trimmedContent,
-					indent,
-					originalLine: content,
-				})
-			} else if (line.startsWith("+")) {
-				currentHunk.changes.push({
-					type: "add",
-					content: trimmedContent,
-					indent,
-					originalLine: content,
-				})
-			} else if (line.startsWith("-")) {
-				currentHunk.changes.push({
-					type: "remove",
-					content: trimmedContent,
-					indent,
-					originalLine: content,
-				})
-			} else {
-				const finalContent = trimmedContent ? " " + trimmedContent : " "
-				currentHunk.changes.push({
-					type: "context",
-					content: finalContent,
-					indent,
-					originalLine: content,
-				})
-			}
-		}
-
-		if (
-			currentHunk &&
-			currentHunk.changes.length > 0 &&
-			currentHunk.changes.some((change) => change.type === "add" || change.type === "remove")
-		) {
-			hunks.push(currentHunk)
-		}
-
-		return { hunks }
-	}
-
-	getToolDescription(args: { cwd: string; toolOptions?: { [key: string]: string } }): string {
-		return `# apply_diff Tool - Generate Precise Code Changes
-
-Generate a unified diff that can be cleanly applied to modify code files.
-
-## Step-by-Step Instructions:
-
-1. Start with file headers:
-   - First line: "--- {original_file_path}"
-   - Second line: "+++ {new_file_path}"
-
-2. For each change section:
-   - Begin with "@@ ... @@" separator line without line numbers
-   - Include 2-3 lines of context before and after changes
-   - Mark removed lines with "-"
-   - Mark added lines with "+"
-   - Preserve exact indentation
-
-3. Group related changes:
-   - Keep related modifications in the same hunk
-   - Start new hunks for logically separate changes
-   - When modifying functions/methods, include the entire block
-
-## Requirements:
-
-1. MUST include exact indentation
-2. MUST include sufficient context for unique matching
-3. MUST group related changes together
-4. MUST use proper unified diff format
-5. MUST NOT include timestamps in file headers
-6. MUST NOT include line numbers in the @@ header
-
-## Examples:
-
-✅ Good diff (follows all requirements):
-\`\`\`diff
---- src/utils.ts
-+++ src/utils.ts
-@@ ... @@
-    def calculate_total(items):
--      total = 0
--      for item in items:
--          total += item.price
-+      return sum(item.price for item in items)
-\`\`\`
-
-❌ Bad diff (violates requirements #1 and #2):
-\`\`\`diff
---- src/utils.ts
-+++ src/utils.ts
-@@ ... @@
--total = 0
--for item in items:
-+return sum(item.price for item in items)
-\`\`\`
-
-Parameters:
-- path: (required) File path relative to ${args.cwd}
-- diff: (required) Unified diff content in unified format to apply to the file.
-
-Usage:
-<apply_diff>
-<path>path/to/file.ext</path>
-<diff>
-Your diff here
-</diff>
-</apply_diff>`
-	}
-
-	// Helper function to split a hunk into smaller hunks based on contiguous changes
-	private splitHunk(hunk: Hunk): Hunk[] {
-		const result: Hunk[] = []
-		let currentHunk: Hunk | null = null
-		let contextBefore: Change[] = []
-		let contextAfter: Change[] = []
-		const MAX_CONTEXT_LINES = 3 // Keep 3 lines of context before/after changes
-
-		for (let i = 0; i < hunk.changes.length; i++) {
-			const change = hunk.changes[i]
-
-			if (change.type === "context") {
-				if (!currentHunk) {
-					contextBefore.push(change)
-					if (contextBefore.length > MAX_CONTEXT_LINES) {
-						contextBefore.shift()
-					}
-				} else {
-					contextAfter.push(change)
-					if (contextAfter.length > MAX_CONTEXT_LINES) {
-						// We've collected enough context after changes, create a new hunk
-						currentHunk.changes.push(...contextAfter)
-						result.push(currentHunk)
-						currentHunk = null
-						// Keep the last few context lines for the next hunk
-						contextBefore = contextAfter
-						contextAfter = []
-					}
-				}
-			} else {
-				if (!currentHunk) {
-					currentHunk = { changes: [...contextBefore] }
-					contextAfter = []
-				} else if (contextAfter.length > 0) {
-					// Add accumulated context to current hunk
-					currentHunk.changes.push(...contextAfter)
-					contextAfter = []
-				}
-				currentHunk.changes.push(change)
-			}
-		}
-
-		// Add any remaining changes
-		if (currentHunk) {
-			if (contextAfter.length > 0) {
-				currentHunk.changes.push(...contextAfter)
-			}
-			result.push(currentHunk)
-		}
-
-		return result
-	}
-
-	async applyDiff(
-		originalContent: string,
-		diffContent: string,
-		startLine?: number,
-		endLine?: number,
-	): Promise<DiffResult> {
-		const parsedDiff = this.parseUnifiedDiff(diffContent)
-		const originalLines = originalContent.split("\n")
-		let result = [...originalLines]
-
-		if (!parsedDiff.hunks.length) {
-			return {
-				success: false,
-				error: "No hunks found in diff. Please ensure your diff includes actual changes and follows the unified diff format.",
-			}
-		}
-
-		for (const hunk of parsedDiff.hunks) {
-			const contextStr = prepareSearchString(hunk.changes)
-			const {
-				index: matchPosition,
-				confidence,
-				strategy,
-			} = findBestMatch(contextStr, result, 0, this.confidenceThreshold)
-
-			if (confidence < this.confidenceThreshold) {
-				console.log("Full hunk application failed, trying sub-hunks strategy")
-				// Try splitting the hunk into smaller hunks
-				const subHunks = this.splitHunk(hunk)
-				let subHunkSuccess = true
-				let subHunkResult = [...result]
-
-				for (const subHunk of subHunks) {
-					const subContextStr = prepareSearchString(subHunk.changes)
-					const subSearchResult = findBestMatch(subContextStr, subHunkResult, 0, this.confidenceThreshold)
-
-					if (subSearchResult.confidence >= this.confidenceThreshold) {
-						const subEditResult = await applyEdit(
-							subHunk,
-							subHunkResult,
-							subSearchResult.index,
-							subSearchResult.confidence,
-							this.confidenceThreshold,
-						)
-						if (subEditResult.confidence >= this.confidenceThreshold) {
-							subHunkResult = subEditResult.result
-							continue
-						}
-					}
-					subHunkSuccess = false
-					break
-				}
-
-				if (subHunkSuccess) {
-					result = subHunkResult
-					continue
-				}
-
-				// If sub-hunks also failed, return the original error
-				const contextLines = hunk.changes.filter((c) => c.type === "context").length
-				const totalLines = hunk.changes.length
-				const contextRatio = contextLines / totalLines
-
-				let errorMsg = `Failed to find a matching location in the file (${Math.floor(
-					confidence * 100,
-				)}% confidence, needs ${Math.floor(this.confidenceThreshold * 100)}%)\n\n`
-				errorMsg += "Debug Info:\n"
-				errorMsg += `- Search Strategy Used: ${strategy}\n`
-				errorMsg += `- Context Lines: ${contextLines} out of ${totalLines} total lines (${Math.floor(
-					contextRatio * 100,
-				)}%)\n`
-				errorMsg += `- Attempted to split into ${subHunks.length} sub-hunks but still failed\n`
-
-				if (contextRatio < 0.2) {
-					errorMsg += "\nPossible Issues:\n"
-					errorMsg += "- Not enough context lines to uniquely identify the location\n"
-					errorMsg += "- Add a few more lines of unchanged code around your changes\n"
-				} else if (contextRatio > 0.5) {
-					errorMsg += "\nPossible Issues:\n"
-					errorMsg += "- Too many context lines may reduce search accuracy\n"
-					errorMsg += "- Try to keep only 2-3 lines of context before and after changes\n"
-				} else {
-					errorMsg += "\nPossible Issues:\n"
-					errorMsg += "- The diff may be targeting a different version of the file\n"
-					errorMsg +=
-						"- There may be too many changes in a single hunk, try splitting the changes into multiple hunks\n"
-				}
-
-				if (startLine && endLine) {
-					errorMsg += `\nSearch Range: lines ${startLine}-${endLine}\n`
-				}
-
-				return { success: false, error: errorMsg }
-			}
-
-			const editResult = await applyEdit(hunk, result, matchPosition, confidence, this.confidenceThreshold)
-			if (editResult.confidence >= this.confidenceThreshold) {
-				result = editResult.result
-			} else {
-				// Edit failure - likely due to content mismatch
-				let errorMsg = `Failed to apply the edit using ${editResult.strategy} strategy (${Math.floor(
-					editResult.confidence * 100,
-				)}% confidence)\n\n`
-				errorMsg += "Debug Info:\n"
-				errorMsg += "- The location was found but the content didn't match exactly\n"
-				errorMsg += "- This usually means the file has been modified since the diff was created\n"
-				errorMsg += "- Or the diff may be targeting a different version of the file\n"
-				errorMsg += "\nPossible Solutions:\n"
-				errorMsg += "1. Refresh your view of the file and create a new diff\n"
-				errorMsg += "2. Double-check that the removed lines (-) match the current file content\n"
-				errorMsg += "3. Ensure your diff targets the correct version of the file"
-
-				return { success: false, error: errorMsg }
-			}
-		}
-
-		return { success: true, content: result.join("\n") }
-	}
-}

+ 0 - 408
src/core/diff/strategies/new-unified/search-strategies.ts

@@ -1,408 +0,0 @@
-import { compareTwoStrings } from "string-similarity"
-import { closest } from "fastest-levenshtein"
-import { diff_match_patch } from "diff-match-patch"
-import { Change, Hunk } from "./types"
-
-export type SearchResult = {
-	index: number
-	confidence: number
-	strategy: string
-}
-
-const LARGE_FILE_THRESHOLD = 1000 // lines
-const UNIQUE_CONTENT_BOOST = 0.05
-const DEFAULT_OVERLAP_SIZE = 3 // lines of overlap between windows
-const MAX_WINDOW_SIZE = 500 // maximum lines in a window
-
-// Helper function to calculate adaptive confidence threshold based on file size
-function getAdaptiveThreshold(contentLength: number, baseThreshold: number): number {
-	if (contentLength <= LARGE_FILE_THRESHOLD) {
-		return baseThreshold
-	}
-	return Math.max(baseThreshold - 0.07, 0.8) // Reduce threshold for large files but keep minimum at 80%
-}
-
-// Helper function to evaluate content uniqueness
-function evaluateContentUniqueness(searchStr: string, content: string[]): number {
-	const searchLines = searchStr.split("\n")
-	const uniqueLines = new Set(searchLines)
-	const contentStr = content.join("\n")
-
-	// Calculate how many search lines are relatively unique in the content
-	let uniqueCount = 0
-	for (const line of uniqueLines) {
-		const regex = new RegExp(line.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g")
-		const matches = contentStr.match(regex)
-		if (matches && matches.length <= 2) {
-			// Line appears at most twice
-			uniqueCount++
-		}
-	}
-
-	return uniqueCount / uniqueLines.size
-}
-
-// Helper function to prepare search string from context
-export function prepareSearchString(changes: Change[]): string {
-	const lines = changes.filter((c) => c.type === "context" || c.type === "remove").map((c) => c.originalLine)
-	return lines.join("\n")
-}
-
-// Helper function to evaluate similarity between two texts
-export function evaluateSimilarity(original: string, modified: string): number {
-	return compareTwoStrings(original, modified)
-}
-
-// Helper function to validate using diff-match-patch
-export function getDMPSimilarity(original: string, modified: string): number {
-	const dmp = new diff_match_patch()
-	const diffs = dmp.diff_main(original, modified)
-	dmp.diff_cleanupSemantic(diffs)
-	const patches = dmp.patch_make(original, diffs)
-	const [expectedText] = dmp.patch_apply(patches, original)
-
-	const similarity = evaluateSimilarity(expectedText, modified)
-	return similarity
-}
-
-// Helper function to validate edit results using hunk information
-export function validateEditResult(hunk: Hunk, result: string): number {
-	// Build the expected text from the hunk
-	const expectedText = hunk.changes
-		.filter((change) => change.type === "context" || change.type === "add")
-		.map((change) => (change.indent ? change.indent + change.content : change.content))
-		.join("\n")
-
-	// Calculate similarity between the result and expected text
-	const similarity = getDMPSimilarity(expectedText, result)
-
-	// If the result is unchanged from original, return low confidence
-	const originalText = hunk.changes
-		.filter((change) => change.type === "context" || change.type === "remove")
-		.map((change) => (change.indent ? change.indent + change.content : change.content))
-		.join("\n")
-
-	const originalSimilarity = getDMPSimilarity(originalText, result)
-	if (originalSimilarity > 0.97 && similarity !== 1) {
-		return 0.8 * similarity // Some confidence since we found the right location
-	}
-
-	// For partial matches, scale the confidence but keep it high if we're close
-	return similarity
-}
-
-// Helper function to validate context lines against original content
-function validateContextLines(searchStr: string, content: string, confidenceThreshold: number): number {
-	// Extract just the context lines from the search string
-	const contextLines = searchStr.split("\n").filter((line) => !line.startsWith("-")) // Exclude removed lines
-
-	// Compare context lines with content
-	const similarity = evaluateSimilarity(contextLines.join("\n"), content)
-
-	// Get adaptive threshold based on content size
-	const threshold = getAdaptiveThreshold(content.split("\n").length, confidenceThreshold)
-
-	// Calculate uniqueness boost
-	const uniquenessScore = evaluateContentUniqueness(searchStr, content.split("\n"))
-	const uniquenessBoost = uniquenessScore * UNIQUE_CONTENT_BOOST
-
-	// Adjust confidence based on threshold and uniqueness
-	return similarity < threshold ? similarity * 0.3 + uniquenessBoost : similarity + uniquenessBoost
-}
-
-// Helper function to create overlapping windows
-function createOverlappingWindows(
-	content: string[],
-	searchSize: number,
-	overlapSize: number = DEFAULT_OVERLAP_SIZE,
-): { window: string[]; startIndex: number }[] {
-	const windows: { window: string[]; startIndex: number }[] = []
-
-	// Ensure minimum window size is at least searchSize
-	const effectiveWindowSize = Math.max(searchSize, Math.min(searchSize * 2, MAX_WINDOW_SIZE))
-
-	// Ensure overlap size doesn't exceed window size
-	const effectiveOverlapSize = Math.min(overlapSize, effectiveWindowSize - 1)
-
-	// Calculate step size, ensure it's at least 1
-	const stepSize = Math.max(1, effectiveWindowSize - effectiveOverlapSize)
-
-	for (let i = 0; i < content.length; i += stepSize) {
-		const windowContent = content.slice(i, i + effectiveWindowSize)
-		if (windowContent.length >= searchSize) {
-			windows.push({ window: windowContent, startIndex: i })
-		}
-	}
-
-	return windows
-}
-
-// Helper function to combine overlapping matches
-function combineOverlappingMatches(
-	matches: (SearchResult & { windowIndex: number })[],
-	overlapSize: number = DEFAULT_OVERLAP_SIZE,
-): SearchResult[] {
-	if (matches.length === 0) {
-		return []
-	}
-
-	// Sort matches by confidence
-	matches.sort((a, b) => b.confidence - a.confidence)
-
-	const combinedMatches: SearchResult[] = []
-	const usedIndices = new Set<number>()
-
-	for (const match of matches) {
-		if (usedIndices.has(match.windowIndex)) {
-			continue
-		}
-
-		// Find overlapping matches
-		const overlapping = matches.filter(
-			(m) =>
-				Math.abs(m.windowIndex - match.windowIndex) === 1 &&
-				Math.abs(m.index - match.index) <= overlapSize &&
-				!usedIndices.has(m.windowIndex),
-		)
-
-		if (overlapping.length > 0) {
-			// Boost confidence if we find same match in overlapping windows
-			const avgConfidence =
-				(match.confidence + overlapping.reduce((sum, m) => sum + m.confidence, 0)) / (overlapping.length + 1)
-			const boost = Math.min(0.05 * overlapping.length, 0.1) // Max 10% boost
-
-			combinedMatches.push({
-				index: match.index,
-				confidence: Math.min(1, avgConfidence + boost),
-				strategy: `${match.strategy}-overlapping`,
-			})
-
-			usedIndices.add(match.windowIndex)
-			overlapping.forEach((m) => usedIndices.add(m.windowIndex))
-		} else {
-			combinedMatches.push({
-				index: match.index,
-				confidence: match.confidence,
-				strategy: match.strategy,
-			})
-			usedIndices.add(match.windowIndex)
-		}
-	}
-
-	return combinedMatches
-}
-
-export function findExactMatch(
-	searchStr: string,
-	content: string[],
-	startIndex: number = 0,
-	confidenceThreshold: number = 0.97,
-): SearchResult {
-	const searchLines = searchStr.split("\n")
-	const windows = createOverlappingWindows(content.slice(startIndex), searchLines.length)
-	const matches: (SearchResult & { windowIndex: number })[] = []
-
-	windows.forEach((windowData, windowIndex) => {
-		const windowStr = windowData.window.join("\n")
-		const exactMatch = windowStr.indexOf(searchStr)
-
-		if (exactMatch !== -1) {
-			const matchedContent = windowData.window
-				.slice(
-					windowStr.slice(0, exactMatch).split("\n").length - 1,
-					windowStr.slice(0, exactMatch).split("\n").length - 1 + searchLines.length,
-				)
-				.join("\n")
-
-			const similarity = getDMPSimilarity(searchStr, matchedContent)
-			const contextSimilarity = validateContextLines(searchStr, matchedContent, confidenceThreshold)
-			const confidence = Math.min(similarity, contextSimilarity)
-
-			matches.push({
-				index: startIndex + windowData.startIndex + windowStr.slice(0, exactMatch).split("\n").length - 1,
-				confidence,
-				strategy: "exact",
-				windowIndex,
-			})
-		}
-	})
-
-	const combinedMatches = combineOverlappingMatches(matches)
-	return combinedMatches.length > 0 ? combinedMatches[0] : { index: -1, confidence: 0, strategy: "exact" }
-}
-
-// String similarity strategy
-export function findSimilarityMatch(
-	searchStr: string,
-	content: string[],
-	startIndex: number = 0,
-	confidenceThreshold: number = 0.97,
-): SearchResult {
-	const searchLines = searchStr.split("\n")
-	let bestScore = 0
-	let bestIndex = -1
-
-	for (let i = startIndex; i < content.length - searchLines.length + 1; i++) {
-		const windowStr = content.slice(i, i + searchLines.length).join("\n")
-		const score = compareTwoStrings(searchStr, windowStr)
-		if (score > bestScore && score >= confidenceThreshold) {
-			const similarity = getDMPSimilarity(searchStr, windowStr)
-			const contextSimilarity = validateContextLines(searchStr, windowStr, confidenceThreshold)
-			const adjustedScore = Math.min(similarity, contextSimilarity) * score
-
-			if (adjustedScore > bestScore) {
-				bestScore = adjustedScore
-				bestIndex = i
-			}
-		}
-	}
-
-	return {
-		index: bestIndex,
-		confidence: bestIndex !== -1 ? bestScore : 0,
-		strategy: "similarity",
-	}
-}
-
-// Levenshtein strategy
-export function findLevenshteinMatch(
-	searchStr: string,
-	content: string[],
-	startIndex: number = 0,
-	confidenceThreshold: number = 0.97,
-): SearchResult {
-	const searchLines = searchStr.split("\n")
-	const candidates = []
-
-	for (let i = startIndex; i < content.length - searchLines.length + 1; i++) {
-		candidates.push(content.slice(i, i + searchLines.length).join("\n"))
-	}
-
-	if (candidates.length > 0) {
-		const closestMatch = closest(searchStr, candidates)
-		const index = startIndex + candidates.indexOf(closestMatch)
-		const similarity = getDMPSimilarity(searchStr, closestMatch)
-		const contextSimilarity = validateContextLines(searchStr, closestMatch, confidenceThreshold)
-		const confidence = Math.min(similarity, contextSimilarity)
-		return {
-			index: confidence === 0 ? -1 : index,
-			confidence: index !== -1 ? confidence : 0,
-			strategy: "levenshtein",
-		}
-	}
-
-	return { index: -1, confidence: 0, strategy: "levenshtein" }
-}
-
-// Helper function to identify anchor lines
-function identifyAnchors(searchStr: string): { first: string | null; last: string | null } {
-	const searchLines = searchStr.split("\n")
-	let first: string | null = null
-	let last: string | null = null
-
-	// Find the first non-empty line
-	for (const line of searchLines) {
-		if (line.trim()) {
-			first = line
-			break
-		}
-	}
-
-	// Find the last non-empty line
-	for (let i = searchLines.length - 1; i >= 0; i--) {
-		if (searchLines[i].trim()) {
-			last = searchLines[i]
-			break
-		}
-	}
-
-	return { first, last }
-}
-
-// Anchor-based search strategy
-export function findAnchorMatch(
-	searchStr: string,
-	content: string[],
-	startIndex: number = 0,
-	confidenceThreshold: number = 0.97,
-): SearchResult {
-	const searchLines = searchStr.split("\n")
-	const { first, last } = identifyAnchors(searchStr)
-
-	if (!first || !last) {
-		return { index: -1, confidence: 0, strategy: "anchor" }
-	}
-
-	let firstIndex = -1
-	let lastIndex = -1
-
-	// Check if the first anchor is unique
-	let firstOccurrences = 0
-	for (const contentLine of content) {
-		if (contentLine === first) {
-			firstOccurrences++
-		}
-	}
-
-	if (firstOccurrences !== 1) {
-		return { index: -1, confidence: 0, strategy: "anchor" }
-	}
-
-	// Find the first anchor
-	for (let i = startIndex; i < content.length; i++) {
-		if (content[i] === first) {
-			firstIndex = i
-			break
-		}
-	}
-
-	// Find the last anchor
-	for (let i = content.length - 1; i >= startIndex; i--) {
-		if (content[i] === last) {
-			lastIndex = i
-			break
-		}
-	}
-
-	if (firstIndex === -1 || lastIndex === -1 || lastIndex <= firstIndex) {
-		return { index: -1, confidence: 0, strategy: "anchor" }
-	}
-
-	// Validate the context
-	const expectedContext = searchLines.slice(searchLines.indexOf(first) + 1, searchLines.indexOf(last)).join("\n")
-	const actualContext = content.slice(firstIndex + 1, lastIndex).join("\n")
-	const contextSimilarity = evaluateSimilarity(expectedContext, actualContext)
-
-	if (contextSimilarity < getAdaptiveThreshold(content.length, confidenceThreshold)) {
-		return { index: -1, confidence: 0, strategy: "anchor" }
-	}
-
-	const confidence = 1
-
-	return {
-		index: firstIndex,
-		confidence: confidence,
-		strategy: "anchor",
-	}
-}
-
-// Main search function that tries all strategies
-export function findBestMatch(
-	searchStr: string,
-	content: string[],
-	startIndex: number = 0,
-	confidenceThreshold: number = 0.97,
-): SearchResult {
-	const strategies = [findExactMatch, findAnchorMatch, findSimilarityMatch, findLevenshteinMatch]
-
-	let bestResult: SearchResult = { index: -1, confidence: 0, strategy: "none" }
-
-	for (const strategy of strategies) {
-		const result = strategy(searchStr, content, startIndex, confidenceThreshold)
-		if (result.confidence > bestResult.confidence) {
-			bestResult = result
-		}
-	}
-
-	return bestResult
-}

+ 0 - 20
src/core/diff/strategies/new-unified/types.ts

@@ -1,20 +0,0 @@
-export type Change = {
-	type: "context" | "add" | "remove"
-	content: string
-	indent: string
-	originalLine?: string
-}
-
-export type Hunk = {
-	changes: Change[]
-}
-
-export type Diff = {
-	hunks: Hunk[]
-}
-
-export type EditResult = {
-	confidence: number
-	result: string[]
-	strategy: string
-}

+ 0 - 140
src/core/diff/strategies/unified.ts

@@ -1,140 +0,0 @@
-import { applyPatch } from "diff"
-import { DiffStrategy, DiffResult } from "../types"
-
-export class UnifiedDiffStrategy implements DiffStrategy {
-	getName(): string {
-		return "Unified"
-	}
-	getToolDescription(args: { cwd: string; toolOptions?: { [key: string]: string } }): string {
-		return `## apply_diff
-Description: Apply a unified diff to a file at the specified path. This tool is useful when you need to make specific modifications to a file based on a set of changes provided in unified diff format (diff -U3).
-
-Parameters:
-- path: (required) The path of the file to apply the diff to (relative to the current working directory ${args.cwd})
-- diff: (required) The diff content in unified format to apply to the file.
-
-Format Requirements:
-
-1. Header (REQUIRED):
-    \`\`\`
-    --- path/to/original/file
-    +++ path/to/modified/file
-    \`\`\`
-    - Must include both lines exactly as shown
-    - Use actual file paths
-    - NO timestamps after paths
-
-2. Hunks:
-    \`\`\`
-    @@ -lineStart,lineCount +lineStart,lineCount @@
-    -removed line
-    +added line
-    \`\`\`
-    - Each hunk starts with @@ showing line numbers for changes
-    - Format: @@ -originalStart,originalCount +newStart,newCount @@
-    - Use - for removed/changed lines
-    - Use + for new/modified lines
-    - Indentation must match exactly
-
-Complete Example:
-
-Original file (with line numbers):
-\`\`\`
-1 | import { Logger } from '../logger';
-2 | 
-3 | function calculateTotal(items: number[]): number {
-4 |   return items.reduce((sum, item) => {
-5 |     return sum + item;
-6 |   }, 0);
-7 | }
-8 | 
-9 | export { calculateTotal };
-\`\`\`
-
-After applying the diff, the file would look like:
-\`\`\`
-1 | import { Logger } from '../logger';
-2 | 
-3 | function calculateTotal(items: number[]): number {
-4 |   const total = items.reduce((sum, item) => {
-5 |     return sum + item * 1.1;  // Add 10% markup
-6 |   }, 0);
-7 |   return Math.round(total * 100) / 100;  // Round to 2 decimal places
-8 | }
-9 | 
-10 | export { calculateTotal };
-\`\`\`
-
-Diff to modify the file:
-\`\`\`
---- src/utils/helper.ts
-+++ src/utils/helper.ts
-@@ -1,9 +1,10 @@
- import { Logger } from '../logger';
- 
- function calculateTotal(items: number[]): number {
--  return items.reduce((sum, item) => {
--    return sum + item;
-+  const total = items.reduce((sum, item) => {
-+    return sum + item * 1.1;  // Add 10% markup
-   }, 0);
-+  return Math.round(total * 100) / 100;  // Round to 2 decimal places
- }
- 
- export { calculateTotal };
-\`\`\`
-
-Common Pitfalls:
-1. Missing or incorrect header lines
-2. Incorrect line numbers in @@ lines
-3. Wrong indentation in changed lines
-4. Incomplete context (missing lines that need changing)
-5. Not marking all modified lines with - and +
-
-Best Practices:
-1. Replace entire code blocks:
-    - Remove complete old version with - lines
-    - Add complete new version with + lines
-    - Include correct line numbers
-2. Moving code requires two hunks:
-    - First hunk: Remove from old location
-    - Second hunk: Add to new location
-3. One hunk per logical change
-4. Verify line numbers match the line numbers you have in the file
-
-Usage:
-<apply_diff>
-<path>File path here</path>
-<diff>
-Your diff here
-</diff>
-</apply_diff>`
-	}
-
-	async applyDiff(originalContent: string, diffContent: string): Promise<DiffResult> {
-		try {
-			const result = applyPatch(originalContent, diffContent)
-			if (result === false) {
-				return {
-					success: false,
-					error: "Failed to apply unified diff - patch rejected",
-					details: {
-						searchContent: diffContent,
-					},
-				}
-			}
-			return {
-				success: true,
-				content: result,
-			}
-		} catch (error) {
-			return {
-				success: false,
-				error: `Error applying unified diff: ${error.message}`,
-				details: {
-					searchContent: diffContent,
-				},
-			}
-		}
-	}
-}