mirror of
https://github.com/qingchencloud/clawpanel.git
synced 2026-05-06 20:02:49 +08:00
feat: SkillHub skill store (SDK-based, no CLI dependency)
- Rust SDK (skillhub.rs): HTTP search, index fetch, zip download+extract
- Node.js SDK (skillhub-sdk.js): mirrors Rust SDK for Web/Docker mode
- Skills page: new "Store" tab with full index browse + client-side filter
- Remove 6 old CLI-dependent commands, add 3 SDK commands
- Migrate assistant.js skill tools from ClawHub CLI to SkillHub SDK
- Fix index decode error ({total,skills} wrapper vs bare array)
- Fix skill name display (API field 'name' vs 'display_name')
- Clean up 13 dead CSS rules from old skills hero/tips UI
237 lines
8.9 KiB
Rust
237 lines
8.9 KiB
Rust
mod commands;
|
||
mod models;
|
||
mod tray;
|
||
mod utils;
|
||
|
||
use commands::{
|
||
agent, assistant, config, device, extensions, logs, memory, messaging, pairing, service,
|
||
skills, update,
|
||
};
|
||
|
||
pub fn run() {
|
||
let hot_update_dir = commands::openclaw_dir()
|
||
.join("clawpanel")
|
||
.join("web-update");
|
||
|
||
tauri::Builder::default()
|
||
.plugin(tauri_plugin_shell::init())
|
||
.plugin(tauri_plugin_autostart::init(
|
||
tauri_plugin_autostart::MacosLauncher::LaunchAgent,
|
||
None,
|
||
))
|
||
.register_uri_scheme_protocol("tauri", move |ctx, request| {
|
||
let uri_path = request.uri().path();
|
||
let path = if uri_path == "/" || uri_path.is_empty() {
|
||
"index.html"
|
||
} else {
|
||
uri_path.strip_prefix('/').unwrap_or(uri_path)
|
||
};
|
||
|
||
// 1. 优先检查热更新目录
|
||
let update_file = hot_update_dir.join(path);
|
||
if update_file.is_file() {
|
||
if let Ok(data) = std::fs::read(&update_file) {
|
||
return tauri::http::Response::builder()
|
||
.header(
|
||
tauri::http::header::CONTENT_TYPE,
|
||
update::mime_from_path(path),
|
||
)
|
||
.body(data)
|
||
.unwrap();
|
||
}
|
||
}
|
||
|
||
// 2. 回退到内嵌资源
|
||
if let Some(asset) = ctx.app_handle().asset_resolver().get(path.to_string()) {
|
||
let builder = tauri::http::Response::builder()
|
||
.header(tauri::http::header::CONTENT_TYPE, &asset.mime_type);
|
||
// Tauri 内嵌资源可能带 CSP header
|
||
let builder = if let Some(csp) = asset.csp_header {
|
||
builder.header("Content-Security-Policy", csp)
|
||
} else {
|
||
builder
|
||
};
|
||
builder.body(asset.bytes).unwrap()
|
||
} else {
|
||
tauri::http::Response::builder()
|
||
.status(tauri::http::StatusCode::NOT_FOUND)
|
||
.body(b"Not Found".to_vec())
|
||
.unwrap()
|
||
}
|
||
})
|
||
.setup(|app| {
|
||
service::start_backend_guardian(app.handle().clone());
|
||
tray::setup_tray(app.handle())?;
|
||
Ok(())
|
||
})
|
||
.invoke_handler(tauri::generate_handler![
|
||
// 配置
|
||
config::read_openclaw_config,
|
||
config::write_openclaw_config,
|
||
config::validate_openclaw_config,
|
||
config::read_mcp_config,
|
||
config::write_mcp_config,
|
||
config::get_version_info,
|
||
config::check_installation,
|
||
config::init_openclaw_config,
|
||
config::calibrate_openclaw_config,
|
||
config::check_node,
|
||
config::check_node_at_path,
|
||
config::check_openclaw_at_path,
|
||
config::scan_node_paths,
|
||
config::scan_openclaw_paths,
|
||
config::save_custom_node_path,
|
||
config::write_env_file,
|
||
config::list_backups,
|
||
config::create_backup,
|
||
config::restore_backup,
|
||
config::delete_backup,
|
||
config::reload_gateway,
|
||
config::restart_gateway,
|
||
config::test_model,
|
||
config::list_remote_models,
|
||
config::list_openclaw_versions,
|
||
config::upgrade_openclaw,
|
||
config::uninstall_openclaw,
|
||
config::install_gateway,
|
||
config::uninstall_gateway,
|
||
config::patch_model_vision,
|
||
config::check_panel_update,
|
||
config::get_openclaw_dir,
|
||
config::read_panel_config,
|
||
config::write_panel_config,
|
||
config::test_proxy,
|
||
config::get_npm_registry,
|
||
config::set_npm_registry,
|
||
config::check_git,
|
||
config::scan_git_paths,
|
||
config::auto_install_git,
|
||
config::configure_git_https,
|
||
config::invalidate_path_cache,
|
||
config::get_status_summary,
|
||
config::doctor_fix,
|
||
config::doctor_check,
|
||
config::relaunch_app,
|
||
// 设备密钥 + Gateway 握手
|
||
device::create_connect_frame,
|
||
// 设备配对
|
||
pairing::auto_pair_device,
|
||
pairing::check_pairing_status,
|
||
pairing::pairing_list_channel,
|
||
pairing::pairing_approve_channel,
|
||
// 服务
|
||
service::get_services_status,
|
||
service::start_service,
|
||
service::stop_service,
|
||
service::restart_service,
|
||
service::claim_gateway,
|
||
service::guardian_status,
|
||
// 日志
|
||
logs::read_log_tail,
|
||
logs::search_log,
|
||
// 记忆文件
|
||
memory::list_memory_files,
|
||
memory::read_memory_file,
|
||
memory::write_memory_file,
|
||
memory::delete_memory_file,
|
||
memory::export_memory_zip,
|
||
// 扩展工具
|
||
extensions::get_cftunnel_status,
|
||
extensions::cftunnel_action,
|
||
extensions::get_cftunnel_logs,
|
||
extensions::get_clawapp_status,
|
||
extensions::install_cftunnel,
|
||
extensions::install_clawapp,
|
||
// Agent 管理
|
||
agent::list_agents,
|
||
agent::get_agent_detail,
|
||
agent::list_agent_files,
|
||
agent::read_agent_file,
|
||
agent::write_agent_file,
|
||
agent::get_agent_workspace_info,
|
||
agent::list_agent_workspace_entries,
|
||
agent::read_agent_workspace_file,
|
||
agent::write_agent_workspace_file,
|
||
agent::add_agent,
|
||
agent::delete_agent,
|
||
agent::update_agent_config,
|
||
agent::update_agent_identity,
|
||
agent::update_agent_model,
|
||
agent::backup_agent,
|
||
// AI 助手工具
|
||
assistant::assistant_exec,
|
||
assistant::assistant_read_file,
|
||
assistant::assistant_write_file,
|
||
assistant::assistant_list_dir,
|
||
assistant::assistant_system_info,
|
||
assistant::assistant_list_processes,
|
||
assistant::assistant_check_port,
|
||
assistant::assistant_web_search,
|
||
assistant::assistant_fetch_url,
|
||
// 数据目录 & 图片存储
|
||
assistant::assistant_ensure_data_dir,
|
||
assistant::assistant_save_image,
|
||
assistant::assistant_load_image,
|
||
assistant::assistant_delete_image,
|
||
// 消息渠道管理
|
||
messaging::read_platform_config,
|
||
messaging::save_messaging_platform,
|
||
messaging::remove_messaging_platform,
|
||
messaging::toggle_messaging_platform,
|
||
messaging::verify_bot_token,
|
||
messaging::diagnose_channel,
|
||
messaging::repair_qqbot_channel_setup,
|
||
messaging::list_configured_platforms,
|
||
messaging::get_channel_plugin_status,
|
||
messaging::install_channel_plugin,
|
||
messaging::install_qqbot_plugin,
|
||
messaging::run_channel_action,
|
||
messaging::check_weixin_plugin_status,
|
||
// Agent 渠道绑定管理
|
||
messaging::get_agent_bindings,
|
||
messaging::list_all_bindings,
|
||
messaging::save_agent_binding,
|
||
messaging::delete_agent_binding,
|
||
messaging::delete_agent_all_bindings,
|
||
// Skills 管理
|
||
skills::skills_list,
|
||
skills::skills_info,
|
||
skills::skills_check,
|
||
skills::skills_install_dep,
|
||
skills::skills_uninstall,
|
||
skills::skills_validate,
|
||
// SkillHub SDK(内置 HTTP,不依赖 CLI)
|
||
skills::skillhub_search,
|
||
skills::skillhub_index,
|
||
skills::skillhub_install,
|
||
// 前端热更新
|
||
update::check_frontend_update,
|
||
update::download_frontend_update,
|
||
update::rollback_frontend_update,
|
||
update::get_update_status,
|
||
])
|
||
.on_window_event(|window, event| {
|
||
// 关闭窗口时最小化到托盘,不退出应用
|
||
if let tauri::WindowEvent::CloseRequested { api, .. } = event {
|
||
api.prevent_close();
|
||
let _ = window.hide();
|
||
}
|
||
})
|
||
.build(tauri::generate_context!())
|
||
.expect("启动 ClawPanel 失败")
|
||
.run(|_app, event| {
|
||
if let tauri::RunEvent::Exit = event {
|
||
#[cfg(target_os = "windows")]
|
||
{
|
||
// 退出时关闭 Gateway 终端窗口
|
||
use std::os::windows::process::CommandExt;
|
||
const CREATE_NO_WINDOW: u32 = 0x08000000;
|
||
let _ = std::process::Command::new("cmd")
|
||
.args(["/c", "taskkill", "/fi", "WINDOWTITLE eq OpenClaw Gateway"])
|
||
.creation_flags(CREATE_NO_WINDOW)
|
||
.output();
|
||
}
|
||
}
|
||
});
|
||
}
|