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>
75 lines
2.4 KiB
Rust
75 lines
2.4 KiB
Rust
use std::io::Write;
|
|
use std::process::Command;
|
|
use tauri::command;
|
|
use tempfile::NamedTempFile;
|
|
|
|
use crate::process_ext::HideWindow;
|
|
|
|
#[command]
|
|
pub async fn send_vbs_notification(title: String, body: String) -> Result<(), String> {
|
|
// Create a VBScript that shows a Windows notification
|
|
let vbs_content = format!(
|
|
r#"
|
|
Set objShell = CreateObject("WScript.Shell")
|
|
objShell.Popup "{}" & vbCrLf & vbCrLf & "{}", 5, "{}", 64
|
|
"#,
|
|
body.replace("\"", "\"\"").replace("\n", "\" & vbCrLf & \""),
|
|
title.replace("\"", "\"\""),
|
|
title.replace("\"", "\"\"")
|
|
);
|
|
|
|
// Create a temporary VBS file
|
|
let mut temp_file =
|
|
NamedTempFile::new().map_err(|e| format!("Failed to create temp file: {}", e))?;
|
|
|
|
temp_file
|
|
.write_all(vbs_content.as_bytes())
|
|
.map_err(|e| format!("Failed to write VBS content: {}", e))?;
|
|
|
|
let temp_path = temp_file.path().to_string_lossy().to_string();
|
|
|
|
// Convert WSL path to Windows path
|
|
let windows_path = if temp_path.starts_with("/mnt/") {
|
|
// Convert /mnt/c/... to C:\...
|
|
let path_parts: Vec<&str> = temp_path.split('/').collect();
|
|
if path_parts.len() > 2 {
|
|
let drive_letter = path_parts[2].to_uppercase();
|
|
let rest_of_path = path_parts[3..].join("\\");
|
|
format!("{}:\\{}", drive_letter, rest_of_path)
|
|
} else {
|
|
temp_path.clone()
|
|
}
|
|
} else if temp_path.starts_with("/tmp/") {
|
|
// WSL temp files might be in a different location
|
|
// Try to use wslpath to convert
|
|
let output = Command::new("wslpath").hide_window().arg("-w").arg(&temp_path).output();
|
|
|
|
if let Ok(result) = output {
|
|
if result.status.success() {
|
|
String::from_utf8_lossy(&result.stdout).trim().to_string()
|
|
} else {
|
|
temp_path.clone()
|
|
}
|
|
} else {
|
|
temp_path.clone()
|
|
}
|
|
} else {
|
|
temp_path.clone()
|
|
};
|
|
|
|
// Execute the VBScript using wscript.exe
|
|
let output = Command::new("/mnt/c/Windows/System32/wscript.exe")
|
|
.hide_window()
|
|
.arg("//NoLogo")
|
|
.arg(&windows_path)
|
|
.output()
|
|
.map_err(|e| format!("Failed to execute VBScript: {}", e))?;
|
|
|
|
if !output.status.success() {
|
|
let error = String::from_utf8_lossy(&output.stderr);
|
|
return Err(format!("VBScript execution failed: {}", error));
|
|
}
|
|
|
|
Ok(())
|
|
}
|