From 993179c25ec4ed3249bb66d4634222ec340decae Mon Sep 17 00:00:00 2001 From: Christoph Brandau Date: Sun, 16 Aug 2026 15:54:54 +0200 Subject: [PATCH] feat(startup): wire startup repo path from CLI to UI The app now supports opening a repository at startup by reading a --repo argument and passing the path to the UI. A new startup repository state is managed in the backend and exposed via a tauri command and event, enabling the frontend to auto-open the repository when ready. The UI adds a small startup flow with retry handling to ensure the path is consumed once available. - Reads --repo or --repo=PATH and resolves relative paths - Signals UI to open startup repo via open-startup-repository - Frontend retries opening the repo until it succeeds --- src-tauri/src/main.rs | 89 +++++++++++++++++++++++++++++++++++++++++-- src/App.svelte | 40 +++++++++++++++++++ 2 files changed, 126 insertions(+), 3 deletions(-) diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 619935a..7e1f60e 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -31,9 +31,79 @@ use git::{ stash_drop, stash_pop, stash_push, undo_last_commit, unlock_worktree, unstage_files, update_remote, }; -use tauri::Manager; +use std::path::{Path, PathBuf}; +use std::sync::Mutex; +use tauri::{Emitter, Manager}; use telemetry::{emit_frontend_log, emit_frontend_span, set_telemetry_enabled}; +struct StartupRepository(Mutex>); + +fn repository_path_from_args(args: impl IntoIterator, cwd: &Path) -> Option { + let mut args = args.into_iter(); + let mut repository = None; + + while let Some(arg) = args.next() { + if arg == "--repo" { + repository = args.next(); + break; + } + if let Some(path) = arg.strip_prefix("--repo=") { + repository = Some(path.to_string()); + break; + } + if !arg.starts_with('-') { + repository = Some(arg); + break; + } + } + + repository.filter(|path| !path.trim().is_empty()).map(|path| { + let path = PathBuf::from(path); + if path.is_absolute() { + path + } else { + cwd.join(path) + } + .to_string_lossy() + .into_owned() + }) +} + +#[cfg(test)] +mod startup_repository_tests { + use super::repository_path_from_args; + use std::path::Path; + + #[test] + fn accepts_direct_relative_repository_path() { + let path = repository_path_from_args(["projects/repo".to_string()], Path::new("/home/user")); + assert_eq!(path.as_deref(), Some("/home/user/projects/repo")); + } + + #[test] + fn accepts_repo_option() { + let path = repository_path_from_args( + ["--repo".to_string(), "/projects/repo".to_string()], + Path::new("/home/user"), + ); + assert_eq!(path.as_deref(), Some("/projects/repo")); + } + + #[test] + fn accepts_repo_equals_option() { + let path = repository_path_from_args( + ["--repo=projects/repo".to_string()], + Path::new("/home/user"), + ); + assert_eq!(path.as_deref(), Some("/home/user/projects/repo")); + } +} + +#[tauri::command] +fn take_startup_repository(state: tauri::State<'_, StartupRepository>) -> Option { + state.0.lock().ok()?.take() +} + struct ConsoleLogger; impl log::Log for ConsoleLogger { @@ -96,8 +166,19 @@ async fn main() { return; } + let startup_repository = repository_path_from_args( + std::env::args().skip(1), + &std::env::current_dir().unwrap_or_default(), + ); + let builder = tauri::Builder::default() - .plugin(tauri_plugin_single_instance::init(|app, _, _| { + .plugin(tauri_plugin_single_instance::init(|app, args, cwd| { + if let Some(path) = repository_path_from_args(args.into_iter().skip(1), Path::new(&cwd)) { + if let Ok(mut pending) = app.state::().0.lock() { + *pending = Some(path); + } + let _ = app.emit("open-startup-repository", ()); + } #[cfg(desktop)] let _ = app .get_webview_window("main") @@ -112,6 +193,7 @@ async fn main() { }) .build(), ) + .manage(StartupRepository(Mutex::new(startup_repository))) .manage(SearchCancellationState::default()) .manage(commit_ai::CommitAiEngine::new()) .plugin(tauri_plugin_dialog::init()); @@ -226,7 +308,8 @@ async fn main() { close_splashscreen, set_telemetry_enabled, emit_frontend_log, - emit_frontend_span + emit_frontend_span, + take_startup_repository ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); diff --git a/src/App.svelte b/src/App.svelte index d323ec4..bdcb4bd 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -1,6 +1,7 @@