poolSyncDir konfigurierbar: Pool-Runtime-Verlinkung nur bei gesetztem Sync-Ordner (settings.json), Ziel <poolSyncDir>/<pool> statt hartem ~/claude-projects/pool; ungesetzt bleibt alles lokal
This commit is contained in:
+46
-12
@@ -1205,18 +1205,30 @@ fn init_pool_config(
|
||||
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)
|
||||
/// Sync-Ziel für Pool-Laufzeitdaten (settings.json: poolSyncDir).
|
||||
/// Ungesetzt = Feature aus, alle Daten bleiben lokal im Pool-Ordner.
|
||||
fn pool_sync_dir(paths: &Paths) -> Option<PathBuf> {
|
||||
fs::read_to_string(paths.config_dir().join(APP_SETTINGS_FILE))
|
||||
.ok()
|
||||
.and_then(|s| serde_json::from_str::<serde_json::Value>(&s).ok())
|
||||
.and_then(|v| v["poolSyncDir"].as_str().map(|d| expand_home(paths, d)))
|
||||
}
|
||||
|
||||
/// Ersetzt im Pool-Ordner projects/todos/history.jsonl durch Symlinks auf das
|
||||
/// synced Repo. Die Symlinks sind maschinenlokal, die Daten reisen über git.
|
||||
/// Zielort der synced Runtime-Daten eines Pools unterhalb von poolSyncDir.
|
||||
fn pool_data_dir(paths: &Paths, pool: &str) -> Result<PathBuf, String> {
|
||||
pool_sync_dir(paths)
|
||||
.map(|d| d.join(pool))
|
||||
.ok_or_else(|| "poolSyncDir ist nicht konfiguriert".to_string())
|
||||
}
|
||||
|
||||
/// Ersetzt im Pool-Ordner projects/todos/history.jsonl durch Symlinks auf den
|
||||
/// konfigurierten Sync-Ordner. Die Symlinks sind maschinenlokal, die Daten
|
||||
/// reisen über den Sync des Zielordners (z. B. 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);
|
||||
let data = pool_data_dir(paths, pool)?;
|
||||
for (name, is_dir) in SYNCED_RUNTIME {
|
||||
let target = data.join(name);
|
||||
if is_dir {
|
||||
@@ -1266,7 +1278,9 @@ fn create_apikey_pool_in(
|
||||
serde_json::json!({ "apiKeyHelper": apikey_helper_command(&dir, &id) }),
|
||||
)?;
|
||||
write_pool_json(&dir, name, "apikey")?;
|
||||
link_pool_runtime_in(paths, &id)?;
|
||||
if pool_sync_dir(paths).is_some() {
|
||||
link_pool_runtime_in(paths, &id)?;
|
||||
}
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
@@ -1279,7 +1293,9 @@ fn create_oauth_pool_in(paths: &Paths, name: &str) -> Result<String, String> {
|
||||
init_pool_config(&dir, serde_json::json!({}))?;
|
||||
write_pool_json(&dir, name, "oauth")?;
|
||||
let id = dir.file_name().unwrap().to_string_lossy().into_owned();
|
||||
link_pool_runtime_in(paths, &id)?;
|
||||
if pool_sync_dir(paths).is_some() {
|
||||
link_pool_runtime_in(paths, &id)?;
|
||||
}
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
@@ -2611,18 +2627,36 @@ mod tests {
|
||||
#[test]
|
||||
fn pool_anlegen_verlinkt_synced_runtime() {
|
||||
let p = tmp_paths();
|
||||
fs::create_dir_all(p.config_dir()).unwrap();
|
||||
fs::write(
|
||||
p.config_dir().join(APP_SETTINGS_FILE),
|
||||
"{ \"poolSyncDir\": \"~/claude-projects/pool\" }\n",
|
||||
)
|
||||
.unwrap();
|
||||
let id = make_oauth_pool(&p, "privat");
|
||||
let pooldir = p.pool_dir(&id);
|
||||
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, &id).join(name));
|
||||
let target = pool_data_dir(&p, &id).join(name);
|
||||
assert_eq!(fs::read_link(&link).unwrap(), pool_data_dir(&p, &id).unwrap().join(name));
|
||||
let target = pool_data_dir(&p, &id).unwrap().join(name);
|
||||
assert_eq!(target.is_dir(), is_dir);
|
||||
assert!(target.exists());
|
||||
}
|
||||
// Zieldaten liegen im claude-projects-Repo unter pool/<id>/
|
||||
assert!(p.projects_dir().join("pool").join(&id).is_dir());
|
||||
// Zieldaten liegen unter dem konfigurierten poolSyncDir/<id>/
|
||||
assert!(p.home.join("claude-projects/pool").join(&id).is_dir());
|
||||
}
|
||||
|
||||
/// Ohne poolSyncDir bleibt alles lokal: keine Symlinks, Verlinken scheitert laut.
|
||||
#[test]
|
||||
fn pool_anlegen_ohne_sync_dir_bleibt_lokal() {
|
||||
let p = tmp_paths();
|
||||
let id = make_oauth_pool(&p, "privat");
|
||||
for (name, _) in SYNCED_RUNTIME {
|
||||
assert!(!p.pool_dir(&id).join(name).is_symlink(), "{name} darf kein Symlink sein");
|
||||
}
|
||||
let err = link_pool_runtime_in(&p, &id).unwrap_err();
|
||||
assert!(err.contains("poolSyncDir"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user