72 lines
2.2 KiB
Python
72 lines
2.2 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('{"schema": {"type": "array", "items": [{"name": "file_path", "type": "string", "description": "Absolute path to create or overwrite", "required": true}, {"name": "content", "type": "string", "description": "File content to write", "required": true}], "examples": [["/abs/path", "file content here"]]}}')
|
|
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)
|