@@ -7,38 +7,38 @@ import { configureConsoleForHeadless } from "../init.js";
77import { logger } from "../util/logger.js" ;
88
99import { ExtendedCommandOptions } from "./BaseCommandOptions.js" ;
10- import type { CheckState } from "./check/CheckProgress .js" ;
11- import { CheckProgress } from "./check/CheckProgress .js" ;
12- import type { WorkerConfig , WorkerResult } from "./check/checkWorker .js" ;
13- import type { DiffContext } from "./check /diffContext.js" ;
14- import { computeDiffContext } from "./check /diffContext.js" ;
15- import type { CheckResult } from "./check /renderReport.js" ;
16- import { renderReport } from "./check /renderReport.js" ;
17- import { resolveChecks } from "./check/resolveChecks .js" ;
18- import { createWorktree , cleanupWorktree } from "./check /worktree.js" ;
19-
20- export interface CheckOptions extends ExtendedCommandOptions {
10+ import type { ReviewState } from "./review/ReviewProgress .js" ;
11+ import { ReviewProgress } from "./review/ReviewProgress .js" ;
12+ import type { WorkerConfig , WorkerResult } from "./review/reviewWorker .js" ;
13+ import type { DiffContext } from "./review /diffContext.js" ;
14+ import { computeDiffContext } from "./review /diffContext.js" ;
15+ import type { ReviewResult } from "./review /renderReport.js" ;
16+ import { renderReport } from "./review /renderReport.js" ;
17+ import { resolveReviews } from "./review/resolveReviews .js" ;
18+ import { createWorktree , cleanupWorktree } from "./review /worktree.js" ;
19+
20+ export interface ReviewOptions extends ExtendedCommandOptions {
2121 base ?: string ;
2222 format ?: string ;
2323 fix ?: boolean ;
2424 patch ?: boolean ;
2525 failFast ?: boolean ;
26- checkAgents ?: string [ ] ;
26+ reviewAgents ?: string [ ] ;
2727}
2828
2929/**
30- * Run a single check in a forked worker process.
30+ * Run a single review in a forked worker process.
3131 */
32- async function runCheckInWorker (
32+ async function runReviewInWorker (
3333 agentSource : string ,
3434 worktreePath : string ,
3535 diffContext : DiffContext ,
36- options : CheckOptions ,
36+ options : ReviewOptions ,
3737) : Promise < WorkerResult > {
3838 return new Promise < WorkerResult > ( ( resolve , _reject ) => {
3939 // Fork the current CLI entry point with the internal worker flag
4040 const workerPath = process . argv [ 1 ] ;
41- const child = fork ( workerPath , [ "--internal-check -worker" ] , {
41+ const child = fork ( workerPath , [ "--internal-review -worker" ] , {
4242 stdio : [ "pipe" , "pipe" , "pipe" , "ipc" ] ,
4343 env : {
4444 ...process . env ,
@@ -58,7 +58,7 @@ async function runCheckInWorker(
5858 patch : "" ,
5959 agentOutput : "" ,
6060 duration : 0 ,
61- error : "Check timed out after 5 minutes" ,
61+ error : "Review timed out after 5 minutes" ,
6262 } ) ;
6363 }
6464 } ,
@@ -79,7 +79,7 @@ async function runCheckInWorker(
7979 verbose : options . verbose ,
8080 } ,
8181 } ;
82- child . send ( { type : "run-check " , config } ) ;
82+ child . send ( { type : "run-review " , config } ) ;
8383 } else if ( msg . type === "result" && msg . result ) {
8484 if ( ! settled ) {
8585 settled = true ;
@@ -135,7 +135,7 @@ async function runCheckInWorker(
135135/**
136136 * Apply patches to the real working tree (--fix mode).
137137 */
138- function applyPatches ( results : CheckResult [ ] ) : void {
138+ function applyPatches ( results : ReviewResult [ ] ) : void {
139139 const patchResults = results . filter (
140140 ( r ) => r . status === "fail" && r . patch . trim ( ) ,
141141 ) ;
@@ -179,35 +179,37 @@ function applyPatches(results: CheckResult[]): void {
179179}
180180
181181/**
182- * Mount the Ink live progress UI or fall back to static logs.
182+ * Mutable props bag for the live Ink UI so we can update it progressively.
183+ */
184+ interface LiveUIProps {
185+ checks : ReviewState [ ] ;
186+ baseBranch ?: string ;
187+ changedFileCount ?: number ;
188+ loading ?: boolean ;
189+ }
190+
191+ /**
192+ * Mount the Ink live progress UI or return a no-op for non-TTY / special modes.
183193 */
184194async function mountProgressUI (
185- checkStates : CheckState [ ] ,
186- diffContext : DiffContext ,
187- options : CheckOptions ,
188- ) : Promise < { rerender ?: ( ) => void ; unmount ?: ( ) => void } > {
195+ props : LiveUIProps ,
196+ options : ReviewOptions ,
197+ ) : Promise < { rerender : ( ) => void ; unmount : ( ) => void } > {
189198 const useLiveUI =
190199 process . stdout . isTTY && ! options . patch && options . format !== "json" ;
191200
192201 if ( ! useLiveUI ) {
193- console . log (
194- chalk . dim (
195- `Running ${ checkStates . length } check${ checkStates . length > 1 ? "s" : "" } : ${ checkStates . map ( ( c ) => c . name ) . join ( ", " ) } ` ,
196- ) ,
197- ) ;
198- return { } ;
202+ return {
203+ rerender : ( ) => { } ,
204+ unmount : ( ) => { } ,
205+ } ;
199206 }
200207
201208 const { render } = await import ( "ink" ) ;
202- const props = {
203- checks : checkStates ,
204- baseBranch : diffContext . baseBranch ,
205- changedFileCount : diffContext . changedFiles . length ,
206- } ;
207- const instance = render ( React . createElement ( CheckProgress , props ) ) ;
209+ const instance = render ( React . createElement ( ReviewProgress , props ) ) ;
208210 return {
209211 rerender : ( ) =>
210- instance . rerender ( React . createElement ( CheckProgress , props ) ) ,
212+ instance . rerender ( React . createElement ( ReviewProgress , props ) ) ,
211213 unmount : ( ) => instance . unmount ( ) ,
212214 } ;
213215}
@@ -216,9 +218,9 @@ async function mountProgressUI(
216218 * Output results and exit with appropriate code.
217219 */
218220function outputResultsAndExit (
219- results : CheckResult [ ] ,
221+ results : ReviewResult [ ] ,
220222 diffContext : DiffContext ,
221- options : CheckOptions ,
223+ options : ReviewOptions ,
222224 checksFromHub : boolean ,
223225) : void {
224226 const format = options . format === "json" ? "json" : "text" ;
@@ -254,20 +256,30 @@ function outputResultsAndExit(
254256}
255257
256258/**
257- * Main check command handler.
259+ * Main review command handler.
258260 */
259- export async function check ( options : CheckOptions = { } ) : Promise < void > {
261+ export async function review ( options : ReviewOptions = { } ) : Promise < void > {
260262 configureConsoleForHeadless ( false ) ;
261263
262264 if ( options . verbose ) {
263265 logger . setLevel ( "debug" ) ;
264266 }
265267
266- // Step 1: Check for changes
267- console . log ( chalk . dim ( "Computing diff..." ) ) ;
268+ // Mount the live UI immediately with a loading state
269+ const uiProps : LiveUIProps = {
270+ checks : [ ] ,
271+ loading : true ,
272+ } ;
273+ const { rerender, unmount : unmountUI } = await mountProgressUI (
274+ uiProps ,
275+ options ,
276+ ) ;
277+
278+ // Step 1: Compute diff
268279 const diffContext = computeDiffContext ( options . base ) ;
269280
270281 if ( ! diffContext . diff . trim ( ) && diffContext . changedFiles . length === 0 ) {
282+ unmountUI ( ) ;
271283 console . log (
272284 chalk . yellow (
273285 "No changes detected. Make some changes or specify a different base branch with --base." ,
@@ -276,64 +288,60 @@ export async function check(options: CheckOptions = {}): Promise<void> {
276288 process . exit ( 0 ) ;
277289 }
278290
279- console . log (
280- chalk . dim (
281- `Found ${ diffContext . changedFiles . length } changed files against ${ diffContext . baseBranch } ` ,
282- ) ,
283- ) ;
291+ // Update UI with diff info (still loading reviews)
292+ uiProps . baseBranch = diffContext . baseBranch ;
293+ uiProps . changedFileCount = diffContext . changedFiles . length ;
294+ rerender ( ) ;
284295
285- // Step 2: Resolve checks
286- console . log ( chalk . dim ( "Resolving checks..." ) ) ;
287- const checks = await resolveChecks ( options . checkAgents ) ;
296+ // Step 2: Resolve reviews
297+ const reviews = await resolveReviews ( options . reviewAgents ) ;
288298
289- if ( checks . length === 0 ) {
299+ if ( reviews . length === 0 ) {
300+ unmountUI ( ) ;
290301 console . log (
291- chalk . yellow ( "\nNo checks found. To add checks :\n" ) +
302+ chalk . yellow ( "\nNo reviews found. To add reviews :\n" ) +
292303 chalk . dim (
293- " 1. Create .continue/agents/my-check .md with agent instructions\n" ,
304+ " 1. Create .continue/agents/my-review .md with agent instructions\n" ,
294305 ) +
295306 chalk . dim (
296- " 2. Or specify an agent: cn check --agent org/agent-name\n" ,
307+ " 2. Or specify an agent: cn review --review-agents org/agent-name\n" ,
297308 ) +
298- chalk . dim ( " 3. Or configure checks on https://continue.dev\n" ) ,
309+ chalk . dim ( " 3. Or configure reviews on https://continue.dev\n" ) ,
299310 ) ;
300311 process . exit ( 0 ) ;
301312 }
302313
303- const checksFromHub = checks . some ( ( c ) => c . sourceType === "hub" ) ;
314+ const checksFromHub = reviews . some ( ( c ) => c . sourceType === "hub" ) ;
304315
305- // Build mutable state for the live UI
306- const checkStates : CheckState [ ] = checks . map ( ( c ) => ( {
316+ // Build mutable state for the live UI and stop loading
317+ const reviewStates : ReviewState [ ] = reviews . map ( ( c ) => ( {
307318 name : c . name ,
308319 status : "pending" as const ,
309320 } ) ) ;
321+ uiProps . checks = reviewStates ;
322+ uiProps . loading = false ;
323+ rerender ( ) ;
310324
311- const { rerender, unmount : unmountUI } = await mountProgressUI (
312- checkStates ,
313- diffContext ,
314- options ,
315- ) ;
316-
317- // Step 3: Create worktrees and run checks
318- const results : CheckResult [ ] = [ ] ;
325+ // Step 3: Create worktrees and run reviews
326+ const results : ReviewResult [ ] = [ ] ;
319327
320- const runSingleCheck = async (
321- resolvedCheck : ( typeof checks ) [ number ] ,
328+ const runSingleReview = async (
329+ resolvedReview : ( typeof reviews ) [ number ] ,
322330 i : number ,
323- ) : Promise < CheckResult > => {
331+ ) : Promise < ReviewResult > => {
324332 const startTime = Date . now ( ) ;
325333 let worktreePath : string | null = null ;
326334
327335 try {
328336 // Mark as running
329- checkStates [ i ] . status = "running" ;
330- checkStates [ i ] . startTime = Date . now ( ) ;
331- rerender ?. ( ) ;
337+ reviewStates [ i ] . status = "running" ;
338+ reviewStates [ i ] . startTime = Date . now ( ) ;
339+ rerender ( ) ;
332340
333341 worktreePath = await createWorktree ( i ) ;
334342
335- const workerResult = await runCheckInWorker (
336- resolvedCheck . source ,
343+ const workerResult = await runReviewInWorker (
344+ resolvedReview . source ,
337345 worktreePath ,
338346 diffContext ,
339347 options ,
@@ -345,31 +353,33 @@ export async function check(options: CheckOptions = {}): Promise<void> {
345353 ? ( "fail" as const )
346354 : ( "pass" as const ) ;
347355
356+ const duration = ( Date . now ( ) - startTime ) / 1000 ;
357+
348358 // Mark as complete
349- checkStates [ i ] . status = status ;
350- checkStates [ i ] . duration = workerResult . duration ;
351- rerender ?. ( ) ;
359+ reviewStates [ i ] . status = status ;
360+ reviewStates [ i ] . duration = duration ;
361+ rerender ( ) ;
352362
353363 return {
354- agent : resolvedCheck . source ,
355- name : resolvedCheck . name ,
364+ agent : resolvedReview . source ,
365+ name : resolvedReview . name ,
356366 status,
357367 patch : workerResult . patch ,
358368 output : workerResult . agentOutput ,
359- duration : workerResult . duration ,
369+ duration,
360370 error : workerResult . error ,
361371 } ;
362372 } catch ( e : any ) {
363373 const duration = ( Date . now ( ) - startTime ) / 1000 ;
364374
365375 // Mark as error
366- checkStates [ i ] . status = "error" ;
367- checkStates [ i ] . duration = duration ;
368- rerender ?. ( ) ;
376+ reviewStates [ i ] . status = "error" ;
377+ reviewStates [ i ] . duration = duration ;
378+ rerender ( ) ;
369379
370380 return {
371- agent : resolvedCheck . source ,
372- name : resolvedCheck . name ,
381+ agent : resolvedReview . source ,
382+ name : resolvedReview . name ,
373383 status : "error" as const ,
374384 patch : "" ,
375385 output : "" ,
@@ -384,16 +394,16 @@ export async function check(options: CheckOptions = {}): Promise<void> {
384394 } ;
385395
386396 if ( options . failFast ) {
387- for ( let i = 0 ; i < checks . length ; i ++ ) {
388- const result = await runSingleCheck ( checks [ i ] , i ) ;
397+ for ( let i = 0 ; i < reviews . length ; i ++ ) {
398+ const result = await runSingleReview ( reviews [ i ] , i ) ;
389399 results . push ( result ) ;
390400 if ( result . status === "fail" || result . status === "error" ) {
391401 break ;
392402 }
393403 }
394404 } else {
395405 const settled = await Promise . allSettled (
396- checks . map ( ( resolvedCheck , i ) => runSingleCheck ( resolvedCheck , i ) ) ,
406+ reviews . map ( ( resolvedReview , i ) => runSingleReview ( resolvedReview , i ) ) ,
397407 ) ;
398408 for ( const result of settled ) {
399409 if ( result . status === "fulfilled" ) {
@@ -402,6 +412,6 @@ export async function check(options: CheckOptions = {}): Promise<void> {
402412 }
403413 }
404414
405- unmountUI ?. ( ) ;
415+ unmountUI ( ) ;
406416 outputResultsAndExit ( results , diffContext , options , checksFromHub ) ;
407417}
0 commit comments