Skip to content

Commit de7ca50

Browse files
fix(Mountain): Prevent duplicate shutdown and fix static asset path resolution
Add atomic shutdown guard to Entry.rs to prevent the graceful shutdown sequence from running twice. The graceful path ends with `app_handle.exit(0)` which Tauri re-delivers as a second `ExitRequested { code: Some(0) }`. On re-entry we must NOT `prevent_exit` or spawn the shutdown task again — Cocoon has already been SIGKILLed and the second pass would log spurious "tcp connect error" warnings trying to notify a dead sidecar. Extend the static asset path resolution in Utilities.rs to handle both `/Static/Application/` and `Static/Application/` forms. The webview's WASM loader (`vscode-oniguruma` → `onig.wasm`) resolves asset URLs relative to the current document, which strips the leading slash before the path reaches the `file:read` IPC handler. Without this fix, `tokio::fs::read` would fail with ENOENT, breaking TextMate syntax highlighting. Also expand the benign ENOENT ignore list in DevLog.rs to suppress warnings for: `.copilot/agents`, `.vscode/tasks.json`, `/User/tasks.json`, `/User/mcp.json`, `vscode-chat-images`, and `/output_<TIMESTAMP>` window log file patterns.
1 parent 8a06b85 commit de7ca50

3 files changed

Lines changed: 40 additions & 3 deletions

File tree

Source/Binary/Main/Entry.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
//! - [ ] Add startup performance metrics
6060
6161
use std::sync::Arc;
62+
use std::sync::atomic::{AtomicBool, Ordering};
6263

6364
use tauri::{App, Manager, RunEvent, Wry};
6465
use Echo::Scheduler::{Scheduler::Scheduler, SchedulerBuilder::SchedulerBuilder};
@@ -556,6 +557,18 @@ pub fn Fn() {
556557
}
557558

558559
if let RunEvent::ExitRequested { api, .. } = event {
560+
// Shutdown runs once. The graceful path ends with
561+
// `app_handle.exit(0)`, which Tauri re-delivers as a
562+
// second `ExitRequested { code: Some(0) }`. On re-entry
563+
// we must NOT `prevent_exit` or spawn the shutdown task
564+
// again - Cocoon has already been SIGKILLed and the
565+
// second pass would log spurious "tcp connect error"
566+
// warnings trying to notify a dead sidecar.
567+
static SHUTTING_DOWN:AtomicBool = AtomicBool::new(false);
568+
if SHUTTING_DOWN.swap(true, Ordering::SeqCst) {
569+
return;
570+
}
571+
559572
dev_log!(
560573
"lifecycle",
561574
"warn: [Lifecycle] [Shutdown] Exit requested. Starting graceful shutdown..."

Source/IPC/DevLog.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,11 +345,13 @@ const BENIGN_ENOENT_SUBSTRINGS:&[&str] = &[
345345
".claude/agents",
346346
".claude/settings.json",
347347
".claude/settings.local.json",
348+
".copilot/agents",
348349
".github/copilot",
349350
".github/agents",
350351
".vscode/settings.json",
351352
".vscode/launch.json",
352353
".vscode/extensions.json",
354+
".vscode/tasks.json",
353355
"agentPlugins",
354356
"agent-plugins",
355357
"chatEditingSessions",
@@ -358,6 +360,17 @@ const BENIGN_ENOENT_SUBSTRINGS:&[&str] = &[
358360
"machineid",
359361
"terminalSuggestGlobalsCacheV2.json",
360362
"globalStorage",
363+
// Optional user-level workbench config files. On fresh profiles these do
364+
// not exist; the workbench probes them on every boot and creates on first
365+
// write. These are the `$APP/User/<file>` forms emitted after
366+
// `resolve_userdata`.
367+
"/User/tasks.json",
368+
"/User/mcp.json",
369+
// Chat images cache directory is lazy-created on first chat attachment.
370+
"vscode-chat-images",
371+
// Per-window output channel log files probed lazily by the workbench
372+
// before first write. Path shape: `$APP/logs/<SESSION>/window<N>/output_<TIMESTAMP>`.
373+
"/output_20",
361374
// Virtual scheme misses already covered by earlier batches.
362375
"vscode://schemas-associations/",
363376
];

Source/IPC/WindServiceHandlers/Utilities.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,13 +135,24 @@ fn resolve_userdata_path(Path:&str) -> String {
135135

136136
/// Map paths starting with /Static/Application/ to the real Sky Target
137137
/// directory.
138+
///
139+
/// Also accepts the leading-slash-less form `Static/Application/...`: the
140+
/// webview's WASM loader (`vscode-oniguruma` → `onig.wasm`) resolves the
141+
/// asset URL relative to the current document, which strips the leading
142+
/// slash before the path reaches the `file:read` IPC handler. Without this
143+
/// branch, `tokio::fs::read` would be called with a relative path and fail
144+
/// with ENOENT, breaking TextMate syntax highlighting.
138145
fn resolve_static_application_path(Path:&str) -> String {
139-
if !Path.starts_with("/Static/Application/") && Path != "/Static/Application" {
146+
let Normalized = if Path.starts_with("/Static/Application/") || Path == "/Static/Application" {
147+
Path.to_string()
148+
} else if Path.starts_with("Static/Application/") || Path == "Static/Application" {
149+
format!("/{}", Path)
150+
} else {
140151
return Path.to_string();
141-
}
152+
};
142153

143154
if let Some(Root) = STATIC_APPLICATION_ROOT.get() {
144-
let Relative = Path.strip_prefix("/Static/Application").unwrap_or("");
155+
let Relative = Normalized.strip_prefix("/Static/Application").unwrap_or("");
145156
let Resolved = format!("{}/Static/Application{}", Root, Relative);
146157
dev_log!("vfs", "resolve_static: {} -> {}", Path, Resolved);
147158
Resolved

0 commit comments

Comments
 (0)