@@ -257,7 +257,6 @@ async fn review_command(
257257
258258 let diffs = core:: DiffParser :: parse_unified_diff ( & diff_content) ?;
259259 info ! ( "Parsed {} file diffs" , diffs. len( ) ) ;
260-
261260 let model_config = adapters:: llm:: ModelConfig {
262261 model_name : config. model . clone ( ) ,
263262 api_key : config. api_key . clone ( ) ,
@@ -273,7 +272,7 @@ async fn review_command(
273272 base_prompt_config. max_diff_chars = config. max_diff_chars ;
274273 let mut all_comments = Vec :: new ( ) ;
275274
276- for diff in diffs {
275+ for diff in & diffs {
277276 // Check if file should be excluded
278277 if config. should_exclude ( & diff. file_path ) {
279278 info ! ( "Skipping excluded file: {}" , diff. file_path. display( ) ) ;
@@ -301,12 +300,12 @@ async fn review_command(
301300
302301 // Run pre-analyzers to get additional context
303302 let analyzer_chunks = plugin_manager
304- . run_pre_analyzers ( & diff, & repo_path_str)
303+ . run_pre_analyzers ( diff, & repo_path_str)
305304 . await ?;
306305 context_chunks. extend ( analyzer_chunks) ;
307306
308307 // Extract symbols from diff and fetch their definitions
309- let symbols = extract_symbols_from_diff ( & diff) ;
308+ let symbols = extract_symbols_from_diff ( diff) ;
310309 if !symbols. is_empty ( ) {
311310 let definition_chunks = context_fetcher
312311 . fetch_related_definitions ( & diff. file_path , & symbols)
@@ -799,7 +798,7 @@ async fn review_diff_content_raw(
799798 let repo_path_str = repo_path. to_string_lossy ( ) . to_string ( ) ;
800799 let context_fetcher = core:: ContextFetcher :: new ( repo_path. to_path_buf ( ) ) ;
801800
802- for diff in diffs {
801+ for diff in & diffs {
803802 // Check if file should be excluded
804803 if config. should_exclude ( & diff. file_path ) {
805804 info ! ( "Skipping excluded file: {}" , diff. file_path. display( ) ) ;
@@ -827,12 +826,12 @@ async fn review_diff_content_raw(
827826
828827 // Run pre-analyzers to get additional context
829828 let analyzer_chunks = plugin_manager
830- . run_pre_analyzers ( & diff, & repo_path_str)
829+ . run_pre_analyzers ( diff, & repo_path_str)
831830 . await ?;
832831 context_chunks. extend ( analyzer_chunks) ;
833832
834833 // Extract symbols from diff and fetch their definitions
835- let symbols = extract_symbols_from_diff ( & diff) ;
834+ let symbols = extract_symbols_from_diff ( diff) ;
836835 if !symbols. is_empty ( ) {
837836 let definition_chunks = context_fetcher
838837 . fetch_related_definitions ( & diff. file_path , & symbols)
@@ -1227,6 +1226,7 @@ async fn smart_review_command(
12271226
12281227 let diffs = core:: DiffParser :: parse_unified_diff ( & diff_content) ?;
12291228 info ! ( "Parsed {} file diffs" , diffs. len( ) ) ;
1229+ let walkthrough = build_change_walkthrough ( & diffs) ;
12301230
12311231 let model_config = adapters:: llm:: ModelConfig {
12321232 model_name : config. model . clone ( ) ,
@@ -1240,7 +1240,7 @@ async fn smart_review_command(
12401240 let adapter = adapters:: llm:: create_adapter ( & model_config) ?;
12411241 let mut all_comments = Vec :: new ( ) ;
12421242
1243- for diff in diffs {
1243+ for diff in & diffs {
12441244 // Check if file should be excluded
12451245 if config. should_exclude ( & diff. file_path ) {
12461246 info ! ( "Skipping excluded file: {}" , diff. file_path. display( ) ) ;
@@ -1268,7 +1268,7 @@ async fn smart_review_command(
12681268
12691269 // Run pre-analyzers to get additional context
12701270 let analyzer_chunks = plugin_manager
1271- . run_pre_analyzers ( & diff, & repo_path_str)
1271+ . run_pre_analyzers ( diff, & repo_path_str)
12721272 . await ?;
12731273 context_chunks. extend ( analyzer_chunks) ;
12741274
@@ -1295,7 +1295,7 @@ async fn smart_review_command(
12951295 }
12961296
12971297 // Extract symbols and get definitions
1298- let symbols = extract_symbols_from_diff ( & diff) ;
1298+ let symbols = extract_symbols_from_diff ( diff) ;
12991299 if !symbols. is_empty ( ) {
13001300 let definition_chunks = context_fetcher
13011301 . fetch_related_definitions ( & diff. file_path , & symbols)
@@ -1306,7 +1306,7 @@ async fn smart_review_command(
13061306 let guidance = build_review_guidance ( & config, path_config) ;
13071307 let ( system_prompt, user_prompt) =
13081308 core:: SmartReviewPromptBuilder :: build_enhanced_review_prompt (
1309- & diff,
1309+ diff,
13101310 & context_chunks,
13111311 config. max_context_chars ,
13121312 config. max_diff_chars ,
@@ -1344,7 +1344,7 @@ async fn smart_review_command(
13441344 }
13451345 }
13461346
1347- let comments = filter_comments_for_diff ( & diff, comments) ;
1347+ let comments = filter_comments_for_diff ( diff, comments) ;
13481348 all_comments. extend ( comments) ;
13491349 }
13501350 }
@@ -1357,7 +1357,7 @@ async fn smart_review_command(
13571357
13581358 // Generate summary and output results
13591359 let summary = core:: CommentSynthesizer :: generate_summary ( & processed_comments) ;
1360- let output = format_smart_review_output ( & processed_comments, & summary) ;
1360+ let output = format_smart_review_output ( & processed_comments, & summary, & walkthrough ) ;
13611361
13621362 if let Some ( path) = output_path {
13631363 tokio:: fs:: write ( path, output) . await ?;
@@ -1552,6 +1552,7 @@ fn parse_smart_tags(value: &str) -> Vec<String> {
15521552fn format_smart_review_output (
15531553 comments : & [ core:: Comment ] ,
15541554 summary : & core:: comment:: ReviewSummary ,
1555+ walkthrough : & str ,
15551556) -> String {
15561557 let mut output = String :: new ( ) ;
15571558
@@ -1583,6 +1584,11 @@ fn format_smart_review_output(
15831584 summary. files_reviewed
15841585 ) ) ;
15851586
1587+ if !walkthrough. trim ( ) . is_empty ( ) {
1588+ output. push_str ( walkthrough) ;
1589+ output. push ( '\n' ) ;
1590+ }
1591+
15861592 // Quick Stats
15871593 output. push_str ( "### 📈 Issue Breakdown\n \n " ) ;
15881594
@@ -1886,6 +1892,65 @@ fn build_review_guidance(
18861892 }
18871893}
18881894
1895+ fn build_change_walkthrough ( diffs : & [ core:: UnifiedDiff ] ) -> String {
1896+ let mut entries = Vec :: new ( ) ;
1897+ let mut truncated = false ;
1898+ let max_entries = 50usize ;
1899+
1900+ for diff in diffs {
1901+ if diff. is_binary {
1902+ continue ;
1903+ }
1904+
1905+ let mut added = 0usize ;
1906+ let mut removed = 0usize ;
1907+ for hunk in & diff. hunks {
1908+ for change in & hunk. changes {
1909+ match change. change_type {
1910+ core:: diff_parser:: ChangeType :: Added => added += 1 ,
1911+ core:: diff_parser:: ChangeType :: Removed => removed += 1 ,
1912+ _ => { }
1913+ }
1914+ }
1915+ }
1916+
1917+ let status = if diff. is_deleted {
1918+ "deleted"
1919+ } else if diff. is_new {
1920+ "new"
1921+ } else {
1922+ "modified"
1923+ } ;
1924+
1925+ entries. push ( format ! (
1926+ "- `{}` ({}; +{}, -{})" ,
1927+ diff. file_path. display( ) ,
1928+ status,
1929+ added,
1930+ removed
1931+ ) ) ;
1932+
1933+ if entries. len ( ) >= max_entries {
1934+ truncated = true ;
1935+ break ;
1936+ }
1937+ }
1938+
1939+ if entries. is_empty ( ) {
1940+ return String :: new ( ) ;
1941+ }
1942+
1943+ let mut output = String :: new ( ) ;
1944+ output. push_str ( "## 🧭 Change Walkthrough\n \n " ) ;
1945+ output. push_str ( & entries. join ( "\n " ) ) ;
1946+ output. push ( '\n' ) ;
1947+ if truncated {
1948+ output. push_str ( "\n ...truncated (too many files)\n " ) ;
1949+ }
1950+
1951+ output
1952+ }
1953+
18891954fn apply_confidence_threshold (
18901955 comments : Vec < core:: Comment > ,
18911956 min_confidence : f32 ,
0 commit comments