ollie/tools/file_write

72 lines
1.9 KiB
Python

#!/usr/bin/env python3
# ollie:prompt
# ## file_write
#
# Create or overwrite a file. Produces a unified diff.
#
# **Args**: `[path, content]`
#
# ```
# call_tool: calls=[{tool: "file_write", args: ["/abs/path", "file content here"]}]
# ```
#
# **Constraints**: Absolute paths only. Parent directory must exist.
# ollie:end
import sys
import os
import difflib
def format_diff(path, old, new):
old_lines = old.splitlines(keepends=True)
new_lines = new.splitlines(keepends=True)
diff = ''.join(difflib.unified_diff(old_lines, new_lines, fromfile=path, tofile=path))
if not diff:
return None
if not diff.endswith('\n'):
diff += '\n'
return f"```diff\n{diff}```"
if len(sys.argv) < 3:
print("usage: file_write <file_path> <content>")
sys.exit(1)
file_path = sys.argv[1]
content = sys.argv[2]
if not os.path.isabs(file_path):
print(f"STATUS=error STATE_CHANGED=false RETRYABLE=false")
print(f"error: path must be absolute, got: {file_path}")
sys.exit(1)
parent = os.path.dirname(file_path)
if parent and not os.path.isdir(parent):
print(f"STATUS=error STATE_CHANGED=false RETRYABLE=false")
print(f"error: parent directory does not exist: {parent}")
sys.exit(1)
old_content = ""
if os.path.exists(file_path):
try:
with open(file_path, 'r', encoding='utf-8') as f:
old_content = f.read()
except UnicodeDecodeError:
with open(file_path, 'r', encoding='utf-8', errors='replace') as f:
old_content = f.read()
try:
with open(file_path, 'w', encoding='utf-8') as f:
f.write(content)
except OSError as e:
print(f"STATUS=error STATE_CHANGED=false RETRYABLE=false")
print(f"error: {e}")
sys.exit(1)
diff = format_diff(file_path, old_content, content)
if diff is None:
print("STATUS=no_change STATE_CHANGED=false RETRYABLE=false")
print("(no changes)")
else:
print("STATUS=done STATE_CHANGED=true")
print(diff)