Compare commits

..

2 Commits

12 changed files with 33 additions and 194 deletions
-87
View File
@@ -888,7 +888,6 @@ exec bash --norc --noprofile
"kitty" => launch_macos_open_app("kitty", &script_file, false),
"ghostty" => launch_macos_open_app("Ghostty", &script_file, true),
"wezterm" => launch_macos_open_app("WezTerm", &script_file, true),
"tabby" => launch_macos_tabby(&script_file),
_ => launch_macos_terminal_app(&script_file), // "terminal" or default
};
@@ -1006,39 +1005,6 @@ fn launch_macos_open_app(
Ok(())
}
/// macOS: Tabby
#[cfg(target_os = "macos")]
fn launch_macos_tabby(script_file: &std::path::Path) -> Result<(), String> {
use std::process::Command;
let output = Command::new("open")
.args(build_macos_tabby_args(script_file))
.output()
.map_err(|e| format!("启动 Tabby 失败: {e}"))?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
return Err(format!(
"Tabby 启动失败 (exit code: {:?}): {}",
output.status.code(),
stderr
));
}
Ok(())
}
fn build_macos_tabby_args(script_file: &std::path::Path) -> Vec<String> {
vec![
"-na".to_string(),
"Tabby".to_string(),
"--args".to_string(),
"run".to_string(),
"bash".to_string(),
script_file.to_string_lossy().into_owned(),
]
}
/// Linux: 根据用户首选终端启动
#[cfg(target_os = "linux")]
fn launch_linux_terminal(config_file: &std::path::Path) -> Result<(), String> {
@@ -1057,8 +1023,6 @@ fn launch_linux_terminal(config_file: &std::path::Path) -> Result<(), String> {
("alacritty", vec!["-e"]),
("kitty", vec!["-e"]),
("ghostty", vec!["-e"]),
("tabby", vec!["run"]),
("tabby-terminal", vec!["run"]),
];
// Create temp script file
@@ -1184,7 +1148,6 @@ del \"%~f0\" >nul 2>&1
"PowerShell",
),
"wt" => run_windows_start_command(&["wt", "cmd", "/K", &bat_path], "Windows Terminal"),
"tabby" => run_windows_tabby_command(&bat_path),
_ => run_windows_start_command(&["cmd", "/K", &bat_path], "cmd"), // "cmd" or default
};
@@ -1201,56 +1164,6 @@ del \"%~f0\" >nul 2>&1
result
}
#[cfg(target_os = "windows")]
fn run_windows_tabby_command(bat_path: &str) -> Result<(), String> {
use std::process::Command;
let mut last_error = String::from("未找到可用的 Tabby 可执行文件");
for candidate in windows_tabby_executable_candidates() {
let result = Command::new(&candidate)
.args(["run", "cmd", "/K", bat_path])
.creation_flags(CREATE_NO_WINDOW)
.spawn();
match result {
Ok(_) => return Ok(()),
Err(e) => {
last_error = format!("执行 {} 失败: {}", candidate.display(), e);
}
}
}
Err(last_error)
}
#[cfg(target_os = "windows")]
fn windows_tabby_executable_candidates() -> Vec<std::path::PathBuf> {
let mut candidates = Vec::new();
for candidate in ["tabby", "tabby.exe", "Tabby", "Tabby.exe"] {
push_unique_path(&mut candidates, std::path::PathBuf::from(candidate));
}
if let Some(local_app_data) = std::env::var_os("LOCALAPPDATA") {
let tabby_dir = std::path::PathBuf::from(local_app_data)
.join("Programs")
.join("Tabby");
push_unique_path(&mut candidates, tabby_dir.join("Tabby.exe"));
push_unique_path(&mut candidates, tabby_dir.join("tabby.exe"));
}
for env_key in ["ProgramFiles", "ProgramFiles(x86)"] {
if let Some(base_dir) = std::env::var_os(env_key) {
let tabby_dir = std::path::PathBuf::from(base_dir).join("Tabby");
push_unique_path(&mut candidates, tabby_dir.join("Tabby.exe"));
push_unique_path(&mut candidates, tabby_dir.join("tabby.exe"));
}
}
candidates
}
/// Windows: Run a start command with common error handling
#[cfg(target_os = "windows")]
fn run_windows_start_command(args: &[&str], terminal_name: &str) -> Result<(), String> {
+2 -2
View File
@@ -22,10 +22,10 @@ pub mod skill;
mod stream_check;
mod sync_support;
mod lightweight;
mod usage;
mod webdav_sync;
mod workspace;
mod lightweight;
pub use auth::*;
pub use config::*;
@@ -48,7 +48,7 @@ pub use settings::*;
pub use skill::*;
pub use stream_check::*;
pub use lightweight::*;
pub use usage::*;
pub use webdav_sync::*;
pub use workspace::*;
pub use lightweight::*;
+1 -1
View File
@@ -87,4 +87,4 @@ pub fn exit_lightweight_mode(app: &tauri::AppHandle) -> Result<(), String> {
pub fn is_lightweight_mode() -> bool {
LIGHTWEIGHT_MODE.load(Ordering::Acquire)
}
}
@@ -21,7 +21,6 @@ pub fn launch_terminal(
"kitty" => launch_kitty(command, cwd),
"wezterm" => launch_wezterm(command, cwd),
"alacritty" => launch_alacritty(command, cwd),
"tabby" => launch_tabby(command, cwd),
"custom" => launch_custom(command, cwd, custom_config),
_ => Err(format!("Unsupported terminal target: {target}")),
}
@@ -212,35 +211,6 @@ fn launch_alacritty(command: &str, cwd: Option<&str>) -> Result<(), String> {
}
}
fn launch_tabby(command: &str, cwd: Option<&str>) -> Result<(), String> {
let status = Command::new("open")
.args(build_tabby_args(command, cwd))
.status()
.map_err(|e| format!("Failed to launch Tabby: {e}"))?;
if status.success() {
Ok(())
} else {
Err("Failed to launch Tabby.".to_string())
}
}
fn build_tabby_args(command: &str, cwd: Option<&str>) -> Vec<String> {
let full_command = build_shell_command(command, cwd);
let shell = std::env::var("SHELL").unwrap_or_else(|_| "/bin/zsh".to_string());
vec![
"-na".to_string(),
"Tabby".to_string(),
"--args".to_string(),
"run".to_string(),
shell,
"-l".to_string(),
"-c".to_string(),
full_command,
]
}
fn launch_custom(
command: &str,
cwd: Option<&str>,
@@ -335,44 +305,4 @@ mod tests {
"raw:echo foo\\\\\\\\bar\\npwd\\n"
);
}
#[test]
fn tabby_uses_login_shell_for_resume_commands() {
let shell = std::env::var("SHELL").unwrap_or_else(|_| "/bin/zsh".to_string());
let args = build_tabby_args("claude --resume abc-123", Some("/tmp/project dir"));
assert_eq!(
args,
vec![
"-na",
"Tabby",
"--args",
"run",
&shell,
"-l",
"-c",
"cd \"/tmp/project dir\" && claude --resume abc-123",
]
);
}
#[test]
fn tabby_keeps_command_when_no_cwd_is_provided() {
let shell = std::env::var("SHELL").unwrap_or_else(|_| "/bin/zsh".to_string());
let args = build_tabby_args("claude --resume abc-123", None);
assert_eq!(
args,
vec![
"-na",
"Tabby",
"--args",
"run",
&shell,
"-l",
"-c",
"claude --resume abc-123",
]
);
}
}
+3 -3
View File
@@ -264,9 +264,9 @@ pub struct AppSettings {
// ===== 终端设置 =====
/// 首选终端应用(可选,默认使用系统默认终端)
/// - macOS: "terminal" | "iterm2" | "alacritty" | "kitty" | "ghostty" | "wezterm" | "tabby"
/// - Windows: "cmd" | "powershell" | "wt" (Windows Terminal) | "tabby"
/// - Linux: "gnome-terminal" | "konsole" | "xfce4-terminal" | "alacritty" | "kitty" | "ghostty" | "tabby"
/// - macOS: "terminal" | "iterm2" | "warp" | "alacritty" | "kitty" | "ghostty"
/// - Windows: "cmd" | "powershell" | "wt" (Windows Terminal)
/// - Linux: "gnome-terminal" | "konsole" | "xfce4-terminal" | "alacritty" | "kitty" | "ghostty"
#[serde(default, skip_serializing_if = "Option::is_none")]
pub preferred_terminal: Option<String>,
}
+4 -3
View File
@@ -393,10 +393,11 @@ pub fn create_tray_menu(
true,
crate::lightweight::is_lightweight_mode(),
None::<&str>,
)
.map_err(|e| AppError::Message(format!("创建轻量模式菜单失败: {e}")))?;
).map_err(|e| AppError::Message(format!("创建轻量模式菜单失败: {e}")))?;
menu_builder = menu_builder.item(&lightweight_item).separator();
menu_builder = menu_builder
.item(&lightweight_item)
.separator();
// 退出菜单(分隔符已在上面的 section 循环中添加)
let quit_item = MenuItem::with_id(app, "quit", tray_texts.quit, true, None::<&str>)
+11 -4
View File
@@ -123,6 +123,7 @@ export function ProviderCard({
// OMO and OMO Slim share the same card behavior
const isAnyOmo = isOmo || isOmoSlim;
const handleDisableAnyOmo = isOmoSlim ? onDisableOmoSlim : onDisableOmo;
const isAdditiveMode = appId === "opencode" && !isAnyOmo;
const { data: health } = useProviderHealth(provider.id, appId);
@@ -209,9 +210,12 @@ export function ProviderCard({
: isCurrent;
const shouldUseGreen = !isAnyOmo && isProxyTakeover && isActiveProvider;
const hasPersistentConfigHighlight = isAdditiveMode && isInConfig;
const shouldUseBlue =
(isAnyOmo && isActiveProvider) ||
(!isAnyOmo && !isProxyTakeover && isActiveProvider);
(!isAnyOmo &&
!isProxyTakeover &&
(isActiveProvider || hasPersistentConfigHighlight));
return (
<div
@@ -224,7 +228,8 @@ export function ProviderCard({
shouldUseGreen &&
"border-emerald-500/60 shadow-sm shadow-emerald-500/10",
shouldUseBlue && "border-blue-500/60 shadow-sm shadow-blue-500/10",
!isActiveProvider && "hover:shadow-sm",
!(isActiveProvider || hasPersistentConfigHighlight) &&
"hover:shadow-sm",
dragHandleProps?.isDragging &&
"cursor-grabbing border-primary shadow-lg scale-105 z-10",
)}
@@ -234,8 +239,10 @@ export function ProviderCard({
"absolute inset-0 bg-gradient-to-r to-transparent transition-opacity duration-500 pointer-events-none",
shouldUseGreen && "from-emerald-500/10",
shouldUseBlue && "from-blue-500/10",
!isActiveProvider && "from-primary/10",
isActiveProvider ? "opacity-100" : "opacity-0",
!shouldUseGreen && !shouldUseBlue && "from-primary/10",
isActiveProvider || hasPersistentConfigHighlight
? "opacity-100"
: "opacity-0",
)}
/>
<div className="relative flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
@@ -16,7 +16,6 @@ const MACOS_TERMINALS = [
{ value: "kitty", labelKey: "settings.terminal.options.macos.kitty" },
{ value: "ghostty", labelKey: "settings.terminal.options.macos.ghostty" },
{ value: "wezterm", labelKey: "settings.terminal.options.macos.wezterm" },
{ value: "tabby", labelKey: "settings.terminal.options.macos.tabby" },
] as const;
const WINDOWS_TERMINALS = [
@@ -26,7 +25,6 @@ const WINDOWS_TERMINALS = [
labelKey: "settings.terminal.options.windows.powershell",
},
{ value: "wt", labelKey: "settings.terminal.options.windows.wt" },
{ value: "tabby", labelKey: "settings.terminal.options.windows.tabby" },
] as const;
const LINUX_TERMINALS = [
@@ -42,7 +40,6 @@ const LINUX_TERMINALS = [
{ value: "alacritty", labelKey: "settings.terminal.options.linux.alacritty" },
{ value: "kitty", labelKey: "settings.terminal.options.linux.kitty" },
{ value: "ghostty", labelKey: "settings.terminal.options.linux.ghostty" },
{ value: "tabby", labelKey: "settings.terminal.options.linux.tabby" },
] as const;
// Get terminals for the current platform
+3 -6
View File
@@ -496,14 +496,12 @@
"alacritty": "Alacritty",
"kitty": "Kitty",
"ghostty": "Ghostty",
"wezterm": "WezTerm",
"tabby": "Tabby"
"wezterm": "WezTerm"
},
"windows": {
"cmd": "Command Prompt",
"powershell": "PowerShell",
"wt": "Windows Terminal",
"tabby": "Tabby"
"wt": "Windows Terminal"
},
"linux": {
"gnomeTerminal": "GNOME Terminal",
@@ -511,8 +509,7 @@
"xfce4Terminal": "Xfce4 Terminal",
"alacritty": "Alacritty",
"kitty": "Kitty",
"ghostty": "Ghostty",
"tabby": "Tabby"
"ghostty": "Ghostty"
}
}
},
+3 -6
View File
@@ -496,14 +496,12 @@
"alacritty": "Alacritty",
"kitty": "Kitty",
"ghostty": "Ghostty",
"wezterm": "WezTerm",
"tabby": "Tabby"
"wezterm": "WezTerm"
},
"windows": {
"cmd": "コマンドプロンプト",
"powershell": "PowerShell",
"wt": "Windows Terminal",
"tabby": "Tabby"
"wt": "Windows Terminal"
},
"linux": {
"gnomeTerminal": "GNOME Terminal",
@@ -511,8 +509,7 @@
"xfce4Terminal": "Xfce4 Terminal",
"alacritty": "Alacritty",
"kitty": "Kitty",
"ghostty": "Ghostty",
"tabby": "Tabby"
"ghostty": "Ghostty"
}
}
},
+3 -6
View File
@@ -496,14 +496,12 @@
"alacritty": "Alacritty",
"kitty": "Kitty",
"ghostty": "Ghostty",
"wezterm": "WezTerm",
"tabby": "Tabby"
"wezterm": "WezTerm"
},
"windows": {
"cmd": "命令提示符",
"powershell": "PowerShell",
"wt": "Windows Terminal",
"tabby": "Tabby"
"wt": "Windows Terminal"
},
"linux": {
"gnomeTerminal": "GNOME Terminal",
@@ -511,8 +509,7 @@
"xfce4Terminal": "Xfce4 Terminal",
"alacritty": "Alacritty",
"kitty": "Kitty",
"ghostty": "Ghostty",
"tabby": "Tabby"
"ghostty": "Ghostty"
}
}
},
+3 -3
View File
@@ -303,9 +303,9 @@ export interface Settings {
// ===== 终端设置 =====
// 首选终端应用(可选,默认使用系统默认终端)
// macOS: "terminal" | "iterm2" | "alacritty" | "kitty" | "ghostty" | "wezterm" | "tabby"
// Windows: "cmd" | "powershell" | "wt" | "tabby"
// Linux: "gnome-terminal" | "konsole" | "xfce4-terminal" | "alacritty" | "kitty" | "ghostty" | "tabby"
// macOS: "terminal" | "iterm2" | "warp" | "alacritty" | "kitty" | "ghostty"
// Windows: "cmd" | "powershell" | "wt"
// Linux: "gnome-terminal" | "konsole" | "xfce4-terminal" | "alacritty" | "kitty" | "ghostty"
preferredTerminal?: string;
}