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
811 changes: 811 additions & 0 deletions src-tauri/src/commands/claudecode.rs

Large diffs are not rendered by default.

1,024 changes: 1,024 additions & 0 deletions src-tauri/src/commands/codex.rs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src-tauri/src/commands/installer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ pub async fn check_environment() -> Result<EnvironmentStatus, String> {
tuzi_configured
};

let ready = node_installed && node_version_ok && openclaw_installed;
let ready = node_installed && node_version_ok;
info!("[环境检查] 环境就绪状态: ready={}", ready);

Ok(EnvironmentStatus {
Expand Down
2 changes: 2 additions & 0 deletions src-tauri/src/commands/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
pub mod claudecode;
pub mod codex;
pub mod config;
pub mod diagnostics;
pub mod installer;
Expand Down
114 changes: 114 additions & 0 deletions src-tauri/src/commands/process.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,24 @@
use crate::utils::shell;
use log::{debug, info};
use serde::{Deserialize, Serialize};
use std::path::Path;
use tauri::command;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ModuleStatus {
pub module_id: String,
pub installed: bool,
pub version: Option<String>,
pub message: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ModuleStatusOverview {
pub node_installed: bool,
pub node_version: Option<String>,
pub modules: Vec<ModuleStatus>,
}

/// 检查 OpenClaw 是否已安装
#[command]
pub async fn check_openclaw_installed() -> Result<bool, String> {
Expand Down Expand Up @@ -33,6 +50,103 @@ pub async fn get_openclaw_version() -> Result<Option<String>, String> {
}
}

#[command]
pub async fn get_module_statuses() -> Result<ModuleStatusOverview, String> {
let openclaw_installed = shell::get_openclaw_path().is_some();
let openclaw_version = if openclaw_installed {
shell::run_openclaw(&["--version"])
.ok()
.map(|value| value.trim().to_string())
} else {
None
};

let codex_installed = shell::command_exists("codex");
let codex_version = if codex_installed {
shell::run_command_output("codex", &["--version"])
.ok()
.map(|value| value.trim().to_string())
} else {
None
};

let claude_installed = shell::command_exists("claude");
let claude_version = if claude_installed {
shell::run_command_output("claude", &["--version"])
.ok()
.map(|value| value.trim().to_string())
} else {
None
};
let claude_route = get_claude_current_route();

let node_installed = shell::command_exists("node");
let node_version = if node_installed {
shell::run_command_output("node", &["--version"]).ok()
} else {
None
};

Ok(ModuleStatusOverview {
node_installed,
node_version,
modules: vec![
ModuleStatus {
module_id: "openclaw".to_string(),
installed: openclaw_installed,
version: openclaw_version,
message: if openclaw_installed {
"OpenClaw CLI 已可用".to_string()
} else {
"未检测到 OpenClaw CLI".to_string()
},
},
ModuleStatus {
module_id: "codex".to_string(),
installed: codex_installed,
version: codex_version,
message: if codex_installed {
"Codex CLI 已可用".to_string()
} else {
"未检测到 Codex CLI".to_string()
},
},
ModuleStatus {
module_id: "claudecode".to_string(),
installed: claude_installed,
version: claude_version,
message: if claude_installed {
if let Some(route) = claude_route {
format!("Claude Code CLI 已可用(当前路线: {})", route)
} else {
"Claude Code CLI 已可用".to_string()
}
} else {
"未检测到 Claude Code CLI(claude)".to_string()
},
},
],
})
}

fn get_claude_current_route() -> Option<String> {
let home = dirs::home_dir()?;
let route_path = if crate::utils::platform::is_windows() {
format!("{}\\.config\\tuzi\\claude_route_status.txt", home.display())
} else {
format!("{}/.config/tuzi/claude_route_status.txt", home.display())
};

if !Path::new(&route_path).exists() {
return None;
}

let content = std::fs::read_to_string(&route_path).ok()?;
content
.lines()
.find_map(|line| line.trim().strip_prefix("current_route=").map(|v| v.trim().to_string()))
}

/// 检查端口是否被占用(通过尝试连接 openclaw gateway)
#[command]
pub async fn check_port_in_use(port: u16) -> Result<bool, String> {
Expand Down
23 changes: 22 additions & 1 deletion src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ mod commands;
mod models;
mod utils;

use commands::{config, diagnostics, installer, process, service, skills};
use commands::{claudecode, codex, config, diagnostics, installer, process, service, skills};

fn main() {
// 初始化日志 - 默认显示 info 级别日志
Expand All @@ -35,6 +35,7 @@ fn main() {
// 进程管理
process::check_openclaw_installed,
process::get_openclaw_version,
process::get_module_statuses,
process::check_port_in_use,
// 配置管理
config::get_config,
Expand Down Expand Up @@ -88,6 +89,26 @@ fn main() {
skills::remove_tuzi_skills_group,
skills::check_tuzi_skills_requirements,
skills::refresh_tuzi_skills,
// ClaudeCode 管理
claudecode::get_claudecode_status,
claudecode::get_claude_install_reference,
claudecode::install_claudecode,
claudecode::upgrade_claudecode,
claudecode::uninstall_claudecode,
claudecode::list_claude_routes,
claudecode::switch_claude_route,
claudecode::add_claude_route,
claudecode::update_claude_route_key,
// Codex 管理
codex::get_codex_status,
codex::get_codex_install_reference,
codex::install_codex,
codex::upgrade_codex,
codex::uninstall_codex,
codex::reinstall_codex,
codex::list_codex_routes,
codex::switch_codex_route,
codex::set_codex_route_model,
])
.run(tauri::generate_context!())
.expect("运行 Tauri 应用时发生错误");
Expand Down
Loading
Loading