refactor: migrate to shell-env and custom desktop notifications bridge
This commit is contained in:
@@ -480,71 +480,12 @@ async function pruneClaudeAgentSdk(runtimeRoot) {
|
||||
}
|
||||
}
|
||||
|
||||
async function pruneCodexCli(runtimeRoot) {
|
||||
const codexTargetTriple = {
|
||||
darwin: { arm64: "aarch64-apple-darwin", x64: "x86_64-apple-darwin" },
|
||||
linux: { arm64: "aarch64-unknown-linux-musl", x64: "x86_64-unknown-linux-musl" },
|
||||
win32: { arm64: "aarch64-pc-windows-msvc", x64: "x86_64-pc-windows-msvc" },
|
||||
};
|
||||
const codexPlatformPackages = [
|
||||
"@openai/codex-darwin-arm64",
|
||||
"@openai/codex-darwin-x64",
|
||||
"@openai/codex-linux-arm64",
|
||||
"@openai/codex-linux-x64",
|
||||
"@openai/codex-win32-arm64",
|
||||
"@openai/codex-win32-x64",
|
||||
];
|
||||
const currentTriple = codexTargetTriple[process.platform]?.[process.arch];
|
||||
const currentPackage = currentTriple
|
||||
? `@openai/codex-${process.platform === "win32" ? "win32" : process.platform}-${process.arch}`
|
||||
: null;
|
||||
|
||||
const openaiScope = path.join(runtimeRoot, "node_modules", "@openai");
|
||||
for (const pkg of codexPlatformPackages) {
|
||||
const pkgName = pkg.replace("@openai/", "");
|
||||
if (currentPackage && pkg === currentPackage) {
|
||||
continue;
|
||||
}
|
||||
await removeIfExists(path.join(openaiScope, pkgName));
|
||||
}
|
||||
}
|
||||
|
||||
async function pruneOpenCodeCli(runtimeRoot) {
|
||||
const opencodePlatformPackages = [
|
||||
"opencode-darwin-arm64",
|
||||
"opencode-darwin-x64",
|
||||
"opencode-linux-arm64",
|
||||
"opencode-linux-x64",
|
||||
"opencode-linux-x64-baseline",
|
||||
"opencode-linux-arm64-musl",
|
||||
"opencode-linux-x64-musl",
|
||||
"opencode-linux-x64-baseline-musl",
|
||||
"opencode-windows-x64",
|
||||
"opencode-windows-arm64",
|
||||
];
|
||||
const platformMap = { darwin: "darwin", linux: "linux", win32: "windows" };
|
||||
const currentPlatform = platformMap[process.platform];
|
||||
const currentPackage = currentPlatform
|
||||
? `opencode-${currentPlatform}-${process.arch}`
|
||||
: null;
|
||||
|
||||
const nodeModules = path.join(runtimeRoot, "node_modules");
|
||||
for (const pkg of opencodePlatformPackages) {
|
||||
if (currentPackage && pkg === currentPackage) {
|
||||
continue;
|
||||
}
|
||||
await removeIfExists(path.join(nodeModules, pkg));
|
||||
}
|
||||
}
|
||||
|
||||
async function pruneManagedRuntime(runtimeRoot) {
|
||||
await Promise.all([
|
||||
pruneNodeDistribution(runtimeRoot),
|
||||
pruneOnnxRuntime(runtimeRoot),
|
||||
pruneNodePty(runtimeRoot),
|
||||
pruneClaudeAgentSdk(runtimeRoot),
|
||||
pruneCodexCli(runtimeRoot),
|
||||
pruneOpenCodeCli(runtimeRoot),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
Generated
+1
@@ -2637,6 +2637,7 @@ dependencies = [
|
||||
"futures-util",
|
||||
"http",
|
||||
"log",
|
||||
"mac-notification-sys",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri",
|
||||
|
||||
@@ -41,6 +41,8 @@ tauri-plugin-websocket = "2"
|
||||
tokio = { version = "1", features = ["net", "sync"] }
|
||||
tokio-tungstenite = "0.24"
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
mac-notification-sys = "0.6"
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use tauri::{AppHandle, Runtime};
|
||||
|
||||
pub const DESKTOP_NOTIFICATION_CLICK_EVENT: &str = "desktop-notification-click";
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DesktopNotificationInput {
|
||||
pub title: String,
|
||||
pub body: Option<String>,
|
||||
pub data: Option<Value>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct DesktopNotificationClickPayload {
|
||||
data: Option<Value>,
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
mod platform {
|
||||
use super::{
|
||||
AppHandle, DesktopNotificationClickPayload, DesktopNotificationInput,
|
||||
DESKTOP_NOTIFICATION_CLICK_EVENT,
|
||||
};
|
||||
use std::sync::OnceLock;
|
||||
use tauri::{async_runtime, Emitter, Runtime};
|
||||
|
||||
const MACOS_NOTIFICATION_SENDER_BUNDLE_ID: &str = "dev.paseo.desktop";
|
||||
static MACOS_NOTIFICATION_SENDER_INIT: OnceLock<Result<(), String>> = OnceLock::new();
|
||||
|
||||
fn ensure_notification_sender() -> Result<(), String> {
|
||||
MACOS_NOTIFICATION_SENDER_INIT
|
||||
.get_or_init(|| {
|
||||
mac_notification_sys::set_application(MACOS_NOTIFICATION_SENDER_BUNDLE_ID)
|
||||
.map_err(|error| {
|
||||
format!(
|
||||
"Failed to initialize macOS notification sender for {}: {error}",
|
||||
MACOS_NOTIFICATION_SENDER_BUNDLE_ID
|
||||
)
|
||||
})
|
||||
})
|
||||
.clone()
|
||||
}
|
||||
|
||||
pub fn send_notification<R: Runtime>(
|
||||
app: AppHandle<R>,
|
||||
input: DesktopNotificationInput,
|
||||
) -> Result<(), String> {
|
||||
let _task = async_runtime::spawn_blocking(move || {
|
||||
if let Err(error) = ensure_notification_sender() {
|
||||
log::warn!("{error}");
|
||||
return;
|
||||
}
|
||||
|
||||
let mut notification = mac_notification_sys::Notification::default();
|
||||
notification
|
||||
.title(&input.title)
|
||||
.message(input.body.as_deref().unwrap_or(""))
|
||||
.wait_for_click(true);
|
||||
|
||||
match notification.send() {
|
||||
Ok(mac_notification_sys::NotificationResponse::Click) => {
|
||||
let payload = DesktopNotificationClickPayload { data: input.data };
|
||||
if let Err(error) = app.emit(DESKTOP_NOTIFICATION_CLICK_EVENT, payload) {
|
||||
log::warn!("failed to emit desktop notification click event: {error}");
|
||||
}
|
||||
}
|
||||
Ok(_) => {}
|
||||
Err(error) => {
|
||||
log::warn!("failed to send macOS notification: {error}");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
mod platform {
|
||||
use super::{AppHandle, DesktopNotificationInput};
|
||||
use tauri::Runtime;
|
||||
use tauri_plugin_notification::NotificationExt;
|
||||
|
||||
pub fn send_notification<R: Runtime>(
|
||||
app: AppHandle<R>,
|
||||
input: DesktopNotificationInput,
|
||||
) -> Result<(), String> {
|
||||
let mut notification = app.notification().builder().title(&input.title);
|
||||
if let Some(body) = &input.body {
|
||||
notification = notification.body(body);
|
||||
}
|
||||
|
||||
notification
|
||||
.show()
|
||||
.map_err(|error| format!("Failed to send desktop notification: {error}"))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn send_desktop_notification<R: Runtime>(
|
||||
app: AppHandle<R>,
|
||||
input: DesktopNotificationInput,
|
||||
) -> Result<(), String> {
|
||||
platform::send_notification(app, input)
|
||||
}
|
||||
@@ -11,7 +11,9 @@ use tauri::menu::{Menu, MenuItemBuilder, MenuItemKind, PredefinedMenuItem, Subme
|
||||
use tauri::{AppHandle, Manager, WebviewWindow};
|
||||
use tauri_plugin_updater::UpdaterExt;
|
||||
|
||||
mod desktop_notifications;
|
||||
mod runtime_manager;
|
||||
use desktop_notifications::send_desktop_notification;
|
||||
use runtime_manager::{
|
||||
cli_symlink_instructions, close_local_daemon_transport, managed_daemon_logs,
|
||||
managed_daemon_pairing, managed_daemon_status, managed_runtime_status,
|
||||
@@ -544,6 +546,7 @@ pub fn run() {
|
||||
read_file_base64,
|
||||
delete_attachment_file,
|
||||
garbage_collect_attachment_files,
|
||||
send_desktop_notification,
|
||||
webview_log
|
||||
])
|
||||
.setup(|app| {
|
||||
|
||||
Reference in New Issue
Block a user