fix(dashboard): surface launch/crash failures (#100)
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>
This commit is contained in:
+15
-3
@@ -14,11 +14,23 @@ def warn(msg: str) -> None:
|
||||
print(f"bot-bottle: warning: {msg}", file=sys.stderr)
|
||||
|
||||
|
||||
def error(msg: str) -> None:
|
||||
print(f"bot-bottle: error: {msg}", file=sys.stderr)
|
||||
|
||||
|
||||
class Die(SystemExit):
|
||||
"""Raised by die() so callers (and tests) can distinguish a deliberate
|
||||
fatal exit from an unrelated SystemExit."""
|
||||
fatal exit from an unrelated SystemExit.
|
||||
|
||||
Carries the human-facing message so a caller that suppressed stderr
|
||||
— e.g. the curses dashboard, whose alternate screen is wiped when the
|
||||
terminal is restored — can re-surface the reason after the fact."""
|
||||
|
||||
def __init__(self, code: int = 1, message: str = "") -> None:
|
||||
super().__init__(code)
|
||||
self.message = message
|
||||
|
||||
|
||||
def die(msg: str) -> NoReturn:
|
||||
print(f"bot-bottle: error: {msg}", file=sys.stderr)
|
||||
raise Die(1)
|
||||
error(msg)
|
||||
raise Die(1, msg)
|
||||
|
||||
Reference in New Issue
Block a user