Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,9 @@ keyboard alone, and the mouse stays first-class.
checks, conflicts, merge state, and provider freshness before merging with
merge-commit, squash, or rebase through a GitHub-style split control.
Authentication stays in the signed-in `gh` / `az` CLI; provider policies
remain enforced. Azure inline comments need iteration tracking and
remain enforced. Packaged desktop builds import the user's shell `PATH`, so
Homebrew and version-manager CLI installs work without a custom path. Azure
inline comments need iteration tracking and
submit-review and other lifecycle actions are still in progress.
- **Worktrees (⌘5)** — an AI-agent dashboard for every worktree with stable
repo naming, branch/session labels, dirty count, ±lines, "touched 3m ago"
Expand Down Expand Up @@ -131,7 +133,9 @@ keyboard alone, and the mouse stays first-class.
unstaged changes when nothing is staged) via
your ChatGPT subscription (Codex CLI, `gpt-5.6-luna`) or Claude Code CLI
(`claude-sonnet-5`); Settings → AI for sign-in, provider choice, and CLI
health checks. Generation is cancellable, scans conservative sensitive-file
health checks. Packaged builds resolve these tools and their runtimes through
the user's shell `PATH`; custom paths remain available. Generation is
cancellable, scans conservative sensitive-file
signals before provider launch, reports partial-context coverage, preserves
the replaced draft for one-step undo, and can retry explicitly with the other
provider without changing your default. Repository-family writing profiles
Expand Down
8 changes: 8 additions & 0 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -1659,6 +1659,14 @@ short-hash context and read-only tree actions. Opening a historical file pins
Content, image/SVG previews, Markdown, and repo-relative Markdown images to the
same revision instead of accidentally reading the mutable working tree.

**Packaged CLI discovery fixed (2026-07-15):** Desktop launches now recover
the user's interactive login-shell PATH once in the background and pass the
merged value directly to hosted-provider and AI CLI children. Release builds
therefore find Homebrew, local-bin, and version-manager installs of
`gh`/`az`/`codex`/`claude`, including npm launchers whose `env node` runtime
also depends on PATH, while executable lookup remains outside the untrusted
repository working directory.

---

## 1.1+ — Post-1.0
Expand Down
5 changes: 5 additions & 0 deletions TASKS.md
Original file line number Diff line number Diff line change
Expand Up @@ -1782,6 +1782,11 @@ extraction above as prerequisite. **Do not start before 1.0 ships**
stops per-call console flashes in the release build; CommitBar surfaces
suggest failures inline as "Suggestion failed: …" instead of a silently
disabled sparkle / mislabeled "Commit failed:")
- ☑ Desktop-launch CLI environment restoration (`path_env.rs` asynchronously
captures the interactive login-shell PATH once and retains conventional
Homebrew/local-bin fallbacks; shared canonical lookup, blank-override
normalization, and child PATH propagation make `gh`/`az`/`codex`/`claude`
plus npm runtimes available in packaged apps without searching the repo)
- ☑ Broken vendor-CLI installs stay distinct from signed-out sessions
(`AiProviderStatus.error`, auth-failure classification, and `--version`
login preflight prevent false “browser opened” messages)
Expand Down
19 changes: 16 additions & 3 deletions crates/strand-tauri/src/ai/bin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ pub fn resolve_claude(override_path: Option<&str>) -> Option<PathBuf> {
}

pub(crate) fn resolve_cli(default_name: &str, override_path: Option<&str>) -> Option<PathBuf> {
if let Some(p) = override_path {
if let Some(p) = override_path.filter(|path| !path.trim().is_empty()) {
let path = PathBuf::from(p);
return canonical_spawnable(&path);
}
Expand Down Expand Up @@ -76,7 +76,7 @@ fn canonical_spawnable(path: &Path) -> Option<PathBuf> {
}

fn which_on_path(name: &str) -> Option<PathBuf> {
let path_var = std::env::var_os("PATH")?;
let path_var = crate::path_env::effective_path()?;
let dirs: Vec<PathBuf> = std::env::split_paths(&path_var).collect();
find_in_dirs(name, &dirs)
}
Expand Down Expand Up @@ -128,12 +128,19 @@ pub(crate) fn base_command(program: &Path, hide_console: bool) -> Command {
const CREATE_NO_WINDOW: u32 = 0x0800_0000;
cmd.creation_flags(CREATE_NO_WINDOW);
}
if let Some(path) = crate::path_env::effective_path() {
cmd.env("PATH", path);
}
cmd
}
#[cfg(not(windows))]
{
let _ = hide_console;
Command::new(program)
let mut cmd = Command::new(program);
if let Some(path) = crate::path_env::effective_path() {
cmd.env("PATH", path);
}
cmd
}
}

Expand Down Expand Up @@ -463,6 +470,12 @@ mod tests {
assert_eq!(resolved, std::fs::canonicalize(path).ok());
}

#[cfg(unix)]
#[test]
fn blank_override_falls_back_to_path() {
assert!(resolve_cli("sh", Some(" \t ")).is_some());
}

#[cfg(unix)]
#[test]
fn override_rejects_non_executable_file() {
Expand Down
6 changes: 6 additions & 0 deletions crates/strand-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

mod ai;
mod commands;
mod path_env;
mod pull_requests;
mod state;

Expand Down Expand Up @@ -43,6 +44,11 @@ fn main() {
.unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("strand=info,strand_core=info"));
tracing_subscriber::fmt().with_env_filter(filter).init();

// GUI launchers commonly omit the user's shell PATH. Resolve it in the
// background so provider and AI CLIs are ready without delaying the first
// window; child commands receive it explicitly (see `path_env`).
path_env::warm_up();

// Process-global git engine setup (disables git2's owner validation so it
// opens the same repos gix already does — see strand_core::init). Must run
// before the Tauri runtime spawns any command thread.
Expand Down
Loading
Loading