/** * Patch application logic for the edit tool. * * Applies parsed diff hunks to file content using fuzzy matching * for robust handling of whitespace and formatting differences. */ import type { AgentToolResult } from "@gajae-code/agent-core"; import * as z from "zod/v4"; import { type WritethroughCallback, type WritethroughDeferredHandle } from "../../lsp"; import type { ToolSession } from "../../tools"; import type { EditToolDetails, LspBatchRequest } from "../renderer"; export type Operation = "create" | "delete" | "update"; export interface PatchInput { path: string; op: Operation; rename?: string; diff?: string; } export interface FileSystem { exists(path: string): Promise; read(path: string): Promise; readBinary?: (path: string) => Promise; write(path: string, content: string): Promise; delete(path: string): Promise; mkdir(path: string): Promise; } interface FileChange { type: Operation; path: string; newPath?: string; oldContent?: string; newContent?: string; } export interface ApplyPatchResult { change: FileChange; warnings?: string[]; } export interface ApplyPatchOptions { cwd: string; dryRun?: boolean; fuzzyThreshold?: number; allowFuzzy?: boolean; fs?: FileSystem; /** * When false, skip durable cross-process file locks (in-process path mutex * still serializes). Defaults to true only for the real `defaultFileSystem` * (or when `fs` is omitted). Disk-backed adapters that are not * `defaultFileSystem` (notably production `LspFileSystem` via * `executePatchSingle`) MUST pass `crossProcessLock: true` explicitly — * object identity is not a durable-lock capability probe. */ crossProcessLock?: boolean; } /** Default filesystem implementation using Bun APIs */ export declare const defaultFileSystem: FileSystem; /** * Apply a patch operation to the filesystem. * * Concurrent mutations of the same absolute path are serialized (in-process always; * cross-process file lock when using the real filesystem) so disjoint concurrent * edits cannot silently overwrite each other (#2900). */ export declare function applyPatch(input: PatchInput, options: ApplyPatchOptions): Promise; /** * Preview what changes a patch would make without applying it. */ export declare function previewPatch(input: PatchInput, options: ApplyPatchOptions): Promise; export declare function computePatchDiff(input: PatchInput, cwd: string, options?: { fuzzyThreshold?: number; allowFuzzy?: boolean; }): Promise<{ diff: string; firstChangedLine: number | undefined; } | { error: string; }>; export declare const patchEditEntrySchema: z.ZodObject<{ op: z.ZodOptional>; rename: z.ZodOptional; diff: z.ZodOptional; }, z.core.$strict>; export declare const patchEditSchema: z.ZodObject<{ path: z.ZodString; edits: z.ZodArray>; rename: z.ZodOptional; diff: z.ZodOptional; }, z.core.$strict>>; }, z.core.$strict>; export type PatchEditEntry = z.infer; export type PatchParams = z.infer; export interface ExecutePatchSingleOptions { session: ToolSession; path: string; params: PatchEditEntry; signal?: AbortSignal; batchRequest?: LspBatchRequest; allowFuzzy: boolean; fuzzyThreshold: number; writethrough: WritethroughCallback; beginDeferredDiagnosticsForPath: (path: string) => WritethroughDeferredHandle; } export declare function executePatchSingle(options: ExecutePatchSingleOptions): Promise>; export {};