( toolName: string, args: Record<string, unknown>, cwd: string, )
| 138 | * fail to match); the executor surfaces the real error in that case. |
| 139 | */ |
| 140 | export function previewFileChange( |
| 141 | toolName: string, |
| 142 | args: Record<string, unknown>, |
| 143 | cwd: string, |
| 144 | ): string | undefined { |
| 145 | try { |
| 146 | if (toolName === "file_write") { |
| 147 | const relPath = String(args.file_path ?? "") |
| 148 | const filePath = resolveWorkspacePath(cwd, relPath) |
| 149 | let oldContent = "" |
| 150 | try { |
| 151 | oldContent = fs.readFileSync(filePath, "utf8") |
| 152 | } catch { |
| 153 | // new file |
| 154 | } |
| 155 | const diff = unifiedDiff(oldContent, String(args.content ?? "")) |
| 156 | return diff ? `${relPath}\n${diff}` : undefined |
| 157 | } |
| 158 | |
| 159 | const edits: EditSpec[] = |
| 160 | toolName === "file_edit" |
| 161 | ? [ |
| 162 | { |
| 163 | file_path: String(args.file_path ?? ""), |
| 164 | old_string: String(args.old_string ?? ""), |
| 165 | new_string: String(args.new_string ?? ""), |
| 166 | replace_all: parseReplaceAll(args.replace_all), |
| 167 | }, |
| 168 | ] |
| 169 | : ((Array.isArray(args.edits) ? args.edits : []) as EditSpec[]) |
| 170 | if (edits.length === 0) return undefined |
| 171 | |
| 172 | const byFile = new Map<string, EditSpec[]>() |
| 173 | for (const edit of edits) { |
| 174 | const key = edit.file_path |
| 175 | if (!byFile.has(key)) byFile.set(key, []) |
| 176 | byFile.get(key)!.push(edit) |
| 177 | } |
| 178 | |
| 179 | const parts: string[] = [] |
| 180 | for (const [relPath, fileEdits] of byFile) { |
| 181 | const filePath = resolveWorkspacePath(cwd, relPath) |
| 182 | const oldContent = fs.readFileSync(filePath, "utf8") |
| 183 | let content = oldContent |
| 184 | for (const edit of fileEdits) { |
| 185 | const { content: next, error } = applyEdit(content, edit) |
| 186 | if (error) return undefined |
| 187 | content = next |
| 188 | } |
| 189 | const diff = unifiedDiff(oldContent, content) |
| 190 | if (diff) parts.push(`${relPath}\n${diff}`) |
| 191 | } |
| 192 | return parts.length > 0 ? parts.join("\n") : undefined |
| 193 | } catch { |
| 194 | return undefined |
| 195 | } |
| 196 | } |
| 197 |
no test coverage detected