relative file paths
This commit is contained in:
@@ -20,14 +20,16 @@ export async function edit(args: EditArgs): Promise<EditResult> {
|
||||
"Edit",
|
||||
);
|
||||
const { file_path, old_string, new_string, replace_all = false } = args;
|
||||
if (!path.isAbsolute(file_path))
|
||||
throw new Error(`File path must be absolute, got: ${file_path}`);
|
||||
const userCwd = process.env.USER_CWD || process.cwd();
|
||||
const resolvedPath = path.isAbsolute(file_path)
|
||||
? file_path
|
||||
: path.resolve(userCwd, 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(file_path, "utf-8");
|
||||
const content = await fs.readFile(resolvedPath, "utf-8");
|
||||
const occurrences = content.split(old_string).length - 1;
|
||||
if (occurrences === 0)
|
||||
throw new Error(
|
||||
@@ -48,22 +50,21 @@ export async function edit(args: EditArgs): Promise<EditResult> {
|
||||
content.substring(index + old_string.length);
|
||||
replacements = 1;
|
||||
}
|
||||
await fs.writeFile(file_path, newContent, "utf-8");
|
||||
await fs.writeFile(resolvedPath, newContent, "utf-8");
|
||||
return {
|
||||
message: `Successfully replaced ${replacements} occurrence${replacements !== 1 ? "s" : ""} in ${file_path}`,
|
||||
message: `Successfully replaced ${replacements} occurrence${replacements !== 1 ? "s" : ""} in ${resolvedPath}`,
|
||||
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. Current working directory: ${userCwd}`,
|
||||
`File does not exist. Attempted path: ${resolvedPath}. Current working directory: ${userCwd}`,
|
||||
);
|
||||
} else if (err.code === "EACCES")
|
||||
throw new Error(`Permission denied: ${file_path}`);
|
||||
throw new Error(`Permission denied: ${resolvedPath}`);
|
||||
else if (err.code === "EISDIR")
|
||||
throw new Error(`Path is a directory: ${file_path}`);
|
||||
throw new Error(`Path is a directory: ${resolvedPath}`);
|
||||
else if (err.message) throw err;
|
||||
else throw new Error(`Failed to edit file: ${err}`);
|
||||
}
|
||||
|
||||
@@ -33,6 +33,10 @@ 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");
|
||||
@@ -46,12 +50,8 @@ export async function list_dir(
|
||||
throw new Error("depth must be greater than zero");
|
||||
}
|
||||
|
||||
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];
|
||||
const entries = await listDirSlice(resolvedPath, offset, limit, depth);
|
||||
const output = [`Absolute path: ${resolvedPath}`, ...entries];
|
||||
|
||||
return { content: output.join("\n") };
|
||||
}
|
||||
|
||||
@@ -21,8 +21,10 @@ export async function multi_edit(
|
||||
): Promise<MultiEditResult> {
|
||||
validateRequiredParams(args, ["file_path", "edits"], "MultiEdit");
|
||||
const { file_path, edits } = args;
|
||||
if (!path.isAbsolute(file_path))
|
||||
throw new Error(`File path must be absolute, got: ${file_path}`);
|
||||
const userCwd = process.env.USER_CWD || process.cwd();
|
||||
const resolvedPath = path.isAbsolute(file_path)
|
||||
? file_path
|
||||
: path.resolve(userCwd, 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];
|
||||
@@ -40,7 +42,7 @@ export async function multi_edit(
|
||||
);
|
||||
}
|
||||
try {
|
||||
let content = await fs.readFile(file_path, "utf-8");
|
||||
let content = await fs.readFile(resolvedPath, "utf-8");
|
||||
const appliedEdits: string[] = [];
|
||||
for (let i = 0; i < edits.length; i++) {
|
||||
const edit = edits[i];
|
||||
@@ -70,12 +72,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(file_path, content, "utf-8");
|
||||
await fs.writeFile(resolvedPath, 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 ${file_path}:\n${editList}`,
|
||||
message: `Applied ${edits.length} edit${edits.length !== 1 ? "s" : ""} to ${resolvedPath}:\n${editList}`,
|
||||
edits_applied: edits.length,
|
||||
};
|
||||
} catch (error) {
|
||||
@@ -83,14 +85,13 @@ 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. Current working directory: ${userCwd}`,
|
||||
`File does not exist. Attempted path: ${resolvedPath}. Current working directory: ${userCwd}`,
|
||||
);
|
||||
} else if (code === "EACCES")
|
||||
throw new Error(`Permission denied: ${file_path}`);
|
||||
throw new Error(`Permission denied: ${resolvedPath}`);
|
||||
else if (code === "EISDIR")
|
||||
throw new Error(`Path is a directory: ${file_path}`);
|
||||
throw new Error(`Path is a directory: ${resolvedPath}`);
|
||||
else if (message) throw new Error(message);
|
||||
else throw new Error(`Failed to edit file: ${String(err)}`);
|
||||
}
|
||||
|
||||
@@ -13,31 +13,33 @@ interface WriteResult {
|
||||
export async function write(args: WriteArgs): Promise<WriteResult> {
|
||||
validateRequiredParams(args, ["file_path", "content"], "Write");
|
||||
const { file_path, content } = args;
|
||||
if (!path.isAbsolute(file_path))
|
||||
throw new Error(`File path must be absolute, got: ${file_path}`);
|
||||
const userCwd = process.env.USER_CWD || process.cwd();
|
||||
const resolvedPath = path.isAbsolute(file_path)
|
||||
? file_path
|
||||
: path.resolve(userCwd, file_path);
|
||||
try {
|
||||
const dir = path.dirname(file_path);
|
||||
const dir = path.dirname(resolvedPath);
|
||||
await fs.mkdir(dir, { recursive: true });
|
||||
try {
|
||||
const stats = await fs.stat(file_path);
|
||||
const stats = await fs.stat(resolvedPath);
|
||||
if (stats.isDirectory())
|
||||
throw new Error(`Path is a directory, not a file: ${file_path}`);
|
||||
throw new Error(`Path is a directory, not a file: ${resolvedPath}`);
|
||||
} catch (error) {
|
||||
const err = error as NodeJS.ErrnoException;
|
||||
if (err.code !== "ENOENT") throw err;
|
||||
}
|
||||
await fs.writeFile(file_path, content, "utf-8");
|
||||
await fs.writeFile(resolvedPath, content, "utf-8");
|
||||
return {
|
||||
message: `Successfully wrote ${content.length} characters to ${file_path}`,
|
||||
message: `Successfully wrote ${content.length} characters to ${resolvedPath}`,
|
||||
};
|
||||
} catch (error) {
|
||||
const err = error as NodeJS.ErrnoException;
|
||||
if (err.code === "EACCES")
|
||||
throw new Error(`Permission denied: ${file_path}`);
|
||||
throw new Error(`Permission denied: ${resolvedPath}`);
|
||||
else if (err.code === "ENOSPC")
|
||||
throw new Error(`No space left on device: ${file_path}`);
|
||||
throw new Error(`No space left on device: ${resolvedPath}`);
|
||||
else if (err.code === "EISDIR")
|
||||
throw new Error(`Path is a directory: ${file_path}`);
|
||||
throw new Error(`Path is a directory: ${resolvedPath}`);
|
||||
else if (err.message) throw err;
|
||||
else throw new Error(`Failed to write file: ${err}`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user