file-operations.md
1 # File Operations Module 2 3 Safe file reading/writing with backup/restore capabilities for the agent system. 4 5 ## Overview 6 7 The File Operations module (`src/agents/utils/file-operations.js`) provides a comprehensive set of tools for agents to safely interact with the codebase. All operations include built-in safety features to prevent data loss and maintain code integrity. 8 9 ## Key Features 10 11 ### 1. Safety Features 12 13 - **Automatic Backups**: Every write operation creates a backup before modifying files 14 - **Atomic Writes**: Uses temp file → move pattern to prevent partial writes 15 - **Path Traversal Prevention**: Whitelist-based validation (src/, tests/, docs/, scripts/, prompts/) 16 - **Blacklist Protection**: Prevents modification of sensitive files (.env, package-lock.json) 17 - **Syntax Validation**: Validates JavaScript syntax before writing 18 - **Diff Generation**: Provides unified diffs for all edits 19 20 ### 2. Backup Management 21 22 - Backups stored in `.backups/` directory with timestamps 23 - Restore from any backup 24 - List all backups for a file 25 - Cleanup old backups (keep N most recent) 26 27 ### 3. Context Awareness 28 29 - Extract imports and dependencies from files 30 - Find related test files automatically 31 - Identify npm package dependencies 32 33 ## API Reference 34 35 ### Core Functions 36 37 #### `readFile(filePath)` 38 39 Read a file and return its content with metadata. 40 41 ```javascript 42 import { readFile } from './utils/file-operations.js'; 43 44 const file = await readFile('src/utils/logger.js'); 45 console.log(file.content); // File content as string 46 console.log(file.size); // File size in bytes 47 console.log(file.lastModified); // Date object 48 ``` 49 50 **Returns**: `{content: string, path: string, size: number, lastModified: Date}` 51 52 #### `writeFile(filePath, content, options)` 53 54 Write content to a file with automatic backup and validation. 55 56 ```javascript 57 import { writeFile } from './utils/file-operations.js'; 58 59 const result = await writeFile('src/test.js', 'const x = 1;', { 60 backup: true, // Create backup before writing (default: true) 61 validate: true, // Validate JS syntax (default: true for .js files) 62 }); 63 64 console.log(result.backupPath); // Path to backup file 65 console.log(result.diff); // Unified diff of changes 66 ``` 67 68 **Returns**: `{success: boolean, backupPath?: string, diff?: string}` 69 70 #### `editFile(filePath, changes)` 71 72 Edit a file by replacing specific content. 73 74 ```javascript 75 import { editFile } from './utils/file-operations.js'; 76 77 const result = await editFile('src/test.js', { 78 oldContent: 'const x = 1;', 79 newContent: 'const x = 2;', 80 }); 81 82 console.log(result.diff); // Shows what changed 83 ``` 84 85 **Returns**: `{success: boolean, backupPath: string, diff: string}` 86 87 #### `backupFile(filePath)` 88 89 Create a backup of a file. 90 91 ```javascript 92 import { backupFile } from './utils/file-operations.js'; 93 94 const backupPath = await backupFile('src/important.js'); 95 console.log(`Backup created at: ${backupPath}`); 96 ``` 97 98 **Returns**: `string` (path to backup file) 99 100 #### `restoreBackup(backupPath)` 101 102 Restore a file from a backup. 103 104 ```javascript 105 import { restoreBackup } from './utils/file-operations.js'; 106 107 await restoreBackup('/path/to/.backups/src_important.js.2026-02-15.backup'); 108 ``` 109 110 **Returns**: `boolean` (true if successful) 111 112 #### `validateJavaScript(code)` 113 114 Validate JavaScript syntax using ESLint. 115 116 ```javascript 117 import { validateJavaScript } from './utils/file-operations.js'; 118 119 const result = await validateJavaScript('const x = 1;'); 120 if (!result.valid) { 121 console.error('Syntax errors:', result.errors); 122 } 123 ``` 124 125 **Returns**: `{valid: boolean, errors: Array<{line, column, message}>}` 126 127 #### `getFileContext(filePath)` 128 129 Get file context: imports, dependencies, related test files. 130 131 ```javascript 132 import { getFileContext } from './utils/file-operations.js'; 133 134 const context = await getFileContext('src/utils/logger.js'); 135 console.log('Imports:', context.imports); // All imports 136 console.log('NPM deps:', context.dependencies); // Just npm packages 137 console.log('Tests:', context.testFiles); // Related test files 138 ``` 139 140 **Returns**: `{imports: string[], dependencies: string[], testFiles: string[]}` 141 142 #### `listBackups(filePath)` 143 144 List all backups for a file, sorted by date (newest first). 145 146 ```javascript 147 import { listBackups } from './utils/file-operations.js'; 148 149 const backups = await listBackups('src/utils/logger.js'); 150 console.log('Available backups:', backups); 151 ``` 152 153 **Returns**: `string[]` (array of backup file paths) 154 155 #### `cleanupBackups(filePath, keepCount)` 156 157 Delete old backups, keeping only the most recent N backups. 158 159 ```javascript 160 import { cleanupBackups } from './utils/file-operations.js'; 161 162 const deleted = await cleanupBackups('src/utils/logger.js', 5); 163 console.log(`Deleted ${deleted} old backups`); 164 ``` 165 166 **Returns**: `number` (number of backups deleted) 167 168 ## Usage Examples 169 170 ### Example 1: Developer Agent Fixing a Bug 171 172 ```javascript 173 import { readFile, editFile, getFileContext } from './utils/file-operations.js'; 174 175 // Read the buggy file 176 const file = await readFile('src/utils/helper.js'); 177 178 // Get context to understand dependencies 179 const context = await getFileContext('src/utils/helper.js'); 180 console.log('Dependencies:', context.dependencies); 181 console.log('Test files:', context.testFiles); 182 183 // Fix the bug 184 const result = await editFile('src/utils/helper.js', { 185 oldContent: 'return x + y', 186 newContent: 'return Number(x) + Number(y)', 187 }); 188 189 console.log('Changes made:'); 190 console.log(result.diff); 191 console.log('Backup at:', result.backupPath); 192 ``` 193 194 ### Example 2: QA Agent Verifying Changes 195 196 ```javascript 197 import { listBackups, restoreBackup, readFile } from './utils/file-operations.js'; 198 199 // List all backups for a file 200 const backups = await listBackups('src/utils/helper.js'); 201 202 // Compare current version with backup 203 const current = await readFile('src/utils/helper.js'); 204 const backup = await readFile(backups[0]); 205 206 // If changes are bad, restore from backup 207 if (testsFailed) { 208 await restoreBackup(backups[0]); 209 console.log('Restored from backup after failed tests'); 210 } 211 ``` 212 213 ### Example 3: Architect Agent Refactoring 214 215 ```javascript 216 import { getFileContext, writeFile } from './utils/file-operations.js'; 217 218 // Analyze file to understand its role 219 const context = await getFileContext('src/utils/old-module.js'); 220 221 // Create new refactored version 222 const newCode = ` 223 import ${context.dependencies.join(', ')} from 'packages'; 224 225 // Refactored implementation 226 export default function newModule() { 227 // ... 228 } 229 `; 230 231 // Write new version (creates backup automatically) 232 const result = await writeFile('src/utils/new-module.js', newCode); 233 234 console.log('Refactoring complete'); 235 console.log('Tests to update:', context.testFiles); 236 ``` 237 238 ## Security 239 240 ### Allowed Directories (Whitelist) 241 242 Only files in these directories can be modified: 243 244 - `src/` - Source code 245 - `tests/` - Test files 246 - `docs/` - Documentation 247 - `scripts/` - Scripts 248 - `prompts/` - Prompt templates 249 250 ### Blacklisted Files 251 252 These files can never be modified: 253 254 - `.env`, `.env.local`, `.env.production` - Environment variables 255 - `package-lock.json` - Dependency lock file 256 257 ### Path Traversal Protection 258 259 All paths are validated to prevent traversal attacks: 260 261 ```javascript 262 // BLOCKED: Path traversal 263 await readFile('../../../etc/passwd'); 264 // Error: Path traversal detected 265 266 // BLOCKED: Outside allowed directories 267 await writeFile('/tmp/evil.js', 'malicious code'); 268 // Error: Path not in allowed directories 269 270 // BLOCKED: Blacklisted file 271 await writeFile('src/.env', 'API_KEY=stolen'); 272 // Error: File is blacklisted 273 ``` 274 275 ## Error Handling 276 277 All functions throw descriptive errors: 278 279 ```javascript 280 try { 281 await writeFile('src/test.js', 'const x = ;'); // Syntax error 282 } catch (error) { 283 console.error(error.message); 284 // JavaScript syntax errors: 285 // Line 1: Parsing error: Unexpected token ; 286 } 287 ``` 288 289 On write failures, backups are automatically restored: 290 291 ```javascript 292 // File contains: const x = 1; 293 try { 294 await writeFile('src/test.js', 'const x = ;'); // Will fail 295 } catch (error) { 296 // File is automatically restored to: const x = 1; 297 } 298 ``` 299 300 ## Testing 301 302 Comprehensive test suite in `tests/agents/file-operations.test.js`: 303 304 - 33 tests covering all functionality 305 - 85%+ code coverage 306 - Tests for security vulnerabilities 307 - Integration tests for backup/restore cycles 308 309 Run tests: 310 311 ```bash 312 npm test tests/agents/file-operations.test.js 313 ``` 314 315 ## Best Practices 316 317 ### 1. Always Use Backups 318 319 ```javascript 320 // Good: Backup enabled (default) 321 await writeFile('src/important.js', newCode); 322 323 // Risky: Backup disabled 324 await writeFile('src/important.js', newCode, { backup: false }); 325 ``` 326 327 ### 2. Validate Syntax 328 329 ```javascript 330 // Good: Validate before writing 331 const validation = await validateJavaScript(generatedCode); 332 if (validation.valid) { 333 await writeFile('src/generated.js', generatedCode); 334 } 335 336 // Risky: Skip validation 337 await writeFile('src/generated.js', generatedCode, { validate: false }); 338 ``` 339 340 ### 3. Use Context for Awareness 341 342 ```javascript 343 // Good: Understand file context first 344 const context = await getFileContext('src/module.js'); 345 console.log('This will affect tests:', context.testFiles); 346 await editFile('src/module.js', changes); 347 348 // Bad: Modify blindly 349 await editFile('src/module.js', changes); 350 ``` 351 352 ### 4. Cleanup Old Backups 353 354 ```javascript 355 // Prevent backup directory from growing indefinitely 356 await cleanupBackups('src/frequently-edited.js', 10); 357 ``` 358 359 ## Integration with Agent System 360 361 File operations integrate with the agent workflow: 362 363 1. **Developer Agent**: Uses `editFile()` to fix bugs 364 2. **QA Agent**: Uses `listBackups()` and `restoreBackup()` to rollback failed changes 365 3. **Architect Agent**: Uses `getFileContext()` to understand code structure 366 4. **Security Agent**: Benefits from built-in path traversal protection 367 368 See `docs/06-automation/agent-system.md` for full agent system documentation.