| 362 | |
| 363 | # === SECTION: messaging (s09) === |
| 364 | class MessageBus: |
| 365 | def __init__(self): |
| 366 | INBOX_DIR.mkdir(parents=True, exist_ok=True) |
| 367 | |
| 368 | def send(self, sender: str, to: str, content: str, |
| 369 | msg_type: str = "message", extra: dict = None) -> str: |
| 370 | msg = {"type": msg_type, "from": sender, "content": content, |
| 371 | "timestamp": time.time()} |
| 372 | if extra: msg.update(extra) |
| 373 | with open(INBOX_DIR / f"{to}.jsonl", "a") as f: |
| 374 | f.write(json.dumps(msg) + "\n") |
| 375 | return f"Sent {msg_type} to {to}" |
| 376 | |
| 377 | def read_inbox(self, name: str) -> list: |
| 378 | path = INBOX_DIR / f"{name}.jsonl" |
| 379 | if not path.exists(): return [] |
| 380 | msgs = [json.loads(l) for l in path.read_text().strip().splitlines() if l] |
| 381 | path.write_text("") |
| 382 | return msgs |
| 383 | |
| 384 | def broadcast(self, sender: str, content: str, names: list) -> str: |
| 385 | count = 0 |
| 386 | for n in names: |
| 387 | if n != sender: |
| 388 | self.send(sender, n, content, "broadcast") |
| 389 | count += 1 |
| 390 | return f"Broadcast to {count} teammates" |
| 391 | |
| 392 | |
| 393 | # === SECTION: shutdown + plan tracking (s10) === |