Skip to content

Commit 190b7ae

Browse files
committed
fix: prevent global workspace refresh loop
1 parent f37a0a7 commit 190b7ae

1 file changed

Lines changed: 46 additions & 8 deletions

File tree

src-tauri/src/core/file_watcher.rs

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@ fn collect_watch_paths(store: &SkillStore) -> Vec<PathBuf> {
1616
let mut paths = vec![central_repo::skills_dir(), central_repo::scenarios_dir()];
1717

1818
for adapter in tool_adapters::all_tool_adapters(store) {
19-
paths.push(adapter.skills_dir());
20-
paths.extend(adapter.all_scan_dirs());
19+
let skills_dir = adapter.skills_dir();
20+
if skills_dir.exists() {
21+
paths.push(skills_dir);
22+
}
23+
paths.extend(adapter.additional_existing_scan_dirs());
2124
}
2225

2326
if let Ok(projects) = store.get_all_projects() {
@@ -71,15 +74,19 @@ fn watch_target(path: &Path) -> Option<PathBuf> {
7174
.map(|parent| parent.to_path_buf())
7275
}
7376

77+
fn collect_watch_targets(store: &SkillStore) -> HashSet<PathBuf> {
78+
collect_watch_paths(store)
79+
.into_iter()
80+
.filter_map(|path| watch_target(&path))
81+
.collect()
82+
}
83+
7484
fn sync_watch_set(
7585
watcher: &mut RecommendedWatcher,
7686
watched: &mut HashSet<PathBuf>,
7787
store: &SkillStore,
7888
) {
79-
let desired: HashSet<PathBuf> = collect_watch_paths(store)
80-
.into_iter()
81-
.filter_map(|path| watch_target(&path))
82-
.collect();
89+
let desired = collect_watch_targets(store);
8390

8491
for stale in watched.difference(&desired).cloned().collect::<Vec<_>>() {
8592
if let Err(err) = watcher.unwatch(&stale) {
@@ -156,8 +163,11 @@ pub fn start_file_watcher<R: tauri::Runtime>(app: tauri::AppHandle<R>, store: Ar
156163

157164
#[cfg(test)]
158165
mod tests {
159-
use super::collect_watch_paths;
160-
use crate::core::skill_store::{ProjectRecord, SkillStore};
166+
use super::{collect_watch_paths, collect_watch_targets};
167+
use crate::core::{
168+
skill_store::{ProjectRecord, SkillStore},
169+
tool_adapters::CustomToolDef,
170+
};
161171
use std::fs;
162172
use tempfile::tempdir;
163173

@@ -192,4 +202,32 @@ mod tests {
192202
assert!(!paths.contains(&skills_root.parent().unwrap().to_path_buf()));
193203
assert!(!paths.contains(&disabled_root.parent().unwrap().to_path_buf()));
194204
}
205+
206+
#[test]
207+
fn missing_global_agent_paths_do_not_watch_parent_directories() {
208+
let tmp = tempdir().unwrap();
209+
let db_path = tmp.path().join("watcher.db");
210+
let custom_parent = tmp.path().join("custom-agent");
211+
let missing_skills_root = custom_parent.join("skills");
212+
fs::create_dir_all(&custom_parent).unwrap();
213+
214+
let store = SkillStore::new(&db_path).unwrap();
215+
store
216+
.set_setting(
217+
"custom_tools",
218+
&serde_json::to_string(&vec![CustomToolDef {
219+
key: "missing_custom".to_string(),
220+
display_name: "Missing Custom".to_string(),
221+
skills_dir: missing_skills_root.to_string_lossy().to_string(),
222+
project_relative_skills_dir: None,
223+
}])
224+
.unwrap(),
225+
)
226+
.unwrap();
227+
228+
let targets = collect_watch_targets(&store);
229+
230+
assert!(!targets.contains(&custom_parent));
231+
assert!(!targets.contains(&missing_skills_root));
232+
}
195233
}

0 commit comments

Comments
 (0)