diff --git a/src/tools/impl/Edit.ts b/src/tools/impl/Edit.ts index a977c65..b2be2f8 100644 --- a/src/tools/impl/Edit.ts +++ b/src/tools/impl/Edit.ts @@ -20,16 +20,14 @@ export async function edit(args: EditArgs): Promise { "Edit", ); const { file_path, old_string, new_string, replace_all = false } = args; - const userCwd = process.env.USER_CWD || process.cwd(); - const resolvedPath = path.isAbsolute(file_path) - ? file_path - : path.resolve(userCwd, file_path); + if (!path.isAbsolute(file_path)) + throw new Error(`File path must be absolute, got: ${file_path}`); if (old_string === new_string) throw new Error( "No changes to make: old_string and new_string are exactly the same.", ); try { - const content = await fs.readFile(resolvedPath, "utf-8"); + const content = await fs.readFile(file_path, "utf-8"); const occurrences = content.split(old_string).length - 1; if (occurrences === 0) throw new Error( @@ -50,21 +48,22 @@ export async function edit(args: EditArgs): Promise { content.substring(index + old_string.length); replacements = 1; } - await fs.writeFile(resolvedPath, newContent, "utf-8"); + await fs.writeFile(file_path, newContent, "utf-8"); return { - message: `Successfully replaced ${replacements} occurrence${replacements !== 1 ? "s" : ""} in ${resolvedPath}`, + message: `Successfully replaced ${replacements} occurrence${replacements !== 1 ? "s" : ""} in ${file_path}`, replacements, }; } catch (error) { const err = error as NodeJS.ErrnoException; if (err.code === "ENOENT") { + const userCwd = process.env.USER_CWD || process.cwd(); throw new Error( - `File does not exist. Attempted path: ${resolvedPath}. Current working directory: ${userCwd}`, + `File does not exist. Current working directory: ${userCwd}`, ); } else if (err.code === "EACCES") - throw new Error(`Permission denied: ${resolvedPath}`); + throw new Error(`Permission denied: ${file_path}`); else if (err.code === "EISDIR") - throw new Error(`Path is a directory: ${resolvedPath}`); + throw new Error(`Path is a directory: ${file_path}`); else if (err.message) throw err; else throw new Error(`Failed to edit file: ${err}`); } diff --git a/src/tools/impl/ListDirCodex.ts b/src/tools/impl/ListDirCodex.ts index 733b49f..03f1d45 100644 --- a/src/tools/impl/ListDirCodex.ts +++ b/src/tools/impl/ListDirCodex.ts @@ -33,10 +33,6 @@ export async function list_dir( validateRequiredParams(args, ["dir_path"], "list_dir"); const { dir_path, offset = 1, limit = 25, depth = 2 } = args; - const userCwd = process.env.USER_CWD || process.cwd(); - const resolvedPath = path.isAbsolute(dir_path) - ? dir_path - : path.resolve(userCwd, dir_path); if (offset < 1) { throw new Error("offset must be a 1-indexed entry number"); @@ -50,8 +46,12 @@ export async function list_dir( throw new Error("depth must be greater than zero"); } - const entries = await listDirSlice(resolvedPath, offset, limit, depth); - const output = [`Absolute path: ${resolvedPath}`, ...entries]; + if (!path.isAbsolute(dir_path)) { + throw new Error("dir_path must be an absolute path"); + } + + const entries = await listDirSlice(dir_path, offset, limit, depth); + const output = [`Absolute path: ${dir_path}`, ...entries]; return { content: output.join("\n") }; } diff --git a/src/tools/impl/MultiEdit.ts b/src/tools/impl/MultiEdit.ts index 2e642f7..a53084c 100644 --- a/src/tools/impl/MultiEdit.ts +++ b/src/tools/impl/MultiEdit.ts @@ -21,10 +21,8 @@ export async function multi_edit( ): Promise { validateRequiredParams(args, ["file_path", "edits"], "MultiEdit"); const { file_path, edits } = args; - const userCwd = process.env.USER_CWD || process.cwd(); - const resolvedPath = path.isAbsolute(file_path) - ? file_path - : path.resolve(userCwd, file_path); + if (!path.isAbsolute(file_path)) + throw new Error(`File path must be absolute, got: ${file_path}`); if (!edits || edits.length === 0) throw new Error("No edits provided"); for (let i = 0; i < edits.length; i++) { const edit = edits[i]; @@ -42,7 +40,7 @@ export async function multi_edit( ); } try { - let content = await fs.readFile(resolvedPath, "utf-8"); + let content = await fs.readFile(file_path, "utf-8"); const appliedEdits: string[] = []; for (let i = 0; i < edits.length; i++) { const edit = edits[i]; @@ -72,12 +70,12 @@ export async function multi_edit( `Replaced "${old_string.substring(0, 50)}${old_string.length > 50 ? "..." : ""}" with "${new_string.substring(0, 50)}${new_string.length > 50 ? "..." : ""}"`, ); } - await fs.writeFile(resolvedPath, content, "utf-8"); + await fs.writeFile(file_path, content, "utf-8"); const editList = appliedEdits .map((edit, i) => `${i + 1}. ${edit}`) .join("\n"); return { - message: `Applied ${edits.length} edit${edits.length !== 1 ? "s" : ""} to ${resolvedPath}:\n${editList}`, + message: `Applied ${edits.length} edit${edits.length !== 1 ? "s" : ""} to ${file_path}:\n${editList}`, edits_applied: edits.length, }; } catch (error) { @@ -85,13 +83,14 @@ export async function multi_edit( const code = String(err?.code ?? ""); const message = String(err?.message ?? ""); if (code === "ENOENT") { + const userCwd = process.env.USER_CWD || process.cwd(); throw new Error( - `File does not exist. Attempted path: ${resolvedPath}. Current working directory: ${userCwd}`, + `File does not exist. Current working directory: ${userCwd}`, ); } else if (code === "EACCES") - throw new Error(`Permission denied: ${resolvedPath}`); + throw new Error(`Permission denied: ${file_path}`); else if (code === "EISDIR") - throw new Error(`Path is a directory: ${resolvedPath}`); + throw new Error(`Path is a directory: ${file_path}`); else if (message) throw new Error(message); else throw new Error(`Failed to edit file: ${String(err)}`); } diff --git a/src/tools/impl/Write.ts b/src/tools/impl/Write.ts index 9a18ff1..b978f5f 100644 --- a/src/tools/impl/Write.ts +++ b/src/tools/impl/Write.ts @@ -13,33 +13,31 @@ interface WriteResult { export async function write(args: WriteArgs): Promise { validateRequiredParams(args, ["file_path", "content"], "Write"); const { file_path, content } = args; - const userCwd = process.env.USER_CWD || process.cwd(); - const resolvedPath = path.isAbsolute(file_path) - ? file_path - : path.resolve(userCwd, file_path); + if (!path.isAbsolute(file_path)) + throw new Error(`File path must be absolute, got: ${file_path}`); try { - const dir = path.dirname(resolvedPath); + const dir = path.dirname(file_path); await fs.mkdir(dir, { recursive: true }); try { - const stats = await fs.stat(resolvedPath); + const stats = await fs.stat(file_path); if (stats.isDirectory()) - throw new Error(`Path is a directory, not a file: ${resolvedPath}`); + throw new Error(`Path is a directory, not a file: ${file_path}`); } catch (error) { const err = error as NodeJS.ErrnoException; if (err.code !== "ENOENT") throw err; } - await fs.writeFile(resolvedPath, content, "utf-8"); + await fs.writeFile(file_path, content, "utf-8"); return { - message: `Successfully wrote ${content.length} characters to ${resolvedPath}`, + message: `Successfully wrote ${content.length} characters to ${file_path}`, }; } catch (error) { const err = error as NodeJS.ErrnoException; if (err.code === "EACCES") - throw new Error(`Permission denied: ${resolvedPath}`); + throw new Error(`Permission denied: ${file_path}`); else if (err.code === "ENOSPC") - throw new Error(`No space left on device: ${resolvedPath}`); + throw new Error(`No space left on device: ${file_path}`); else if (err.code === "EISDIR") - throw new Error(`Path is a directory: ${resolvedPath}`); + throw new Error(`Path is a directory: ${file_path}`); else if (err.message) throw err; else throw new Error(`Failed to write file: ${err}`); }