caretta 0.16.4

caretta agent
// 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);
}