Modul-Split: Fachlogik nach domain/, OS-Code nach platform/, Tauri-Verdrahtung in app.rs/commands.rs
- lib.rs nur noch Prozessrollen-Dispatch + Panic-Tracer - KWin-Script als KDE-Pendant zur GNOME-Extension (Popup ans Zeiger- Rechteck), wird von deb/rpm mit ausgeliefert - SNI-Tray auf ksni (pure Rust), appindicator-Depends entfallen
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
//! Gemeinsame Test-Helfer der Domänen-Module: Pseudo-Home, In-Memory-Store,
|
||||
//! Kurzformen für Pool-/Projekt-Anlage.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
|
||||
use crate::domain::credentials::ApikeyStore;
|
||||
use crate::domain::paths::Paths;
|
||||
use crate::domain::pool::{create_apikey_pool_in, create_oauth_pool_in};
|
||||
use crate::domain::registry::register_project;
|
||||
|
||||
static N: AtomicU32 = AtomicU32::new(0);
|
||||
|
||||
/// Frisches Pseudo-Home pro Test; claude-projects existiert wie auf dem
|
||||
/// echten System.
|
||||
pub(crate) fn tmp_paths() -> Paths {
|
||||
let dir = std::env::temp_dir().join(format!(
|
||||
"ai-control-test-{}-{}",
|
||||
std::process::id(),
|
||||
N.fetch_add(1, Ordering::SeqCst)
|
||||
));
|
||||
fs::create_dir_all(dir.join("claude-projects")).unwrap();
|
||||
Paths { home: dir }
|
||||
}
|
||||
|
||||
/// In-Memory-ApikeyStore statt echtem Keychain.
|
||||
pub(crate) struct MapStore(pub(crate) std::sync::Mutex<HashMap<String, String>>);
|
||||
|
||||
pub(crate) fn map_store() -> MapStore {
|
||||
MapStore(std::sync::Mutex::new(HashMap::new()))
|
||||
}
|
||||
|
||||
impl ApikeyStore for MapStore {
|
||||
fn set(&self, pool: &str, key: &str) -> Result<(), String> {
|
||||
self.0.lock().unwrap().insert(pool.into(), key.into());
|
||||
Ok(())
|
||||
}
|
||||
fn has(&self, pool: &str) -> Result<bool, String> {
|
||||
Ok(self.0.lock().unwrap().contains_key(pool))
|
||||
}
|
||||
fn delete(&self, pool: &str) -> Result<(), String> {
|
||||
self.0.lock().unwrap().remove(pool);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Store ohne Keychain/Keyring — Schreiben scheitert, Lesen findet nichts.
|
||||
pub(crate) struct FailStore;
|
||||
|
||||
impl ApikeyStore for FailStore {
|
||||
fn set(&self, _pool: &str, _key: &str) -> Result<(), String> {
|
||||
Err("kein Keychain".into())
|
||||
}
|
||||
fn has(&self, _pool: &str) -> Result<bool, String> {
|
||||
Ok(false)
|
||||
}
|
||||
fn delete(&self, _pool: &str) -> Result<(), String> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Liefert die Pool-ID (UUID-Ordnername).
|
||||
pub(crate) fn make_oauth_pool(p: &Paths, name: &str) -> String {
|
||||
create_oauth_pool_in(p, name).unwrap()
|
||||
}
|
||||
|
||||
pub(crate) fn make_apikey_pool(
|
||||
p: &Paths,
|
||||
store: &dyn ApikeyStore,
|
||||
name: &str,
|
||||
key: &str,
|
||||
) -> String {
|
||||
create_apikey_pool_in(p, store, name, key, true).unwrap()
|
||||
}
|
||||
|
||||
/// Minimal-Projekt: Ordner mit .claude/ + Registry-Eintrag.
|
||||
pub(crate) fn create_project(paths: &Paths, name: &str) -> Result<(), String> {
|
||||
crate::domain::check_name(name)?;
|
||||
let dir = paths.projects_dir().join(name);
|
||||
if dir.exists() {
|
||||
return Err(format!("Projekt existiert bereits: {name}"));
|
||||
}
|
||||
fs::create_dir_all(dir.join(".claude"))
|
||||
.map_err(|e| format!("{}: {e}", dir.join(".claude").display()))?;
|
||||
register_project(paths, name, &dir)
|
||||
}
|
||||
|
||||
pub(crate) fn mode(path: &PathBuf) -> u32 {
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
fs::metadata(path).unwrap().permissions().mode() & 0o777
|
||||
}
|
||||
Reference in New Issue
Block a user