diff options
Diffstat (limited to 'packages/core/src/tools/edit.ts')
| -rw-r--r-- | packages/core/src/tools/edit.ts | 172 |
1 files changed, 40 insertions, 132 deletions
diff --git a/packages/core/src/tools/edit.ts b/packages/core/src/tools/edit.ts index 39352121..3317d460 100644 --- a/packages/core/src/tools/edit.ts +++ b/packages/core/src/tools/edit.ts @@ -6,7 +6,6 @@ import * as fs from 'fs'; import * as path from 'path'; -import * as os from 'os'; import * as Diff from 'diff'; import { BaseTool, @@ -23,9 +22,8 @@ import { GeminiClient } from '../core/client.js'; import { Config, ApprovalMode } from '../config/config.js'; import { ensureCorrectEdit } from '../utils/editCorrector.js'; import { DEFAULT_DIFF_OPTIONS } from './diffOptions.js'; -import { openDiff } from '../utils/editor.js'; import { ReadFileTool } from './read-file.js'; -import { EditorType } from '../utils/editor.js'; +import { ModifiableTool, ModifyContext } from './modifiable-tool.js'; /** * Parameters for the Edit tool @@ -64,13 +62,14 @@ interface CalculatedEdit { /** * Implementation of the Edit tool logic */ -export class EditTool extends BaseTool<EditToolParams, ToolResult> { +export class EditTool + extends BaseTool<EditToolParams, ToolResult> + implements ModifiableTool<EditToolParams> +{ static readonly Name = 'replace'; private readonly config: Config; private readonly rootDirectory: string; private readonly client: GeminiClient; - private tempOldDiffPath?: string; - private tempNewDiffPath?: string; /** * Creates a new instance of the EditLogic @@ -433,132 +432,6 @@ Expectation for required parameters: } /** - * Creates temp files for the current and proposed file contents and opens a diff tool. - * When the diff tool is closed, the tool will check if the file has been modified and provide the updated params. - * @returns Updated params and diff if the file has been modified, undefined otherwise. - */ - async onModify( - params: EditToolParams, - _abortSignal: AbortSignal, - editorType: EditorType, - ): Promise< - { updatedParams: EditToolParams; updatedDiff: string } | undefined - > { - const { oldPath, newPath } = this.createTempFiles(params); - this.tempOldDiffPath = oldPath; - this.tempNewDiffPath = newPath; - - await openDiff(this.tempOldDiffPath, this.tempNewDiffPath, editorType); - return await this.getUpdatedParamsIfModified(params, _abortSignal); - } - - private async getUpdatedParamsIfModified( - params: EditToolParams, - _abortSignal: AbortSignal, - ): Promise< - { updatedParams: EditToolParams; updatedDiff: string } | undefined - > { - if (!this.tempOldDiffPath || !this.tempNewDiffPath) return undefined; - let oldContent = ''; - let newContent = ''; - try { - oldContent = fs.readFileSync(this.tempOldDiffPath, 'utf8'); - } catch (err) { - if (!isNodeError(err) || err.code !== 'ENOENT') throw err; - oldContent = ''; - } - try { - newContent = fs.readFileSync(this.tempNewDiffPath, 'utf8'); - } catch (err) { - if (!isNodeError(err) || err.code !== 'ENOENT') throw err; - newContent = ''; - } - - // Combine the edits into a single edit - const updatedParams: EditToolParams = { - ...params, - old_string: oldContent, - new_string: newContent, - }; - - const updatedDiff = Diff.createPatch( - path.basename(params.file_path), - oldContent, - newContent, - 'Current', - 'Proposed', - DEFAULT_DIFF_OPTIONS, - ); - - this.deleteTempFiles(); - return { updatedParams, updatedDiff }; - } - - private createTempFiles(params: EditToolParams): Record<string, string> { - this.deleteTempFiles(); - - const tempDir = os.tmpdir(); - const diffDir = path.join(tempDir, 'gemini-cli-edit-tool-diffs'); - - if (!fs.existsSync(diffDir)) { - fs.mkdirSync(diffDir, { recursive: true }); - } - - const fileName = path.basename(params.file_path); - const timestamp = Date.now(); - const tempOldPath = path.join( - diffDir, - `gemini-cli-edit-${fileName}-old-${timestamp}`, - ); - const tempNewPath = path.join( - diffDir, - `gemini-cli-edit-${fileName}-new-${timestamp}`, - ); - - let currentContent = ''; - try { - currentContent = fs.readFileSync(params.file_path, 'utf8'); - } catch (err) { - if (!isNodeError(err) || err.code !== 'ENOENT') throw err; - currentContent = ''; - } - - let proposedContent = currentContent; - proposedContent = this._applyReplacement( - proposedContent, - params.old_string, - params.new_string, - params.old_string === '' && currentContent === '', - ); - - fs.writeFileSync(tempOldPath, currentContent, 'utf8'); - fs.writeFileSync(tempNewPath, proposedContent, 'utf8'); - return { - oldPath: tempOldPath, - newPath: tempNewPath, - }; - } - - private deleteTempFiles(): void { - try { - if (this.tempOldDiffPath) { - fs.unlinkSync(this.tempOldDiffPath); - this.tempOldDiffPath = undefined; - } - } catch { - console.error(`Error deleting temp diff file: `, this.tempOldDiffPath); - } - try { - if (this.tempNewDiffPath) { - fs.unlinkSync(this.tempNewDiffPath); - this.tempNewDiffPath = undefined; - } - } catch { - console.error(`Error deleting temp diff file: `, this.tempNewDiffPath); - } - } - - /** * Creates parent directories if they don't exist */ private ensureParentDirectoriesExist(filePath: string): void { @@ -567,4 +440,39 @@ Expectation for required parameters: fs.mkdirSync(dirName, { recursive: true }); } } + + getModifyContext(_: AbortSignal): ModifyContext<EditToolParams> { + return { + getFilePath: (params: EditToolParams) => params.file_path, + getCurrentContent: async (params: EditToolParams): Promise<string> => { + try { + return fs.readFileSync(params.file_path, 'utf8'); + } catch (err) { + if (!isNodeError(err) || err.code !== 'ENOENT') throw err; + return ''; + } + }, + getProposedContent: async (params: EditToolParams): Promise<string> => { + try { + const currentContent = fs.readFileSync(params.file_path, 'utf8'); + return this._applyReplacement( + currentContent, + params.old_string, + params.new_string, + params.old_string === '' && currentContent === '', + ); + } catch (err) { + if (!isNodeError(err) || err.code !== 'ENOENT') throw err; + return ''; + } + }, + createUpdatedParams: ( + modifiedProposedContent: string, + originalParams: EditToolParams, + ): EditToolParams => ({ + ...originalParams, + new_string: modifiedProposedContent, + }), + }; + } } |
