NexusCoder / nexus /tools /archive.py
AdminReal's picture
Import NexusCoder from github.com/mhieuhonda/NexusCoder
eca5751 verified
Raw History Blame Contribute Delete
5.19 kB
"""Archive Tool - zip/tar operations."""
from __future__ import annotations
import os
import zipfile
import tarfile
from typing import Dict, Any
from .base import Tool, ToolResult, ToolContext, ToolCategory, ToolSafety
class ArchiveTool(Tool):
"""Tạo/giải nén zip/tar archives."""
category = ToolCategory.FILE
safety = ToolSafety.MODERATE
@property
def name(self) -> str:
return "archive"
@property
def description(self) -> str:
return "Tạo/giải nén ZIP/TAR/GZ archives."
@property
def parameters(self) -> Dict[str, Any]:
return {
"type": "object",
"properties": {
"action": {"type": "string", "enum": ["create", "extract", "list"]},
"archive_path": {"type": "string"},
"source_path": {"type": "string", "description": "For create: dir to compress; for extract: target dir"},
"format": {"type": "string", "enum": ["zip", "tar", "tar.gz", "tar.bz2"], "default": "zip"},
},
"required": ["action", "archive_path"],
}
def execute(self, args: Dict[str, Any], context: ToolContext) -> ToolResult:
action = args["action"]
archive_path = args["archive_path"]
source = args.get("source_path")
fmt = args.get("format", "zip")
full_archive = archive_path if os.path.isabs(archive_path) else os.path.join(context.working_dir, archive_path)
try:
if action == "create":
if not source:
return ToolResult(success=False, error="source_path required for create", return_code=2)
full_source = source if os.path.isabs(source) else os.path.join(context.working_dir, source)
if not os.path.exists(full_source):
return ToolResult(success=False, error=f"Source not found: {full_source}", return_code=1)
if fmt == "zip":
with zipfile.ZipFile(full_archive, "w", zipfile.ZIP_DEFLATED) as zf:
if os.path.isfile(full_source):
zf.write(full_source, os.path.basename(full_source))
else:
for root, dirs, files in os.walk(full_source):
for fname in files:
fpath = os.path.join(root, fname)
arcname = os.path.relpath(fpath, full_source)
zf.write(fpath, arcname)
else:
mode = {"tar": "w", "tar.gz": "w:gz", "tar.bz2": "w:bz2"}[fmt]
with tarfile.open(full_archive, mode) as tf:
tf.add(full_source, arcname=os.path.basename(full_source))
size = os.path.getsize(full_archive)
return ToolResult(
success=True,
output=f"Created {full_archive} ({size} bytes)",
artifacts=[full_archive],
metadata={"action": "create", "format": fmt, "size": size},
)
elif action == "extract":
if not source:
source = os.path.dirname(full_archive) or "."
full_target = source if os.path.isabs(source) else os.path.join(context.working_dir, source)
os.makedirs(full_target, exist_ok=True)
if full_archive.endswith(".zip"):
with zipfile.ZipFile(full_archive, "r") as zf:
zf.extractall(full_target)
names = zf.namelist()
else:
with tarfile.open(full_archive, "r:*") as tf:
tf.extractall(full_target)
names = tf.getnames()
return ToolResult(
success=True,
output=f"Extracted {len(names)} files to {full_target}",
metadata={"action": "extract", "files": names[:20], "total": len(names)},
)
elif action == "list":
if full_archive.endswith(".zip"):
with zipfile.ZipFile(full_archive, "r") as zf:
names = zf.namelist()
else:
with tarfile.open(full_archive, "r:*") as tf:
names = tf.getnames()
output = "\n".join(names[:100])
if len(names) > 100:
output += f"\n... and {len(names) - 100} more"
return ToolResult(
success=True,
output=output or "(empty archive)",
metadata={"total_files": len(names)},
)
else:
return ToolResult(success=False, error=f"Unknown action: {action}", return_code=2)
except Exception as e:
return ToolResult(success=False, error=str(e), return_code=1)