1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// Copyright (c) 2026 Geoff Seemueller
//
// Licensed under the MIT License or Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// See LICENSE-MIT or LICENSE-APACHE for the full license text.
//
// Additionally, this file is subject to the Revenue Sharing Agreement terms
// as defined in REVENUE-SHARING.md for covered organizations.
//! `generate-aiignore` — have the selected agent explore the project and write
//! an `.aiignore` at the repo root to optimize the AI snapshot token budget.
//!
//! `toak-rs` (used by [`crate::agent::snapshot`]) already honors `.aiignore`
//! when it builds codebase snapshots for agent runs, so a well-chosen
//! `.aiignore` shrinks the token budget of every subsequent snapshot-based flow
//! (e.g. `security-review`). Caretta only builds the prompt and streams output;
//! the agent writes the file with its own tools, matching the `security-review`
//! and `code-review` pattern.
use crate::agent::cmd::{cmd_stdout, log};
use crate::agent::launch::log_resolved_agent_launch;
use crate::agent::process::emit_event;
use crate::agent::run::run_agent_with_env;
use crate::agent::tracker::build_generate_aiignore_prompt;
use crate::agent::types::{AgentEvent, Config};
use std::path::Path;
pub fn run_generate_aiignore(cfg: &Config) {
log("Generating .aiignore to optimize the AI snapshot token budget...");
// Orient the agent with a shallow inventory of tracked files (the same
// source toak-rs walks, so git-ignored paths are already excluded). This is
// only a starting point — the agent explores freely and reads what it needs.
let file_listing = cmd_stdout("git", &["-C", &cfg.root, "ls-files"]).unwrap_or_default();
// Pass any existing .aiignore so the agent extends it instead of discarding
// useful entries.
let existing =
std::fs::read_to_string(Path::new(&cfg.root).join(".aiignore")).unwrap_or_default();
let prompt =
build_generate_aiignore_prompt(&cfg.project_name, &cfg.root, &file_listing, &existing);
if cfg.dry_run {
log_resolved_agent_launch(cfg, &[]);
log("[dry-run] Would ask the agent to explore the project and write .aiignore");
emit_event(AgentEvent::Done);
return;
}
run_agent_with_env(cfg, &prompt, &[]);
emit_event(AgentEvent::Done);
}