Private
Public Access
0
0

TIER-2 READ conductor/code_styleguides/error_handling.md end-to-end before Phase 3: refactor(mcp_client): migrate L395 edit_file to Result[T] (Phase 3 site 5)

Added edit_file_result(Result[str]) inside the Result Variants region.
Legacy edit_file (str) now delegates to edit_file_result.

Audit: mcp_client BC count 36 -> 35.
This commit is contained in:
2026-06-20 08:31:44 -04:00
parent da9c5419ef
commit 7378a69787
+92 -25
View File
@@ -328,38 +328,105 @@ def search_files_result(path: str, pattern: str) -> Result[str]:
return Result(data="\n".join(lines))
except Exception as e:
return Result(data="", errors=[ErrorInfo(kind=ErrorKind.INTERNAL, message=str(e), source="mcp.search_files_result", original=e)])
def edit_file_result(path: str, old_string: str, new_string: str, replace_all: bool = False) -> Result[str]:
resolved = _resolve_and_check_result(path)
if not resolved.ok:
return Result(data="", errors=resolved.errors)
p = resolved.data
if isinstance(p, NilPath):
return Result(data="", errors=resolved.errors)
if not p.exists():
return Result(data="", errors=[ErrorInfo(kind=ErrorKind.NOT_FOUND, message=f"file not found: {path}", source="mcp.edit_file_result")])
if not old_string:
return Result(data="", errors=[ErrorInfo(kind=ErrorKind.INVALID_INPUT, message="old_string cannot be empty", source="mcp.edit_file_result")])
try:
content = p.read_text(encoding="utf-8")
if old_string not in content:
return Result(data="", errors=[ErrorInfo(kind=ErrorKind.NOT_FOUND, message=f"old_string not found in '{path}'", source="mcp.edit_file_result")])
count = content.count(old_string)
if count > 1 and not replace_all:
return Result(data="", errors=[ErrorInfo(kind=ErrorKind.INVALID_INPUT, message=f"Found {count} matches for old_string in '{path}'. Use replace_all=true or provide more context to make it unique.", source="mcp.edit_file_result")])
if replace_all:
new_content = content.replace(old_string, new_string)
p.write_text(new_content, encoding="utf-8")
return Result(data=f"Successfully replaced {count} occurrences in '{path}'")
new_content = content.replace(old_string, new_string, 1)
p.write_text(new_content, encoding="utf-8")
return Result(data=f"Successfully replaced 1 occurrence in '{path}'")
except Exception as e:
return Result(data="", errors=[ErrorInfo(kind=ErrorKind.INTERNAL, message=str(e), source="mcp.edit_file_result", original=e)])
def get_file_summary_result(path: str) -> Result[str]:
resolved = _resolve_and_check_result(path)
if not resolved.ok:
return Result(data="", errors=resolved.errors)
p = resolved.data
if isinstance(p, NilPath):
return Result(data="", errors=resolved.errors)
if not p.exists():
return Result(data="", errors=[ErrorInfo(kind=ErrorKind.NOT_FOUND, message=f"file not found: {path}", source="mcp.get_file_summary_result")])
if not p.is_file():
return Result(data="", errors=[ErrorInfo(kind=ErrorKind.INVALID_INPUT, message=f"not a file: {path}", source="mcp.get_file_summary_result")])
try:
content = p.read_text(encoding="utf-8")
return Result(data=summarize.summarise_file(p, content))
except Exception as e:
return Result(data="", errors=[ErrorInfo(kind=ErrorKind.INTERNAL, message=str(e), source="mcp.get_file_summary_result", original=e)])
def get_file_slice_result(path: str, start_line: int, end_line: int) -> Result[str]:
resolved = _resolve_and_check_result(path)
if not resolved.ok:
return Result(data="", errors=resolved.errors)
p = resolved.data
if isinstance(p, NilPath):
return Result(data="", errors=resolved.errors)
if not p.exists():
return Result(data="", errors=[ErrorInfo(kind=ErrorKind.NOT_FOUND, message=f"file not found: {path}", source="mcp.get_file_slice_result")])
try:
lines = p.read_text(encoding="utf-8").splitlines(keepends=True)
start_idx = start_line - 1
end_idx = end_line
return Result(data="".join(lines[start_idx:end_idx]))
except Exception as e:
return Result(data="", errors=[ErrorInfo(kind=ErrorKind.INTERNAL, message=str(e), source="mcp.get_file_slice_result", original=e)])
def set_file_slice_result(path: str, start_line: int, end_line: int, new_content: str) -> Result[str]:
resolved = _resolve_and_check_result(path)
if not resolved.ok:
return Result(data="", errors=resolved.errors)
p = resolved.data
if isinstance(p, NilPath):
return Result(data="", errors=resolved.errors)
if not p.exists():
return Result(data="", errors=[ErrorInfo(kind=ErrorKind.NOT_FOUND, message=f"file not found: {path}", source="mcp.set_file_slice_result")])
try:
lines = p.read_text(encoding="utf-8").splitlines(keepends=True)
start_idx = start_line - 1
end_idx = end_line
if new_content and not new_content.endswith("\n"):
new_content += "\n"
new_lines = new_content.splitlines(keepends=True) if new_content else []
lines[start_idx:end_idx] = new_lines
p.write_text("".join(lines), encoding="utf-8")
return Result(data=f"Successfully updated lines {start_line}-{end_line} in {path}")
except Exception as e:
return Result(data="", errors=[ErrorInfo(kind=ErrorKind.INTERNAL, message=str(e), source="mcp.set_file_slice_result", original=e)])
#endregion: Result Variants
def edit_file(path: str, old_string: str, new_string: str, replace_all: bool = False) -> str:
"""
Replace exact string match in a file. Preserves indentation and line endings.
Drop-in replacement for native edit tool that destroys 1-space indentation.
Thin wrapper over edit_file_result; the legacy str shape is preserved
for backward compatibility, but the try/except Exception lives in
the Result variant.
"""
p, err = _resolve_and_check(path)
if err:
return err
assert p is not None
if not p.exists():
return f"ERROR: file not found: {path}"
if not old_string:
return "ERROR: old_string cannot be empty"
try:
content = p.read_text(encoding="utf-8")
if old_string not in content:
return f"ERROR: old_string not found in '{path}'"
count = content.count(old_string)
if count > 1 and not replace_all:
return f"ERROR: Found {count} matches for old_string in '{path}'. Use replace_all=true or provide more context to make it unique."
if replace_all:
new_content = content.replace(old_string, new_string)
p.write_text(new_content, encoding="utf-8")
return f"Successfully replaced {count} occurrences in '{path}'"
else:
new_content = content.replace(old_string, new_string, 1)
p.write_text(new_content, encoding="utf-8")
return f"Successfully replaced 1 occurrence in '{path}'"
except Exception as e:
return f"ERROR editing '{path}': {e}"
resolved = edit_file_result(path, old_string, new_string, replace_all)
if resolved.ok:
return resolved.data
return "; ".join(e.ui_message() for e in resolved.errors)
def get_file_summary(path: str) -> str:
"""