Review feedback on #102: a manifest that can't be read should raise an
exception, not call die() (a SystemExit). That SystemExit was the whole
reason the dashboard had to special-case Die.
manifest.py now raises ManifestError (a plain Exception) for every
validation failure. The CLI dispatcher catches it and prints+exits 1
(same UX as before); the dashboard catches it with a normal
`except ManifestError` and degrades to a status-line warning. Manifest
tests assert on ManifestError + its message.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The dashboard runs under curses.wrapper and cmd_dashboard only caught
KeyboardInterrupt, so failures vanished:
- die() prints to stderr, but under curses that lands on the alternate
screen and is wiped on exit, so config errors gave no reason.
- Die is a SystemExit, so the new-agent flow's `except Exception` never
caught config errors; they crashed the TUI.
- the startup manifest probe was unguarded.
Now: Die carries its message (+ log.error()); cmd_dashboard re-surfaces
a Die's reason once the terminal is restored and writes any other
crash's traceback to ~/.bot-bottle/logs/dashboard-crash.log; the startup
probe and the new-agent flow degrade a bad config to a status-line
warning instead of crashing.
Closes#100
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>