mirror of
https://github.com/qingchencloud/clawpanel.git
synced 2026-05-29 20:30:00 +08:00
fix(gateway): release 0.16.5
This commit is contained in:
@@ -2496,12 +2496,37 @@ fn scan_all_installations(
|
||||
try_add(prefix_path.join("openclaw"));
|
||||
}
|
||||
if let Ok(localappdata) = std::env::var("LOCALAPPDATA") {
|
||||
let localappdata_path = std::path::PathBuf::from(&localappdata);
|
||||
try_add(
|
||||
std::path::PathBuf::from(&localappdata)
|
||||
localappdata_path
|
||||
.join("Programs")
|
||||
.join("OpenClaw")
|
||||
.join("openclaw.exe"),
|
||||
);
|
||||
try_add(localappdata_path.join("OpenClaw").join("openclaw.cmd"));
|
||||
try_add(localappdata_path.join("OpenClaw").join("openclaw.exe"));
|
||||
try_add(
|
||||
localappdata_path
|
||||
.join("Programs")
|
||||
.join("nodejs")
|
||||
.join("openclaw.cmd"),
|
||||
);
|
||||
try_add(
|
||||
localappdata_path
|
||||
.join("Programs")
|
||||
.join("nodejs")
|
||||
.join("openclaw.exe"),
|
||||
);
|
||||
try_add(
|
||||
localappdata_path
|
||||
.join("Programs")
|
||||
.join("nodejs")
|
||||
.join("node_modules")
|
||||
.join("@qingchencloud")
|
||||
.join("openclaw-zh")
|
||||
.join("bin")
|
||||
.join("openclaw.js"),
|
||||
);
|
||||
}
|
||||
if let Ok(program_files) = std::env::var("ProgramFiles") {
|
||||
try_add(
|
||||
@@ -2607,6 +2632,15 @@ fn scan_all_installations(
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
try_add(base.join("openclaw.cmd"));
|
||||
try_add(base.join("openclaw.exe"));
|
||||
try_add(base.join("openclaw"));
|
||||
try_add(
|
||||
base.join("node_modules")
|
||||
.join("@qingchencloud")
|
||||
.join("openclaw-zh")
|
||||
.join("bin")
|
||||
.join("openclaw.js"),
|
||||
);
|
||||
}
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
|
||||
@@ -1,6 +1,142 @@
|
||||
#[cfg(target_os = "windows")]
|
||||
use std::os::windows::process::CommandExt;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn push_unique_candidate(
|
||||
candidates: &mut Vec<std::path::PathBuf>,
|
||||
seen: &mut std::collections::HashSet<String>,
|
||||
path: std::path::PathBuf,
|
||||
) {
|
||||
let key = path.to_string_lossy().replace('/', "\\").to_lowercase();
|
||||
if seen.insert(key) {
|
||||
candidates.push(path);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn push_windows_cli_files(
|
||||
candidates: &mut Vec<std::path::PathBuf>,
|
||||
seen: &mut std::collections::HashSet<String>,
|
||||
base: std::path::PathBuf,
|
||||
) {
|
||||
push_unique_candidate(candidates, seen, base.join("openclaw.cmd"));
|
||||
push_unique_candidate(candidates, seen, base.join("openclaw.exe"));
|
||||
push_unique_candidate(candidates, seen, base.join("openclaw"));
|
||||
push_unique_candidate(
|
||||
candidates,
|
||||
seen,
|
||||
base.join("node_modules")
|
||||
.join("@qingchencloud")
|
||||
.join("openclaw-zh")
|
||||
.join("bin")
|
||||
.join("openclaw.js"),
|
||||
);
|
||||
push_unique_candidate(
|
||||
candidates,
|
||||
seen,
|
||||
base.join("node_modules")
|
||||
.join("openclaw")
|
||||
.join("bin")
|
||||
.join("openclaw.js"),
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn common_windows_cli_candidates() -> Vec<std::path::PathBuf> {
|
||||
let mut candidates = Vec::new();
|
||||
let mut seen = std::collections::HashSet::new();
|
||||
|
||||
// 先按 enhanced PATH 顺序找,保持与用户命令行优先级一致。
|
||||
for dir in crate::commands::enhanced_path().split(';') {
|
||||
let dir = dir.trim();
|
||||
if dir.is_empty() {
|
||||
continue;
|
||||
}
|
||||
push_windows_cli_files(&mut candidates, &mut seen, std::path::PathBuf::from(dir));
|
||||
}
|
||||
|
||||
if let Ok(appdata) = std::env::var("APPDATA") {
|
||||
push_windows_cli_files(
|
||||
&mut candidates,
|
||||
&mut seen,
|
||||
std::path::PathBuf::from(appdata).join("npm"),
|
||||
);
|
||||
}
|
||||
if let Some(prefix) = crate::commands::windows_npm_global_prefix() {
|
||||
push_windows_cli_files(&mut candidates, &mut seen, std::path::PathBuf::from(prefix));
|
||||
}
|
||||
for sa_dir in crate::commands::config::all_standalone_dirs() {
|
||||
push_windows_cli_files(&mut candidates, &mut seen, sa_dir);
|
||||
}
|
||||
if let Ok(localappdata) = std::env::var("LOCALAPPDATA") {
|
||||
let localappdata = std::path::PathBuf::from(localappdata);
|
||||
push_windows_cli_files(
|
||||
&mut candidates,
|
||||
&mut seen,
|
||||
localappdata.join("Programs").join("OpenClaw"),
|
||||
);
|
||||
push_windows_cli_files(&mut candidates, &mut seen, localappdata.join("OpenClaw"));
|
||||
push_windows_cli_files(
|
||||
&mut candidates,
|
||||
&mut seen,
|
||||
localappdata.join("Programs").join("nodejs"),
|
||||
);
|
||||
}
|
||||
if let Ok(program_files) = std::env::var("ProgramFiles") {
|
||||
let program_files = std::path::PathBuf::from(program_files);
|
||||
push_windows_cli_files(&mut candidates, &mut seen, program_files.join("nodejs"));
|
||||
push_windows_cli_files(&mut candidates, &mut seen, program_files.join("OpenClaw"));
|
||||
}
|
||||
if let Ok(program_files_x86) = std::env::var("ProgramFiles(x86)") {
|
||||
push_windows_cli_files(
|
||||
&mut candidates,
|
||||
&mut seen,
|
||||
std::path::PathBuf::from(program_files_x86).join("nodejs"),
|
||||
);
|
||||
}
|
||||
if let Ok(profile) = std::env::var("USERPROFILE") {
|
||||
push_windows_cli_files(
|
||||
&mut candidates,
|
||||
&mut seen,
|
||||
std::path::PathBuf::from(profile).join(".openclaw-bin"),
|
||||
);
|
||||
}
|
||||
for drive in ["C", "D", "E", "F", "G"] {
|
||||
push_windows_cli_files(
|
||||
&mut candidates,
|
||||
&mut seen,
|
||||
std::path::PathBuf::from(format!(r"{drive}:\OpenClaw")),
|
||||
);
|
||||
push_windows_cli_files(
|
||||
&mut candidates,
|
||||
&mut seen,
|
||||
std::path::PathBuf::from(format!(r"{drive}:\AI\OpenClaw")),
|
||||
);
|
||||
}
|
||||
|
||||
const CREATE_NO_WINDOW: u32 = 0x08000000;
|
||||
let mut where_cmd = std::process::Command::new("where");
|
||||
where_cmd.arg("openclaw");
|
||||
where_cmd.env("PATH", crate::commands::enhanced_path());
|
||||
where_cmd.creation_flags(CREATE_NO_WINDOW);
|
||||
if let Ok(output) = where_cmd.output() {
|
||||
if output.status.success() {
|
||||
for line in String::from_utf8_lossy(&output.stdout).lines() {
|
||||
let trimmed = line.trim();
|
||||
if !trimmed.is_empty() {
|
||||
push_unique_candidate(
|
||||
&mut candidates,
|
||||
&mut seen,
|
||||
std::path::PathBuf::from(trimmed),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
candidates
|
||||
}
|
||||
|
||||
pub fn is_rejected_cli_path(cli_path: &str) -> bool {
|
||||
let lower = cli_path.replace('\\', "/").to_lowercase();
|
||||
lower.contains("/.cherrystudio/") || lower.contains("cherry-studio")
|
||||
@@ -41,7 +177,7 @@ fn configured_cli_candidates() -> Vec<std::path::PathBuf> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Windows: 在 PATH 中查找 openclaw.cmd 的完整路径
|
||||
/// Windows: 在 PATH 和常见安装目录中查找 openclaw CLI 的完整路径
|
||||
/// 避免通过 `cmd /c openclaw` 调用时 npm .cmd shim 中的引号导致
|
||||
/// "\"node\"" is not recognized 错误
|
||||
#[cfg(target_os = "windows")]
|
||||
@@ -55,14 +191,9 @@ fn find_openclaw_cmd() -> Option<std::path::PathBuf> {
|
||||
return Some(candidate);
|
||||
}
|
||||
}
|
||||
let path = crate::commands::enhanced_path();
|
||||
for dir in path.split(';') {
|
||||
let candidate = std::path::Path::new(dir).join("openclaw.cmd");
|
||||
if candidate.exists() && !is_rejected_cli_path(&candidate.to_string_lossy()) {
|
||||
return Some(candidate);
|
||||
}
|
||||
}
|
||||
None
|
||||
common_windows_cli_candidates()
|
||||
.into_iter()
|
||||
.find(|candidate| candidate.exists() && !is_rejected_cli_path(&candidate.to_string_lossy()))
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
@@ -95,14 +226,7 @@ pub fn resolve_openclaw_cli_path() -> Option<String> {
|
||||
}
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
let path = crate::commands::enhanced_path();
|
||||
for dir in path.split(';') {
|
||||
let candidate = std::path::Path::new(dir).join("openclaw.cmd");
|
||||
if candidate.exists() && !is_rejected_cli_path(&candidate.to_string_lossy()) {
|
||||
return Some(candidate.to_string_lossy().to_string());
|
||||
}
|
||||
}
|
||||
None
|
||||
find_openclaw_cmd().map(|p| p.to_string_lossy().to_string())
|
||||
}
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
@@ -161,7 +285,15 @@ pub fn openclaw_command() -> std::process::Command {
|
||||
// 优先:找到 openclaw.cmd 完整路径,用 cmd /c "完整路径" 避免引号问题
|
||||
if let Some(cmd_path) = find_openclaw_cmd() {
|
||||
let mut cmd = std::process::Command::new("cmd");
|
||||
cmd.arg("/c").arg(cmd_path);
|
||||
if cmd_path
|
||||
.extension()
|
||||
.and_then(|s| s.to_str())
|
||||
.is_some_and(|ext| ext.eq_ignore_ascii_case("js"))
|
||||
{
|
||||
cmd.arg("/c").arg("node").arg(cmd_path);
|
||||
} else {
|
||||
cmd.arg("/c").arg(cmd_path);
|
||||
}
|
||||
cmd.env("PATH", &enhanced);
|
||||
apply_openclaw_dir_env(&mut cmd);
|
||||
crate::commands::apply_proxy_env(&mut cmd);
|
||||
@@ -197,7 +329,15 @@ pub fn openclaw_command_async() -> tokio::process::Command {
|
||||
// 优先:找到 openclaw.cmd 完整路径
|
||||
if let Some(cmd_path) = find_openclaw_cmd() {
|
||||
let mut cmd = tokio::process::Command::new("cmd");
|
||||
cmd.arg("/c").arg(cmd_path);
|
||||
if cmd_path
|
||||
.extension()
|
||||
.and_then(|s| s.to_str())
|
||||
.is_some_and(|ext| ext.eq_ignore_ascii_case("js"))
|
||||
{
|
||||
cmd.arg("/c").arg("node").arg(cmd_path);
|
||||
} else {
|
||||
cmd.arg("/c").arg(cmd_path);
|
||||
}
|
||||
cmd.env("PATH", &enhanced);
|
||||
apply_openclaw_dir_env_tokio(&mut cmd);
|
||||
crate::commands::apply_proxy_env_tokio(&mut cmd);
|
||||
|
||||
Reference in New Issue
Block a user