Skip to content

Commit e3fa527

Browse files
fix(headless): give hosted reviews room to conclude (OpenCoven#119)
Signed-off-by: Timothy Wayne Gregg <Timothy.Gregg@complete.tech>
1 parent e723dfd commit e3fa527

2 files changed

Lines changed: 67 additions & 1 deletion

File tree

src-rust/crates/cli/src/headless.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1086,7 +1086,14 @@ impl ReviewTrace {
10861086
let normalized = normalize_existing_or_lexical(&absolute);
10871087
let root = normalize_existing_or_lexical(&self.workspace_root);
10881088
let relative = normalized.strip_prefix(&root).ok()?;
1089-
normalize_relative_path(&relative.to_string_lossy())
1089+
if normalized.exists() && !normalized.is_file() {
1090+
return None;
1091+
}
1092+
let path = normalize_relative_path(&relative.to_string_lossy())?;
1093+
if path.split('/').any(|part| part == ".git") {
1094+
return None;
1095+
}
1096+
Some(path)
10901097
}
10911098
}
10921099

@@ -1746,6 +1753,8 @@ mod tests {
17461753
std::fs::write(ws.join("src/support.rs"), "").unwrap();
17471754
std::fs::write(ws.join("src/config.rs"), "").unwrap();
17481755
std::fs::write(ws.join("README.md"), "").unwrap();
1756+
std::fs::create_dir_all(ws.join(".git/hooks")).unwrap();
1757+
std::fs::write(ws.join(".git/config"), "").unwrap();
17491758

17501759
let mut trace = ReviewTrace::new(ws);
17511760
trace.record_tool_start("Read", r#"{"file_path":"src/lib.rs"}"#);
@@ -1766,6 +1775,7 @@ mod tests {
17661775
false,
17671776
);
17681777
trace.record_tool_end("Glob", "src/lib.rs\nsrc/support.rs\n", false);
1778+
trace.record_tool_end("Glob", ".git\n.git/config\nsrc\n", false);
17691779
trace.record_tool_start("Read", r#"{"file_path":"../outside.rs"}"#);
17701780

17711781
assert_eq!(

src-rust/crates/cli/src/main.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -865,6 +865,7 @@ async fn main() -> anyhow::Result<()> {
865865
} else {
866866
tools
867867
};
868+
apply_headless_review_query_defaults(&mut query_config, github_context.as_ref());
868869
let tools = filter_tools_for_hosted_review(tools, &config);
869870

870871
// Spawn the background cron scheduler (fires cron tasks at scheduled times).
@@ -1564,6 +1565,18 @@ fn filter_search_only_tools() -> Arc<Vec<Box<dyn claurst_tools::Tool>>> {
15641565
Arc::new(filtered)
15651566
}
15661567

1568+
fn apply_headless_review_query_defaults(
1569+
query_config: &mut claurst_query::QueryConfig,
1570+
github_context: Option<&SessionBrief>,
1571+
) {
1572+
if github_context
1573+
.map(|brief| brief.review_mode() != headless::ReviewMode::None)
1574+
.unwrap_or(false)
1575+
{
1576+
query_config.max_turns = query_config.max_turns.max(20);
1577+
}
1578+
}
1579+
15671580
// ---------------------------------------------------------------------------
15681581
// Headless mode: read prompt from arg/stdin, run, print response
15691582
// ---------------------------------------------------------------------------
@@ -5253,6 +5266,49 @@ mod tests {
52535266
}
52545267
}
52555268

5269+
#[test]
5270+
fn hosted_review_headless_gets_extra_turn_budget() {
5271+
let raw = r#"{
5272+
"contract_version": "2",
5273+
"trigger": "issue_mention",
5274+
"repo": { "owner": "o", "name": "r", "clone_url": "https://github.com/o/r.git", "default_branch": "main" },
5275+
"task": { "kind": "respond_to_mention", "issue_number": 7, "comment_body": "review this" },
5276+
"familiar": { "id": "cody", "display_name": "Cody", "skills": [] },
5277+
"workspace": { "root": "/tmp/ws" },
5278+
"review_context": { "kind": "pull_request", "files": [{ "filename": "src/lib.rs" }] }
5279+
}"#;
5280+
let brief: SessionBrief = serde_json::from_str(raw).expect("brief parses");
5281+
let mut query_config = claurst_query::QueryConfig {
5282+
max_turns: 10,
5283+
..Default::default()
5284+
};
5285+
5286+
apply_headless_review_query_defaults(&mut query_config, Some(&brief));
5287+
5288+
assert_eq!(query_config.max_turns, 20);
5289+
}
5290+
5291+
#[test]
5292+
fn non_review_headless_keeps_turn_budget() {
5293+
let raw = r#"{
5294+
"contract_version": "2",
5295+
"trigger": "issue_mention",
5296+
"repo": { "owner": "o", "name": "r", "clone_url": "https://github.com/o/r.git", "default_branch": "main" },
5297+
"task": { "kind": "respond_to_mention", "issue_number": 7, "comment_body": "answer this" },
5298+
"familiar": { "id": "cody", "display_name": "Cody", "skills": [] },
5299+
"workspace": { "root": "/tmp/ws" }
5300+
}"#;
5301+
let brief: SessionBrief = serde_json::from_str(raw).expect("brief parses");
5302+
let mut query_config = claurst_query::QueryConfig {
5303+
max_turns: 10,
5304+
..Default::default()
5305+
};
5306+
5307+
apply_headless_review_query_defaults(&mut query_config, Some(&brief));
5308+
5309+
assert_eq!(query_config.max_turns, 10);
5310+
}
5311+
52565312
#[test]
52575313
fn hosted_review_filters_write_and_execute_tools_by_default() {
52585314
let all = Arc::new(claurst_tools::all_tools());

0 commit comments

Comments
 (0)