mirror of
https://github.com/different-ai/openwork
synced 2026-04-25 17:15:34 +02:00
bug: (#563)
Root cause: On macOS, GUI applications don't inherit shell profile modifications (.zshrc, .bashrc). When OpenWork spawns the opencode engine, the PATH doesn't include paths like /opt/homebrew/bin where Homebrew-installed tools like npx reside. The fix (packages/desktop/src-tauri/src/paths.rs): Added a common_tool_paths() function that returns typical locations where user-installed tools are found: - macOS: /opt/homebrew/bin, /usr/local/bin, ~/.nvm/current/bin, ~/.volta/bin, ~/.bun/bin, ~/.cargo/bin, etc. - Linux: Similar paths adapted for Linux conventions - Windows: volta, pnpm, cargo, npm global paths These paths are now prepended to the PATH environment variable when spawning processes. To test the fix: Build and run the app, then try enabling your Playwright MCP server - it should now find npx correctly without needing to specify the full path.
This commit is contained in:
12
package-lock.json
generated
Normal file
12
package-lock.json
generated
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"name": "@different-ai/openwork-workspace",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "@different-ai/openwork-workspace",
|
||||||
|
"version": "0.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -125,6 +125,89 @@ pub fn sidecar_path_candidates(
|
|||||||
unique
|
unique
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns common paths where user-installed tools are typically located.
|
||||||
|
/// On macOS, GUI apps don't inherit shell profile modifications (.zshrc, .bashrc),
|
||||||
|
/// so tools installed via Homebrew, nvm, volta, etc. won't be found unless we
|
||||||
|
/// explicitly include these common locations.
|
||||||
|
fn common_tool_paths() -> Vec<PathBuf> {
|
||||||
|
let mut paths = Vec::new();
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
{
|
||||||
|
// Homebrew paths (Apple Silicon and Intel)
|
||||||
|
paths.push(PathBuf::from("/opt/homebrew/bin"));
|
||||||
|
paths.push(PathBuf::from("/opt/homebrew/sbin"));
|
||||||
|
paths.push(PathBuf::from("/usr/local/bin"));
|
||||||
|
paths.push(PathBuf::from("/usr/local/sbin"));
|
||||||
|
|
||||||
|
// User-specific paths for common version managers
|
||||||
|
if let Some(home) = home_dir() {
|
||||||
|
// nvm, fnm (Node version managers)
|
||||||
|
paths.push(home.join(".nvm/current/bin"));
|
||||||
|
paths.push(home.join(".fnm/current/bin"));
|
||||||
|
// volta
|
||||||
|
paths.push(home.join(".volta/bin"));
|
||||||
|
// pnpm
|
||||||
|
paths.push(home.join("Library/pnpm"));
|
||||||
|
// bun
|
||||||
|
paths.push(home.join(".bun/bin"));
|
||||||
|
// cargo/rustup
|
||||||
|
paths.push(home.join(".cargo/bin"));
|
||||||
|
// pyenv
|
||||||
|
paths.push(home.join(".pyenv/shims"));
|
||||||
|
// local bin
|
||||||
|
paths.push(home.join(".local/bin"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
{
|
||||||
|
paths.push(PathBuf::from("/usr/local/bin"));
|
||||||
|
paths.push(PathBuf::from("/usr/local/sbin"));
|
||||||
|
|
||||||
|
if let Some(home) = home_dir() {
|
||||||
|
// nvm, fnm
|
||||||
|
paths.push(home.join(".nvm/current/bin"));
|
||||||
|
paths.push(home.join(".fnm/current/bin"));
|
||||||
|
// volta
|
||||||
|
paths.push(home.join(".volta/bin"));
|
||||||
|
// pnpm
|
||||||
|
paths.push(home.join(".local/share/pnpm"));
|
||||||
|
// bun
|
||||||
|
paths.push(home.join(".bun/bin"));
|
||||||
|
// cargo
|
||||||
|
paths.push(home.join(".cargo/bin"));
|
||||||
|
// pyenv
|
||||||
|
paths.push(home.join(".pyenv/shims"));
|
||||||
|
// local bin
|
||||||
|
paths.push(home.join(".local/bin"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
{
|
||||||
|
if let Some(home) = home_dir() {
|
||||||
|
// volta
|
||||||
|
paths.push(home.join(".volta/bin"));
|
||||||
|
// pnpm
|
||||||
|
if let Some(local) = env::var_os("LOCALAPPDATA") {
|
||||||
|
paths.push(PathBuf::from(local).join("pnpm"));
|
||||||
|
}
|
||||||
|
// bun
|
||||||
|
paths.push(home.join(".bun/bin"));
|
||||||
|
// cargo
|
||||||
|
paths.push(home.join(".cargo/bin"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// npm global
|
||||||
|
if let Some(app_data) = env::var_os("APPDATA") {
|
||||||
|
paths.push(PathBuf::from(app_data).join("npm"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
paths
|
||||||
|
}
|
||||||
|
|
||||||
pub fn prepended_path_env(prefixes: &[PathBuf]) -> Option<std::ffi::OsString> {
|
pub fn prepended_path_env(prefixes: &[PathBuf]) -> Option<std::ffi::OsString> {
|
||||||
let mut entries = Vec::<PathBuf>::new();
|
let mut entries = Vec::<PathBuf>::new();
|
||||||
|
|
||||||
@@ -134,8 +217,19 @@ pub fn prepended_path_env(prefixes: &[PathBuf]) -> Option<std::ffi::OsString> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add common tool paths that may not be in the GUI app's inherited PATH
|
||||||
|
for path in common_tool_paths() {
|
||||||
|
if path.is_dir() && !entries.contains(&path) {
|
||||||
|
entries.push(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(existing) = env::var_os("PATH") {
|
if let Some(existing) = env::var_os("PATH") {
|
||||||
entries.extend(env::split_paths(&existing));
|
for path in env::split_paths(&existing) {
|
||||||
|
if !entries.contains(&path) {
|
||||||
|
entries.push(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if entries.is_empty() {
|
if entries.is_empty() {
|
||||||
|
|||||||
Reference in New Issue
Block a user