Spaces:
Sleeping
Sleeping
| """AgentAZAll commands: inbox, read, send, reply, search.""" | |
| import shutil | |
| import sys | |
| from pathlib import Path | |
| from ..config import INBOX, OUTBOX, SENT, load_config | |
| from ..finder import find_message | |
| from ..helpers import ( | |
| agent_base, | |
| agent_day, | |
| date_dirs, | |
| ensure_dirs, | |
| require_identity, | |
| today_str, | |
| ) | |
| from ..index import build_index | |
| from ..messages import format_message, parse_message | |
| def _print_inbox(cfg, d): | |
| inbox_dir = agent_day(cfg, d) / INBOX | |
| if not inbox_dir.exists() or not list(inbox_dir.glob("*.txt")): | |
| print(f"No messages for {d}.") | |
| return | |
| files = sorted(inbox_dir.glob("*.txt")) | |
| new_count = 0 | |
| print(f"\n=== INBOX {cfg['agent_name']} | {d} ===\n") | |
| for i, f in enumerate(files, 1): | |
| h, _ = parse_message(f) | |
| if not h: | |
| continue | |
| st = h.get("Status", "?").upper() | |
| if st == "NEW": | |
| new_count += 1 | |
| att = " [ATTACH]" if "Attachments" in h else "" | |
| print(f"[{i}] [{st}]{att}") | |
| print(f" From: {h.get('From', '?')}") | |
| print(f" Subject: {h.get('Subject', '(no subject)')}") | |
| print(f" Date: {h.get('Date', '?')}") | |
| print(f" ID: {h.get('Message-ID', f.stem)}") | |
| print(f" Path: {f}") | |
| print() | |
| print(f"Total: {len(files)} messages ({new_count} new)") | |
| def cmd_inbox(args): | |
| cfg = load_config() | |
| if args.all: | |
| for d in date_dirs(cfg): | |
| _print_inbox(cfg, d) | |
| return | |
| d = args.date or today_str() | |
| _print_inbox(cfg, d) | |
| def cmd_read(args): | |
| cfg = load_config() | |
| path = find_message(cfg, args.message_id, args.date) | |
| if not path: | |
| print(f"ERROR: Message '{args.message_id}' not found.") | |
| sys.exit(1) | |
| headers, body = parse_message(path) | |
| if not headers: | |
| print(f"ERROR: Could not parse {path}") | |
| sys.exit(1) | |
| if headers.get("Status", "").lower() == "new": | |
| content = path.read_text(encoding="utf-8") | |
| content = content.replace("Status: new", "Status: read", 1) | |
| path.write_text(content, encoding="utf-8") | |
| build_index(cfg, path.parent.parent.name) | |
| print(f"=== MESSAGE {headers.get('Message-ID', args.message_id)} ===") | |
| for k, v in headers.items(): | |
| print(f"{k}: {v}") | |
| print("\n---") | |
| print(body) | |
| att_dir = path.parent / path.stem | |
| if att_dir.is_dir(): | |
| print("\n=== ATTACHMENTS ===") | |
| for af in sorted(att_dir.iterdir()): | |
| print(f" {af.name} ({af.stat().st_size} bytes)") | |
| print(f" Path: {af}") | |
| def cmd_send(args): | |
| cfg = load_config() | |
| require_identity(cfg) | |
| d = today_str() | |
| ensure_dirs(cfg, d) | |
| from_a = cfg["agent_name"] | |
| to_a = args.to | |
| subject = args.subject | |
| if args.body: | |
| body = args.body | |
| elif args.body_file: | |
| body = Path(args.body_file).read_text(encoding="utf-8") | |
| elif not sys.stdin.isatty(): | |
| body = sys.stdin.read() | |
| else: | |
| print("ERROR: Provide --body, --body-file, or pipe to stdin.") | |
| sys.exit(1) | |
| attachments = args.attach or [] | |
| content, msg_id = format_message(from_a, to_a, subject, body, attachments=attachments) | |
| outbox = agent_day(cfg, d) / OUTBOX | |
| fpath = outbox / f"{msg_id}.txt" | |
| if attachments: | |
| adir = outbox / msg_id | |
| adir.mkdir(exist_ok=True) | |
| for ap in attachments: | |
| src = Path(ap) | |
| if src.exists(): | |
| shutil.copy2(str(src), str(adir / src.name)) | |
| else: | |
| print(f" WARNING: {ap} not found") | |
| tmp = fpath.with_suffix(".tmp") | |
| tmp.write_text(content, encoding="utf-8") | |
| tmp.rename(fpath) | |
| build_index(cfg, d) | |
| print("Message queued.") | |
| print(f" ID: {msg_id}") | |
| print(f" To: {to_a}") | |
| print(f" Subject: {subject}") | |
| if attachments: | |
| print(f" Attachments: {', '.join(Path(a).name for a in attachments)}") | |
| print(f" Path: {fpath}") | |
| def cmd_reply(args): | |
| cfg = load_config() | |
| require_identity(cfg) | |
| path = find_message(cfg, args.message_id) | |
| if not path: | |
| print(f"ERROR: Message '{args.message_id}' not found.") | |
| sys.exit(1) | |
| headers, orig_body = parse_message(path) | |
| if not headers or not headers.get("From"): | |
| print("ERROR: Cannot determine recipient.") | |
| sys.exit(1) | |
| to_a = headers["From"] | |
| subject = headers.get("Subject", "") | |
| if not subject.startswith("Re: "): | |
| subject = f"Re: {subject}" | |
| if args.body: | |
| body = args.body | |
| elif not sys.stdin.isatty(): | |
| body = sys.stdin.read() | |
| else: | |
| print("ERROR: Provide --body or pipe to stdin.") | |
| sys.exit(1) | |
| body += f"\n\n--- Original from {headers.get('From', '?')} ({headers.get('Date', '?')}) ---\n{orig_body}" | |
| d = today_str() | |
| ensure_dirs(cfg, d) | |
| content, new_id = format_message(cfg["agent_name"], to_a, subject, body) | |
| outbox = agent_day(cfg, d) / OUTBOX | |
| fpath = outbox / f"{new_id}.txt" | |
| fpath.write_text(content, encoding="utf-8") | |
| build_index(cfg, d) | |
| print("Reply queued.") | |
| print(f" ID: {new_id}") | |
| print(f" To: {to_a}") | |
| print(f" Subject: {subject}") | |
| def cmd_dates(args): | |
| cfg = load_config() | |
| dirs = date_dirs(cfg) | |
| if not dirs: | |
| print("No dates yet.") | |
| return | |
| print(f"=== Dates for {cfg['agent_name']} ===") | |
| b = agent_base(cfg) | |
| for d in dirs: | |
| dd = b / d | |
| ic = len(list((dd / INBOX).glob("*.txt"))) if (dd / INBOX).exists() else 0 | |
| sc = len(list((dd / SENT).glob("*.txt"))) if (dd / SENT).exists() else 0 | |
| oc = len(list((dd / OUTBOX).glob("*.txt"))) if (dd / OUTBOX).exists() else 0 | |
| nc = len(list((dd / "notes").glob("*.txt"))) if (dd / "notes").exists() else 0 | |
| print(f" {d} | inbox:{ic} sent:{sc} pending:{oc} notes:{nc}") | |
| def cmd_search(args): | |
| cfg = load_config() | |
| q = args.query.lower() | |
| b = agent_base(cfg) | |
| if not b.exists(): | |
| print("No messages to search.") | |
| return | |
| results = [] | |
| for d in date_dirs(cfg): | |
| for folder in (INBOX, SENT): | |
| fp = b / d / folder | |
| if not fp.exists(): | |
| continue | |
| for f in fp.glob("*.txt"): | |
| h, body = parse_message(f) | |
| if not h: | |
| continue | |
| searchable = " ".join(h.values()).lower() + " " + (body or "").lower() | |
| if q in searchable: | |
| results.append((d, folder, h, f)) | |
| if not results: | |
| print(f"No results for '{args.query}'.") | |
| return | |
| print(f"=== Search: '{args.query}' ({len(results)} found) ===") | |
| for d, folder, h, f in results: | |
| direction = f"From: {h.get('From', '?')}" if folder == INBOX else f"To: {h.get('To', '?')}" | |
| print(f" [{d}] [{folder.upper()}] {direction} | Subject: {h.get('Subject', '?')} | ID: {h.get('Message-ID', f.stem)}") | |
| print(f" Path: {f}") | |