agent-ecosystem/src/main/services/editor/conflictDetection.ts
iliya 5b0c7d13fc feat: add project editor with drag & drop file management
- Backend: ProjectFileService with file CRUD, search, git status, file watcher
- IPC: 12 editor channels with security validation and path containment
- Store: editorSlice with multi-tab management, draft persistence, conflict detection
- UI: CodeMirror 6 editor, file tree with DnD, search-in-files, context menus
- Move: fs.rename with EXDEV fallback, full path remapping across all caches
- Tests: comprehensive coverage for services, IPC handlers, store, and utilities
2026-02-28 23:40:41 +02:00

52 lines
1.6 KiB
TypeScript

/**
* Conflict detection utility for the project editor.
*
* Checks if a file has been modified externally since the last known mtime.
* Used before saving to prevent silently overwriting external changes.
*/
import * as fs from 'fs/promises';
// =============================================================================
// Types
// =============================================================================
export interface ConflictCheckResult {
/** True if the file was modified externally */
hasConflict: boolean;
/** Current mtime on disk */
currentMtimeMs: number;
/** True if the file no longer exists on disk */
deleted: boolean;
}
// =============================================================================
// Functions
// =============================================================================
/**
* Check if a file has been modified since the given baseline mtime.
*
* @param filePath - Absolute path to the file
* @param baselineMtimeMs - Last known mtime (from readFile result)
* @returns Conflict check result
*/
export async function checkFileConflict(
filePath: string,
baselineMtimeMs: number
): Promise<ConflictCheckResult> {
try {
const stats = await fs.stat(filePath);
const currentMtimeMs = stats.mtimeMs;
// Allow 1ms tolerance for filesystem rounding
const hasConflict = Math.abs(currentMtimeMs - baselineMtimeMs) > 1;
return { hasConflict, currentMtimeMs, deleted: false };
} catch (error) {
if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
return { hasConflict: true, currentMtimeMs: 0, deleted: true };
}
throw error;
}
}