Pool-Runtime (projects/todos/history) als Symlinks ins synced Repo, auch bei Pool-Anlage
This commit is contained in:
+71
-2
@@ -642,6 +642,44 @@ fn init_pool_config(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Runtime, die pro Pool ins synced Repo gelinkt wird: Transkripte, Todos,
|
||||
/// Prompt-Historie. (name, ist_ordner)
|
||||
const SYNCED_RUNTIME: [(&str, bool); 3] =
|
||||
[("projects", true), ("todos", true), ("history.jsonl", false)];
|
||||
|
||||
/// Zielort der synced Runtime-Daten eines Pools im claude-projects-Repo.
|
||||
fn pool_data_dir(paths: &Paths, pool: &str) -> PathBuf {
|
||||
paths.projects_dir().join("pool").join(pool)
|
||||
}
|
||||
|
||||
/// Ersetzt im Pool-Ordner projects/todos/history.jsonl durch Symlinks auf das
|
||||
/// synced Repo. Die Symlinks sind maschinenlokal, die Daten reisen über git.
|
||||
/// Vorhandene echte Inhalte werden verworfen (kein History-Erhalt — bewusst).
|
||||
fn link_pool_runtime_in(paths: &Paths, pool: &str) -> Result<(), String> {
|
||||
check_name(pool)?;
|
||||
let src = paths.pool_dir(pool);
|
||||
let data = pool_data_dir(paths, pool);
|
||||
for (name, is_dir) in SYNCED_RUNTIME {
|
||||
let target = data.join(name);
|
||||
if is_dir {
|
||||
fs::create_dir_all(&target).map_err(|e| e.to_string())?;
|
||||
} else {
|
||||
fs::create_dir_all(&data).map_err(|e| e.to_string())?;
|
||||
if !target.exists() {
|
||||
fs::write(&target, "").map_err(|e| e.to_string())?;
|
||||
}
|
||||
}
|
||||
let link = src.join(name);
|
||||
if link.is_dir() && !link.is_symlink() {
|
||||
fs::remove_dir_all(&link).map_err(|e| e.to_string())?;
|
||||
} else if link.is_symlink() || link.exists() {
|
||||
fs::remove_file(&link).map_err(|e| e.to_string())?;
|
||||
}
|
||||
std::os::unix::fs::symlink(&target, &link).map_err(|e| e.to_string())?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Legt einen apikey-Pool an: Key-Datei (0600), settings.json mit
|
||||
/// apiKeyHelper auf diese Datei, CLAUDE.md, pool.json.
|
||||
fn create_apikey_pool_in(paths: &Paths, name: &str, key: &str) -> Result<(), String> {
|
||||
@@ -656,7 +694,8 @@ fn create_apikey_pool_in(paths: &Paths, name: &str, key: &str) -> Result<(), Str
|
||||
&dir,
|
||||
serde_json::json!({ "apiKeyHelper": format!("cat '{}'", key_path.display()) }),
|
||||
)?;
|
||||
write_pool_json(&dir, name, "apikey")
|
||||
write_pool_json(&dir, name, "apikey")?;
|
||||
link_pool_runtime_in(paths, name)
|
||||
}
|
||||
|
||||
/// Legt einen oauth-Pool an: Grundausstattung (leere settings.json + CLAUDE.md)
|
||||
@@ -665,7 +704,8 @@ fn create_apikey_pool_in(paths: &Paths, name: &str, key: &str) -> Result<(), Str
|
||||
fn create_oauth_pool_in(paths: &Paths, name: &str) -> Result<(), String> {
|
||||
let dir = check_new_pool(paths, name)?;
|
||||
init_pool_config(&dir, serde_json::json!({}))?;
|
||||
write_pool_json(&dir, name, "oauth")
|
||||
write_pool_json(&dir, name, "oauth")?;
|
||||
link_pool_runtime_in(paths, name)
|
||||
}
|
||||
|
||||
/// Löscht einen Pool samt Ordner (inkl. Credentials). Zugeordnete Projekte
|
||||
@@ -1096,6 +1136,17 @@ fn set_sync_setting(enabled: bool) -> Result<(), String> {
|
||||
set_sync_on_session_end_in(&Paths::real(), enabled)
|
||||
}
|
||||
|
||||
/// Verlinkt die synced Runtime eines bestehenden Pools. Nur bei idlem Pool —
|
||||
/// sonst würde das Transkript der laufenden Session ersetzt.
|
||||
#[tauri::command]
|
||||
fn link_pool_runtime(pool: String) -> Result<(), String> {
|
||||
let paths = Paths::real();
|
||||
if !running_projects_using_pool(&paths, &pool)?.is_empty() {
|
||||
return Err(format!("{pool} wird benutzt — erst Session beenden"));
|
||||
}
|
||||
link_pool_runtime_in(&paths, &pool)
|
||||
}
|
||||
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
pub fn run() {
|
||||
// generate_context! darf pro Crate nur einmal expandieren (_EMBED_INFO_PLIST).
|
||||
@@ -1213,6 +1264,7 @@ fn main_builder() -> tauri::Builder<tauri::Wry> {
|
||||
restart_project,
|
||||
sync_setting,
|
||||
set_sync_setting,
|
||||
link_pool_runtime,
|
||||
oauth_login,
|
||||
keychain_status,
|
||||
set_apikey,
|
||||
@@ -1647,6 +1699,23 @@ mod tests {
|
||||
assert!(!p.project_config("proj").exists());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pool_anlegen_verlinkt_synced_runtime() {
|
||||
let p = tmp_paths();
|
||||
create_oauth_pool_in(&p, "privat").unwrap();
|
||||
let pooldir = p.pool_dir("privat");
|
||||
for (name, is_dir) in SYNCED_RUNTIME {
|
||||
let link = pooldir.join(name);
|
||||
assert!(link.is_symlink(), "{name} sollte Symlink sein");
|
||||
assert_eq!(fs::read_link(&link).unwrap(), pool_data_dir(&p, "privat").join(name));
|
||||
let target = pool_data_dir(&p, "privat").join(name);
|
||||
assert_eq!(target.is_dir(), is_dir);
|
||||
assert!(target.exists());
|
||||
}
|
||||
// Zieldaten liegen im claude-projects-Repo unter pool/<name>/
|
||||
assert!(p.projects_dir().join("pool").join("privat").is_dir());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sync_optin_default_aus_und_umschaltbar() {
|
||||
let p = tmp_paths();
|
||||
|
||||
Reference in New Issue
Block a user