Build AI provenance from CLI flags and environment variables. Environment variables take precedence over CLI flags for consistency with AI tool integrations that set environment variables.
(&self)
| 6 | /// Environment variables take precedence over CLI flags for consistency |
| 7 | /// with AI tool integrations that set environment variables. |
| 8 | pub(super) fn build_provenance(&self) -> Option<Provenance> { |
| 9 | // Check if AI-assisted via flag or environment variable |
| 10 | let ai_enabled = self.ai_assisted |
| 11 | || std::env::var("ATOMIC_AI_ENABLED") |
| 12 | .map(|v| v == "true" || v == "1") |
| 13 | .unwrap_or(false); |
| 14 | |
| 15 | if !ai_enabled { |
| 16 | return None; |
| 17 | } |
| 18 | |
| 19 | // Get provider (required for provenance) |
| 20 | let provider = self |
| 21 | .ai_provider |
| 22 | .clone() |
| 23 | .or_else(|| std::env::var("ATOMIC_AI_PROVIDER").ok()); |
| 24 | |
| 25 | let provider = match provider { |
| 26 | Some(p) => p, |
| 27 | None => { |
| 28 | // No provider specified - can't create meaningful provenance |
| 29 | return None; |
| 30 | } |
| 31 | }; |
| 32 | |
| 33 | // Get model (required for provenance) |
| 34 | let model = self |
| 35 | .ai_model |
| 36 | .clone() |
| 37 | .or_else(|| std::env::var("ATOMIC_AI_MODEL").ok()) |
| 38 | .unwrap_or_else(|| "unknown".to_string()); |
| 39 | |
| 40 | // Parse vendor from provider string |
| 41 | let vendor = AIVendor::parse(&provider); |
| 42 | |
| 43 | // Get tool type |
| 44 | let tool_from_env = std::env::var("ATOMIC_AI_TOOL").ok(); |
| 45 | |
| 46 | let tool_str = self |
| 47 | .ai_tool |
| 48 | .clone() |
| 49 | .or(tool_from_env) |
| 50 | .unwrap_or_else(|| "cli".to_string()); |
| 51 | |
| 52 | let tool = match tool_str.to_lowercase().as_str() { |
| 53 | "api" => AITool::Api, |
| 54 | "chat" => AITool::Chat, |
| 55 | "cli" => AITool::Cli("atomic".to_string()), |
| 56 | "ci" => AITool::CI("atomic-ci".to_string()), |
| 57 | "code-review" | "codereview" => AITool::CodeReview("atomic".to_string()), |
| 58 | // AI coding assistants - treat as editors/IDEs |
| 59 | "opencode" => AITool::Editor("opencode".to_string()), |
| 60 | "cursor" => AITool::Editor("cursor".to_string()), |
| 61 | "aider" => AITool::Cli("aider".to_string()), |
| 62 | "claude-code" | "claude_code" => AITool::Cli("claude-code".to_string()), |
| 63 | other => { |
| 64 | // Check prefixes FIRST before contains patterns |
| 65 | // This ensures "cli:opencode" becomes Cli("opencode") not Editor("cli:opencode") |