fix(browser): platform-aware error messages with WSL detection
- Add is_wsl() detection via /proc/version - Add example_npx_path() returning platform-appropriate example path - Replace all hardcoded macOS paths in error messages with dynamic ones - Add WSL-specific hints: Node.js must be installed inside WSL, not Windows - WSL hint includes nvm install instructions - Clean build: 0 errors, 0 warnings
This commit is contained in:
@@ -11,12 +11,19 @@
|
|||||||
//! 3. Waits for the Unix socket to appear (up to 30 seconds)
|
//! 3. Waits for the Unix socket to appear (up to 30 seconds)
|
||||||
//! 4. Returns a ready-to-use `BrowserClient`
|
//! 4. Returns a ready-to-use `BrowserClient`
|
||||||
//!
|
//!
|
||||||
//! # Cross-platform npx resolution
|
//! Cross-platform npx resolution
|
||||||
//!
|
//!
|
||||||
//! The daemon is started via Node.js's `npx`. Resolution order:
|
//! The daemon is started via Node.js's `npx`. Resolution order:
|
||||||
//! 1. `config.browser.node_path` — explicit path in config (e.g.
|
//! 1. `config.browser.node_path` — explicit path in config (e.g.
|
||||||
//! `/home/user/.nvm/versions/node/v22/bin/npx`)
|
//! `/home/user/.nvm/versions/node/v22/bin/npx`)
|
||||||
//! 2. `"npx"` on Linux/macOS, `"npx.cmd"` on Windows — PATH lookup
|
//! 2. `"npx"` on Linux/macOS, `"npx.cmd"` on Windows — PATH lookup
|
||||||
|
//!
|
||||||
|
//! WSL Detection
|
||||||
|
//!
|
||||||
|
//! Windows Subsystem for Linux is detected by reading `/proc/version` for
|
||||||
|
//! the presence of "microsoft" or "wsl" (case-insensitive). WSL-specific
|
||||||
|
//! error messages guide users to ensure Node.js is installed via nvm or
|
||||||
|
//! fnm inside WSL (not via the Windows-side Node).
|
||||||
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
@@ -61,6 +68,28 @@ fn resolve_npx(node_path: Option<&str>) -> &str {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Detect if we're running inside Windows Subsystem for Linux (WSL).
|
||||||
|
///
|
||||||
|
/// Checks `/proc/version` for the presence of "microsoft" or "wsl"
|
||||||
|
/// (case-insensitive). Returns `true` if WSL is detected.
|
||||||
|
fn is_wsl() -> bool {
|
||||||
|
std::fs::read_to_string("/proc/version")
|
||||||
|
.map(|content| {
|
||||||
|
let lower = content.to_lowercase();
|
||||||
|
lower.contains("microsoft") || lower.contains("wsl")
|
||||||
|
})
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a platform-aware example npx path for error messages.
|
||||||
|
fn example_npx_path() -> &'static str {
|
||||||
|
if cfg!(target_os = "macos") {
|
||||||
|
"\"/Users/yourname/.nvm/versions/node/v22/bin/npx\""
|
||||||
|
} else {
|
||||||
|
"\"/home/user/.nvm/versions/node/v22/bin/npx\""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Initialize the camoufox-browser daemon and return a ready client.
|
/// Initialize the camoufox-browser daemon and return a ready client.
|
||||||
///
|
///
|
||||||
/// `node_path` — optional explicit path to `npx`/`npx.cmd` (from
|
/// `node_path` — optional explicit path to `npx`/`npx.cmd` (from
|
||||||
@@ -93,7 +122,7 @@ pub async fn init_browser(node_path: Option<&str>) -> BrowserInitResult {
|
|||||||
}
|
}
|
||||||
Ok(false) => {
|
Ok(false) => {
|
||||||
let msg = format!(
|
let msg = format!(
|
||||||
"Daemon did not start within {}s — socket not found at {}",
|
"Daemon did not start within {}s \u{2014} socket not found at {}",
|
||||||
DAEMON_STARTUP_TIMEOUT_SECS,
|
DAEMON_STARTUP_TIMEOUT_SECS,
|
||||||
socket_path.display()
|
socket_path.display()
|
||||||
);
|
);
|
||||||
@@ -109,18 +138,33 @@ pub async fn init_browser(node_path: Option<&str>) -> BrowserInitResult {
|
|||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let npx_name = resolve_npx(node_path);
|
let npx_name = resolve_npx(node_path);
|
||||||
let msg = format!(
|
let mut msg = format!(
|
||||||
"Could not start camoufox daemon: {}\n\n\
|
"Could not start camoufox daemon: {}\n\n\
|
||||||
Make sure Node.js v20+ and the package are installed:\n \
|
Make sure Node.js v20+ and the package are installed:\n \
|
||||||
npm install -g camoufox-browser\n \
|
npm install -g camoufox-browser\n \
|
||||||
{} camoufox-browser@latest install\n\n\
|
{} camoufox-browser@latest install\n\n\
|
||||||
If Node is installed via nvm/fnm/asdf, set browser.node_path\n\
|
If Node is installed via nvm/fnm/asdf, set browser.node_path\n\
|
||||||
in your config, e.g.:\n \
|
in your config:\n \
|
||||||
[browser]\n \
|
[browser]\n \
|
||||||
node_path = \"/home/user/.nvm/versions/node/v22/bin/npx\"\n\n\
|
node_path = {}\n\n\
|
||||||
Then try again.",
|
Then try again.",
|
||||||
e, npx_name
|
e, npx_name, example_npx_path()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Add WSL-specific hints
|
||||||
|
if is_wsl() {
|
||||||
|
msg.push_str(
|
||||||
|
"\n\n\u{26a0}\u{fe0f} WSL detected: Make sure Node.js is installed INSIDE WSL\n\
|
||||||
|
(e.g., via nvm or fnm in your WSL terminal). The Windows-side\n\
|
||||||
|
Node.js is not accessible from WSL by default.\n\
|
||||||
|
Test with: which npx\n\
|
||||||
|
If 'which npx' returns empty, run:\n \
|
||||||
|
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash\n \
|
||||||
|
nvm install 22\n\
|
||||||
|
Then run 'gyandoot run' again.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
warn!("{}", msg);
|
warn!("{}", msg);
|
||||||
BrowserInitResult::Unavailable(msg)
|
BrowserInitResult::Unavailable(msg)
|
||||||
}
|
}
|
||||||
@@ -148,11 +192,27 @@ async fn trigger_daemon_start(session: &str, node_path: Option<&str>) -> Result<
|
|||||||
.await
|
.await
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
let hint = if node_path.is_none() {
|
let hint = if node_path.is_none() {
|
||||||
"\n → Set [browser].node_path in your config, e.g.:\n [browser]\n node_path = \"/Users/yourname/.nvm/versions/node/v22/bin/npx\"".to_string()
|
format!(
|
||||||
|
"\n \u{2192} Set [browser].node_path in your config:\n [browser]\n node_path = {}",
|
||||||
|
example_npx_path()
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
format!("\n → npx at '{}' not found or not executable", npx)
|
format!("\n \u{2192} npx at '{}' not found or not executable", npx)
|
||||||
};
|
};
|
||||||
format!("{} failed: {}. Is Node.js installed?{}", npx, e, hint)
|
|
||||||
|
let wsl_hint = if is_wsl() {
|
||||||
|
"\n\n\u{26a0}\u{fe0f} WSL detected: npx was not found. Install Node.js inside WSL:\n \
|
||||||
|
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash\n \
|
||||||
|
nvm install 22"
|
||||||
|
.to_string()
|
||||||
|
} else {
|
||||||
|
String::new()
|
||||||
|
};
|
||||||
|
|
||||||
|
format!(
|
||||||
|
"{} failed: {}. Is Node.js installed?{}{}",
|
||||||
|
npx, e, hint, wsl_hint
|
||||||
|
)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
if !output.status.success() {
|
if !output.status.success() {
|
||||||
@@ -169,17 +229,27 @@ async fn trigger_daemon_start(session: &str, node_path: Option<&str>) -> Result<
|
|||||||
));
|
));
|
||||||
|
|
||||||
let hint = if node_path.is_none() {
|
let hint = if node_path.is_none() {
|
||||||
"\n → Try setting [browser].node_path in your config:\n [browser]\n node_path = \"/Users/yourname/.nvm/versions/node/v22/bin/npx\"".to_string()
|
format!(
|
||||||
|
"\n \u{2192} Try setting [browser].node_path in your config:\n [browser]\n node_path = {}",
|
||||||
|
example_npx_path()
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
String::new()
|
||||||
|
};
|
||||||
|
|
||||||
|
let wsl_hint = if is_wsl() {
|
||||||
|
"".to_string()
|
||||||
} else {
|
} else {
|
||||||
String::new()
|
String::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"camoufox-browser failed (exit: {}):\n {}\n → Full log saved to {}{}",
|
"camoufox-browser failed (exit: {}):\n {}\n \u{2192} Full log saved to {}{}{}",
|
||||||
output.status.code().unwrap_or(-1),
|
output.status.code().unwrap_or(-1),
|
||||||
details,
|
details,
|
||||||
log_file.display(),
|
log_file.display(),
|
||||||
hint,
|
hint,
|
||||||
|
wsl_hint,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user