use skillpack::cli::Target;
use skillpack::generate::{render, render_targets};
use skillpack::types::{Intent, Language, ProjectProfile};
fn cli_profile() -> ProjectProfile {
ProjectProfile {
name: "chronicle".to_string(),
language: Language::Rust,
has_cli: true,
cli_command: Some(vec!["chronicle".to_string(), "--help".to_string()]),
cli_help_output: Some(
"Usage: chronicle [OPTIONS]\n\
--new <entry> Create an entry\n\
--verbose Verbose output\n"
.to_string(),
),
cli_subcommand_help: Vec::new(),
diag: skillpack::types::DiagTrace::default(),
repo_url: Some("https://github.com/example/chronicle".to_string()),
license: Some("MIT".to_string()),
description_hint: None,
version: Some("0.1.0".to_string()),
authors: None,
}
}
fn cli_intent() -> Intent {
Intent {
one_line_description: "Journal events to a chronological log".to_string(),
when_to_use_phrases: vec![
"log a journal entry".to_string(),
"record an incident".to_string(),
],
invocation_command: Some("chronicle --new \"entry\"".to_string()),
import_pattern: None,
author: Some("Mikey".to_string()),
license: Some("MIT".to_string()),
..Default::default()
}
}
fn lib_profile() -> ProjectProfile {
ProjectProfile {
name: "fastcsv".to_string(),
language: Language::Node,
has_cli: false,
cli_command: None,
cli_help_output: None,
cli_subcommand_help: Vec::new(),
diag: skillpack::types::DiagTrace::default(),
repo_url: Some("https://github.com/example/fastcsv".to_string()),
license: Some("MIT".to_string()),
description_hint: None,
version: Some("0.1.0".to_string()),
authors: None,
}
}
fn lib_intent() -> Intent {
Intent {
one_line_description: "Parse CSV files fast".to_string(),
when_to_use_phrases: vec!["ingest csv".to_string(), "convert rows".to_string()],
invocation_command: None,
import_pattern: Some("import { parse } from 'fastcsv'".to_string()),
license: Some("MIT".to_string()),
..Default::default()
}
}
#[test]
fn snapshot_cli_marketplace_json() {
let files = render(&cli_profile(), &cli_intent(), None).unwrap();
let mp = files
.iter()
.find(|f| f.rel_path.ends_with("marketplace.json"))
.unwrap();
insta::assert_snapshot!("marketplace_cli", mp.contents);
}
#[test]
fn snapshot_cli_plugin_json() {
let files = render(&cli_profile(), &cli_intent(), None).unwrap();
let pj = files
.iter()
.find(|f| f.rel_path.ends_with("plugin.json"))
.unwrap();
insta::assert_snapshot!("plugin_cli", pj.contents);
}
#[test]
fn snapshot_cli_skill_md() {
let files = render(&cli_profile(), &cli_intent(), None).unwrap();
let skill = files
.iter()
.find(|f| f.rel_path.ends_with("SKILL.md"))
.unwrap();
insta::assert_snapshot!("skill_cli", skill.contents);
}
#[test]
fn snapshot_lib_marketplace_json() {
let files = render(&lib_profile(), &lib_intent(), None).unwrap();
let mp = files
.iter()
.find(|f| f.rel_path.ends_with("marketplace.json"))
.unwrap();
insta::assert_snapshot!("marketplace_lib", mp.contents);
}
#[test]
fn snapshot_lib_plugin_json() {
let files = render(&lib_profile(), &lib_intent(), None).unwrap();
let pj = files
.iter()
.find(|f| f.rel_path.ends_with("plugin.json"))
.unwrap();
insta::assert_snapshot!("plugin_lib", pj.contents);
}
#[test]
fn snapshot_lib_skill_md() {
let files = render(&lib_profile(), &lib_intent(), None).unwrap();
let skill = files
.iter()
.find(|f| f.rel_path.ends_with("SKILL.md"))
.unwrap();
insta::assert_snapshot!("skill_lib", skill.contents);
}
#[test]
fn snapshot_render_is_idempotent_byte_identical() {
let a = render(&cli_profile(), &cli_intent(), None).unwrap();
let b = render(&cli_profile(), &cli_intent(), None).unwrap();
for (x, y) in a.iter().zip(b.iter()) {
assert_eq!(x.contents, y.contents, "{} not idempotent", x.rel_path);
}
}
#[test]
fn snapshot_cli_cursor_mdc() {
let files = render_targets(&cli_profile(), &cli_intent(), &[Target::Cursor], None).unwrap();
let mdc = files.iter().find(|f| f.rel_path.ends_with(".mdc")).unwrap();
insta::assert_snapshot!("cursor_cli", mdc.contents);
}
#[test]
fn snapshot_cli_opencode_agent() {
let files = render_targets(&cli_profile(), &cli_intent(), &[Target::OpenCode], None).unwrap();
let agent = files.iter().find(|f| f.rel_path.ends_with(".md")).unwrap();
insta::assert_snapshot!("opencode_cli", agent.contents);
}
#[test]
fn snapshot_cli_copilot_instructions() {
let files = render_targets(&cli_profile(), &cli_intent(), &[Target::Copilot], None).unwrap();
let instr = files
.iter()
.find(|f| f.rel_path.ends_with("copilot-instructions.md"))
.unwrap();
insta::assert_snapshot!("copilot_cli", instr.contents);
}
#[test]
fn snapshot_php_cursor_globs() {
let mut p = cli_profile();
p.language = Language::Php;
let files = render_targets(&p, &cli_intent(), &[Target::Cursor], None).unwrap();
let mdc = files.iter().find(|f| f.rel_path.ends_with(".mdc")).unwrap();
insta::assert_snapshot!("cursor_php", mdc.contents);
}
#[test]
fn snapshot_jvm_cursor_globs() {
let mut p = cli_profile();
p.language = Language::Jvm;
let files = render_targets(&p, &cli_intent(), &[Target::Cursor], None).unwrap();
let mdc = files.iter().find(|f| f.rel_path.ends_with(".mdc")).unwrap();
insta::assert_snapshot!("cursor_jvm", mdc.contents);
}
#[test]
fn snapshot_csharp_cursor_globs() {
let mut p = cli_profile();
p.language = Language::CSharp;
let files = render_targets(&p, &cli_intent(), &[Target::Cursor], None).unwrap();
let mdc = files.iter().find(|f| f.rel_path.ends_with(".mdc")).unwrap();
insta::assert_snapshot!("cursor_csharp", mdc.contents);
}
#[test]
fn snapshot_target_all_produces_all_six_ecosystems() {
let files = render_targets(
&cli_profile(),
&cli_intent(),
&[
Target::Claude,
Target::Cursor,
Target::Codex,
Target::OpenCode,
Target::Copilot,
Target::AgentsMd,
],
None,
)
.unwrap();
let rel_paths: Vec<&str> = files.iter().map(|f| f.rel_path.as_str()).collect();
insta::assert_snapshot!("target_all_rel_paths", rel_paths.join("\n"));
}