Files
hikari-desktop/src-tauri/src/wsl_notifications.rs
T
hikari b745100bd5
Security Scan and Upload / Security & DefectDojo Upload (push) Successful in 1m28s
CI / Lint & Test (push) Has started running
CI / Build Linux (push) Has been cancelled
CI / Build Windows (cross-compile) (push) Has been cancelled
feat: Claude CLI 2.1.50–2.1.53 audit (#171)
## 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>
2026-02-25 22:55:47 -08:00

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())
}