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
31 changes: 31 additions & 0 deletions src-tauri/src/services/command_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ pub(crate) fn generate_command_markdown(command: &Command) -> String {
}
}

if let Some(ref tags) = command.tags {
if !tags.is_empty() {
frontmatter.push_str(&format!("tags: {}\n", serde_json::to_string(tags).unwrap()));
}
}

frontmatter.push_str("---\n\n");
format!("{}{}", frontmatter, command.content)
}
Expand Down Expand Up @@ -267,6 +273,31 @@ mod tests {
assert!(md.contains("Minimal content."));
}

#[test]
fn test_generate_command_markdown_emits_tags_as_json_array() {
// Mirrors the rule_writer fix: `tags` is read from the DB via
// `serde_json::from_str`, so if a scanner ever ingests a command
// frontmatter the value must be valid JSON, not comma-joined.
// Also pins against silent-drop: previously `command.tags` was not
// written to frontmatter at all.
let mut command = sample_minimal_command();
command.tags = Some(vec!["triage".to_string(), "prs".to_string()]);

let md = generate_command_markdown(&command);

assert!(md.contains("tags: [\"triage\",\"prs\"]\n"));
}

#[test]
fn test_generate_command_markdown_omits_empty_tags() {
let mut command = sample_minimal_command();
command.tags = Some(vec![]);

let md = generate_command_markdown(&command);

assert!(!md.contains("tags:"));
}

// =========================================================================
// write_command_file tests
// =========================================================================
Expand Down
31 changes: 31 additions & 0 deletions src-tauri/src/services/skill_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ pub(crate) fn generate_skill_markdown(skill: &Skill) -> String {
}
}

if let Some(ref tags) = skill.tags {
if !tags.is_empty() {
frontmatter.push_str(&format!("tags: {}\n", serde_json::to_string(tags).unwrap()));
}
}

frontmatter.push_str("---\n\n");
format!("{}{}", frontmatter, skill.content)
}
Expand Down Expand Up @@ -271,6 +277,31 @@ mod tests {
assert!(md.contains("name: minimal\n"));
}

#[test]
fn test_generate_skill_markdown_emits_tags_as_json_array() {
// Mirrors the rule_writer fix: `tags` is read from the DB via
// `serde_json::from_str`, so if a scanner ever ingests a skill
// frontmatter the value must be valid JSON, not comma-joined.
// Also pins against silent-drop: previously `skill.tags` was not
// written to frontmatter at all.
let mut skill = sample_minimal_skill();
skill.tags = Some(vec!["refactor".to_string(), "typescript".to_string()]);

let md = generate_skill_markdown(&skill);

assert!(md.contains("tags: [\"refactor\",\"typescript\"]\n"));
}

#[test]
fn test_generate_skill_markdown_omits_empty_tags() {
let mut skill = sample_minimal_skill();
skill.tags = Some(vec![]);

let md = generate_skill_markdown(&skill);

assert!(!md.contains("tags:"));
}

// =========================================================================
// write_skill_file tests (file system)
// =========================================================================
Expand Down
31 changes: 31 additions & 0 deletions src-tauri/src/services/subagent_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ pub(crate) fn generate_subagent_markdown(subagent: &SubAgent) -> String {
}
}

if let Some(ref tags) = subagent.tags {
if !tags.is_empty() {
frontmatter.push_str(&format!("tags: {}\n", serde_json::to_string(tags).unwrap()));
}
}

frontmatter.push_str("---\n\n");
format!("{}{}", frontmatter, subagent.content)
}
Expand Down Expand Up @@ -320,6 +326,31 @@ mod tests {
assert!(md.contains("---\n\nYou are a helpful assistant."));
}

#[test]
fn test_generate_subagent_markdown_emits_tags_as_json_array() {
// Mirrors the rule_writer fix: `tags` is read from the DB via
// `serde_json::from_str`, so if a scanner ever ingests a subagent
// frontmatter the value must be valid JSON, not comma-joined.
// Also pins against silent-drop: previously `subagent.tags` was not
// written to frontmatter at all.
let mut subagent = sample_minimal_subagent();
subagent.tags = Some(vec!["review".to_string(), "quality".to_string()]);

let md = generate_subagent_markdown(&subagent);

assert!(md.contains("tags: [\"review\",\"quality\"]\n"));
}

#[test]
fn test_generate_subagent_markdown_omits_empty_tags() {
let mut subagent = sample_minimal_subagent();
subagent.tags = Some(vec![]);

let md = generate_subagent_markdown(&subagent);

assert!(!md.contains("tags:"));
}

#[test]
fn test_generate_subagent_markdown_empty_tools_skipped() {
let mut subagent = sample_full_subagent();
Expand Down
Loading