Files
fireclaw/skills/read_file/run.py
ansible 5b312e34de Add read_file skill, session persistence, and update script
- New read_file skill: paginated file reading with line ranges,
  path restricted to /workspace, binary detection, directory listing
- Session persistence via SQLite + FTS5: conversation history survives
  agent restarts, last N messages restored into deque on boot,
  auto-prune to 1000 messages
- Update truncation hint to reference read_file instead of run_command
- New scripts/update.sh for patching rootfs + rebuilding snapshot

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 14:49:54 +00:00

68 lines
1.9 KiB
Python

#!/usr/bin/env python3
"""Read a file from /workspace with optional line range."""
import json
import os
import sys
args = json.loads(sys.stdin.read())
path = args.get("path", "")
offset = max(int(args.get("offset", 1)), 1)
limit = max(int(args.get("limit", 200)), 1)
WORKSPACE = os.environ.get("WORKSPACE", "/workspace")
# Resolve to absolute and ensure it stays under /workspace
resolved = os.path.realpath(path)
if not resolved.startswith(WORKSPACE + "/") and resolved != WORKSPACE:
print(f"[error: path must be under {WORKSPACE}]")
sys.exit(0)
if not os.path.exists(resolved):
print(f"[error: file not found: {path}]")
sys.exit(0)
if os.path.isdir(resolved):
entries = sorted(os.listdir(resolved))
print(f"Directory listing of {path} ({len(entries)} entries):")
for entry in entries[:100]:
full = os.path.join(resolved, entry)
kind = "dir" if os.path.isdir(full) else "file"
print(f" {entry} ({kind})")
if len(entries) > 100:
print(f" ... and {len(entries) - 100} more")
sys.exit(0)
# Binary detection — check first 512 bytes
try:
with open(resolved, "rb") as f:
chunk = f.read(512)
if b"\x00" in chunk:
size = os.path.getsize(resolved)
print(f"[binary file: {path} ({size} bytes)]")
sys.exit(0)
except Exception as e:
print(f"[error reading file: {e}]")
sys.exit(0)
# Read with line range
try:
with open(resolved) as f:
lines = f.readlines()
except Exception as e:
print(f"[error reading file: {e}]")
sys.exit(0)
total = len(lines)
start_idx = offset - 1 # 0-based
end_idx = min(start_idx + limit, total)
if start_idx >= total:
print(f"[file has {total} lines — offset {offset} is beyond end of file]")
sys.exit(0)
for i in range(start_idx, end_idx):
print(f"{i + 1}\t{lines[i]}", end="")
if end_idx < total:
print(f"\n[showing lines {offset}-{end_idx} of {total} — use offset={end_idx + 1} to read more]")