battlecommand_forge/
voice.rs1use std::process::Command;
7
8pub fn is_enabled() -> bool {
10 std::env::var("BATTLECOMMAND_VOICE")
11 .map(|v| v == "1" || v == "true")
12 .unwrap_or(false)
13}
14
15pub fn say(message: &str) {
18 if !is_enabled() || !cfg!(target_os = "macos") {
19 return;
20 }
21 let msg = message.to_string();
22 tokio::spawn(async move {
23 let _ = Command::new("say").args(["-v", "Samantha", &msg]).output();
24 });
25}
26
27pub fn mission_start(prompt: &str) {
29 let short: String = prompt.chars().take(60).collect();
30 say(&format!("Mission starting. {}", short));
31}
32
33pub fn quality_gate(score: f32, passed: bool) {
35 if passed {
36 say(&format!(
37 "Quality gate passed with score {:.1}. Shipping production grade code.",
38 score
39 ));
40 } else {
41 say(&format!(
42 "Quality gate failed. Score {:.1}. Starting fix round.",
43 score
44 ));
45 }
46}
47
48pub fn fix_round(round: usize, max: usize) {
50 say(&format!("Fix round {} of {}.", round, max));
51}
52
53pub fn mission_complete(passed: bool, score: f32) {
55 if passed {
56 say(&format!(
57 "Mission complete. Production grade code shipped. Score {:.1}.",
58 score
59 ));
60 } else {
61 say(&format!(
62 "Mission complete. Human review required. Best score {:.1}.",
63 score
64 ));
65 }
66}
67
68pub fn decomposed(count: usize) {
70 say(&format!("Mission decomposed into {} subtasks.", count));
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76
77 #[test]
78 fn test_is_enabled_default() {
79 assert!(!is_enabled());
81 }
82}