-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Read paths from an interactive & login shell #5774
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
6136df0 to
07981df
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR adds functionality to read PATH environment variables from an interactive and login shell, addressing the common issue where GUI-launched applications don't inherit the user's shell PATH configuration.
Key changes:
- New
paths.rsmodule that asynchronously retrieves PATH from the user's shell using login and interactive modes - Integration in
rmcp_developer.rsto override PATH before executing shell commands - Lazy initialization with caching to avoid repeatedly spawning shells
Reviewed Changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| crates/goose-mcp/src/developer/paths.rs | New module implementing shell PATH retrieval with platform-specific logic for Unix and Windows, using OnceCell for caching |
| crates/goose-mcp/src/developer/rmcp_developer.rs | Integrates shell PATH retrieval by calling get_shell_path_dirs() and setting PATH environment variable before command execution |
| crates/goose-mcp/src/developer/mod.rs | Exposes the new paths module as public |
| let output = output.map_err(|e| anyhow::anyhow!("Failed to execute shell command: {}", e))?; | ||
|
|
||
| if !output.status.success() { | ||
| let stderr = String::from_utf8_lossy(&output.stderr); |
Copilot
AI
Nov 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The -NoProfile flag prevents loading PowerShell profiles, which means this won't get the user's customized PATH. This is inconsistent with the Unix implementation which uses -l (login) to load profiles. Consider removing -NoProfile or using -NoLogo instead if you want to suppress the banner while still loading profiles.
| .map_err(|e| anyhow::anyhow!("Invalid UTF-8 in shell output: {}", e))? | ||
| .trim() | ||
| .to_string(); | ||
|
|
Copilot
AI
Nov 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The -l -i flag combination will fail with fish shell, which doesn't support using -l with -c. Consider using only -l (login mode sources profile files) or detecting the shell type and adjusting flags accordingly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i mean fish?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I blindly accepted copilot's suggestion, but if I try it myself this works just fine:
% fish -i -l -c 'echo $PATH'
/usr/local/bin ...
| async fn get_shell_path_async() -> Result<String> { | ||
| let shell = env::var("SHELL").unwrap_or_else(|_| { | ||
| if cfg!(windows) { | ||
| "cmd".to_string() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could use a macro, but then I think this is probably fine (and probably less lines of code)
| }); | ||
|
|
||
| { | ||
| #[cfg(windows)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if using macro here, could use it for if statement above?
|
I think this is good - the copilot feedback if right is quite helpful (ie powershell woudln't pick things up, and fish shell would break with -c - not sure if true though!) |
| .map_err(|e| anyhow::anyhow!("Invalid UTF-8 in shell output: {}", e))? | ||
| .trim() | ||
| .to_string(); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i mean fish?
|
@DOsinga fish shell has a lot of fans! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Copilot reviewed 9 out of 10 changed files in this pull request and generated 2 comments.
crates/goose-cli/src/cli.rs
Outdated
| Some(Command::Mcp { server }) => match server { | ||
| McpCommand::AutoVisualiser => serve(AutoVisualiserRouter::new()).await?, | ||
| McpCommand::ComputerController => serve(ComputerControllerServer::new()).await?, | ||
| McpCommand::Memory => serve(MemoryServer::new()).await?, | ||
| McpCommand::Tutorial => serve(TutorialServer::new()).await?, | ||
| McpCommand::Developer => serve(DeveloperServer::new()).await?, |
Copilot
AI
Nov 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Logging setup was removed for MCP commands. This means MCP servers started via goose-cli won't have logging configured. Consider adding crate::logging::setup_logging(Some(&format!("mcp-{}", server.name())), None)?; before the match statement.
| Some(Command::Mcp { server }) => match server { | |
| McpCommand::AutoVisualiser => serve(AutoVisualiserRouter::new()).await?, | |
| McpCommand::ComputerController => serve(ComputerControllerServer::new()).await?, | |
| McpCommand::Memory => serve(MemoryServer::new()).await?, | |
| McpCommand::Tutorial => serve(TutorialServer::new()).await?, | |
| McpCommand::Developer => serve(DeveloperServer::new()).await?, | |
| Some(Command::Mcp { server }) => { | |
| crate::logging::setup_logging(Some(&format!("mcp-{}", server.name())), None)?; | |
| match server { | |
| McpCommand::AutoVisualiser => serve(AutoVisualiserRouter::new()).await?, | |
| McpCommand::ComputerController => serve(ComputerControllerServer::new()).await?, | |
| McpCommand::Memory => serve(MemoryServer::new()).await?, | |
| McpCommand::Tutorial => serve(TutorialServer::new()).await?, | |
| McpCommand::Developer => serve(DeveloperServer::new()).await?, | |
| } |
| let output = Command::new(shell) | ||
| .args(["-l", "-i", "-c", "echo $PATH"]) |
Copilot
AI
Nov 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The -i flag is not supported by fish shell, which will cause this command to fail for fish users. Consider conditionally using ["-l", "-c", "echo $PATH"] for fish and ["-l", "-i", "-c", "echo $PATH"] for bash/zsh.
| let output = Command::new(shell) | |
| .args(["-l", "-i", "-c", "echo $PATH"]) | |
| // Use different args for fish shell, which does not support -i | |
| let shell_name = std::path::Path::new(shell) | |
| .file_stem() | |
| .and_then(|s| s.to_str()) | |
| .unwrap_or(""); | |
| let args: [&str; 4] = if shell_name == "fish" { | |
| ["-l", "", "-c", "echo $PATH"] | |
| } else { | |
| ["-l", "-i", "-c", "echo $PATH"] | |
| }; | |
| // Remove empty string from args for fish | |
| let args: Vec<&str> = args.iter().filter(|&&a| !a.is_empty()).copied().collect(); | |
| let output = Command::new(shell) | |
| .args(&args) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Copilot reviewed 9 out of 10 changed files in this pull request and generated 2 comments.
| McpCommand::ComputerController => serve(ComputerControllerServer::new()).await?, | ||
| McpCommand::Memory => serve(MemoryServer::new()).await?, | ||
| McpCommand::Tutorial => serve(TutorialServer::new()).await?, | ||
| McpCommand::Developer => serve(DeveloperServer::new()).await?, |
Copilot
AI
Nov 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The goose-cli Developer server doesn't enable shell PATH extension like goose-server does. This creates inconsistent behavior - users will get different PATH environments depending on which binary they use. Either add .extend_path_with_shell(true).bash_env_file(Some(Paths::config_dir().join(\".bash_env\"))) here to match goose-server, or document why the CLI version intentionally has different behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes that is the idea!
| fn safe_truncate(s: &str, max_chars: usize) -> String { | ||
| if s.chars().count() <= max_chars { | ||
| s.to_string() | ||
| } else { | ||
| let truncated: String = s.chars().take(max_chars.saturating_sub(3)).collect(); | ||
| format!("{}...", truncated) | ||
| } | ||
| } |
Copilot
AI
Nov 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duplicating safe_truncate creates a maintenance burden - changes to the original won't propagate here. Consider creating a shared utility crate that both goose and goose-mcp can depend on, or re-evaluate whether breaking the goose dependency is worth this duplication.
| fn safe_truncate(s: &str, max_chars: usize) -> String { | |
| if s.chars().count() <= max_chars { | |
| s.to_string() | |
| } else { | |
| let truncated: String = s.chars().take(max_chars.saturating_sub(3)).collect(); | |
| format!("{}...", truncated) | |
| } | |
| } | |
| use goose_util::safe_truncate; |
…xt-test * 'main' of github.com:block/goose: chore: Add Adrian Cole to Maintainers (#5815) [MCP-UI] Proxy and Better Message Handling (#5487) Release 1.15.0 Document New Window menu in macOS dock (#5811) Catch cron errors (#5707) feat/fix Re-enabled WAL with commit transaction management (Linux Verification Requested) (#5793) chore: remove autopilot experimental feature (#5781) Read paths from an interactive & login shell (#5774) docs: acp clients (#5800)
* main: feat/fix Re-enabled WAL with commit transaction management (Linux Verification Requested) (#5793) chore: remove autopilot experimental feature (#5781) Read paths from an interactive & login shell (#5774) docs: acp clients (#5800) Provider error proxy for simulating various types of errors (#5091) chore: Add links to maintainer profiles (#5788) Quick fix for community all stars script (#5798) Document Mistral AI provider (#5799) docs: Add Community Stars recipe script and txt file (#5776)
* main: (33 commits) fix: support Gemini 3's thought signatures (#5806) chore: Add Adrian Cole to Maintainers (#5815) [MCP-UI] Proxy and Better Message Handling (#5487) Release 1.15.0 Document New Window menu in macOS dock (#5811) Catch cron errors (#5707) feat/fix Re-enabled WAL with commit transaction management (Linux Verification Requested) (#5793) chore: remove autopilot experimental feature (#5781) Read paths from an interactive & login shell (#5774) docs: acp clients (#5800) Provider error proxy for simulating various types of errors (#5091) chore: Add links to maintainer profiles (#5788) Quick fix for community all stars script (#5798) Document Mistral AI provider (#5799) docs: Add Community Stars recipe script and txt file (#5776) chore: incorporate LF feedback (#5787) docs: quick launcher (#5779) Bump auto scroll threshold (#5738) fix: add one-time cleanup for linux hermit locking issues (#5742) Don't show update tray icon if GOOSE_VERSION is set (#5750) ...
Signed-off-by: Blair Allan <[email protected]>
No description provided.