Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion crates/skill-registry/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ regex = "1"
thiserror = "2"
dirs = "6"
flare-search-kit = { path = "../flare-search-kit" }
agent-registry = { package = "agentflare-agent-registry", path = "../agent-registry" }
gateway-registry = { package = "agentflare-gateway-registry", path = "../gateway-registry" }

[dev-dependencies]
Expand Down
24 changes: 13 additions & 11 deletions crates/skill-registry/src/load.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ pub fn load(conn: &Connection, name: &str, original: bool) -> Result<LoadedSkill
/// Facade owning the connection + refresh debounce.
pub struct Registry {
conn: Connection,
detected_agents: Vec<String>,
last_refresh: std::time::Instant,
refreshed_once: bool,
}
Expand All @@ -114,27 +115,28 @@ impl Registry {
let conn = crate::db::open_db(db_path).map_err(|e| LoadError::Db(e.to_string()))?;
Ok(Registry {
conn,
detected_agents: Vec::new(),
last_refresh: std::time::Instant::now(),
refreshed_once: false,
})
}

/// Rescan sources when never scanned or debounce elapsed.
pub fn ensure_fresh(&mut self) -> Result<(), LoadError> {
/// Rescan sources when never scanned or debounce elapsed. `detect_agents` is
/// only invoked when a rescan actually happens (not on every debounced call),
/// so a long-lived cached `Registry` (e.g. mcp_server.rs's per-process cache)
/// still picks up newly-installed agent CLIs roughly every
/// `REFRESH_DEBOUNCE_SECS`, instead of freezing detection at construction time.
pub fn ensure_fresh(
&mut self,
detect_agents: impl FnOnce() -> Vec<String>,
) -> Result<(), LoadError> {
if self.refreshed_once && self.last_refresh.elapsed().as_secs() < REFRESH_DEBOUNCE_SECS {
return Ok(());
}
self.detected_agents = detect_agents();
let home = dirs::home_dir().unwrap_or_else(|| PathBuf::from("."));
let cwd = std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."));
// Detected agents: agent-registry's detect_all needs a version cache;
// skill discovery only needs agent IDs, so pass an empty cache.
let mut cache = std::collections::HashMap::new();
let detected: Vec<String> =
agent_registry::detect_all(agent_registry::REGISTRY, &mut cache)
.into_iter()
.map(|d| d.id.to_lowercase())
.collect();
let sources = crate::sources::default_sources(&home, &cwd, &detected);
let sources = crate::sources::default_sources(&home, &cwd, &self.detected_agents);
let out = crate::sources::scan_sources(&sources);
crate::db::rebuild(&mut self.conn, &out.entries)
.map_err(|e| LoadError::Db(e.to_string()))?;
Expand Down
19 changes: 18 additions & 1 deletion src/components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,14 +197,31 @@ pub(crate) fn rule_targets(host: &str) -> Vec<(PathBuf, String)> {
}
}

/// Agent IDs detected on this machine, for `skill_registry::Registry::open_default`'s
/// `detected_agents` param. skill-registry itself has no `agent-registry` dependency
/// (deliberately decoupled — skill discovery only needs agent IDs, not the version-
/// detection machinery); every call site collects them the same way, using a
/// throwaway cache since none of these callers need cross-call version caching.
Comment on lines +200 to +204

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Correct the detected-agent callback documentation.

The comment describes a detected_agents parameter on Registry::open_default, but the supplied implementation has no such parameter; the callback is passed to Registry::ensure_fresh.

Based on the supplied crates/skill-registry/src/load.rs contract.

Proposed documentation fix
-/// Agent IDs detected on this machine, for `skill_registry::Registry::open_default`'s
-/// `detected_agents` param.
+/// Agent IDs detected on this machine for `skill_registry::Registry::ensure_fresh`'s
+/// `detect_agents` callback.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/// Agent IDs detected on this machine, for `skill_registry::Registry::open_default`'s
/// `detected_agents` param. skill-registry itself has no `agent-registry` dependency
/// (deliberately decoupled — skill discovery only needs agent IDs, not the version-
/// detection machinery); every call site collects them the same way, using a
/// throwaway cache since none of these callers need cross-call version caching.
/// Agent IDs detected on this machine for `skill_registry::Registry::ensure_fresh`'s
/// `detect_agents` callback. skill-registry itself has no `agent-registry` dependency
/// (deliberately decoupled — skill discovery only needs agent IDs, not the version-
/// detection machinery); every call site collects them the same way, using a
/// throwaway cache since none of these callers need cross-call version caching.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components.rs` around lines 200 - 204, Update the documentation comment
above the agent-ID callback to reference Registry::ensure_fresh, not
Registry::open_default, and describe the callback according to the ensure_fresh
contract. Preserve the explanation that callers provide detected agent IDs and
use a throwaway cache because cross-call version caching is unnecessary.

pub(crate) fn detected_skill_agents() -> Vec<String> {
agent_registry::detect_all(
agent_registry::REGISTRY,
&mut std::collections::HashMap::new(),
)
.into_iter()
.map(|d| d.id.to_lowercase())
.collect()
}

/// Every skill name the shared skill_registry cache currently knows about —
/// same source `skill_search`/`skill_load` (mcp_server.rs) already serve
/// from, so "known skills" here always matches what those tools can find.
#[cfg(feature = "skill-overrides-sync")]
fn discover_skill_names() -> Result<Vec<String>, String> {
let mut registry = skill_registry::Registry::open_default(&crate::paths::skills_db_path())
.map_err(|e| e.to_string())?;
registry.ensure_fresh().map_err(|e| e.to_string())?;
registry
.ensure_fresh(detected_skill_agents)
.map_err(|e| e.to_string())?;
registry.list_all_names().map_err(|e| e.to_string())
}

Expand Down
4 changes: 2 additions & 2 deletions src/hook.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ fn session_start_message(agent: &str) -> String {
if db_path.exists()
&& let Ok(mut registry) = skill_registry::Registry::open_default(&db_path)
{
let _ = registry.ensure_fresh();
let _ = registry.ensure_fresh(crate::components::detected_skill_agents);
for q in &project_queries {
if let Ok(hits) = registry.search(q, 2, skill_registry::MatchMode::Any)
&& !hits.is_empty()
Expand Down Expand Up @@ -515,7 +515,7 @@ pub fn prompt_submit(agent: &str) {
if db_path.exists()
&& let Ok(mut registry) = skill_registry::Registry::open_default(&db_path)
{
let _ = registry.ensure_fresh();
let _ = registry.ensure_fresh(crate::components::detected_skill_agents);
if let Ok(skills) = crate::skill_detect::find_skills(
&intent,
&registry,
Expand Down
2 changes: 1 addition & 1 deletion src/mcp_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ impl AgentflareMcp {
*guard = Some(reg);
}
let reg = guard.as_mut().expect("just initialized above");
reg.ensure_fresh()?;
reg.ensure_fresh(crate::components::detected_skill_agents)?;
Ok(f(reg))
}
#[tool(
Expand Down
Loading