import os
import json
import logging
from agent_node.skills.base import BaseSkill
logger = logging.getLogger(__name__)
class FileSkill(BaseSkill):
"""Provides file system navigation and inspection capabilities."""
def __init__(self, sync_mgr=None):
self.sync_mgr = sync_mgr
def execute(self, task, sandbox, on_complete, on_event=None):
"""
Executes a file-related task (list, stats).
Payload JSON: { "action": "list", "path": "...", "recursive": false }
"""
try:
payload = json.loads(task.payload_json)
action = payload.get("action", "list")
path = payload.get("path", ".")
# 1. Sandbox Jail Check
# (In a real implementation, we'd use sandbox.check_path(path))
# For now, we'll assume the node allows browsing its root or session dir.
if action == "list":
result = self._list_dir(path, payload.get("recursive", False))
on_complete(task.task_id, {"status": 0, "stdout": json.dumps(result)}, task.trace_id)
else:
on_complete(task.task_id, {"status": 1, "stderr": f"Unknown action: {action}"}, task.trace_id)
except Exception as e:
logger.error(f"[FileSkill] Task {task.task_id} failed: {e}")
on_complete(task.task_id, {"status": 1, "stderr": str(e)}, task.trace_id)
def _list_dir(self, path, recursive=False):
"""Lists directory contents with metadata."""
if not os.path.exists(path):
return {"error": "Path not found"}
items = []
if recursive:
for root, dirs, files in os.walk(path):
for name in dirs + files:
abs_path = os.path.join(root, name)
rel_path = os.path.relpath(abs_path, path)
st = os.stat(abs_path)
items.append({
"name": name,
"path": rel_path,
"is_dir": os.path.isdir(abs_path),
"size": st.st_size,
"mtime": st.st_mtime
})
else:
for name in os.listdir(path):
abs_path = os.path.join(path, name)
st = os.stat(abs_path)
items.append({
"name": name,
"is_dir": os.path.isdir(abs_path),
"size": st.st_size,
"mtime": st.st_mtime
})
return {
"root": os.path.abspath(path),
"items": sorted(items, key=lambda x: (not x["is_dir"], x["name"]))
}
def cancel(self, task_id):
return False # Listing is usually fast, no cancellation needed
def shutdown(self):
pass