1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import fs from 'fs';
import path from 'path';
import * as Diff from 'diff';
import {
WriteFileLogic,
WriteFileToolParams,
ToolResult,
makeRelative,
shortenPath,
} from '@gemini-code/server';
import { BaseTool } from './tools.js';
import {
ToolCallConfirmationDetails,
ToolConfirmationOutcome,
ToolEditConfirmationDetails,
} from '../ui/types.js';
/**
* CLI wrapper for the WriteFile tool.
*/
export class WriteFileTool extends BaseTool<WriteFileToolParams, ToolResult> {
static readonly Name: string = WriteFileLogic.Name;
private shouldAlwaysWrite = false;
private coreLogic: WriteFileLogic;
constructor(rootDirectory: string) {
const coreLogicInstance = new WriteFileLogic(rootDirectory);
super(
WriteFileTool.Name,
'WriteFile',
'Writes content to a specified file in the local filesystem.',
(coreLogicInstance.schema.parameters as Record<string, unknown>) ?? {},
);
this.coreLogic = coreLogicInstance;
}
validateToolParams(params: WriteFileToolParams): string | null {
return this.coreLogic.validateParams(params);
}
getDescription(params: WriteFileToolParams): string {
return this.coreLogic.getDescription(params);
}
/**
* Handles the confirmation prompt for the WriteFile tool in the CLI.
*/
async shouldConfirmExecute(
params: WriteFileToolParams,
): Promise<ToolCallConfirmationDetails | false> {
if (this.shouldAlwaysWrite) {
return false;
}
const validationError = this.validateToolParams(params);
if (validationError) {
console.error(
`[WriteFile Wrapper] Attempted confirmation with invalid parameters: ${validationError}`,
);
return false;
}
const relativePath = makeRelative(
params.file_path,
this.coreLogic['rootDirectory'],
);
const fileName = path.basename(params.file_path);
let currentContent = '';
try {
currentContent = fs.readFileSync(params.file_path, 'utf8');
} catch {
// File might not exist, that's okay for write/create
}
const fileDiff = Diff.createPatch(
fileName,
currentContent,
params.content,
'Current',
'Proposed',
{ context: 3 },
);
const confirmationDetails: ToolEditConfirmationDetails = {
title: `Confirm Write: ${shortenPath(relativePath)}`,
fileName,
fileDiff,
onConfirm: async (outcome: ToolConfirmationOutcome) => {
if (outcome === ToolConfirmationOutcome.ProceedAlways) {
this.shouldAlwaysWrite = true;
}
},
};
return confirmationDetails;
}
/**
* Delegates execution to the core logic.
*/
async execute(params: WriteFileToolParams): Promise<ToolResult> {
return this.coreLogic.execute(params);
}
}
|