Skip to content

Commit f9855ca

Browse files
committed
Bugfix: startup panic, blocking_lock in async ctx
- `live_event_task` used `tokio::sync::Mutex` but `blocking_lock()` was called from a tokio worker thread (via `tauri::async_runtime::spawn`), which panics - Switched to `std::sync::Mutex` — the lock is only held briefly to store/take a `JoinHandle`, never across an await point, so an async mutex was unnecessary - Fixed two unrelated eslint errors in `ScanStatusOverlay` and `AiSection`
1 parent 9493f88 commit f9855ca

4 files changed

Lines changed: 24 additions & 17 deletions

File tree

AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ There are two MCP servers available to you:
147147
## Things to avoid
148148

149149
- ❌ Don't touch git, user handles commits manually. Unless explicitly asked to.
150+
- ❌ NEVER use `git stash`, `git checkout`, `git reset`, or any write operation on git. Multiple agents may be working on the codebase simultaneously — stashing or checking out will silently destroy another agent's uncommitted work. To test whether a failure is pre-existing, use `isolation: "worktree"` via the Agent tool, or simply check `git log` / `git blame`.
150151
- ❌ Don't add JSDoc that just repeats types or obvious function names
151152
- ❌ Don't ignore linter warnings (fix them or justify with a comment)
152153
- ❌ Don't add dependencies without checking license compatibility (`cargo deny check`)

apps/desktop/src-tauri/src/ai/manager.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,12 @@ fn macos_memory_info() -> SystemMemoryInfo {
464464
// Free = everything not wired or app (includes file cache, inactive, purgeable, speculative)
465465
let free_bytes = total_bytes.saturating_sub(wired_bytes + app_bytes);
466466

467-
SystemMemoryInfo { total_bytes, wired_bytes, app_bytes, free_bytes }
467+
SystemMemoryInfo {
468+
total_bytes,
469+
wired_bytes,
470+
app_bytes,
471+
free_bytes,
472+
}
468473
}
469474

470475
/// Stores provider + context size + OpenAI config in manager state.

apps/desktop/src-tauri/src/indexing/mod.rs

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ pub struct IndexManager {
336336
drive_watcher: Option<DriveWatcher>,
337337
/// Live event processing task (runs after reconciliation completes).
338338
/// Shared with spawned async tasks so they can store the handle.
339-
live_event_task: Arc<tokio::sync::Mutex<Option<tauri::async_runtime::JoinHandle<()>>>>,
339+
live_event_task: Arc<std::sync::Mutex<Option<tauri::async_runtime::JoinHandle<()>>>>,
340340
/// Tauri app handle for emitting events
341341
app: AppHandle,
342342
/// Whether a full scan is currently running. Shared with the completion handler.
@@ -381,7 +381,7 @@ impl IndexManager {
381381
micro_scans,
382382
scan_handle: None,
383383
drive_watcher: None,
384-
live_event_task: Arc::new(tokio::sync::Mutex::new(None)),
384+
live_event_task: Arc::new(std::sync::Mutex::new(None)),
385385
app,
386386
scanning: Arc::new(AtomicBool::new(false)),
387387
})
@@ -531,7 +531,7 @@ impl IndexManager {
531531
}
532532
});
533533
{
534-
let mut guard = live_event_task_slot.blocking_lock();
534+
let mut guard = live_event_task_slot.lock().unwrap();
535535
*guard = Some(handle);
536536
}
537537

@@ -553,7 +553,7 @@ impl IndexManager {
553553
}
554554
mgr.drive_watcher = None;
555555
{
556-
let mut task_guard = mgr.live_event_task.blocking_lock();
556+
let mut task_guard = mgr.live_event_task.lock().unwrap();
557557
if let Some(task) = task_guard.take() {
558558
task.abort();
559559
}
@@ -793,8 +793,10 @@ impl IndexManager {
793793
});
794794

795795
// Store the handle so shutdown() can wait for it to drain
796-
let mut guard = live_event_task_slot.lock().await;
797-
*guard = Some(handle);
796+
{
797+
let mut guard = live_event_task_slot.lock().unwrap();
798+
*guard = Some(handle);
799+
}
798800

799801
// Store scan metadata via writer
800802
let now = std::time::SystemTime::now()
@@ -850,7 +852,7 @@ impl IndexManager {
850852

851853
// Abort the live event processing task
852854
{
853-
let mut guard = self.live_event_task.blocking_lock();
855+
let mut guard = self.live_event_task.lock().unwrap();
854856
if let Some(task) = guard.take() {
855857
task.abort();
856858
}
@@ -1006,19 +1008,18 @@ impl IndexManager {
10061008
// 3. Wait for the event loop to drain (process final batch + UpdateLastEventId).
10071009
// Use block_in_place so we can .await the join handle without blocking the
10081010
// tokio runtime thread pool.
1009-
let live_event_task = Arc::clone(&self.live_event_task);
1010-
tokio::task::block_in_place(|| {
1011-
tauri::async_runtime::block_on(async {
1012-
let mut guard = live_event_task.lock().await;
1013-
if let Some(task) = guard.take() {
1011+
let task = self.live_event_task.lock().unwrap().take();
1012+
if let Some(task) = task {
1013+
tokio::task::block_in_place(|| {
1014+
tauri::async_runtime::block_on(async {
10141015
match tokio::time::timeout(Duration::from_secs(5), task).await {
10151016
Ok(Ok(())) => log::debug!("Live event loop drained successfully"),
10161017
Ok(Err(e)) => log::debug!("Live event loop task error: {e}"),
10171018
Err(_) => log::warn!("Live event loop drain timed out after 5s"),
10181019
}
1019-
}
1020+
});
10201021
});
1021-
});
1022+
}
10221023

10231024
// 4. Now shut down the writer (all final writes have been queued)
10241025
self.writer.shutdown();

apps/desktop/src/lib/indexing/ScanStatusOverlay.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@
4747
if (rate <= 0) return ''
4848
const remaining = (aggTotal - aggCurrent) / rate
4949
if (remaining < 2) return 'Almost done'
50-
if (remaining < 60) return `${Math.round(remaining)}s left`
51-
return `${Math.round(remaining / 60)}m left`
50+
if (remaining < 60) return `${String(Math.round(remaining))}s left`
51+
return `${String(Math.round(remaining / 60))}m left`
5252
})
5353
5454
const showProgressBar = $derived(

0 commit comments

Comments
 (0)