brief_file.py 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. """Best-effort atomic writer for the durable brief markdown snapshot.
  2. Enabled via `[brief].write = true` (off by default). When enabled, each brief
  3. update replaces `[brief].dir`/`[brief].filename` (default `brief/brief.md`)
  4. with the exact text supplied by the assistant, using the same
  5. `tempfile.mkstemp` + `os.replace` atomic pattern as the rest of the codebase.
  6. The `brief/` directory is cwd-relative user state and gitignored. Best-effort
  7. by design: any `OSError` is logged and swallowed so the brief writer can never
  8. disturb the assistant flow; `clear()` truncates to empty and likewise never
  9. raises.
  10. """
  11. import logging
  12. import os
  13. import tempfile
  14. logger = logging.getLogger(__name__)
  15. class BriefFile:
  16. """Best-effort, atomic, opt-in writer for the durable brief document."""
  17. def __init__(self, write_enabled: bool, directory: str, filename: str = "brief.md") -> None:
  18. self._write_enabled = bool(write_enabled)
  19. self._directory = str(directory)
  20. self._filename = str(filename)
  21. @property
  22. def write_enabled(self) -> bool:
  23. return self._write_enabled
  24. def write(self, text: str) -> None:
  25. """Atomically replace the brief file with `text` (no-op when disabled)."""
  26. if not self._write_enabled:
  27. return
  28. path = os.path.join(self._directory, self._filename)
  29. try:
  30. os.makedirs(self._directory, exist_ok=True)
  31. fd, tmp = tempfile.mkstemp(dir=self._directory, suffix=".tmp")
  32. try:
  33. with os.fdopen(fd, "w", encoding="utf-8") as f:
  34. f.write(text)
  35. os.replace(tmp, path)
  36. except OSError:
  37. try:
  38. os.unlink(tmp)
  39. except OSError:
  40. pass
  41. raise
  42. except OSError as e: # noqa: BLE001 - brief write is best-effort, never raises
  43. logger.warning("brief file write failed: %s", e)
  44. def clear(self) -> None:
  45. """Truncate the brief file to empty (no-op when disabled; never raises)."""
  46. if not self._write_enabled:
  47. return
  48. path = os.path.join(self._directory, self._filename)
  49. try:
  50. with open(path, "w", encoding="utf-8"):
  51. pass
  52. except OSError as e: # noqa: BLE001 - brief clear is best-effort, never raises
  53. logger.warning("brief file clear failed: %s", e)