diff --git a/nix/default.nix b/nix/default.nix index 8647c6a..fa14483 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -52,15 +52,16 @@ let ]; gstPluginPath = pkgs.lib.concatMapStringsSep ":" (p: "${p}/lib/gstreamer-1.0") gstPlugins + + ":${pkgs.gst_all_1.gstreamer.out}/lib/gstreamer-1.0" + ":${pkgs.pipewire}/lib/gstreamer-1.0"; # Laufzeit-Binaries die die App spawnen muss (node fuer claude-bridge.js, # npm fuer apply_bundle_update, tar fuer Bundle-Extract) - runtimeBins = [ pkgs.nodejs_22 pkgs.gnutar pkgs.gzip ]; + runtimeBins = [ pkgs.nodejs_22 pkgs.gnutar pkgs.gzip pkgs.ffmpeg-headless ]; in pkgs.stdenv.mkDerivation { pname = "claude-desktop"; - version = "0.1.0"; + version = "0.1.1"; # Keine Quelldateien — Wir packen nur Wrapper + Desktop-Entry dontUnpack = true; diff --git a/package-lock.json b/package-lock.json index 8c022c3..07c6575 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@anthropic-ai/claude-code": "^0.2.0", "@anthropic-ai/sdk": "^0.88.0", "@tauri-apps/api": "^2.0.0", + "@tauri-apps/plugin-dialog": "^2.7.0", "@tauri-apps/plugin-shell": "^2.0.0", "marked": "^18.0.0", "mermaid": "^11.4.0", @@ -1821,6 +1822,15 @@ "node": ">= 10" } }, + "node_modules/@tauri-apps/plugin-dialog": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-dialog/-/plugin-dialog-2.7.0.tgz", + "integrity": "sha512-4nS/hfGMGCXiAS3LtVjH9AgsSAPJeG/7R+q8agTFqytjnMa4Zq95Bq8WzVDkckpanX+yyRHXnRtrKXkANKDHvw==", + "license": "MIT OR Apache-2.0", + "dependencies": { + "@tauri-apps/api": "^2.10.1" + } + }, "node_modules/@tauri-apps/plugin-shell": { "version": "2.3.5", "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-shell/-/plugin-shell-2.3.5.tgz", diff --git a/package.json b/package.json index 014ba6b..b89a620 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "@anthropic-ai/claude-code": "^0.2.0", "@anthropic-ai/sdk": "^0.88.0", "@tauri-apps/api": "^2.0.0", + "@tauri-apps/plugin-dialog": "^2.7.0", "@tauri-apps/plugin-shell": "^2.0.0", "marked": "^18.0.0", "mermaid": "^11.4.0", diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index f8419cd..90e400c 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -490,6 +490,7 @@ dependencies = [ "sha2", "tauri", "tauri-build", + "tauri-plugin-dialog", "tauri-plugin-shell", "tokio", "tokio-tungstenite", @@ -2743,6 +2744,7 @@ checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ "bitflags 2.11.0", "block2", + "libc", "objc2", "objc2-core-foundation", ] @@ -3618,6 +3620,30 @@ dependencies = [ "web-sys", ] +[[package]] +name = "rfd" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15ad77d9e70a92437d8f74c35d99b4e4691128df018833e99f90bcd36152672" +dependencies = [ + "block2", + "dispatch2", + "glib-sys", + "gobject-sys", + "gtk-sys", + "js-sys", + "log", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "raw-window-handle", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-sys 0.60.2", +] + [[package]] name = "ring" version = "0.17.14" @@ -4637,6 +4663,48 @@ dependencies = [ "walkdir", ] +[[package]] +name = "tauri-plugin-dialog" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1fa4150c95ae391946cc8b8f905ab14797427caba3a8a2f79628e956da91809" +dependencies = [ + "log", + "raw-window-handle", + "rfd", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "tauri-plugin-fs", + "thiserror 2.0.18", + "url", +] + +[[package]] +name = "tauri-plugin-fs" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36e1ec28b79f3d0683f4507e1615c36292c0ea6716668770d4396b9b39871ed8" +dependencies = [ + "anyhow", + "dunce", + "glob", + "log", + "objc2-foundation", + "percent-encoding", + "schemars 0.8.22", + "serde", + "serde_json", + "serde_repr", + "tauri", + "tauri-plugin", + "tauri-utils", + "thiserror 2.0.18", + "toml 0.9.12+spec-1.1.0", + "url", +] + [[package]] name = "tauri-plugin-shell" version = "2.3.5" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index a2abb2e..26facc8 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -27,6 +27,7 @@ base64 = "0.22" tokio-tungstenite = "0.23" futures-util = "0.3" sha2 = "0.10" +tauri-plugin-dialog = "2.7.0" [target.'cfg(target_os = "linux")'.dependencies] webkit2gtk = "2.0" diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json index b802384..c0c2169 100644 --- a/src-tauri/capabilities/default.json +++ b/src-tauri/capabilities/default.json @@ -16,6 +16,7 @@ "shell:allow-execute", "shell:allow-spawn", "shell:allow-stdin-write", - "shell:allow-kill" + "shell:allow-kill", + "dialog:allow-open" ] } diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index fc5b0c0..21ab39b 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -33,6 +33,7 @@ mod chat_window; pub fn run() { tauri::Builder::default() .plugin(tauri_plugin_shell::init()) + .plugin(tauri_plugin_dialog::init()) .manage(Arc::new(Mutex::new(claude::ClaudeState::default()))) .manage(guard::GuardState::new(Mutex::new(guard::GuardRails::new()))) .manage::(Arc::new(Mutex::new(hooks::HookManager::default()))) diff --git a/src/lib/components/SessionList.svelte b/src/lib/components/SessionList.svelte index 3b40bc7..31bedd7 100644 --- a/src/lib/components/SessionList.svelte +++ b/src/lib/components/SessionList.svelte @@ -2,6 +2,7 @@ import { onMount, onDestroy } from 'svelte'; import { invoke } from '@tauri-apps/api/core'; import { listen, type UnlistenFn } from '@tauri-apps/api/event'; + import { open } from '@tauri-apps/plugin-dialog'; import { messages, clearAll, isProcessing, currentSessionId, setMessagesFromDb, type DbMessage } from '$lib/stores/app'; interface Session { @@ -53,6 +54,27 @@ } } + async function browseDir() { + try { + const selected = await open({ + directory: true, + multiple: false, + title: 'Projektverzeichnis wählen', + defaultPath: '/mnt', + }); + if (selected && typeof selected === 'string') { + newProjectDir = selected; + // Auto-Name aus Verzeichnisname wenn leer + if (!newProjectName.trim()) { + const parts = selected.replace(/\/+$/, '').split('/'); + newProjectName = parts[parts.length - 1] || ''; + } + } + } catch (err) { + console.error('Fehler beim Verzeichnis-Dialog:', err); + } + } + async function addProject() { const name = newProjectName.trim(); const dir = newProjectDir.trim(); @@ -274,14 +296,18 @@ placeholder="Projektname" onkeydown={(e: KeyboardEvent) => e.key === 'Enter' && addProject()} /> - e.key === 'Enter' && addProject()} - /> +
+ e.key === 'Enter' && addProject()} + readonly + /> + +
- +
@@ -541,6 +567,28 @@ padding: var(--spacing-xs) var(--spacing-sm); } + .dir-input-row { + display: flex; + gap: var(--spacing-xs); + } + + .dir-input-row input { + flex: 1; + cursor: pointer; + } + + .btn-browse { + padding: var(--spacing-xs) var(--spacing-sm); + background: var(--accent); + border-radius: var(--radius-sm); + font-size: 0.75rem; + flex-shrink: 0; + } + + .btn-browse:hover { + background: var(--accent-hover); + } + .project-add-buttons { display: flex; gap: var(--spacing-xs);