fix: route warnings to file and add in-app toast notifications

- Replace all eprintln! with tracing::warn! to avoid TUI corruption
  via stderr writes during alternate screen mode
- Route tracing output to ~/.local/share/zesdex/zesdex.log instead of
  stderr by configuring tracing_subscriber with a Mutex<File> writer
- Add render_toasts() widget: floating notification stack at top-right
  of the terminal, color-coded by severity (Info/Success/Warning/Error/
  Lesson), auto-expires after 5s, max 4 visible
- Apply to 12 files: stream parser, MCP client, subagent engine,
  state/rest, controller/input, app_config, provider, OAuth, agent_def,
  dto/chat/tool

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
asepharyana
2026-07-12 10:57:32 +07:00
co-authored by Claude Opus 4.8
parent e29dfadaa7
commit 89b63b1bc2
13 changed files with 92 additions and 30 deletions
+6 -6
View File
@@ -62,11 +62,11 @@ impl AppStateRest {
let settings = Settings::load();
let app_config = AppConfig::load();
let download_dir = memory_dir.parent().unwrap_or_else(|| {
eprintln!("[state] memory_dir '{}' has no parent, using it for downloads", memory_dir.display());
tracing::warn!("[state] memory_dir '{}' has no parent, using it for downloads", memory_dir.display());
&memory_dir
}).join("downloads");
let worktrees_dir = memory_dir.parent().unwrap_or_else(|| {
eprintln!("[state] memory_dir '{}' has no parent, using it for worktrees", memory_dir.display());
tracing::warn!("[state] memory_dir '{}' has no parent, using it for worktrees", memory_dir.display());
&memory_dir
}).join("worktrees");
let dir_cache = DirCache::new();
@@ -74,7 +74,7 @@ impl AppStateRest {
.file_name()
.map(|n| n.to_string_lossy().to_string())
.unwrap_or_else(|| {
eprintln!("[state] session_dir has no file_name component, using empty session_id");
tracing::warn!("[state] session_dir has no file_name component, using empty session_id");
String::new()
});
AppStateRest {
@@ -107,7 +107,7 @@ impl AppStateRest {
pub fn turn_in_flight(&self) -> bool {
self.turn_in_flight.lock().map(|g| *g).unwrap_or_else(|_| {
eprintln!("[state] turn_in_flight mutex poisoned");
tracing::warn!("[state] turn_in_flight mutex poisoned");
false
})
}
@@ -133,11 +133,11 @@ impl AppStateRest {
.and_then(|p| p.parent())
.map(|p| p.to_path_buf())
.unwrap_or_else(|| {
eprintln!("[state] session_dir '{}' has no grandparent, using parent", self.session_dir.display());
tracing::warn!("[state] session_dir '{}' has no grandparent, using parent", self.session_dir.display());
self.session_dir.parent()
.map(|p| p.to_path_buf())
.unwrap_or_else(|| {
eprintln!("[state] session_dir '{}' has no parent at all, using itself", self.session_dir.display());
tracing::warn!("[state] session_dir '{}' has no parent at all, using itself", self.session_dir.display());
self.session_dir.clone()
})
})