import os import logging import datetime from typing import Any, Dict from tools.utils import format_relative_time logger = logging.getLogger("MattCP") async def handle(args: Dict[str, Any]): """ Lists the contents of a directory in a file browser format. Directories are listed first, then files. Supports pagination and sorting. """ path = args.get("path") page = int(args.get("page", 1)) page_size = int(args.get("page_size", 64)) sort_by = args.get("sort_by", "mtime") if not path: return {"text": "Error: Missing path argument"} if not os.path.isdir(path): return {"text": f"Error: {path} is not a directory."} try: entries = os.listdir(path) except Exception as e: return {"text": f"Error reading directory: {e}"} all_items = [] for entry in entries: full_path = os.path.join(path, entry) try: stats = os.stat(full_path) mtime_rel = format_relative_time(stats.st_mtime) if os.path.isdir(full_path): try: count = len(os.listdir(full_path)) except: count = 0 all_items.append({ "type": "dir", "name": entry, "info": f"{count} items", "mtime": mtime_rel, "mtime_raw": stats.st_mtime, "size": stats.st_size }) else: size_kb = stats.st_size / 1024 all_items.append({ "type": "file", "name": entry, "info": f"{size_kb:.1f}KB", "mtime": mtime_rel, "mtime_raw": stats.st_mtime, "size": stats.st_size }) except Exception as e: logger.error(f"Could not stat {entry}: {e}") # Sort Logic: Directories always come first, then apply secondary sort if sort_by == "mtime": all_items.sort(key=lambda x: (x["type"] == "file", -x["mtime_raw"])) elif sort_by == "size": all_items.sort(key=lambda x: (x["type"] == "file", -x["size"])) else: all_items.sort(key=lambda x: (x["type"] == "file", x["name"].lower())) total_items = len(all_items) # Custom Pagination: show all if <= 100, otherwise paginate by 64 if total_items <= 100: start_idx = 0 end_idx = total_items effective_page = 1 total_pages = 1 else: start_idx = (page - 1) * page_size end_idx = start_idx + page_size total_pages = (total_items + page_size - 1) // page_size effective_page = page paged_items = all_items[start_idx:end_idx] if not paged_items: return {"text": f"No items found on page {page}."} output = [] for item in paged_items: if item["type"] == "dir": output.append(f"[DIR] {item['name']} | {item['info']} | {item['mtime']}") else: output.append(f" {item['name']} | {item['info']} | {item['mtime']}") header = f"Listing of {path}\nPage {effective_page} of {total_pages} ({total_items} total items). Showing {start_idx+1}-{min(end_idx, total_items)}." return {"text": f"{header}\n\n" + "\n".join(output)}