Skip to content

Commit c2a43de

Browse files
committed
feat(ignore): add built-in agentic template for AI tool artifacts
1 parent 324ab5c commit c2a43de

1 file changed

Lines changed: 72 additions & 7 deletions

File tree

src/ignore/mod.rs

Lines changed: 72 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const API_BASE: &str = "https://www.toptal.com/developers/gitignore/api";
1010
pub enum IgnoreCommand {
1111
/// Generate .gitignore for the given templates
1212
Add {
13-
/// Comma-separated list of templates (e.g. rust,vscode)
13+
/// Comma-separated list of templates (e.g. rust,vscode,agentic)
1414
templates: String,
1515
#[arg(short, long)]
1616
yes: bool,
@@ -44,12 +44,7 @@ fn add(templates: &str, yes: bool, force: bool, dry_run: bool) -> Result<()> {
4444
return Ok(());
4545
}
4646

47-
let url = format!("{API_BASE}/{templates}");
48-
let content = ureq::get(&url)
49-
.call()
50-
.context("Failed to fetch gitignore templates")?
51-
.into_string()
52-
.context("Failed to read response")?;
47+
let content = resolve_templates(templates)?;
5348

5449
if dry_run {
5550
println!("[dry-run] Would write .gitignore:\n{content}");
@@ -61,7 +56,48 @@ fn add(templates: &str, yes: bool, force: bool, dry_run: bool) -> Result<()> {
6156
Ok(())
6257
}
6358

59+
/// Split templates, resolve built-ins locally, fetch the rest from the API.
60+
/// Combines both into a single output.
61+
fn resolve_templates(templates: &str) -> Result<String> {
62+
let mut builtin_parts: Vec<&str> = Vec::new();
63+
let mut api_templates: Vec<&str> = Vec::new();
64+
65+
for t in templates.split(',').map(str::trim) {
66+
if builtins::get(t).is_some() {
67+
builtin_parts.push(t);
68+
} else {
69+
api_templates.push(t);
70+
}
71+
}
72+
73+
let mut output = String::new();
74+
75+
for name in &builtin_parts {
76+
output.push_str(builtins::get(name).unwrap());
77+
}
78+
79+
if !api_templates.is_empty() {
80+
let joined = api_templates.join(",");
81+
let url = format!("{API_BASE}/{joined}");
82+
let fetched = ureq::get(&url)
83+
.call()
84+
.context("Failed to fetch gitignore templates")?
85+
.into_string()
86+
.context("Failed to read response")?;
87+
output.push_str(&fetched);
88+
}
89+
90+
Ok(output)
91+
}
92+
6493
fn list(filter: Option<&str>) -> Result<()> {
94+
// Always show built-ins first
95+
for name in builtins::NAMES {
96+
if filter.is_none_or(|f| name.contains(f)) {
97+
println!("{name} (built-in)");
98+
}
99+
}
100+
65101
let url = format!("{API_BASE}/list?format=lines");
66102
let content = ureq::get(&url)
67103
.call()
@@ -76,3 +112,32 @@ fn list(filter: Option<&str>) -> Result<()> {
76112
}
77113
Ok(())
78114
}
115+
116+
mod builtins {
117+
pub(super) const NAMES: &[&str] = &["agentic"];
118+
119+
pub(super) fn get(name: &str) -> Option<&'static str> {
120+
match name {
121+
"agentic" => Some(AGENTIC),
122+
_ => None,
123+
}
124+
}
125+
126+
const AGENTIC: &str = "\
127+
# Kiro
128+
.kiro/
129+
skills-lock.json
130+
131+
# Agent specs / project context
132+
.agents/
133+
134+
# Cursor
135+
.cursor/
136+
137+
# GitHub Copilot
138+
.copilot/
139+
140+
# Continue
141+
.continue/
142+
";
143+
}

0 commit comments

Comments
 (0)