diff --git a/crates/hk-core/src/manager.rs b/crates/hk-core/src/manager.rs index 72f59c12..3d9f0daa 100644 --- a/crates/hk-core/src/manager.rs +++ b/crates/hk-core/src/manager.rs @@ -5,6 +5,20 @@ use crate::{adapter, deployer, sanitize, scanner}; use std::path::{Path, PathBuf}; use std::process::Command; +/// Create a `Command` that does NOT flash a console window on Windows. +#[cfg(target_os = "windows")] +fn silent_command(program: &str) -> Command { + use std::os::windows::process::CommandExt; + let mut cmd = Command::new(program); + cmd.creation_flags(0x08000000); // CREATE_NO_WINDOW + cmd +} + +#[cfg(not(target_os = "windows"))] +fn silent_command(program: &str) -> Command { + Command::new(program) +} + /// Field names under which an MCP server entry stores its environment-variable /// block. Most agents use `"env"`; OpenCode's schema names the same block /// `"environment"`. Centralized so secret-handling code (redaction, restore @@ -614,7 +628,7 @@ pub fn check_update_with_cache( } pub fn get_remote_head(url: &str) -> Result { - let output = Command::new("git") + let output = silent_command("git") .args(["ls-remote", "--heads", "--", url]) .output() .map_err(|e| HkError::CommandFailed(format!("Failed to run git ls-remote: {e}")))?; @@ -659,7 +673,7 @@ pub fn install_from_git_with_id( .map_err(|e| HkError::Internal(format!("Failed to create temp directory: {e}")))?; let clone_dir = temp.path().join("repo"); - let output = Command::new("git") + let output = silent_command("git") .args(["clone", "--depth", "1", "--", url, &clone_dir.to_string_lossy()]) .output() .map_err(|e| HkError::CommandFailed(format!("Failed to run git clone: {e}")))?; @@ -1042,7 +1056,7 @@ fn find_skill_dir_in_tree( /// Run `git rev-parse HEAD` in the given directory to capture the current revision. /// Returns None if the command fails (e.g. not a git repo). fn capture_git_revision(repo_dir: &Path) -> Option { - Command::new("git") + silent_command("git") .args(["rev-parse", "HEAD"]) .current_dir(repo_dir) .output() diff --git a/crates/hk-core/src/scanner.rs b/crates/hk-core/src/scanner.rs index 2c2139c2..12202639 100644 --- a/crates/hk-core/src/scanner.rs +++ b/crates/hk-core/src/scanner.rs @@ -6,6 +6,20 @@ use std::collections::{HashMap, HashSet}; use std::path::{Path, PathBuf}; use std::sync::LazyLock; +/// Create a `Command` that does NOT flash a console window on Windows. +#[cfg(target_os = "windows")] +fn silent_command(program: &str) -> std::process::Command { + use std::os::windows::process::CommandExt; + let mut cmd = std::process::Command::new(program); + cmd.creation_flags(0x08000000); // CREATE_NO_WINDOW + cmd +} + +#[cfg(not(target_os = "windows"))] +fn silent_command(program: &str) -> std::process::Command { + std::process::Command::new(program) +} + struct KnownCli { binary_name: &'static str, display_name: &'static str, @@ -479,7 +493,7 @@ pub(crate) fn run_which(name: &str) -> Option { #[cfg(not(target_os = "windows"))] const WHICH_CMD: &str = "which"; - std::process::Command::new(WHICH_CMD) + silent_command(WHICH_CMD) .arg(name) .output() .ok() @@ -548,7 +562,7 @@ fn get_binary_version(name: &str) -> Option { } static VERSION_RE: LazyLock = LazyLock::new(|| Regex::new(r"(\d+\.\d+(?:\.\d+)?)").unwrap()); - let output = std::process::Command::new(name) + let output = silent_command(name) .arg("--version") .output() .ok()?; diff --git a/crates/hk-desktop/src/commands/extensions.rs b/crates/hk-desktop/src/commands/extensions.rs index 56befd6a..100a6a04 100644 --- a/crates/hk-desktop/src/commands/extensions.rs +++ b/crates/hk-desktop/src/commands/extensions.rs @@ -4,6 +4,20 @@ use hk_core::service::ExtensionContent; use hk_core::{HkError, manager, models::*, scanner, service}; use tauri::{Emitter, State}; +/// Create a `Command` that does NOT flash a console window on Windows. +#[cfg(target_os = "windows")] +fn silent_command(program: &str) -> std::process::Command { + use std::os::windows::process::CommandExt; + let mut cmd = std::process::Command::new(program); + cmd.creation_flags(0x08000000); // CREATE_NO_WINDOW + cmd +} + +#[cfg(not(target_os = "windows"))] +fn silent_command(program: &str) -> std::process::Command { + std::process::Command::new(program) +} + #[tauri::command] pub fn list_extensions( state: State, @@ -455,7 +469,7 @@ pub async fn check_updates( Err(_) => continue, }; let clone_path = temp.path().join("repo"); - let output = std::process::Command::new("git") + let output = silent_command("git") .args(["clone", "--depth", "1", "--", url, &clone_path.to_string_lossy()]) .output(); let ok = output.map(|o| o.status.success()).unwrap_or(false); @@ -582,7 +596,7 @@ pub async fn update_extension( // Clone the repo once let temp = tempfile::tempdir().map_err(|e| HkError::Internal(e.to_string()))?; let clone_dir = temp.path().join("repo"); - let output = std::process::Command::new("git") + let output = silent_command("git") .args(["clone", "--depth", "1", "--", url, &clone_dir.to_string_lossy()]) .output() .map_err(|e| HkError::CommandFailed(format!("Failed to run git clone: {}", e)))?; diff --git a/crates/hk-desktop/src/commands/install.rs b/crates/hk-desktop/src/commands/install.rs index 96ae1e2d..49dd6516 100644 --- a/crates/hk-desktop/src/commands/install.rs +++ b/crates/hk-desktop/src/commands/install.rs @@ -2,6 +2,20 @@ use super::{AppState, PendingClone}; use hk_core::{HkError, deployer, manager, marketplace, models::*, scanner, service}; use tauri::State; +/// Create a `Command` that does NOT flash a console window on Windows. +#[cfg(target_os = "windows")] +fn silent_command(program: &str) -> std::process::Command { + use std::os::windows::process::CommandExt; + let mut cmd = std::process::Command::new(program); + cmd.creation_flags(0x08000000); // CREATE_NO_WINDOW + cmd +} + +#[cfg(not(target_os = "windows"))] +fn silent_command(program: &str) -> std::process::Command { + std::process::Command::new(program) +} + // --- Multi-skill git install flow --- #[derive(serde::Serialize)] @@ -219,7 +233,7 @@ pub async fn scan_git_repo( let temp = tempfile::tempdir()?; let clone_dir = temp.path().join("repo"); - let output = std::process::Command::new("git") + let output = silent_command("git") .args([ "clone", "--depth", @@ -476,7 +490,7 @@ pub async fn install_new_repo_skills( let temp = tempfile::tempdir() .map_err(|e| HkError::Internal(format!("Failed to create temp directory: {e}")))?; let clone_dir = temp.path().join("repo"); - let output = std::process::Command::new("git") + let output = silent_command("git") .args([ "clone", "--depth", diff --git a/crates/hk-desktop/tauri.conf.json b/crates/hk-desktop/tauri.conf.json index 56656190..52f93583 100644 --- a/crates/hk-desktop/tauri.conf.json +++ b/crates/hk-desktop/tauri.conf.json @@ -20,12 +20,7 @@ "width": 1280, "height": 800, "minWidth": 900, - "minHeight": 600, - "transparent": true, - "windowEffects": { - "effects": ["sidebar"], - "state": "followsWindowActiveState" - } + "minHeight": 600 } ], "security": { diff --git a/src/App.tsx b/src/App.tsx index 11999765..8d40a4f5 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -115,6 +115,10 @@ export default function App() { if (!isDesktop()) { root.setAttribute("data-web", "true"); } + // Detect Windows platform for CSS background handling + if (isDesktop() && navigator.userAgent.includes("Windows")) { + root.setAttribute("data-platform", "windows"); + } // Force macOS vibrancy to match — "light" | "dark" | null (system) if (isDesktop()) { getCurrentWindow() diff --git a/src/index.css b/src/index.css index f87cb22c..2fdc1664 100644 --- a/src/index.css +++ b/src/index.css @@ -688,6 +688,12 @@ html.dark[data-theme="tiesen"][data-web="true"] { #root { background: transparent; } + /* Windows: no vibrancy support, use solid background instead of transparent */ + html[data-platform="windows"], + html[data-platform="windows"] body, + html[data-platform="windows"] #root { + background: var(--background); + } /* Web mode: lock the browser's canvas color to our theme so the translucent bg-sidebar/25 layer has a stable backdrop regardless of OS prefers-color-scheme or Chrome's Force Dark Mode. `only` defeats