MCPcopy
hub / github.com/coder/mux / executeFileEditOperation

Function executeFileEditOperation

src/node/services/tools/file_edit_operation.ts:107–276  ·  view source on GitHub ↗
({
  config,
  filePath,
  operation,
  abortSignal,
}: ExecuteFileEditOperationOptions<TMetadata>)

Source from the content-addressed store, hash-verified

105 * Handles validation, file IO, diff generation, and common error handling.
106 */
107export async function executeFileEditOperation<TMetadata>({
108 config,
109 filePath,
110 operation,
111 abortSignal,
112}: ExecuteFileEditOperationOptions<TMetadata>): Promise<
113 FileEditErrorResult | (FileEditDiffSuccessBase & TMetadata)
114> {
115 try {
116 const {
117 correctedPath: validatedPath,
118 warning: pathWarning,
119 resolvedPath,
120 } = resolvePathWithinCwd(filePath, config.cwd, config.runtime);
121 filePath = validatedPath;
122
123 // Validate plan mode access restrictions
124 const planModeError = await validatePlanModeAccess(filePath, config);
125 if (planModeError) {
126 return planModeError;
127 }
128
129 const abortedBeforeLock = getAbortedFileEditResult(abortSignal);
130 if (abortedBeforeLock) {
131 return abortedBeforeLock;
132 }
133
134 // Serialize same-file edits so a later operation re-reads the file after the
135 // earlier write lands instead of racing on stale content or temp-file writes.
136 let writeStarted = false;
137 const lockedEditPromise: Promise<ExecuteFileEditReturn<TMetadata>> = getFileEditLocks(
138 config.runtime
139 ).withLock(resolvedPath, async () => {
140 // Abort can fire while we wait on the lock, and local runtime file I/O does
141 // not observe abort signals on its own, so re-check before touching disk.
142 const abortedAfterLock = getAbortedFileEditResult(abortSignal);
143 if (abortedAfterLock) {
144 return abortedAfterLock;
145 }
146
147 // Check if file exists and get stats using runtime
148 let fileStat;
149 try {
150 fileStat = await config.runtime.stat(resolvedPath, abortSignal);
151 } catch (err) {
152 if (err instanceof RuntimeError) {
153 return {
154 success: false,
155 error: err.message,
156 };
157 }
158 throw err;
159 }
160
161 if (fileStat.isDirectory) {
162 return {
163 success: false,
164 error: `Path is a directory, not a file: ${resolvedPath}`,

Calls 13

resolvePathWithinCwdFunction · 0.90
validatePlanModeAccessFunction · 0.90
validateFileSizeFunction · 0.90
readFileStringFunction · 0.90
writeFileStringFunction · 0.90
generateDiffFunction · 0.90
getErrorMessageFunction · 0.90
getAbortedFileEditResultFunction · 0.85
getFileEditLocksFunction · 0.85
waitForFileEditOrAbortFunction · 0.85
withLockMethod · 0.80
recordFileStateMethod · 0.80

Tested by

no test coverage detected