Add full disk access checks and settings
Add background themes and custom images Add shell command logging toggle Add UTF-8 locale guarantee for PTY Add Claude hook settings injection Add hotkey system for GUI Add glass panel styling Add search disabled state for agent panels Add zoom toggle command Add device report filtering Add entitlements for notarization Update version to 0.1.27
This commit is contained in:
Generated
+1
-1
@@ -3440,7 +3440,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "spacesh-proto"
|
||||
version = "0.1.10"
|
||||
version = "0.1.26"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"serde",
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<!-- WKWebView's JavaScriptCore needs JIT + writable/executable memory under the
|
||||
hardened runtime required for notarization. -->
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
<!-- The bundle embeds the spaceshd sidecar (same Team) and loads system/webview
|
||||
components; relax library validation so loading never trips the hardened runtime. -->
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -534,6 +534,32 @@ pub fn open_external(url: String) -> Result<(), String> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Whether spaceshell.app has Full Disk Access. Terminals spawned inside the app
|
||||
/// inherit its TCC grants (the app is their "responsible process"), so without FDA
|
||||
/// commands like `tmutil` fail. Probe: reading the user's TCC database requires FDA —
|
||||
/// a permission error means we lack it; success (or the file being absent) means we
|
||||
/// have it.
|
||||
#[tauri::command]
|
||||
pub fn has_full_disk_access() -> bool {
|
||||
let Some(home) = std::env::var_os("HOME") else { return false };
|
||||
let probe = std::path::Path::new(&home).join("Library/Application Support/com.apple.TCC/TCC.db");
|
||||
match std::fs::File::open(&probe) {
|
||||
Ok(_) => true,
|
||||
Err(e) => e.kind() == std::io::ErrorKind::NotFound,
|
||||
}
|
||||
}
|
||||
|
||||
/// Open System Settings → Privacy & Security → Full Disk Access so the user can add
|
||||
/// spaceshell. macOS cannot grant this programmatically; we only deep-link the pane.
|
||||
#[tauri::command]
|
||||
pub fn open_full_disk_access_settings() -> Result<(), String> {
|
||||
std::process::Command::new("open")
|
||||
.arg("x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles")
|
||||
.spawn()
|
||||
.map_err(|e| e.to_string())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// List the user's installed font families (CoreText) so Settings can offer any of
|
||||
/// them for the terminal. Hidden system families (".SF NS" etc.) are dropped; the
|
||||
/// result is de-duplicated and sorted case-insensitively.
|
||||
@@ -568,8 +594,29 @@ pub async fn set_config(
|
||||
font_size: Option<u16>,
|
||||
theme: Option<String>,
|
||||
accent: Option<String>,
|
||||
background: Option<String>,
|
||||
background_image: Option<String>,
|
||||
log_shell_commands: Option<bool>,
|
||||
) -> Result<Value, String> {
|
||||
data_of(state.request(Cmd::SetConfig { default_shell, font_family, font_size, theme, accent }).await.map_err(|e| e.to_string())?)
|
||||
data_of(state.request(Cmd::SetConfig { default_shell, font_family, font_size, theme, accent, background, background_image, log_shell_commands }).await.map_err(|e| e.to_string())?)
|
||||
}
|
||||
|
||||
/// Read a local image file and return it as a `data:` URL for use as a CSS
|
||||
/// background. Kept in the GUI bridge (not the daemon) so the bytes load straight
|
||||
/// into the webview without crossing the socket.
|
||||
#[tauri::command]
|
||||
pub async fn read_image_data_url(path: String) -> Result<String, String> {
|
||||
use base64::Engine as _;
|
||||
let bytes = tokio::fs::read(&path).await.map_err(|e| e.to_string())?;
|
||||
let mime = match std::path::Path::new(&path).extension().and_then(|e| e.to_str()).map(|e| e.to_ascii_lowercase()).as_deref() {
|
||||
Some("png") => "image/png",
|
||||
Some("jpg") | Some("jpeg") => "image/jpeg",
|
||||
Some("webp") => "image/webp",
|
||||
Some("gif") => "image/gif",
|
||||
_ => "application/octet-stream",
|
||||
};
|
||||
let b64 = base64::engine::general_purpose::STANDARD.encode(&bytes);
|
||||
Ok(format!("data:{mime};base64,{b64}"))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
|
||||
@@ -57,9 +57,12 @@ pub fn run() {
|
||||
bridge::which_agents,
|
||||
bridge::check_update,
|
||||
bridge::open_external,
|
||||
bridge::has_full_disk_access,
|
||||
bridge::open_full_disk_access_settings,
|
||||
bridge::list_fonts,
|
||||
bridge::get_config,
|
||||
bridge::set_config,
|
||||
bridge::read_image_data_url,
|
||||
bridge::shutdown_daemon,
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"bundle": {
|
||||
"externalBin": ["bin/spaceshd"]
|
||||
"externalBin": ["bin/spaceshd"],
|
||||
"macOS": {
|
||||
"entitlements": "Entitlements.plist"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "spaceshell",
|
||||
"version": "0.1.10",
|
||||
"version": "0.1.27",
|
||||
"identifier": "xyz.spacesh.app",
|
||||
"build": {
|
||||
"frontendDist": "../dist",
|
||||
@@ -14,7 +14,9 @@
|
||||
{
|
||||
"title": "spaceshell",
|
||||
"width": 1100,
|
||||
"height": 720
|
||||
"height": 720,
|
||||
"titleBarStyle": "Overlay",
|
||||
"hiddenTitle": true
|
||||
}
|
||||
],
|
||||
"security": {
|
||||
|
||||
Reference in New Issue
Block a user