From 9d63433070cfbf8da3e4ba72a8cc11c044bf846a Mon Sep 17 00:00:00 2001 From: "zanwei.guo" Date: Sat, 21 Feb 2026 10:25:05 +0800 Subject: [PATCH] chore: prepare v1.0.5 release Bundle the latest install flow and UI updates with a version bump to 1.0.5 so the next release artifacts and app metadata stay aligned. Co-authored-by: Cursor --- package.json | 2 +- src-tauri/Cargo.lock | 256 +++++++++++++++++++++++++- src-tauri/Cargo.toml | 3 +- src-tauri/src/commands.rs | 88 ++++++++- src-tauri/src/lib.rs | 1 + src-tauri/tauri.conf.json | 2 +- src/App.tsx | 4 +- src/api/registry.ts | 12 +- src/assets/icons/logo/antigravity.svg | 224 ++++++++++++++++++++++ src/assets/icons/logo/codebuddy.svg | 1 + src/assets/icons/logo/qoder.svg | 16 ++ src/assets/icons/logo/trae.svg | 3 + src/assets/icons/logo/windsurf.svg | 3 + src/components/ConfirmDialog.css | 12 +- src/components/ConfirmDialog.tsx | 8 +- src/components/InstallMenu.css | 6 +- src/components/InstallMenu.tsx | 23 ++- src/components/Panel.css | 10 +- src/components/Settings.tsx | 2 +- src/types/index.ts | 20 ++ 20 files changed, 649 insertions(+), 47 deletions(-) create mode 100644 src/assets/icons/logo/antigravity.svg create mode 100644 src/assets/icons/logo/codebuddy.svg create mode 100644 src/assets/icons/logo/qoder.svg create mode 100644 src/assets/icons/logo/trae.svg create mode 100644 src/assets/icons/logo/windsurf.svg diff --git a/package.json b/package.json index 51ca2b9..0eae17b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "skiller", - "version": "1.0.4", + "version": "1.0.5", "description": "A lightweight desktop menubar app for browsing and installing Claude Code plugins and Agent Skills", "type": "module", "private": true, diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 40a2057..d9aafea 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -8,6 +8,17 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + [[package]] name = "aho-corasick" version = "1.1.4" @@ -47,6 +58,15 @@ version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" +dependencies = [ + "derive_arbitrary", +] + [[package]] name = "async-broadcast" version = "0.7.2" @@ -331,6 +351,25 @@ dependencies = [ "serde", ] +[[package]] +name = "bzip2" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49ecfb22d906f800d4fe833b6282cf4dc1c298f5057ca0b5445e5c209735ca47" +dependencies = [ + "bzip2-sys", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.13+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14" +dependencies = [ + "cc", + "pkg-config", +] + [[package]] name = "cairo-rs" version = "0.18.5" @@ -405,6 +444,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd4932aefd12402b36c60956a4fe0035421f544799057659ff86f923657aada3" dependencies = [ "find-msvc-tools", + "jobserver", + "libc", "shlex", ] @@ -459,6 +500,16 @@ dependencies = [ "windows-link 0.2.1", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "cocoa" version = "0.26.1" @@ -507,6 +558,12 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + [[package]] name = "convert_case" version = "0.4.0" @@ -619,6 +676,21 @@ dependencies = [ "libc", ] +[[package]] +name = "crc" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + [[package]] name = "crc32fast" version = "1.5.0" @@ -731,6 +803,12 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be1e0bca6c3637f992fc1cc7cbc52a78c1ef6db076dbf1059c4323d6a2048376" +[[package]] +name = "deflate64" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26bf8fc351c5ed29b5c2f0cbbac1b209b74f60ecd62e675a998df72c49af5204" + [[package]] name = "deranged" version = "0.5.5" @@ -741,6 +819,17 @@ dependencies = [ "serde_core", ] +[[package]] +name = "derive_arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + [[package]] name = "derive_more" version = "0.99.20" @@ -762,6 +851,7 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", + "subtle", ] [[package]] @@ -1588,6 +1678,15 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + [[package]] name = "html5ever" version = "0.29.1" @@ -1907,6 +2006,15 @@ dependencies = [ "cfb", ] +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + [[package]] name = "ipnet" version = "2.11.0" @@ -1993,6 +2101,16 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + [[package]] name = "js-sys" version = "0.3.83" @@ -2143,6 +2261,27 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" +[[package]] +name = "lzma-rs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e" +dependencies = [ + "byteorder", + "crc", +] + +[[package]] +name = "lzma-sys" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "mac" version = "0.1.1" @@ -2740,6 +2879,16 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest", + "hmac", +] + [[package]] name = "percent-encoding" version = "2.3.2" @@ -3819,6 +3968,17 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sha2" version = "0.10.9" @@ -3898,7 +4058,7 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "skiller" -version = "1.0.3" +version = "1.0.5" dependencies = [ "cocoa", "dirs 5.0.1", @@ -3914,6 +4074,7 @@ dependencies = [ "tauri-plugin-shell", "tauri-plugin-single-instance", "tauri-plugin-store", + "zip", ] [[package]] @@ -5951,6 +6112,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" +[[package]] +name = "xz2" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2" +dependencies = [ + "lzma-sys", +] + [[package]] name = "yoke" version = "0.8.1" @@ -6081,6 +6251,20 @@ name = "zeroize" version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] [[package]] name = "zerotrie" @@ -6115,12 +6299,82 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "zip" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fabe6324e908f85a1c52063ce7aa26b68dcb7eb6dbc83a2d148403c9bc3eba50" +dependencies = [ + "aes", + "arbitrary", + "bzip2", + "constant_time_eq", + "crc32fast", + "crossbeam-utils", + "deflate64", + "displaydoc", + "flate2", + "getrandom 0.3.4", + "hmac", + "indexmap 2.13.0", + "lzma-rs", + "memchr", + "pbkdf2", + "sha1", + "thiserror 2.0.17", + "time", + "xz2", + "zeroize", + "zopfli", + "zstd", +] + [[package]] name = "zmij" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fc5a66a20078bf1251bde995aa2fdcc4b800c70b5d92dd2c62abc5c60f679f8" +[[package]] +name = "zopfli" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" +dependencies = [ + "bumpalo", + "crc32fast", + "log", + "simd-adler32", +] + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.16+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" +dependencies = [ + "cc", + "pkg-config", +] + [[package]] name = "zvariant" version = "5.8.0" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 09a46f8..04a4c5a 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "skiller" -version = "1.0.4" +version = "1.0.5" description = "A desktop menubar app for Claude Code plugins and Agent Skills" authors = ["Skiller"] edition = "2021" @@ -23,6 +23,7 @@ serde = { version = "1", features = ["derive"] } serde_json = "1" dirs = "5" reqwest = { version = "0.12", features = ["blocking"] } +zip = "2" [target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] tauri-plugin-single-instance = "2" diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index 4b1c3bd..93019b3 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -1,8 +1,10 @@ use std::process::Command; use std::path::{Path, PathBuf}; use std::fs; -use std::io::Write; +use std::io::{Write, Cursor}; use serde::Serialize; +use zip::ZipWriter; +use zip::write::SimpleFileOptions; #[derive(Serialize)] pub struct TerminalApp { @@ -384,6 +386,54 @@ pub async fn open_in_explorer(path: String) -> Result<(), String> { Ok(()) } +#[tauri::command] +pub async fn reveal_in_explorer(path: String) -> Result<(), String> { + #[cfg(target_os = "macos")] + { + let target = Path::new(&path); + let mut command = Command::new("open"); + if target.is_dir() { + command.arg(&path); + } else { + command.args(["-R", &path]); + } + command + .spawn() + .map_err(|e| format!("Failed to reveal path in Finder: {}", e))?; + } + + #[cfg(target_os = "windows")] + { + let target = Path::new(&path); + let mut command = Command::new("explorer"); + if target.is_dir() { + command.arg(&path); + } else { + command.args(["/select,", &path]); + } + command + .spawn() + .map_err(|e| format!("Failed to reveal path in Explorer: {}", e))?; + } + + #[cfg(target_os = "linux")] + { + let target = Path::new(&path); + let open_target = if target.is_file() { + target.parent().unwrap_or(target) + } else { + target + }; + + Command::new("xdg-open") + .arg(open_target) + .spawn() + .map_err(|e| format!("Failed to reveal path in file manager: {}", e))?; + } + + Ok(()) +} + #[tauri::command] pub async fn get_default_download_path() -> Result { let download_dir = dirs::download_dir() @@ -414,10 +464,7 @@ pub async fn download_skill(url: String, filename: String, download_path: Option fs::create_dir_all(&target_dir) .map_err(|e| format!("Failed to create directory: {}", e))?; - // Build the full file path - let file_path = target_dir.join(&filename); - - // Download the file using reqwest (blocking) + // Download the markdown content using reqwest (blocking) let response = reqwest::blocking::get(&url) .map_err(|e| format!("Failed to download: {}", e))?; @@ -425,14 +472,39 @@ pub async fn download_skill(url: String, filename: String, download_path: Option return Err(format!("Download failed with status: {}", response.status())); } - let bytes = response.bytes() + let md_content = response.bytes() .map_err(|e| format!("Failed to read response: {}", e))?; - // Write to file + // Create zip file in memory + let mut zip_buffer = Cursor::new(Vec::new()); + { + let mut zip = ZipWriter::new(&mut zip_buffer); + let options = SimpleFileOptions::default() + .compression_method(zip::CompressionMethod::Deflated); + + // Get the md filename from the zip filename (replace .zip with .md) + let md_filename = if filename.ends_with(".zip") { + filename[..filename.len() - 4].to_string() + ".md" + } else { + filename.clone() + ".md" + }; + + zip.start_file(&md_filename, options) + .map_err(|e| format!("Failed to create file in zip: {}", e))?; + zip.write_all(&md_content) + .map_err(|e| format!("Failed to write to zip: {}", e))?; + zip.finish() + .map_err(|e| format!("Failed to finalize zip: {}", e))?; + } + + // Build the full file path for the zip + let file_path = target_dir.join(&filename); + + // Write zip to file let mut file = fs::File::create(&file_path) .map_err(|e| format!("Failed to create file: {}", e))?; - file.write_all(&bytes) + file.write_all(zip_buffer.get_ref()) .map_err(|e| format!("Failed to write file: {}", e))?; file_path diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 91be376..f810890 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -274,6 +274,7 @@ pub fn run() { .invoke_handler(tauri::generate_handler![ commands::execute_in_terminal, commands::open_in_explorer, + commands::reveal_in_explorer, commands::get_installed_terminals, commands::get_default_download_path, commands::download_skill, diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 2423c76..5864c10 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "Skiller", - "version": "1.0.4", + "version": "1.0.5", "identifier": "dev.skiller.desktop", "build": { "beforeDevCommand": "npm run dev", diff --git a/src/App.tsx b/src/App.tsx index e2f2bb2..e46483a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -15,9 +15,7 @@ function AppContent() { try { if (window.__TAURI__) { const { invoke } = await import('@tauri-apps/api/core'); - // Get the directory containing the file - const dirPath = filePath.substring(0, filePath.lastIndexOf('/')); - await invoke('open_in_explorer', { path: dirPath }); + await invoke('reveal_in_explorer', { path: filePath }); } } catch (error) { console.error('Failed to reveal in finder:', error); diff --git a/src/api/registry.ts b/src/api/registry.ts index 303a401..9c6ae33 100644 --- a/src/api/registry.ts +++ b/src/api/registry.ts @@ -82,7 +82,7 @@ function parseSkill(data: any): Skill { stars: data.stars || 0, tags: data.keywords || data.tags || [], installIdentifier: namespace || `@${owner}/${repo}/${data.name}`, - supportedClients: ['claude-code', 'cursor', 'vscode', 'codex', 'amp', 'opencode', 'goose', 'letta', 'github'], + supportedClients: ['claude-code', 'cursor', 'vscode', 'codex', 'amp', 'opencode', 'goose', 'letta', 'antigravity', 'windsurf', 'trae', 'codebuddy', 'qoder', 'github'], rawFileUrl: data.metadata?.rawFileUrl || undefined, }; } @@ -363,7 +363,7 @@ function getMockSkills(): Skill[] { stars: 52420, tags: [], installIdentifier: '@anthropics/claude-code/frontend-design', - supportedClients: ['claude-code', 'cursor', 'vscode', 'codex', 'amp', 'opencode', 'goose', 'letta', 'github'], + supportedClients: ['claude-code', 'cursor', 'vscode', 'codex', 'amp', 'opencode', 'goose', 'letta', 'antigravity', 'windsurf', 'trae', 'codebuddy', 'qoder', 'github'], rawFileUrl: 'https://raw.githubusercontent.com/anthropics/claude-code/main/plugins/frontend-design/skills/frontend-design/SKILL.md', }, { @@ -376,7 +376,7 @@ function getMockSkills(): Skill[] { stars: 20969, tags: [], installIdentifier: '@wshobson/agents/prompt-engineering-patterns', - supportedClients: ['claude-code', 'cursor', 'vscode', 'codex', 'amp', 'opencode', 'goose', 'letta', 'github'], + supportedClients: ['claude-code', 'cursor', 'vscode', 'codex', 'amp', 'opencode', 'goose', 'letta', 'antigravity', 'windsurf', 'trae', 'codebuddy', 'qoder', 'github'], rawFileUrl: 'https://raw.githubusercontent.com/wshobson/agents/main/skills/prompt-engineering-patterns/SKILL.md', }, { @@ -389,7 +389,7 @@ function getMockSkills(): Skill[] { stars: 14889, tags: [], installIdentifier: '@obra/superpowers/brainstorming', - supportedClients: ['claude-code', 'cursor', 'vscode', 'codex', 'amp', 'opencode', 'goose', 'letta', 'github'], + supportedClients: ['claude-code', 'cursor', 'vscode', 'codex', 'amp', 'opencode', 'goose', 'letta', 'antigravity', 'windsurf', 'trae', 'codebuddy', 'qoder', 'github'], rawFileUrl: 'https://raw.githubusercontent.com/obra/superpowers/main/skills/brainstorming/SKILL.md', }, ]; @@ -430,8 +430,8 @@ export function getSkillDownloadInfo(skill: Skill): { url: string; filename: str } // rawFileUrl format: https://raw.githubusercontent.com/{owner}/{repo}/{branch}/{path}/SKILL.md - // We can directly use this URL to download the SKILL.md file - const filename = `${skill.name}.md`; + // We download the SKILL.md and compress it to a zip file + const filename = `${skill.name}.zip`; return { url: skill.rawFileUrl, diff --git a/src/assets/icons/logo/antigravity.svg b/src/assets/icons/logo/antigravity.svg new file mode 100644 index 0000000..c530d64 --- /dev/null +++ b/src/assets/icons/logo/antigravity.svg @@ -0,0 +1,224 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/logo/codebuddy.svg b/src/assets/icons/logo/codebuddy.svg new file mode 100644 index 0000000..450caea --- /dev/null +++ b/src/assets/icons/logo/codebuddy.svg @@ -0,0 +1 @@ + diff --git a/src/assets/icons/logo/qoder.svg b/src/assets/icons/logo/qoder.svg new file mode 100644 index 0000000..db52832 --- /dev/null +++ b/src/assets/icons/logo/qoder.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/logo/trae.svg b/src/assets/icons/logo/trae.svg new file mode 100644 index 0000000..71dde09 --- /dev/null +++ b/src/assets/icons/logo/trae.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/logo/windsurf.svg b/src/assets/icons/logo/windsurf.svg new file mode 100644 index 0000000..3e49a6f --- /dev/null +++ b/src/assets/icons/logo/windsurf.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/ConfirmDialog.css b/src/components/ConfirmDialog.css index 0116cd0..96863e2 100644 --- a/src/components/ConfirmDialog.css +++ b/src/components/ConfirmDialog.css @@ -116,6 +116,17 @@ gap: 8px; } +.dialog-cancel-btn { + min-width: 78px; +} + +.dialog-confirm-btn { + min-width: 78px; + display: inline-flex; + align-items: center; + justify-content: center; +} + .btn-copy { display: flex; align-items: center; @@ -135,7 +146,6 @@ border-top-color: currentColor; border-radius: 50%; animation: spin 0.6s linear infinite; - margin-right: 6px; } @keyframes spin { diff --git a/src/components/ConfirmDialog.tsx b/src/components/ConfirmDialog.tsx index 1b22e94..2717ce6 100644 --- a/src/components/ConfirmDialog.tsx +++ b/src/components/ConfirmDialog.tsx @@ -71,19 +71,19 @@ export function ConfirmDialog({ )}
diff --git a/src/components/InstallMenu.css b/src/components/InstallMenu.css index 9a19e19..72bcc04 100644 --- a/src/components/InstallMenu.css +++ b/src/components/InstallMenu.css @@ -25,7 +25,11 @@ box-shadow: 0 4px 12px hsl(0 0% 0% / 0.3); z-index: 1000; animation: menuFadeIn 0.15s ease; - overflow: hidden; + max-height: min(400px, calc(100vh - 24px)); + overflow-x: hidden; + overflow-y: auto; + overscroll-behavior-y: contain; + -webkit-overflow-scrolling: touch; } /* Dark mode: lighter background for menu */ diff --git a/src/components/InstallMenu.tsx b/src/components/InstallMenu.tsx index 04af007..d01ffd9 100644 --- a/src/components/InstallMenu.tsx +++ b/src/components/InstallMenu.tsx @@ -11,6 +11,11 @@ import AmpCodeLogo from '../assets/icons/logo/amp-code.svg'; import OpenCodeLogo from '../assets/icons/logo/open-code.svg'; import GooseLogo from '../assets/icons/logo/goose.svg'; import LettaLogo from '../assets/icons/logo/letta.svg'; +import AntigravityLogo from '../assets/icons/logo/antigravity.svg'; +import WindsurfLogo from '../assets/icons/logo/windsurf.svg'; +import TraeLogo from '../assets/icons/logo/trae.svg'; +import CodeBuddyLogo from '../assets/icons/logo/codebuddy.svg'; +import QoderLogo from '../assets/icons/logo/qoder.svg'; interface InstallMenuProps { skill: Skill; @@ -19,12 +24,13 @@ interface InstallMenuProps { defaultPackageManager: PackageManager; } -const CLIENTS: Client[] = ['claude', 'claude-code', 'cursor', 'vscode', 'codex', 'amp', 'opencode', 'goose', 'letta', 'github']; +const CLIENTS: Client[] = ['claude', 'claude-code', 'cursor', 'vscode', 'codex', 'amp', 'opencode', 'goose', 'letta', 'antigravity', 'windsurf', 'trae', 'codebuddy', 'qoder', 'github']; const SKILL_TYPES: { value: SkillType; label: string }[] = [ { value: 'personal', label: 'As Personal Skill' }, { value: 'project', label: 'As Project Skill' }, ]; const PACKAGE_MANAGERS: PackageManager[] = ['npm', 'bun', 'pnpm', 'yarn']; +const MENU_MAX_HEIGHT = 400; interface MenuPosition { top: number; @@ -45,12 +51,12 @@ export function InstallMenu({ skill, onInstall, disabled, defaultPackageManager const triggerRect = triggerRef.current.getBoundingClientRect(); const menuWidth = 180; - const menuHeight = 400; const gap = 8; const padding = 12; const viewportWidth = window.innerWidth; const viewportHeight = window.innerHeight; + const menuHeight = Math.min(MENU_MAX_HEIGHT, viewportHeight - padding * 2); let left: number; let top: number; @@ -111,22 +117,14 @@ export function InstallMenu({ skill, onInstall, disabled, defaultPackageManager const scrollableParent = document.querySelector('.panel-content'); if (!scrollableParent) return; - const preventScroll = (e: Event) => { - e.preventDefault(); - }; - if (open) { scrollableParent.classList.add('no-scroll'); - scrollableParent.addEventListener('wheel', preventScroll, { passive: false }); - scrollableParent.addEventListener('touchmove', preventScroll, { passive: false }); } else { scrollableParent.classList.remove('no-scroll'); } return () => { scrollableParent.classList.remove('no-scroll'); - scrollableParent.removeEventListener('wheel', preventScroll); - scrollableParent.removeEventListener('touchmove', preventScroll); }; }, [open]); @@ -246,6 +244,11 @@ const CLIENT_LOGOS: Record = { 'opencode': OpenCodeLogo, 'goose': GooseLogo, 'letta': LettaLogo, + 'antigravity': AntigravityLogo, + 'windsurf': WindsurfLogo, + 'trae': TraeLogo, + 'codebuddy': CodeBuddyLogo, + 'qoder': QoderLogo, 'github': null, }; diff --git a/src/components/Panel.css b/src/components/Panel.css index f9894ad..8938886 100644 --- a/src/components/Panel.css +++ b/src/components/Panel.css @@ -73,15 +73,7 @@ } .panel-content.no-scroll { - overflow-y: scroll; -} - -.panel-content.no-scroll::-webkit-scrollbar-thumb { - background-color: transparent !important; -} - -.panel-content.no-scroll::-webkit-scrollbar-track { - background-color: transparent !important; + overflow-y: hidden; } /* Loading state */ diff --git a/src/components/Settings.tsx b/src/components/Settings.tsx index d85a225..1218a4c 100644 --- a/src/components/Settings.tsx +++ b/src/components/Settings.tsx @@ -32,7 +32,7 @@ export function Settings({ settings, onUpdate, onBack }: SettingsProps) { const shortcutInputRef = useRef(null); useEffect(() => { - getVersion().then(setAppVersion).catch(() => setAppVersion('1.0.0')); + getVersion().then(setAppVersion).catch(() => setAppVersion('1.0.5')); }, []); const handleDownloadPathSelect = async () => { diff --git a/src/types/index.ts b/src/types/index.ts index 720a8f5..890d7e0 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -37,6 +37,11 @@ export type Client = | 'opencode' | 'goose' | 'letta' + | 'antigravity' + | 'windsurf' + | 'trae' + | 'codebuddy' + | 'qoder' | 'github'; export const CLIENT_LABELS: Record = { @@ -49,6 +54,11 @@ export const CLIENT_LABELS: Record = { 'opencode': 'OpenCode', 'goose': 'Goose', 'letta': 'Letta', + 'antigravity': 'Antigravity', + 'windsurf': 'Windsurf', + 'trae': 'Trae', + 'codebuddy': 'CodeBuddy', + 'qoder': 'Qoder', 'github': 'GitHub', }; @@ -62,6 +72,11 @@ export const CLIENT_LOCAL_SKILL_PATHS: Record = { 'opencode': '.opencode/skills/', 'goose': '.goose/skills/', 'letta': '.letta/skills/', + 'antigravity': '.antigravity/skills/', + 'windsurf': '.windsurf/skills/', + 'trae': '.trae/skills/', + 'codebuddy': '.codebuddy/skills/', + 'qoder': '.qoder/skills/', 'github': '.github/skills/', }; @@ -75,6 +90,11 @@ export const CLIENT_PERSONAL_SKILL_PATHS: Record = { 'opencode': '~/.opencode/skills/', 'goose': '~/.goose/skills/', 'letta': '~/.letta/skills/', + 'antigravity': '~/.antigravity/skills/', + 'windsurf': '~/.windsurf/skills/', + 'trae': '~/.trae/skills/', + 'codebuddy': '~/.codebuddy/skills/', + 'qoder': '~/.qoder/skills/', 'github': '~/.github/skills/', };