settings.json effortLevel="max" gets silently demoted to "xhigh" by the
schema validator; the CLI flag form is honored correctly. Pass --effort max
explicitly so every claude-code invocation (reviewer / analyzer / summarizer /
audit) actually runs at the real max effort tier rather than the demoted
xhigh tier from settings.json fallback.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per-repo conventions now live at a stable user-level path instead of being
read from cwd. Audit extracts owner/repo from the PR URL in taskPrompt and
looks up ~/.magpie/house-rules/<owner>_<repo>.md. Works for both bot mode
and CLI mode without anyone needing to stage files into the worktree.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The per-reviewer summary step was removed in 0f03726, dropping the
summaries field from DebateResult, but this test still asserted on it
and failed. Remove the stale assertion.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
By default the orchestrator is resilient: a single reviewer (or context
gatherer) failure is logged and the round continues with the survivors,
aborting only when all reviewers fail.
The new --fail-fast flag flips to strict mode — any reviewer or
context-gathering failure re-throws immediately and terminates the
whole flow. Wired through the review and discuss commands via
OrchestratorOptions.failFast, with a regression test and README docs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Claude CLI in -p mode only outputs text to stdout when generating the
final response. During tool-heavy reviews (reading files, running
commands), no stdout/stderr is produced, causing the 900s inactivity
timeout to kill actively-working Claude processes.
Switch runClaudeStream to --output-format stream-json --verbose, which
emits JSON events for every tool call, tool result, and assistant
message. This keeps lastActivity alive during tool execution. The final
result text is extracted from the "result" event.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When chat/chatStream throws (timeout, crash, etc.), the session ID was
left intact, causing subsequent rounds to --resume a dead session and
fail with "Session ID already in use". Now all 4 CLI providers reset
to a fresh session ID on error.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Reviewers now fetch diff and read code themselves (CLI providers)
instead of receiving pre-embedded diff text. Enables verification
of issues against actual code context during review.
- Merge audit into magpie as verifyIssues() with Read/Grep/Glob tools,
replacing the separate downstream audit step in li-bot.
- Add --no-conclusion flag to skip summarize step (bot mode).
- Context gatherer: support Go/C++/Proto/Python/Java/Scala symbol
extraction and multi-language grep (was JS/TS only).
- Structurizer: standardize categories to 12 enums, add strict severity
definitions, simplify description template for direct GitHub posting.
- Add isCliModel() helper to detect CLI vs API providers.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Stream mode was discarding stderr (_data), making it impossible to
diagnose exit code 1 failures. Now buffers stderr (capped at 10KB)
and appends the last 500 chars to error messages on crash or timeout.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The summarizer now generates the final conclusion directly from the full
debate conversation history, eliminating the intermediate step where each
reviewer was asked to summarize their own points. This saves one round of
API calls per reviewer without losing information.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
After the summarizer produces the final conclusion, a new verification step
re-examines it against the original PR diff/code to confirm correctness,
flag false positives, catch missed issues, and produce an authoritative
verified final conclusion.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Allow CLI providers (claude-code, codex-cli, gemini-cli, qwen-code) to
accept a model override using colon syntax (e.g., `claude-code:claude-opus-4-6`).
Display the model name alongside reviewer IDs in review and discuss output.
Update default Gemini API model to gemini-3.1-pro-preview.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
gh pr diff returns HTTP 406 for PRs with >20,000 lines of diff.
Added fallback: fetch full diff via commit diff API endpoint (no line
limit), split into per-file sections, prioritize core files over tests,
and truncate to 15k lines to fit model context windows.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Introduce an optional General Discussion phase for PR reviews that sits
between review completion and the issue-by-issue comment loop. Users can
select participants, ask general questions, and resolve issues inline
(/post, /skip, /edit, /discuss, /issues) so only remaining issues flow
into the per-issue loop.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move language instructions from user message suffix to system prompt prefix
where LLMs give them higher weight. Add langPrefix/withLang() to orchestrator
so all reviewer/analyzer/summarizer calls get the language requirement.
Also wire discuss command to use config.defaults.language instead of only
following user input language.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add extractDiffLineRanges() to include valid line ranges in structurizer prompt
- Add content-based matching (extractCodeFromBody + findLineByContent) as fallback
- Add full diff fallback via gh api when per-file patches are null
- Widen nearest-line threshold from 20 to 50 for better coverage
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace execSync with spawnSync in getFileHistory() and getPRDetails()
to prevent shell injection through file paths and PR numbers. Add input
validation for prNumber (must be a positive integer).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace execSync with spawnSync in findReferences() to prevent shell
injection through malicious symbol names in PR diffs. Use -F (fixed-string)
and -e flags for safe argument passing to ripgrep.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When the AI reviewer references a line not exactly in a diff hunk,
find the nearest valid diff line (within 20 lines) and post inline
there instead of falling back to file-level. Also constrain the
structurizer prompt to only reference files actually in the diff.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add stdin EPIPE error handlers to prevent unhandled exception crashes
when child processes exit before reading all input
- Clear CLAUDECODE env var to avoid nested session detection when
running from within Claude Code
- Write large prompts (>100KB) to temp files instead of stdin to bypass
CLI prompt size limits; CLI tools read the file via their built-in
file access capabilities
- Capture stderr in claude-code streaming mode for better error reporting
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add interactivePostReviewDiscussion() for chatting with any role after review conclusion
- Show all roles (reviewers + analyzer + summarizer) in comment discussion picker
- Add comment style prompt before issue loop to style-guide first-gen comments
- Add /skip and /drop to abandon issues mid-discussion
- Add defaults.language config for localized output (e.g. language: zh)
- Expose getAnalyzer() and getSummarizer() from orchestrator
- Share reviewer sessions across discussion and comment phases
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Li Liu <li.liu@zilliz.com>
When a bare PR number is given while in a fork's local clone, the code
now uses `gh pr view` to resolve the actual upstream repo before falling
back to git remote detection. This prevents 404 errors when posting
review comments on PRs that live on the upstream repository.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reviewer prompts previously allowed LLMs to stop after finding a handful
of issues. Now every round demands systematic coverage of all changed
files/functions, and debate rounds additionally require reviewers to
identify what others missed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Classify comments against PR diff before posting. When comments cannot
be placed inline (line not in diff), show user the fallback plan and
offer choices: post all with fallback, inline only, retry as inline,
or skip.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use GitHub Reviews API to batch-post comments as a proper code review.
Parse PR diff to determine valid line placements, with three-level
fallback: inline (exact line) → file-level (attached to file) → global.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Show a dim "Enter to end discussion" hint at the input prompt that
automatically clears when the user starts typing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Maintain a single session per reviewer across all issue discussions,
so that context (PR diff, gathered context, debate history) is sent
once at session start and subsequent issues use --resume for
claude-code provider. This enables cross-issue context sharing and
eliminates cold-start overhead per issue.
- Add ReviewerSessionState interface and session management helpers
- buildInitialSessionContext: rich first message with full PR context
- getOrCreateSession: lazy session creation with provider startSession
- Use DebateResult type instead of inline type for better type safety
- Wrap discussion flow in try/finally to guarantee session cleanup
- Synthetic assistant reply after initial context to maintain
user/assistant alternation for API-based providers
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When reviewing a PR from a different repository using a full GitHub URL,
the commenter commands (gh pr view, gh pr comment) defaulted to the
current directory's git remote, causing "Could not resolve PullRequest"
errors. Now extracts owner/repo from the PR URL and passes --repo flag.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
After discuss generates a comment, users can now press [r] to
regenerate with custom instructions (e.g. "more concise", "add code
example"). Supports unlimited regeneration cycles with full
conversation context preserved.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rewrote commenter to post each issue as an individual inline comment
on the specific line via GitHub PR comments API. If the line is not
in the diff, falls back to a regular PR comment with file:line context.
Previously used batch PR review API where one invalid line would fail
the entire batch.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Discussion mode ('d') now auto-sends first message asking the
reviewer to explain the issue in detail (where, why, how to fix)
before user interaction begins
- Progress bar shows running tally: posted/edited/discussed/skipped
counts displayed on each issue header
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Root cause: ora's default discardStdin=true calls process.stdin.pause()
when spinner stops. This makes the stdin handle inactive in libuv, and
since readline's question() does not call resume(), the event loop sees
no active handles and the process exits silently. Only affects TTY
environments (stdinDiscarder checks isTTY).
Fix: use discardStdin:false on all ora spinners that coexist with
readline, plus explicit process.stdin.resume() safety net.
Also includes:
- Multi-turn discussion with conversation history and debate context
- AI-generated final comments after discussion
- unhandledRejection guard for async generator cleanup
- Pre-fetch PR diff so API-only models get the code
- Solo review/discuss support (min 1 reviewer, skip convergence)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- AnthropicProvider: stream.abort() in finally block ensures HTTP
connection is released even if consumer breaks early
- OpenAIProvider: stream.controller.abort() for same reason
- GeminiProvider: document that consuming all chunks is sufficient
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- MockProvider for debug mode: supports MAGPIE_MOCK_DELAY,
MAGPIE_MOCK_RESPONSE, MAGPIE_MOCK_FILE env vars; echoes input by default
- QwenCodeProvider: wraps qwen-code CLI (OAuth-based)
- MiniMaxProvider: API-based provider using MiniMax-M2.5
- config.mock top-level flag: when true, all models route to MockProvider
- model prefix matching: mock, mock1, mock2 etc. all map to mock provider
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use `codex exec --json` and `codex exec resume <thread_id>` to maintain
multi-turn conversation state, matching Claude and Gemini CLI behavior.
In debate rounds, only the last message is sent instead of full history.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1. Structurizer now requests comprehensive markdown descriptions with
original code quotes, impact analysis, and fix rationale — suitable
for GitHub PR comments.
2. Fix discuss (d) silently skipping: raisedBy was stripped by
parseReviewerOutput, defaulting to ['summarizer'] which matched no
reviewer. Now preserved through parsing pipeline, with fallback to
first available reviewer.
3. Issue display now renders markdown via marked() for proper formatting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When extracting structured issues from review text, Claude Code with
--dangerously-skip-permissions would interpret file paths and fix suggestions
as instructions to modify code, producing "All fixes applied..." instead of
JSON. Fix by passing --tools "" to disable all tools for the structurizer call.
Also: end summarizer session before structurization for clean non-session call,
make issue-parser more lenient (accept raw JSON objects, optional verdict/summary).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The analysis content was still buffered when onContextGathered fired,
causing the context section to appear before the analysis text.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reviewer output format is not under our control. Instead of trying to
parse JSON blocks from reviewer messages (which may not match our schema),
always use the summarizer to extract structured issues from the review
discussion text. This is more robust and removes any dependency on
reviewer prompt configuration.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When reviewers don't include structured JSON blocks in their output,
the summarizer is called to extract issues from the unstructured review
text into the standard JSON format. This ensures the per-issue
interactive post-processing flow always works for PR reviews.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1. Session names now include explicit role: "reviewer:gemini" instead of
just "gemini", matching analyzer/summarizer pattern
2. PR post-processing no longer requires structured JSON issues. When
reviewers don't output JSON blocks, offers to post the final
conclusion as a general PR comment instead.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move onContextGathered callback to after Promise.all resolves, so context
displays after analysis finishes streaming. Work is still parallel, only
the display is sequential.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Prevents AI from outputting chatty preamble like "Here's my analysis"
before the actual content.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Gemini CLI: full session persistence via -o json/stream-json and
--resume <uuid>, NDJSON parsing for streaming session_id capture
- Claude Code & Gemini CLI: session naming via [name] prefix in first
message, visible in gemini --list-sessions and claude --resume
- Provider interface: startSession() now accepts optional name parameter
- Codex CLI: include stderr in error messages for better diagnostics
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Validates that PR numbers are numeric-only in postPRReview and
getPRHeadSha before passing them to shell commands.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add human-in-the-loop review for each issue before posting to GitHub.
After structured issues are displayed, users can review each issue and
choose to post as-is, edit, discuss with the original reviewer, skip,
or stop. Approved comments are batched and posted via the GitHub API.
- Add getReviewers() method to DebateOrchestrator
- Add interactiveCommentReview function with per-issue actions (p/e/d/s/q)
- Add discuss mode: back-and-forth with the AI reviewer who raised the issue
- Wire post-processing prompt into PR review flow after issue table display
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add commenter module that builds GitHub PR review payloads from merged
issues. Issues with file+line become inline review comments, issues
without line info go into the review body. Includes gh CLI wrappers for
posting reviews and fetching PR head SHA.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add formatCallChainForReviewer to display exact code snippets at each
call site, giving reviewers precise context about how changed symbols
are used across the codebase. Raw references are now stored in
GatheredContext and formatted into the reviewer prompt.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add parseFocusAreas to extract suggested review focus from analyzer
output and inject them as hints into each reviewer's first-round
prompt. Focus areas are suggestions, not constraints — reviewers are
explicitly told to also flag anything else they notice.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add parseReviewerOutput to extract structured issues from reviewer
JSON blocks and deduplicateIssues to merge similar issues across
multiple reviewers using Jaccard similarity on title words.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add reference collector module that:
- Extracts function/class symbols from git diffs
- Uses ripgrep to find where symbols are referenced in the codebase
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add onConvergenceJudgment callback to display why judge ruled converged/not
- Increase joke rotation interval from 8s to 15s
- Fix markdown rendering issues from LLMs like Codex:
- Add fixMarkdown() to convert indented lists to standard format
- Increase terminal width from 80 to 120
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The previous convergence check had two issues:
1. It could declare convergence after round 1, when reviewers hadn't
seen each other's opinions yet (independent reviews)
2. The parsing logic was too loose - any response containing "CONVERGED"
would pass, even if it was part of a sentence
Changes:
- Require at least 2 completed rounds before checking convergence
- Add stricter consensus criteria (critical issues must be cross-validated)
- Fix parsing to only accept exact "CONVERGED" as first word
- Clarify that silence on another's point is NOT agreement
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix readline stdin state issue causing immediate exit in -i mode
- Fix analysis content not displaying before interactive prompt
- Add follow-up Q&A after Final Conclusion in review command
- Refactor selectReviewers to accept optional shared readline instance
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add ReviewerStatus type for tracking reviewer state
- Track start/end time and duration for each reviewer
- Display live status during parallel execution:
✓ done (with duration) | ⋯ thinking | ○ pending
- Update spinner in real-time as reviewers complete
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix convergence check: NOT_CONVERGED was incorrectly matching CONVERGED
- Allow convergence after round 1 (was requiring 2 rounds minimum)
- Unify codex-cli streaming/non-streaming to use same bypass flag
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add Fair Debate Model and Parallel Execution to core concepts
- Update max_rounds default from 2 to 5
- Document new CLI options: --reviewers, --all/-a, --git-remote
- Add Reviewer Selection section with interactive/CLI examples
- Rewrite Workflow to show Round 1 independent → Round 2+ debate model
- Add Fair Debate Model explanation section
- Add Parallel Execution section with example output
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Each round now executes all reviewers in parallel using Promise.all:
1. Build messages for all reviewers (same info)
2. Execute all chatStream calls concurrently
3. Collect all responses
4. Display results after all complete
Benefits:
- Faster execution (N reviewers run simultaneously)
- Semantically correct (same round = simultaneous)
- Same total API usage, just concurrent
Display shows: "Round N: All reviewers thinking (parallel)"
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changed debate model:
- Round N: each reviewer sees only rounds 1 to N-1
- Reviewers in same round have identical information (fair)
- No anchoring bias from earlier reviewers in same round
Example with 3 reviewers:
Round 2: claude sees [gemini_r1, codex_r1]
gemini sees [claude_r1, codex_r1] <- same info level
codex sees [claude_r1, gemini_r1] <- same info level
Also increased default max_rounds from 3 to 5 since convergence
may take longer with this fairer model.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Bug: Round 1 is independent (no one sees others), so session doesn't
have other reviewers' messages. When entering Round 2 debate phase,
we were only sending messages after lastSeen, missing others' Round 1.
Fix: Check if reviewer just finished Round 1 (myMessageCount === 1).
If so, send ALL other reviewers' messages, not just incremental.
Round 3+ continues to use incremental (lastSeen + 1) since debate
context is already established in session.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Round 1: Each reviewer gives independent assessment
- Only sees analysis, not other reviewers' opinions
- Avoids anchoring bias from first reviewer
Round 2+: Full debate mode
- Sees all previous discussion
- Can agree/disagree with specific points from [reviewer_id]
This ensures diverse initial perspectives before debate begins.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- claude-code: add --dangerously-skip-permissions
- codex-cli: use --dangerously-bypass-approvals-and-sandbox
- gemini-cli: already has -y (yolo mode)
This allows CLI tools to access network (e.g., gh commands to fetch PR)
without permission prompts.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Usage:
- Default: shows interactive menu to select reviewers
[0] All reviewers
[1] claude
[2] gemini
...
- --all (-a): use all reviewers, skip selection
- --reviewers claude,gemini: specify reviewers directly
Requires at least 2 reviewers for a debate.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Now shows convergence check as a distinct step:
┌─ 🔍 Convergence Judge ─────────────────────────
⠋ Evaluating if reviewers reached consensus...
└─ Verdict: CONVERGED / NOT CONVERGED
Makes it clear this is a separate judge, not another reviewer.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previous prompt was too lenient ("mostly agree on key points").
Now requires TRUE consensus:
- All reviewers must agree on the same verdict
- NOT converged if any reviewer says "I disagree/reject [X]'s view"
- NOT converged if they agree on problems but disagree on actions
- System prompt: "Be conservative - when in doubt, say NOT_CONVERGED"
This fixes false positives like Gemini saying "I reject [claude]'s view"
but still being marked as converged.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>