Skip to content

Commit 1a12ae6

Browse files
haasonsaasclaude
andcommitted
Move GitHub integration to backend, add live progress & inline PR reviews
- Move all GitHub API calls from client-side @octokit/rest to backend /api/gh/* endpoints (repos, PRs, status, PR review) - Remove @octokit/rest dependency and web/src/lib/github.ts - Upgrade post_pr_review_comments to post inline comments with the GitHub Reviews API (severity icons, suggestions, code blocks) - Add avatar_url to GhStatusResponse, stargazers_count/private to GhRepo - Add React Query hooks for GitHub operations (useGhStatus, useGhRepos, useGhPrs, useStartPrReview) - Add ProgressCallback/ProgressUpdate to review pipeline for live per-file progress tracking - Add ProgressBanner and EventPanel components to ReviewView - Frontend shows partial results during scan (comments stream in) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent eda811a commit 1a12ae6

File tree

12 files changed

+565
-707
lines changed

12 files changed

+565
-707
lines changed

src/review/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ mod rule_helpers;
77
pub use filters::apply_review_filters;
88
pub use pipeline::{
99
review_diff_content, review_diff_content_with_repo, review_diff_content_raw,
10+
review_diff_content_raw_with_progress,
1011
extract_symbols_from_diff, filter_comments_for_diff,
1112
build_symbol_index, build_review_guidance,
13+
ProgressCallback, ProgressUpdate,
1214
};
1315
pub use feedback::{
1416
load_feedback_store, load_feedback_store_from_path, save_feedback_store,

src/review/pipeline.rs

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,28 @@ use std::path::PathBuf;
88
use std::time::Instant;
99
use tracing::{info, warn};
1010

11+
use std::sync::Arc;
12+
1113
use crate::adapters;
1214
use crate::config;
1315
use crate::core;
1416
use crate::core::offline::optimize_prompt_for_local;
1517
use crate::output::OutputFormat;
1618
use crate::parsing::parse_llm_response;
1719
use crate::plugins;
20+
21+
/// Progress update emitted per file during review.
22+
pub struct ProgressUpdate {
23+
pub current_file: String,
24+
pub files_total: usize,
25+
pub files_completed: usize,
26+
pub files_skipped: usize,
27+
/// Comments found so far (accumulated from all completed files).
28+
pub comments_so_far: Vec<core::Comment>,
29+
}
30+
31+
/// Callback invoked before each file's LLM call and after completion.
32+
pub type ProgressCallback = Arc<dyn Fn(ProgressUpdate) + Send + Sync>;
1833
use super::context_helpers::{
1934
inject_custom_context, inject_pattern_repository_context,
2035
rank_and_trim_context_chunks, resolve_pattern_repositories,
@@ -46,6 +61,16 @@ pub async fn review_diff_content_raw(
4661
diff_content: &str,
4762
config: config::Config,
4863
repo_path: &Path,
64+
) -> Result<Vec<core::Comment>> {
65+
review_diff_content_raw_with_progress(diff_content, config, repo_path, None).await
66+
}
67+
68+
/// Like `review_diff_content_raw` but with an optional progress callback.
69+
pub async fn review_diff_content_raw_with_progress(
70+
diff_content: &str,
71+
config: config::Config,
72+
repo_path: &Path,
73+
on_progress: Option<ProgressCallback>,
4974
) -> Result<Vec<core::Comment>> {
5075
// For local models, chunk oversized diffs instead of truncating
5176
if should_optimize_for_local(&config) {
@@ -61,7 +86,7 @@ pub async fn review_diff_content_raw(
6186
let mut all_comments = Vec::new();
6287
for (i, chunk) in chunks.iter().enumerate() {
6388
eprintln!("Processing chunk {}/{}...", i + 1, chunks.len());
64-
match review_diff_content_raw_inner(chunk, config.clone(), repo_path).await {
89+
match review_diff_content_raw_inner(chunk, config.clone(), repo_path, on_progress.clone()).await {
6590
Ok(comments) => all_comments.extend(comments),
6691
Err(e) => {
6792
eprintln!("Warning: chunk {} failed: {}", i + 1, e);
@@ -72,17 +97,23 @@ pub async fn review_diff_content_raw(
7297
}
7398
}
7499

75-
review_diff_content_raw_inner(diff_content, config, repo_path).await
100+
review_diff_content_raw_inner(diff_content, config, repo_path, on_progress).await
76101
}
77102

78103
async fn review_diff_content_raw_inner(
79104
diff_content: &str,
80105
config: config::Config,
81106
repo_path: &Path,
107+
on_progress: Option<ProgressCallback>,
82108
) -> Result<Vec<core::Comment>> {
83109
let diffs = core::DiffParser::parse_unified_diff(diff_content)?;
84110
info!("Parsed {} file diffs", diffs.len());
85111

112+
// Pre-count reviewable files for progress tracking
113+
let files_total = diffs.len();
114+
let mut files_completed: usize = 0;
115+
let mut files_skipped: usize = 0;
116+
86117
// Check file change limit
87118
if let Some(limit) = config.file_change_limit {
88119
if limit > 0 && diffs.len() > limit {
@@ -151,17 +182,31 @@ async fn review_diff_content_raw_inner(
151182
// Check if file should be excluded
152183
if config.should_exclude(&diff.file_path) {
153184
info!("Skipping excluded file: {}", diff.file_path.display());
185+
files_skipped += 1;
154186
continue;
155187
}
156188
if diff.is_deleted {
157189
info!("Skipping deleted file: {}", diff.file_path.display());
190+
files_skipped += 1;
158191
continue;
159192
}
160193
if diff.is_binary || diff.hunks.is_empty() {
161194
info!("Skipping non-text diff: {}", diff.file_path.display());
195+
files_skipped += 1;
162196
continue;
163197
}
164198

199+
// Emit progress: about to review this file
200+
if let Some(ref cb) = on_progress {
201+
cb(ProgressUpdate {
202+
current_file: diff.file_path.display().to_string(),
203+
files_total,
204+
files_completed,
205+
files_skipped,
206+
comments_so_far: all_comments.clone(),
207+
});
208+
}
209+
165210
let mut context_chunks = context_fetcher
166211
.fetch_context_for_file(
167212
&diff.file_path,
@@ -337,6 +382,8 @@ async fn review_diff_content_raw_inner(
337382
let comments = filter_comments_for_diff(diff, comments);
338383
all_comments.extend(comments);
339384
}
385+
386+
files_completed += 1;
340387
}
341388

342389
// Run post-processors to filter and refine comments

0 commit comments

Comments
 (0)