Skip to content

Commit e2bd6e0

Browse files
committed
fix(review): gate re-review prompt on command stdin
Entire-Checkpoint: 01KXGTKA4VF60BYNEPDWQQ3NNC
1 parent dfd203c commit e2bd6e0

2 files changed

Lines changed: 27 additions & 6 deletions

File tree

cmd/entire/cli/review/cmd.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -977,12 +977,12 @@ func nonLaunchableEligibleNames(profile settings.ReviewProfileConfig, eligible [
977977
// (true, nil). In a non-interactive context it cannot prompt, so it proceeds
978978
// (the user explicitly invoked `entire review`) after printing a note rather
979979
// than blocking on a confirm form that would error out.
980-
func confirmReReviewOrProceed(ctx context.Context, out io.Writer, deps Deps) (bool, error) {
980+
func confirmReReviewOrProceed(ctx context.Context, out io.Writer, deps Deps, canPrompt bool) (bool, error) {
981981
reviewed, meta := deps.HeadHasReviewCheckpoint(ctx)
982982
if !reviewed {
983983
return true, nil
984984
}
985-
if !interactive.CanPromptInteractively() {
985+
if !canPrompt {
986986
fmt.Fprintf(out, "Note: HEAD was already reviewed (%s); re-running.\n", meta)
987987
return true, nil
988988
}
@@ -1044,7 +1044,8 @@ func runSingleAgentPath(
10441044
}
10451045

10461046
// 4. Re-run guard: check if HEAD's checkpoint already has a review.
1047-
if proceed, guardErr := confirmReReviewOrProceed(ctx, out, deps); guardErr != nil {
1047+
canPrompt := reviewCommandIsInteractive(cmd)
1048+
if proceed, guardErr := confirmReReviewOrProceed(ctx, out, deps, canPrompt); guardErr != nil {
10481049
fmt.Fprintln(out, "prompt cancelled")
10491050
return silentErr(guardErr)
10501051
} else if !proceed {
@@ -1098,7 +1099,6 @@ func runSingleAgentPath(
10981099
defer cancelRun()
10991100

11001101
runCfg.EnrichSummary = reviewSummaryTokenEnricher(worktreeRoot, headSHA)
1101-
canPrompt := reviewCommandIsInteractive(cmd)
11021102
sinks := composeSingleAgentSinks(singleAgentSinkInputs{
11031103
out: out,
11041104
isTTY: canPrompt,
@@ -1188,7 +1188,8 @@ func runMultiAgentPath(
11881188
return fmt.Errorf("resolve HEAD: %w", shaErr)
11891189
}
11901190

1191-
if proceed, guardErr := confirmReReviewOrProceed(ctx, out, deps); guardErr != nil {
1191+
canPrompt := reviewCommandIsInteractive(cmd)
1192+
if proceed, guardErr := confirmReReviewOrProceed(ctx, out, deps, canPrompt); guardErr != nil {
11921193
fmt.Fprintln(out, "prompt cancelled")
11931194
return deps.NewSilentError(guardErr)
11941195
} else if !proceed {
@@ -1270,7 +1271,7 @@ func runMultiAgentPath(
12701271
masterLabel := judgeLabel(judge)
12711272
sinks := composeMultiAgentSinks(multiAgentSinkInputs{
12721273
out: out,
1273-
isTTY: reviewCommandIsInteractive(cmd),
1274+
isTTY: canPrompt,
12741275
agentNames: agentNames,
12751276
cancelRun: cancelRun,
12761277
runContext: runCtx,

cmd/entire/cli/review/configure_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,26 @@ func TestApplyLegacyReviewProfileFallback_RepairsGeneratedCodexSkill(t *testing.
8888
}
8989
}
9090

91+
func TestConfirmReReviewOrProceed_NonInteractiveDoesNotPrompt(t *testing.T) {
92+
t.Parallel()
93+
94+
out := &bytes.Buffer{}
95+
proceed, err := confirmReReviewOrProceed(context.Background(), out, Deps{
96+
HeadHasReviewCheckpoint: func(context.Context) (bool, string) {
97+
return true, "existing review"
98+
},
99+
}, false)
100+
if err != nil {
101+
t.Fatalf("confirmReReviewOrProceed: %v", err)
102+
}
103+
if !proceed {
104+
t.Fatal("non-interactive re-review should proceed")
105+
}
106+
if !strings.Contains(out.String(), "already reviewed") {
107+
t.Fatalf("missing non-interactive re-review note: %q", out.String())
108+
}
109+
}
110+
91111
func TestReviewInteractivityHardDisabled(t *testing.T) {
92112
t.Parallel()
93113

0 commit comments

Comments
 (0)