feat(hands): restructure Hands UI with Chinese localization
Major changes: - Add HandList.tsx component for left sidebar - Add HandTaskPanel.tsx for middle content area - Restructure Sidebar tabs: 分身/HANDS/Workflow - Remove Hands tab from RightPanel - Localize all UI text to Chinese - Archive legacy OpenClaw documentation - Add Hands integration lessons document - Update feature checklist with new components UI improvements: - Left sidebar now shows Hands list with status icons - Middle area shows selected Hand's tasks and results - Consistent styling with Tailwind CSS - Chinese status labels and buttons Documentation: - Create docs/archive/openclaw-legacy/ for old docs - Add docs/knowledge-base/hands-integration-lessons.md - Update docs/knowledge-base/feature-checklist.md - Update docs/knowledge-base/README.md Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
5431
desktop/src-tauri/Cargo.lock
generated
Normal file
5431
desktop/src-tauri/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,6 @@
|
||||
fn main() {
|
||||
if let Ok(target) = std::env::var("TARGET") {
|
||||
println!("cargo:rustc-env=TARGET={target}");
|
||||
}
|
||||
tauri_build::build()
|
||||
}
|
||||
|
||||
@@ -753,6 +753,183 @@ fn openfang_doctor(app: AppHandle) -> Result<String, String> {
|
||||
Ok(result.stdout)
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Process Monitoring Commands
|
||||
// ============================================================================
|
||||
|
||||
/// Process information structure
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct ProcessInfo {
|
||||
pid: u32,
|
||||
name: String,
|
||||
status: String,
|
||||
cpu_percent: Option<f64>,
|
||||
memory_mb: Option<f64>,
|
||||
uptime_seconds: Option<u64>,
|
||||
}
|
||||
|
||||
/// Process list response
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct ProcessListResponse {
|
||||
processes: Vec<ProcessInfo>,
|
||||
total_count: usize,
|
||||
runtime_source: Option<String>,
|
||||
}
|
||||
|
||||
/// Process logs response
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct ProcessLogsResponse {
|
||||
pid: Option<u32>,
|
||||
logs: String,
|
||||
lines: usize,
|
||||
runtime_source: Option<String>,
|
||||
}
|
||||
|
||||
/// Version information response
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct VersionResponse {
|
||||
version: String,
|
||||
commit: Option<String>,
|
||||
build_date: Option<String>,
|
||||
runtime_source: Option<String>,
|
||||
raw: Value,
|
||||
}
|
||||
|
||||
/// List OpenFang processes
|
||||
#[tauri::command]
|
||||
fn openfang_process_list(app: AppHandle) -> Result<ProcessListResponse, String> {
|
||||
let result = run_openfang(&app, &["process", "list", "--json"])?;
|
||||
|
||||
let raw = parse_json_output(&result.stdout).unwrap_or_else(|_| json!({"processes": []}));
|
||||
|
||||
let processes: Vec<ProcessInfo> = raw
|
||||
.get("processes")
|
||||
.and_then(Value::as_array)
|
||||
.map(|arr| {
|
||||
arr.iter()
|
||||
.filter_map(|p| {
|
||||
Some(ProcessInfo {
|
||||
pid: p.get("pid").and_then(Value::as_u64)?.try_into().ok()?,
|
||||
name: p.get("name").and_then(Value::as_str)?.to_string(),
|
||||
status: p
|
||||
.get("status")
|
||||
.and_then(Value::as_str)
|
||||
.unwrap_or("unknown")
|
||||
.to_string(),
|
||||
cpu_percent: p.get("cpuPercent").and_then(Value::as_f64),
|
||||
memory_mb: p.get("memoryMb").and_then(Value::as_f64),
|
||||
uptime_seconds: p.get("uptimeSeconds").and_then(Value::as_u64),
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
Ok(ProcessListResponse {
|
||||
total_count: processes.len(),
|
||||
processes,
|
||||
runtime_source: Some(result.runtime.source),
|
||||
})
|
||||
}
|
||||
|
||||
/// Get OpenFang process logs
|
||||
#[tauri::command]
|
||||
fn openfang_process_logs(
|
||||
app: AppHandle,
|
||||
pid: Option<u32>,
|
||||
lines: Option<usize>,
|
||||
) -> Result<ProcessLogsResponse, String> {
|
||||
let line_count = lines.unwrap_or(100);
|
||||
let lines_str = line_count.to_string();
|
||||
|
||||
// Build owned strings first to avoid lifetime issues
|
||||
let args: Vec<String> = if let Some(pid_value) = pid {
|
||||
vec![
|
||||
"process".to_string(),
|
||||
"logs".to_string(),
|
||||
"--pid".to_string(),
|
||||
pid_value.to_string(),
|
||||
"--lines".to_string(),
|
||||
lines_str,
|
||||
"--json".to_string(),
|
||||
]
|
||||
} else {
|
||||
vec![
|
||||
"process".to_string(),
|
||||
"logs".to_string(),
|
||||
"--lines".to_string(),
|
||||
lines_str,
|
||||
"--json".to_string(),
|
||||
]
|
||||
};
|
||||
|
||||
// Convert to &str for the command
|
||||
let args_refs: Vec<&str> = args.iter().map(|s| s.as_str()).collect();
|
||||
let result = run_openfang(&app, &args_refs)?;
|
||||
|
||||
// Parse the logs - could be JSON array or plain text
|
||||
let logs = if let Ok(json) = parse_json_output(&result.stdout) {
|
||||
// If JSON format, extract logs array or convert to string
|
||||
if let Some(log_lines) = json.get("logs").and_then(Value::as_array) {
|
||||
log_lines
|
||||
.iter()
|
||||
.filter_map(|l| l.as_str())
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
} else if let Some(log_text) = json.get("log").and_then(Value::as_str) {
|
||||
log_text.to_string()
|
||||
} else {
|
||||
result.stdout.clone()
|
||||
}
|
||||
} else {
|
||||
result.stdout.clone()
|
||||
};
|
||||
|
||||
let log_lines_count = logs.lines().count();
|
||||
|
||||
Ok(ProcessLogsResponse {
|
||||
pid,
|
||||
logs,
|
||||
lines: log_lines_count,
|
||||
runtime_source: Some(result.runtime.source),
|
||||
})
|
||||
}
|
||||
|
||||
/// Get OpenFang version information
|
||||
#[tauri::command]
|
||||
fn openfang_version(app: AppHandle) -> Result<VersionResponse, String> {
|
||||
let result = run_openfang(&app, &["--version", "--json"])?;
|
||||
|
||||
let raw = parse_json_output(&result.stdout).unwrap_or_else(|_| {
|
||||
// Fallback: try to parse plain text version output
|
||||
json!({
|
||||
"version": result.stdout.trim(),
|
||||
"raw": result.stdout.trim()
|
||||
})
|
||||
});
|
||||
|
||||
let version = raw
|
||||
.get("version")
|
||||
.and_then(Value::as_str)
|
||||
.unwrap_or("unknown")
|
||||
.to_string();
|
||||
|
||||
let commit = raw.get("commit").and_then(Value::as_str).map(ToOwned::to_owned);
|
||||
let build_date = raw.get("buildDate").and_then(Value::as_str).map(ToOwned::to_owned);
|
||||
|
||||
Ok(VersionResponse {
|
||||
version,
|
||||
commit,
|
||||
build_date,
|
||||
runtime_source: Some(result.runtime.source),
|
||||
raw,
|
||||
})
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Backward-compatible aliases (OpenClaw naming)
|
||||
// These delegate to OpenFang commands for backward compatibility
|
||||
@@ -817,6 +994,10 @@ pub fn run() {
|
||||
openfang_prepare_for_tauri,
|
||||
openfang_approve_device_pairing,
|
||||
openfang_doctor,
|
||||
// Process monitoring commands
|
||||
openfang_process_list,
|
||||
openfang_process_logs,
|
||||
openfang_version,
|
||||
// Backward-compatible aliases (OpenClaw naming)
|
||||
gateway_status,
|
||||
gateway_start,
|
||||
|
||||
Reference in New Issue
Block a user