use std::path::{Path, PathBuf};
use super::{Caps, DroneWake, Harness, Probe, Transcript, Wiring};
pub const EVENTS: [(&str, &str); 6] = [
("SimPrompt", "prompt"),
("SimPreTool", "pre_tool"),
("SimPostTool", "post_tool"),
("SimPostToolFailure", "post_tool_failure"),
("SimStop", "stop"),
("SimEnd", "end"),
];
pub const CAPS_ENV: &str = "BORG_SIM_CAPS";
const DEFAULT_CAPS: &str = "prompt,tool,deny";
pub struct Sim;
pub fn caps_of(list: &str) -> Caps {
let on = |f: &str| list.split(',').any(|x| x.trim() == f);
Caps {
prompt_context: on("prompt"),
tool_context: on("tool"),
early_delivery: on("early"),
question_dialog: on("dialog"),
transcript: if on("transcript") { Transcript::Claude } else { Transcript::None },
deny_capture: on("deny"),
sends_pid: on("pid"),
stop_budget: None,
session_env: None,
pid_env: None,
drone_wake: DroneWake::Model,
}
}
impl Harness for Sim {
fn name(&self) -> &'static str {
"sim"
}
fn caps(&self) -> Caps {
caps_of(&std::env::var(CAPS_ENV).unwrap_or_else(|_| DEFAULT_CAPS.into()))
}
fn wiring(&self) -> Wiring {
Wiring::CommandHooks { events: &EVENTS, timeouts: &[("stop", 90)], retired: &[], through_links: false }
}
fn target(&self, home: &Path, _var: &dyn Fn(&str) -> Option<PathBuf>) -> PathBuf {
home.join(".sim/hooks.json")
}
fn probe(&self) -> Probe {
Probe { cli: "sim", tested: "" }
}
fn hidden(&self) -> bool {
true
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn caps_come_from_the_list() {
let c = caps_of("early,transcript");
assert!(c.early_delivery && !c.question_dialog && !c.prompt_context);
assert_eq!(c.transcript, Transcript::Claude);
let d = caps_of(DEFAULT_CAPS);
assert!(d.prompt_context && d.tool_context && d.deny_capture && !d.early_delivery && !d.sends_pid);
}
}