UNPKG

ken-you-code

Version:

Connect your codebase to Kimi: Ultra-fast AI code analysis with Kimi-K2 model via MCP

134 lines (111 loc) 3.52 kB
import { createPatch } from 'diff'; import { writeFile, copyFile } from 'fs/promises'; import path from 'path'; import { randomUUID } from 'crypto'; import { FileOperations } from './fileOperations.js'; export interface DiffOperation { id: string; filePath: string; originalContent: string; newContent: string; patch: string; reason: string; createdAt: Date; applied: boolean; } export class DiffManager { private static pendingOperations = new Map<string, DiffOperation>(); static async createDiff( filePath: string, newContent: string, reason: string ): Promise<DiffOperation> { try { // Read current file content const fileResult = await FileOperations.readFileSecurely(filePath); const originalContent = fileResult.content; // Generate diff patch const patch = createPatch( path.basename(filePath), originalContent, newContent, 'current', 'proposed' ); // Create operation const operation: DiffOperation = { id: randomUUID(), filePath, originalContent, newContent, patch, reason, createdAt: new Date(), applied: false, }; // Store pending operation this.pendingOperations.set(operation.id, operation); return operation; } catch (error) { throw new Error( `Failed to create diff: ${error instanceof Error ? error.message : 'Unknown error'}` ); } } static getPendingOperation(operationId: string): DiffOperation | undefined { return this.pendingOperations.get(operationId); } static async applyDiff( operationId: string, approved: boolean ): Promise<{ success: boolean; message: string }> { const operation = this.pendingOperations.get(operationId); if (!operation) { return { success: false, message: 'Operation not found' }; } if (operation.applied) { return { success: false, message: 'Operation already applied' }; } if (!approved) { this.pendingOperations.delete(operationId); return { success: true, message: 'Operation cancelled by user' }; } try { // Create backup const backupPath = `${operation.filePath}.backup.${Date.now()}`; await copyFile(operation.filePath, backupPath); // Apply changes await writeFile(operation.filePath, operation.newContent, 'utf-8'); // Mark as applied operation.applied = true; // Clean up pending operation this.pendingOperations.delete(operationId); return { success: true, message: `File updated successfully. Backup created at: ${backupPath}`, }; } catch (error) { return { success: false, message: `Failed to apply diff: ${error instanceof Error ? error.message : 'Unknown error'}`, }; } } static listPendingOperations(): DiffOperation[] { return Array.from(this.pendingOperations.values()); } static cancelOperation(operationId: string): boolean { return this.pendingOperations.delete(operationId); } static clearExpiredOperations(maxAgeMinutes: number = 60): number { const cutoff = new Date(Date.now() - maxAgeMinutes * 60 * 1000); let cleared = 0; for (const [id, operation] of this.pendingOperations.entries()) { if (operation.createdAt < cutoff && !operation.applied) { this.pendingOperations.delete(id); cleared++; } } return cleared; } }