116 lines
3.6 KiB
Rust
116 lines
3.6 KiB
Rust
//! Skill registered to a project.
|
|
//!
|
|
//! Skills can be sourced manually (by project admin) or auto-discovered from
|
|
//! repositories within the project (via `.claude/skills/` directory scanning).
|
|
|
|
use crate::{DateTimeUtc, ProjectId, RepoId, UserId};
|
|
use sea_orm::entity::prelude::*;
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
/// Skill source: `"manual"` or `"repo"`.
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
pub enum SkillSource {
|
|
Manual,
|
|
Repo,
|
|
}
|
|
|
|
impl std::fmt::Display for SkillSource {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
match self {
|
|
SkillSource::Manual => write!(f, "manual"),
|
|
SkillSource::Repo => write!(f, "repo"),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl std::str::FromStr for SkillSource {
|
|
type Err = &'static str;
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
match s {
|
|
"manual" => Ok(SkillSource::Manual),
|
|
"repo" => Ok(SkillSource::Repo),
|
|
_ => Err("unknown skill source"),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Parsed frontmatter from a skill's SKILL.md file.
|
|
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
|
pub struct SkillMetadata {
|
|
/// Human-readable name (falls back to slug/folder name).
|
|
#[serde(default)]
|
|
pub name: Option<String>,
|
|
/// Short description of what the skill does.
|
|
#[serde(default)]
|
|
pub description: Option<String>,
|
|
/// SPDX license identifier.
|
|
#[serde(default)]
|
|
pub license: Option<String>,
|
|
/// Compatibility notes (e.g. "Requires openspec CLI").
|
|
#[serde(default)]
|
|
pub compatibility: Option<String>,
|
|
/// Free-form metadata from the frontmatter.
|
|
#[serde(default)]
|
|
pub metadata: serde_json::Value,
|
|
}
|
|
|
|
impl From<serde_json::Value> for SkillMetadata {
|
|
fn from(v: serde_json::Value) -> Self {
|
|
serde_json::from_value(v).unwrap_or_default()
|
|
}
|
|
}
|
|
|
|
/// Skill record persisted in the `project_skill` table.
|
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
|
|
#[sea_orm(table_name = "project_skill")]
|
|
pub struct Model {
|
|
#[sea_orm(primary_key)]
|
|
pub id: i64,
|
|
/// Project this skill belongs to.
|
|
pub project_uuid: ProjectId,
|
|
/// URL-safe identifier, unique within a project.
|
|
pub slug: String,
|
|
/// Display name (extracted from frontmatter or folder name).
|
|
pub name: String,
|
|
/// Optional short description.
|
|
pub description: Option<String>,
|
|
/// `"manual"` or `"repo"`.
|
|
pub source: String,
|
|
/// If source=repo, the repo this skill was discovered from.
|
|
#[sea_orm(nullable)]
|
|
pub repo_id: Option<RepoId>,
|
|
/// If source=repo, the commit SHA where the skill was found.
|
|
#[sea_orm(nullable)]
|
|
pub commit_sha: Option<String>,
|
|
/// If source=repo, the blob SHA of the SKILL.md file.
|
|
#[sea_orm(nullable)]
|
|
pub blob_hash: Option<String>,
|
|
/// Raw markdown content (SKILL.md body after frontmatter).
|
|
pub content: String,
|
|
/// Full frontmatter as JSON.
|
|
#[sea_orm(column_type = "JsonBinary")]
|
|
pub metadata: serde_json::Value,
|
|
/// Whether this skill is currently active.
|
|
pub enabled: bool,
|
|
/// Who added this skill (null for repo-sourced skills).
|
|
#[sea_orm(nullable)]
|
|
pub created_by: Option<UserId>,
|
|
pub created_at: DateTimeUtc,
|
|
pub updated_at: DateTimeUtc,
|
|
}
|
|
|
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
|
pub enum Relation {}
|
|
|
|
impl ActiveModelBehavior for ActiveModel {}
|
|
|
|
impl Model {
|
|
pub fn source_enum(&self) -> Result<SkillSource, &'static str> {
|
|
self.source.parse()
|
|
}
|
|
|
|
pub fn metadata_parsed(&self) -> SkillMetadata {
|
|
SkillMetadata::from(self.metadata.clone())
|
|
}
|
|
}
|