fix(settings): support custom git path and robust skills bundled scanning

This commit is contained in:
晴天
2026-04-05 21:33:35 +08:00
parent 2829be1bd2
commit b2ab316353
5 changed files with 372 additions and 33 deletions

View File

@@ -275,13 +275,27 @@ fn recommended_version_for(source: &str) -> Option<String> {
}
}
/// 获取用户配置的 git 可执行文件路径,回退到 "git"
fn configured_git_path() -> Option<String> {
super::read_panel_config_value()
.and_then(|v| v.get("gitPath")?.as_str().map(String::from))
.map(|custom| custom.trim().to_string())
.filter(|custom| !custom.is_empty())
}
/// 获取用户配置的 git 可执行文件路径,回退到 "git"
pub fn git_executable() -> String {
configured_git_path().unwrap_or_else(|| "git".into())
}
fn configure_git_https_rules() -> usize {
let git = git_executable();
// Collect unique target prefixes to unset old rules
let targets: std::collections::HashSet<&str> =
GIT_HTTPS_REWRITES.iter().map(|(t, _)| *t).collect();
for target in &targets {
let key = format!("url.{target}.insteadOf");
let mut unset = Command::new("git");
let mut unset = Command::new(&git);
unset.args(["config", "--global", "--unset-all", &key]);
#[cfg(target_os = "windows")]
unset.creation_flags(0x08000000);
@@ -291,7 +305,7 @@ fn configure_git_https_rules() -> usize {
let mut success = 0;
for (target, from) in GIT_HTTPS_REWRITES {
let key = format!("url.{target}.insteadOf");
let mut cmd = Command::new("git");
let mut cmd = Command::new(&git);
cmd.args(["config", "--global", "--add", &key, from]);
#[cfg(target_os = "windows")]
cmd.creation_flags(0x08000000);
@@ -303,6 +317,21 @@ fn configure_git_https_rules() -> usize {
}
fn apply_git_install_env(cmd: &mut Command) {
if let Some(custom_git) = configured_git_path() {
let git_path = PathBuf::from(&custom_git);
if let Some(parent) = git_path.parent() {
let mut paths: Vec<PathBuf> = std::env::var_os("PATH")
.map(|value| std::env::split_paths(&value).collect())
.unwrap_or_default();
if !paths.iter().any(|p| p == parent) {
paths.insert(0, parent.to_path_buf());
}
if let Ok(joined) = std::env::join_paths(paths) {
cmd.env("PATH", joined);
}
}
cmd.env("GIT", &custom_git);
}
crate::commands::apply_proxy_env(cmd);
cmd.env("GIT_TERMINAL_PROMPT", "0")
.env(
@@ -5297,8 +5326,15 @@ pub fn set_npm_registry(registry: String) -> Result<(), String> {
#[tauri::command]
pub fn check_git() -> Result<Value, String> {
let mut result = serde_json::Map::new();
let git_path = find_git_path();
let mut cmd = Command::new("git");
let configured = configured_git_path();
let git = configured.clone().unwrap_or_else(|| "git".into());
let is_custom = configured.is_some();
let git_path = if is_custom {
Some(git.clone())
} else {
find_git_path()
};
let mut cmd = Command::new(&git);
cmd.arg("--version");
#[cfg(target_os = "windows")]
cmd.creation_flags(0x08000000);
@@ -5311,11 +5347,13 @@ pub fn check_git() -> Result<Value, String> {
"path".into(),
git_path.map(Value::String).unwrap_or(Value::Null),
);
result.insert("isCustom".into(), Value::Bool(is_custom));
}
_ => {
result.insert("installed".into(), Value::Bool(false));
result.insert("version".into(), Value::Null);
result.insert("path".into(), Value::Null);
result.insert("isCustom".into(), Value::Bool(is_custom));
}
}
Ok(Value::Object(result))

View File

@@ -821,6 +821,36 @@ fn custom_skill_roots() -> Vec<(std::path::PathBuf, &'static str)> {
roots.push((claude_skills, "Claude 自定义"));
}
}
// 从已解析的 CLI 路径推导 npm 包内的 bundled skills 目录
// 例如 CLI 在 /usr/lib/node_modules/openclaw/bin/openclaw
// → 包根 /usr/lib/node_modules/openclaw/
// → skills 目录 /usr/lib/node_modules/openclaw/skills/
if let Some(cli_path) = crate::utils::resolve_openclaw_cli_path() {
let cli = std::path::PathBuf::from(&cli_path);
let cli = std::fs::canonicalize(&cli).unwrap_or(cli);
// CLI 可能在 bin/ 子目录或包根目录
for ancestor in [cli.parent(), cli.parent().and_then(|p| p.parent())] {
if let Some(pkg_root) = ancestor {
let bundled = pkg_root.join("skills");
if bundled.is_dir() && !roots.iter().any(|(dir, _)| dir == &bundled) {
roots.push((bundled, "OpenClaw 内置"));
break;
}
}
}
}
#[cfg(target_os = "windows")]
if let Some(prefix) = super::windows_npm_global_prefix() {
for pkg in ["openclaw", "@qingchencloud/openclaw-zh"] {
let bundled = std::path::PathBuf::from(&prefix)
.join("node_modules")
.join(pkg)
.join("skills");
if bundled.is_dir() && !roots.iter().any(|(dir, _)| dir == &bundled) {
roots.push((bundled, "OpenClaw 内置"));
}
}
}
roots
}