generated from nhcarrigan/template
b745100bd5
## Summary This PR covers the full audit of Claude CLI changes from 2.1.50 to 2.1.53, plus a batch of bug fixes, new features, and maintenance work identified during that review. ### New Features - **Workspace trust gate** — detects hooks, MCP servers, and custom commands in a workspace before connecting; persists trust decisions so users aren't prompted repeatedly - **Custom background image** — users can set a background image with configurable opacity; character panel and compact mode go transparent when active - **Draggable tab reordering** — conversation tabs can be reordered via pointer-event drag-and-drop (HTML5 drag is intercepted by Tauri/WebView2, so pointer events are used instead) - **Org UUID in account info** — exposes the org UUID from Claude auth status ### Bug Fixes - **Unread dot false positives** — initialise unread counts on mount to prevent all tabs showing the blue dot after toggling the file editor (Closes #164) - **Watchdog for hung WSL bridge** — detects connections that never receive `system:init` and kills the stale process after 1 minute (Closes #166) - **Suppress terminal window flash on Windows** — applies `CREATE_NO_WINDOW` to all subprocesses via a `HideWindow` trait extension (Closes #165) - **HTML escaping in markdown renderer** — escape `<` and `>` in `codespan` and `html` renderer callbacks to prevent raw HTML injection (Closes #169) ### Maintenance - Verify stream-JSON handles tool results above the 50K threshold correctly (Closes #162) - Reviewed hook security fixes from CLI 2.1.51 — not applicable to our setup (Closes #163) - Expose org UUID from `claude auth status` (Closes #160) - Clean up Svelte and Vite build warnings (`a11y_click_events_have_key_events`, `state_referenced_locally`, `non_reactive_update`, `codeSplitting`, chunk size, CodeMirror dynamic import) - Update all npm dependencies to latest compatible versions with exact pinning (Closes #81, Closes #82, Closes #83, Closes #84, Closes #85, Closes #86, Closes #87, Closes #90, Closes #91, Closes #93, Closes #94, Closes #95, Closes #96, Closes #97, Closes #98, Closes #99, Closes #101, Closes #141, Closes #142, Closes #143, Closes #145, Closes #146, Closes #147) - Run `cargo update` to bring Cargo.lock up to date ### Closes Closes #160 Closes #162 Closes #163 Closes #164 Closes #165 Closes #166 Closes #167 Closes #168 Closes #169 Closes #81 Closes #82 Closes #83 Closes #84 Closes #85 Closes #86 Closes #87 Closes #90 Closes #91 Closes #93 Closes #94 Closes #95 Closes #96 Closes #97 Closes #98 Closes #99 Closes #101 Closes #141 Closes #142 Closes #143 Closes #145 Closes #146 Closes #147 ✨ This PR was created with help from Hikari~ 🌸 Reviewed-on: #171 Co-authored-by: Hikari <hikari@nhcarrigan.com> Co-committed-by: Hikari <hikari@nhcarrigan.com>
89 lines
2.6 KiB
Rust
89 lines
2.6 KiB
Rust
use std::process::Command;
|
|
use tauri::command;
|
|
|
|
use crate::process_ext::HideWindow;
|
|
|
|
#[command]
|
|
pub async fn send_wsl_notification(title: String, body: String) -> Result<(), String> {
|
|
// Method 1: Try Windows 10/11 toast notification using PowerShell
|
|
let toast_command = format!(
|
|
r#"
|
|
Add-Type -AssemblyName System.Runtime.WindowsRuntime
|
|
$null = [Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime]
|
|
$null = [Windows.Data.Xml.Dom.XmlDocument, Windows.Data.Xml.Dom.XmlDocument, ContentType = WindowsRuntime]
|
|
|
|
$APP_ID = 'Hikari Desktop'
|
|
|
|
$template = @"
|
|
<toast>
|
|
<visual>
|
|
<binding template="ToastGeneric">
|
|
<text>{0}</text>
|
|
<text>{1}</text>
|
|
</binding>
|
|
</visual>
|
|
</toast>
|
|
"@
|
|
|
|
$xml = New-Object Windows.Data.Xml.Dom.XmlDocument
|
|
$xml.LoadXml($template -f ('{0}' -replace "'", "''"), ('{1}' -replace "'", "''"))
|
|
|
|
$toast = New-Object Windows.UI.Notifications.ToastNotification $xml
|
|
$notifier = [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier($APP_ID)
|
|
$notifier.Show($toast)
|
|
"#,
|
|
title.replace("'", "''").replace("\"", "\\\""),
|
|
body.replace("'", "''").replace("\"", "\\\"")
|
|
);
|
|
|
|
// Try PowerShell.exe through WSL
|
|
let output = Command::new("/mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe")
|
|
.hide_window()
|
|
.arg("-NoProfile")
|
|
.arg("-ExecutionPolicy")
|
|
.arg("Bypass")
|
|
.arg("-WindowStyle")
|
|
.arg("Hidden")
|
|
.arg("-Command")
|
|
.arg(&toast_command)
|
|
.output();
|
|
|
|
match output {
|
|
Ok(result) => {
|
|
if result.status.success() {
|
|
tracing::info!("WSL notification sent successfully");
|
|
return Ok(());
|
|
} else {
|
|
let stderr = String::from_utf8_lossy(&result.stderr);
|
|
tracing::error!("PowerShell toast failed: {}", stderr);
|
|
}
|
|
}
|
|
Err(e) => {
|
|
tracing::error!("Failed to run PowerShell: {}", e);
|
|
}
|
|
}
|
|
|
|
// Skip msg.exe as it creates alert boxes
|
|
// Method 2 removed
|
|
|
|
// Method 3: Try wsl-notify-send if available
|
|
let notify_result = Command::new("wsl-notify-send")
|
|
.hide_window()
|
|
.arg("--appId")
|
|
.arg("HikariDesktop")
|
|
.arg("--category")
|
|
.arg(&title)
|
|
.arg(&body)
|
|
.output();
|
|
|
|
if let Ok(result) = notify_result {
|
|
if result.status.success() {
|
|
tracing::info!("Notification sent via wsl-notify-send");
|
|
return Ok(());
|
|
}
|
|
}
|
|
|
|
// If all methods fail, return an error
|
|
Err("All WSL notification methods failed".to_string())
|
|
}
|