UNPKG

capsule-ai-cli

Version:

The AI Model Orchestrator - Intelligent multi-model workflows with device-locked licensing

111 lines 4.43 kB
import { FileEditTool } from './file-edit.js'; import path from 'path'; import { readFile } from 'fs/promises'; import { toolExecutionService } from '../../services/tool-execution.js'; import { v4 as uuidv4 } from 'uuid'; export class FileEditUnifiedTool extends FileEditTool { constructor() { super(); this.name = 'file_edit'; this.description = 'Edit files with confirmation from user before applying changes'; } async run(params, context) { const resolvedPath = path.isAbsolute(params.path) ? params.path : path.join(context.workingDirectory || process.cwd(), params.path); if (!params.oldText) { return this.handleFileWrite(resolvedPath, params.newText, context); } let oldContent = ''; try { oldContent = await readFile(resolvedPath, 'utf8'); } catch (error) { throw new Error(`Failed to read file: ${error}`); } let newContent = oldContent; if (params.replaceAll) { const occurrences = oldContent.split(params.oldText).length - 1; if (occurrences === 0) { throw new Error(`String "${params.oldText}" not found in file`); } newContent = oldContent.split(params.oldText).join(params.newText); } else { if (!oldContent.includes(params.oldText)) { throw new Error(`String "${params.oldText}" not found in file`); } newContent = oldContent.replace(params.oldText, params.newText); } const toolCallId = uuidv4(); const approved = await toolExecutionService.requestConfirmation(toolCallId, 'edit', { filePath: resolvedPath, oldContent, newContent }); if (!approved) { const { contextManager } = await import('../../services/context.js'); contextManager.addMessage({ role: 'system', content: `Edit to ${resolvedPath} was cancelled by user` }); throw new Error('Edit cancelled by user'); } const { contextManager } = await import('../../services/context.js'); contextManager.addMessage({ role: 'system', content: `Edit to ${resolvedPath} was approved by user` }); return super.run(params, context); } async handleFileWrite(resolvedPath, content, context) { let oldContent = ''; let isNewFile = false; try { oldContent = await readFile(resolvedPath, 'utf8'); } catch (error) { if (error.code === 'ENOENT') { isNewFile = true; } else { throw error; } } const toolCallId = uuidv4(); const approved = await toolExecutionService.requestConfirmation(toolCallId, 'edit', { filePath: resolvedPath + (isNewFile ? ' (new file)' : ''), oldContent, newContent: content }); if (!approved) { const { contextManager } = await import('../../services/context.js'); contextManager.addMessage({ role: 'system', content: `Write to ${resolvedPath}${isNewFile ? ' (new file)' : ''} was cancelled by user` }); throw new Error('Write cancelled by user'); } const { contextManager } = await import('../../services/context.js'); contextManager.addMessage({ role: 'system', content: `Write to ${resolvedPath}${isNewFile ? ' (new file)' : ''} was approved by user` }); if (isNewFile) { const { mkdir, writeFile } = await import('fs/promises'); const dir = path.dirname(resolvedPath); await mkdir(dir, { recursive: true }); await writeFile(resolvedPath, content, 'utf8'); return { path: resolvedPath, created: true, linesChanged: content.split('\n').length, preview: content.substring(0, 200) + (content.length > 200 ? '...' : '') }; } else { return super.run({ path: resolvedPath, oldText: oldContent, newText: content, replaceAll: true }, context); } } } //# sourceMappingURL=file-edit-unified.js.map