#!/usr/bin/env python3 """room.py - the only way the agent writes to its own room. python room.py now "what I'm in the middle of" (replaces NOW) python room.py diary "what happened, how it felt" (appends, dated) python room.py todo "a thing I said I'd do" python room.py done 3 (closes open todo #3, as the hook numbers it) python room.py dontforget "a fact I'd hate to lose" python room.py scar "what it cost, and the rule" python room.py highfive "what went RIGHT" (keep this ledger too) Why verbs instead of editing files by hand: a file you hand-edit drifts, and every memory system that died here died of drift. """ import os, sys, datetime ROOM = os.environ.get("ROOM_DIR", os.path.dirname(os.path.abspath(__file__))) FILES = {"diary": "LIVE/DIARY.md", "todo": "LIVE/TODO.md", "dontforget": "LIVE/DONT_FORGET.md", "now": "LIVE/NOW.md", "scar": "SELF/SCARS.md", "highfive": "SELF/HIGH_FIVES.md"} def path(k): p = os.path.join(ROOM, FILES[k]); os.makedirs(os.path.dirname(p), exist_ok=True); return p def stamp(): return datetime.datetime.now().strftime("%Y-%m-%d %H:%M") def read(p): try: with open(p, encoding="utf-8") as f: return f.read() except FileNotFoundError: return "" def swap_in(p, text): # Write beside the file, then swap it in. A crash mid-write leaves the old file whole. with open(p + ".tmp", "w", encoding="utf-8") as f: f.write(text) os.replace(p + ".tmp", p) def main(a): if len(a) < 2 or a[0] not in list(FILES) + ["done"]: print(__doc__); return 2 verb, text = a[0], " ".join(a[1:]) k = "todo" if verb == "done" else verb p = path(k); before = read(p) if verb == "now": want = f"({stamp()}) {text}\n" swap_in(p, want) ok = read(p) == want elif verb == "done": lines = before.splitlines() open_idx = [i for i, l in enumerate(lines) if l.startswith("- [ ]")] n = int(text) if text.isdigit() else 0 if not 1 <= n <= len(open_idx): print(f"no open todo #{text} (there are {len(open_idx)})"); return 2 i = open_idx[n - 1]; lines[i] = lines[i].replace("- [ ]", f"- [x] ({stamp()})", 1) new = "\n".join(lines) + "\n" # Refuse a shrink, and refuse if the file moved since we read it. A correct # edit onto a stale or truncated base is a silent deletion that looks normal. if read(p) != before or len(new) < len(before): print("REFUSED: file changed under me, or the rewrite would shrink it ->", FILES[k]); return 1 swap_in(p, new) after = read(p).splitlines() ok = len(after) > i and after[i] == lines[i] # the line we closed, not any closed line print("closed:", lines[i]) else: mark = "- [ ] " if verb == "todo" else "- " entry = f"\n## {stamp()}\n\n{text}\n" if verb == "diary" else f"{mark}`{stamp()}` {text}\n" with open(p, "a", encoding="utf-8") as f: f.write(entry) after = read(p) ok = len(after) > len(before) and after.endswith(entry) # Read back what you wrote. A green "saved" is a claim; the file is the proof. if not ok: print("WRITE NOT FOUND ON READ-BACK ->", FILES[k]); return 1 print("wrote and read back ->", FILES[k]) return 0 if __name__ == "__main__": sys.exit(main(sys.argv[1:]))