gitdataai/libs/service/skill/scan.rs
2026-04-15 09:08:09 +08:00

54 lines
1.8 KiB
Rust

//! Scan all repos in a project for skills.
use crate::AppService;
use crate::error::AppError;
use models::repos::repo::Entity as RepoEntity;
use models::repos::repo::Column as RCol;
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};
use uuid::Uuid;
use super::scanner;
impl AppService {
/// Scan all repositories in a project and sync skills from `.claude/skills/` directories.
///
/// This is called automatically during `git hook sync` and can also be triggered
/// manually via `POST /api/projects/{name}/skills/scan`.
///
/// - Discovers skills in each repo's `.claude/skills/` folder
/// - Upserts repo-sourced skills (source = "repo")
/// - Removes skills whose source repo no longer has the file
/// - Manual skills (source = "manual") are never affected
pub async fn skill_scan_repos(
&self,
project_uid: Uuid,
_caller_uid: Uuid,
) -> Result<scanner::ScanSyncResult, AppError> {
// Collect all repo IDs for this project
let repos: Vec<_> = RepoEntity::find()
.filter(RCol::Project.eq(project_uid))
.all(&self.db)
.await?;
let mut total_created = 0i64;
let mut total_updated = 0i64;
let mut total_removed = 0i64;
let mut total_discovered = 0i64;
for repo in repos {
let result = scanner::scan_and_sync_skills(&self.db, project_uid, &repo).await?;
total_created += result.created;
total_updated += result.updated;
total_removed += result.removed;
total_discovered += result.discovered;
}
Ok(scanner::ScanSyncResult {
discovered: total_discovered,
created: total_created,
updated: total_updated,
removed: total_removed,
})
}
}