supercode_harness/
startup_prompts.rs1use std::path::Path;
11
12use serde::Deserialize;
13
14#[derive(Deserialize)]
15struct Prompts {
16 startup: Vec<Vec<String>>,
17 unattended: Vec<String>,
18 unattended_chosen_by: Vec<String>,
19}
20
21fn table() -> std::collections::BTreeMap<String, Prompts> {
22 serde_json::from_str(include_str!("startup_prompts.json"))
23 .expect("startup_prompts.json is the harness crate's own table")
24}
25
26pub fn startup_arguments(
30 harness: &str,
31 cwd: Option<&Path>,
32 given: &[String],
33 unattended: bool,
34) -> Vec<String> {
35 let table = table();
36 let Some(prompts) = table.get(harness) else {
37 return Vec::new();
38 };
39 let cwd = cwd.map(|cwd| {
40 serde_json::to_string(cwd.to_string_lossy().as_ref())
41 .expect("a filesystem path always serializes as JSON text")
42 });
43 let mut arguments = Vec::new();
44 for pair in &prompts.startup {
45 let needs_cwd = pair.iter().any(|flag| flag.contains("{cwd}"));
46 if needs_cwd && cwd.is_none() {
47 continue;
48 }
49 let key = pair
50 .last()
51 .and_then(|flag| flag.split('=').next())
52 .unwrap_or_default();
53 if !key.is_empty() && given.iter().any(|argument| argument.contains(key)) {
54 continue;
55 }
56 arguments.extend(pair.iter().map(|flag| match &cwd {
57 Some(cwd) => flag.replace("{cwd}", cwd),
58 None => flag.clone(),
59 }));
60 }
61 let chosen = given.iter().any(|argument| {
62 prompts
63 .unattended_chosen_by
64 .iter()
65 .any(|flag| argument == flag || argument.starts_with(&format!("{flag}=")))
66 });
67 if unattended && !chosen {
68 arguments.extend(prompts.unattended.iter().cloned());
69 }
70 arguments
71}