mod commands; mod db; mod mcp_inject; mod mcp_server; mod models; use git2; /// 创建不弹 CMD 窗口的子进程(Windows 专用 CREATE_NO_WINDOW 标志)。 /// 所有后台静默命令都应通过此函数创建,避免在 Windows 上频繁闪出黑框。 pub(crate) fn silent_cmd(program: &str) -> std::process::Command { let mut cmd = std::process::Command::new(program); #[cfg(target_os = "windows")] { use std::os::windows::process::CommandExt; const CREATE_NO_WINDOW: u32 = 0x0800_0000; cmd.creation_flags(CREATE_NO_WINDOW); } cmd } use commands::{activity::*, blueprint::*, buff::{apply_blueprint_buff, remove_blueprint_buff, get_buff_status, list_buffed_projects}, canvas::*, cicd::*, claude_config::get_beast_global_status, devtools::*, git_ops::*, git_repos::*, groups::*, mentor::{add_project_note, get_group_mentor_report, get_mentor_context, get_project_notes, get_startup_alerts, run_startup_health_scan}, network::{get_wsl_ip, sync_wsl_proxy, get_wsl_proxy_status, clear_wsl_proxy, test_wsl_proxy_ip, test_win_proxy_ip}, project_scan::*, project_tools::*, projects::{batch_create_projects, create_project, delete_project, get_project, get_projects, scan_subfolders, update_project, update_project_tags}, proxy::*, publish::*, settings::{check_mcp_health, detect_editors, get_settings, run_health_check, search_editor_path, update_settings}, shell::*, spaces::*, tags::*, templates::*}; #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { tauri::Builder::default() .plugin(tauri_plugin_single_instance::init(|app, _argv, _cwd| { // 第二个实例启动时,激活已有窗口 use tauri::Manager; if let Some(w) = app.get_webview_window("main") { let _ = w.show(); let _ = w.unminimize(); let _ = w.set_focus(); } })) .plugin(tauri_plugin_http::init()) .plugin(tauri_plugin_opener::init()) .plugin(tauri_plugin_updater::Builder::new().build()) .plugin(tauri_plugin_process::init()) .plugin(tauri_plugin_dialog::init()) .plugin(tauri_plugin_shell::init()) .setup(|app| { use tauri::{ menu::{Menu, MenuItem}, tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent}, Manager, }; let data_dir = app.path().app_data_dir().expect("no app data dir"); db::init(data_dir.clone()); commands::blueprint::init_user_conventions_dir(data_dir); // 禁用 libgit2 目录所有者验证,允许访问 WSL UNC 路径(\\wsl.localhost\...) unsafe { let _ = git2::opts::set_verify_owner_validation(false); } // 种植内置模板(首次启动时执行) commands::templates::seed_builtin_templates(); // ── 启动 MCP Server ─────────────────────────────────────── let mcp_port = mcp_server::read_port(); tauri::async_runtime::spawn(mcp_server::start(mcp_port)); // ── Gitea 远端轮询(G6):每 10 分钟拉取绑定仓库 commit ─── // 出站 HTTPS 采集,适配公网 Gitea + 内网炼境拓扑(webhook 不可达时的降级) std::thread::spawn(|| { std::thread::sleep(std::time::Duration::from_secs(30)); // 等 DB 与网络就绪 loop { let _ = commands::gitea::poll_all_repos(); std::thread::sleep(std::time::Duration::from_secs(600)); } }); // ── 启动健康扫描(异步,不阻塞窗口渲染)──────────────── tauri::async_runtime::spawn(async { tokio::task::spawn_blocking(run_startup_health_scan).await.ok(); }); // ── 启动蓝图 Buff 后台轮询 ──────────────────────────── commands::buff::start_blueprint_watchers(app.handle().clone()); // ── 系统托盘 ────────────────────────────────────────────── let show_i = MenuItem::with_id(app, "show", "显示窗口", true, None::<&str>)?; let quit_i = MenuItem::with_id(app, "quit", "退出炼境", true, None::<&str>)?; let menu = Menu::with_items(app, &[&show_i, &quit_i])?; TrayIconBuilder::new() .icon(app.default_window_icon().unwrap().clone()) .menu(&menu) .show_menu_on_left_click(false) .tooltip("炼境") .on_menu_event(|app, event| match event.id.as_ref() { "quit" => app.exit(0), "show" => { if let Some(w) = app.get_webview_window("main") { let _ = w.show(); let _ = w.set_focus(); } } _ => {} }) .on_tray_icon_event(|tray, event| { // 左键单击托盘图标 → 显示/聚焦窗口 if let TrayIconEvent::Click { button: MouseButton::Left, button_state: MouseButtonState::Up, .. } = event { let app = tray.app_handle(); if let Some(w) = app.get_webview_window("main") { let _ = w.show(); let _ = w.set_focus(); } } }) .build(app)?; // ── 关闭窗口 → 最小化到托盘 ────────────────────────────── if let Some(window) = app.get_webview_window("main") { let win = window.clone(); window.on_window_event(move |event| { if let tauri::WindowEvent::CloseRequested { api, .. } = event { api.prevent_close(); let _ = win.hide(); } }); } Ok(()) }) .invoke_handler(tauri::generate_handler![ // projects get_projects, get_project, create_project, update_project, update_project_tags, delete_project, scan_subfolders, batch_create_projects, // activity get_activity, add_activity, // groups get_groups, create_group, update_group, delete_group, reorder_groups, get_group_maps, add_group_member, remove_group_member, // settings get_settings, update_settings, detect_editors, search_editor_path, check_mcp_health, run_health_check, // project tools get_project_tools, add_project_tool, update_project_tool, remove_project_tool, launch_tool, // global quick launch get_global_tools, add_global_tool, update_global_tool, remove_global_tool, // devtools scan_dev_tools, scan_wsl_dev_tools, get_dev_tools, save_dev_tools, delete_dev_tool, upsert_dev_tool, // wsl proxy get_wsl_ip, sync_wsl_proxy, get_wsl_proxy_status, clear_wsl_proxy, test_wsl_proxy_ip, test_win_proxy_ip, // v2rayn import scan_v2rayn_nodes, detect_v2rayn_db_path, get_active_v2rayn_node, // project env scan scan_project_env, get_project_env_tools, save_project_env_tools, // shell open_editor, open_terminal, // git ops git_clone, git_status, git_fetch, git_pull, git_push, git_head_commit, git_upstream_behind, git_create_branch, git_list_branches, git_checkout_branch, // spaces get_spaces, create_space, update_space, delete_space, set_current_space, get_deploy_commands, add_deploy_command, remove_deploy_command, execute_deploy, // git repos registry get_git_repos, import_git_repos, update_git_repo_deploy, mount_repo, delete_git_repo, // 本地 git 工具 scan_local_git, git_init_and_commit, git_remote_set, register_and_link_repo, write_gitignore, resolve_wsl_path, get_wsl_distros, // project templates list_templates, get_template, save_template, delete_template, create_project_from_template, // tags get_tags, create_tag, update_tag, delete_tag, get_project_tags, set_project_tags, get_all_project_tag_maps, // cicd get_cicd_config, save_cicd_config, generate_workflow, // blueprint get_blueprint, generate_blueprint_prompt, get_blueprint_status, sync_blueprint_rules, get_flywheel_stats, generate_muhe_prompt, archive_project_docs, get_user_conventions_status, save_user_conventions, reset_conventions_to_builtin, // canvas state get_canvas_state, save_canvas_state, // blueprint buff apply_blueprint_buff, remove_blueprint_buff, get_buff_status, list_buffed_projects, // onboarding pack commands::onboarding::apply_onboarding_pack, // agent infrastructure commands::agent_infra::scan_agent_infra_stack, commands::agent_infra::generate_agent_infra_files, commands::agent_infra::scan_doc_freshness, commands::agent_infra::get_doc_freshness_cache, commands::agent_infra::get_agent_health, commands::commit_metrics::get_commit_stats, commands::commit_metrics::ingest_full_git_history, commands::commit_metrics::get_project_commit_health, commands::commit_metrics::get_all_commit_health, // mentor get_mentor_context, get_project_notes, add_project_note, get_group_mentor_report, get_startup_alerts, // user todos commands::user_todos::get_user_todos, commands::user_todos::add_user_todo, commands::user_todos::toggle_user_todo, commands::user_todos::delete_user_todo, // servers commands::servers::get_servers, commands::servers::add_server, commands::servers::edit_server, commands::servers::delete_server, commands::servers::link_server, commands::servers::unlink_server, commands::servers::get_project_server_links, commands::servers::get_server_project_links, // ssh config & vscode remote commands::ssh_config::sync_ssh_config, commands::ssh_config::get_ssh_config_status, commands::ssh_config::check_vscode_status, commands::ssh_config::open_vscode_remote, commands::ssh_config::open_server_terminal, commands::ssh_config::parse_ssh_config_entries, commands::ssh_config::import_ssh_config_entries, // server software & mirrors commands::server_software::get_github_mirrors, commands::server_software::add_github_mirror, commands::server_software::delete_github_mirror, commands::server_software::test_mirror_local, commands::server_software::get_server_network_config, commands::server_software::set_server_mirror, commands::server_software::get_server_software_list, commands::server_software::add_server_software, commands::server_software::update_server_software, commands::server_software::delete_server_software, commands::server_software::generate_install_command, commands::server_software::get_software_categories, commands::server_software::add_software_category, commands::server_software::update_software_category, commands::server_software::delete_software_category, // api keys commands::api_keys::get_api_keys, commands::api_keys::add_api_key, commands::api_keys::edit_api_key, commands::api_keys::delete_api_key, // host apps commands::host_apps::get_host_apps, commands::host_apps::add_host_app, commands::host_apps::edit_host_app, commands::host_apps::delete_host_app, // server service configs commands::service_config::get_service_configs, commands::service_config::add_service_config, commands::service_config::edit_service_config, commands::service_config::delete_service_config, // gitea integration commands::gitea::gitea_save_instance, commands::gitea::gitea_list_instances, commands::gitea::gitea_delete_instance, commands::gitea::gitea_update_instance, commands::gitea::gitea_test_connection, commands::gitea::gitea_list_linked_repos, commands::gitea::gitea_get_repo_link, commands::gitea::gitea_create_repo, commands::gitea::gitea_migrate_repo, commands::gitea::gitea_link_repo, commands::gitea::gitea_setup_webhook, commands::gitea::gitea_unlink_repo, commands::gitea::gitea_poll_now, // beast status (read-only) get_beast_global_status, // source library commands::source_library::get_source_categories, commands::source_library::create_source_category, commands::source_library::update_source_category, commands::source_library::delete_source_category, commands::source_library::get_source_projects, commands::source_library::create_source_project, commands::source_library::update_source_project, commands::source_library::delete_source_project, commands::source_library::get_source_versions, commands::source_library::add_source_version, commands::source_library::set_primary_version, commands::source_library::delete_source_version, commands::source_library::update_version_notes, commands::source_library::scan_source_dir_tree, commands::source_library::reveal_source_in_explorer, commands::source_library::copy_source_to, // cloud products commands::cloud_products::get_cloud_products, commands::cloud_products::add_cloud_product, commands::cloud_products::edit_cloud_product, commands::cloud_products::delete_cloud_product, // cloud db databases commands::cloud_db_databases::get_cloud_databases, commands::cloud_db_databases::add_cloud_database, commands::cloud_db_databases::edit_cloud_database, commands::cloud_db_databases::delete_cloud_database, // docker apps commands::docker_apps::get_docker_apps, commands::docker_apps::add_docker_app, commands::docker_apps::edit_docker_app, commands::docker_apps::delete_docker_app, ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); }