goose2 session working dir (#8624)
This commit is contained in:
@@ -7,6 +7,7 @@ pub mod extensions;
|
||||
pub mod git;
|
||||
pub mod git_changes;
|
||||
pub mod model_setup;
|
||||
pub mod path_resolver;
|
||||
pub mod projects;
|
||||
pub mod skills;
|
||||
pub mod system;
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ResolvePathRequest {
|
||||
pub parts: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ResolvePathResponse {
|
||||
pub path: String,
|
||||
}
|
||||
|
||||
fn trim_part(part: &str) -> Option<&str> {
|
||||
let trimmed = part.trim();
|
||||
if trimmed.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(trimmed)
|
||||
}
|
||||
}
|
||||
|
||||
fn expand_home_prefix(part: &str) -> Option<PathBuf> {
|
||||
let home = dirs::home_dir()?;
|
||||
match part {
|
||||
"~" => Some(home),
|
||||
_ => part
|
||||
.strip_prefix("~/")
|
||||
.or_else(|| part.strip_prefix("~\\"))
|
||||
.map(|relative| home.join(relative)),
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_path_parts(parts: Vec<String>) -> Result<String, String> {
|
||||
let mut normalized_parts = parts.iter().filter_map(|part| trim_part(part)).peekable();
|
||||
|
||||
let first = normalized_parts
|
||||
.next()
|
||||
.ok_or_else(|| "Path parts must include at least one non-empty segment".to_string())?;
|
||||
let mut path = expand_home_prefix(first).unwrap_or_else(|| PathBuf::from(first));
|
||||
|
||||
for part in normalized_parts {
|
||||
path.push(part);
|
||||
}
|
||||
|
||||
Ok(path.to_string_lossy().into_owned())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn resolve_path(request: ResolvePathRequest) -> Result<ResolvePathResponse, String> {
|
||||
Ok(ResolvePathResponse {
|
||||
path: resolve_path_parts(request.parts)?,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::resolve_path_parts;
|
||||
|
||||
#[test]
|
||||
fn joins_absolute_path_and_subpath() {
|
||||
assert_eq!(
|
||||
resolve_path_parts(vec!["/tmp/project".to_string(), "artifacts".to_string()]),
|
||||
Ok("/tmp/project/artifacts".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ignores_empty_parts() {
|
||||
assert_eq!(
|
||||
resolve_path_parts(vec![" ".to_string(), "/tmp/project".to_string()]),
|
||||
Ok("/tmp/project".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expands_home_segments() {
|
||||
let Some(home) = dirs::home_dir() else {
|
||||
return;
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
resolve_path_parts(vec![
|
||||
"~".to_string(),
|
||||
".goose".to_string(),
|
||||
"artifacts".to_string()
|
||||
]),
|
||||
Ok(home
|
||||
.join(".goose")
|
||||
.join("artifacts")
|
||||
.to_string_lossy()
|
||||
.into_owned())
|
||||
);
|
||||
assert_eq!(
|
||||
resolve_path_parts(vec!["~/artifacts".to_string()]),
|
||||
Ok(home.join("artifacts").to_string_lossy().into_owned())
|
||||
);
|
||||
assert_eq!(
|
||||
resolve_path_parts(vec!["~\\artifacts".to_string()]),
|
||||
Ok(home.join("artifacts").to_string_lossy().into_owned())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn errors_when_no_non_empty_parts_exist() {
|
||||
assert_eq!(
|
||||
resolve_path_parts(vec![" ".to_string(), "".to_string()]),
|
||||
Err("Path parts must include at least one non-empty segment".to_string())
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -84,6 +84,7 @@ pub fn run() {
|
||||
commands::agent_setup::check_agent_auth,
|
||||
commands::agent_setup::install_agent,
|
||||
commands::agent_setup::authenticate_agent,
|
||||
commands::path_resolver::resolve_path,
|
||||
commands::system::get_home_dir,
|
||||
commands::system::save_exported_session_file,
|
||||
commands::system::path_exists,
|
||||
|
||||
Reference in New Issue
Block a user