feat(tui): interactive diff view with unified/side-by-side/plain modes #5
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: AI PR Review | |
| on: | |
| pull_request: | |
| types: [opened, synchronize, reopened] | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| models: read | |
| jobs: | |
| review: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v5 | |
| with: | |
| fetch-depth: 0 | |
| - name: Get PR diff | |
| id: diff | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| gh pr diff ${{ github.event.pull_request.number }} > /tmp/pr.diff | |
| # Truncate to ~100k chars to fit model context | |
| head -c 100000 /tmp/pr.diff > /tmp/pr-truncated.diff | |
| echo "diff_size=$(wc -c < /tmp/pr.diff)" >> "$GITHUB_OUTPUT" | |
| echo "truncated=$([ $(wc -c < /tmp/pr.diff) -gt 100000 ] && echo true || echo false)" >> "$GITHUB_OUTPUT" | |
| - name: Get PR info | |
| id: pr | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| gh pr view ${{ github.event.pull_request.number }} --json title,body > /tmp/pr-info.json | |
| - name: Check for relevant proposals | |
| id: proposals | |
| run: | | |
| # Extract key terms from PR title for proposal matching | |
| PROPOSALS="" | |
| if [ -d "docs/03-development/proposals" ]; then | |
| PROPOSALS=$(ls docs/03-development/proposals/ 2>/dev/null | head -20) | |
| fi | |
| echo "list<<EOF" >> "$GITHUB_OUTPUT" | |
| echo "$PROPOSALS" >> "$GITHUB_OUTPUT" | |
| echo "EOF" >> "$GITHUB_OUTPUT" | |
| - name: Read project context | |
| id: context | |
| run: | | |
| # Read CLAUDE.md summary (first 100 lines for context) | |
| if [ -f "CLAUDE.md" ]; then | |
| head -100 CLAUDE.md > /tmp/project-context.txt | |
| else | |
| echo "No CLAUDE.md found" > /tmp/project-context.txt | |
| fi | |
| - name: AI Review | |
| id: review | |
| env: | |
| GITHUB_TOKEN: ${{ github.token }} | |
| run: | | |
| # Build the review prompt | |
| DIFF=$(cat /tmp/pr-truncated.diff) | |
| PR_INFO=$(cat /tmp/pr-info.json) | |
| PROJECT_CONTEXT=$(cat /tmp/project-context.txt) | |
| PROPOSALS="${{ steps.proposals.outputs.list }}" | |
| TRUNCATED="${{ steps.diff.outputs.truncated }}" | |
| TRUNCATION_NOTE="" | |
| if [ "$TRUNCATED" = "true" ]; then | |
| TRUNCATION_NOTE="NOTE: The diff was truncated to 100k characters. Total size: ${{ steps.diff.outputs.diff_size }} bytes. Focus on what's visible." | |
| fi | |
| # Call GitHub Models API | |
| RESPONSE=$(curl -s -X POST \ | |
| -H "Authorization: Bearer $GITHUB_TOKEN" \ | |
| -H "Content-Type: application/json" \ | |
| https://models.github.ai/inference/chat/completions \ | |
| -d "$(jq -n \ | |
| --arg diff "$DIFF" \ | |
| --arg pr_info "$PR_INFO" \ | |
| --arg context "$PROJECT_CONTEXT" \ | |
| --arg proposals "$PROPOSALS" \ | |
| --arg truncation "$TRUNCATION_NOTE" \ | |
| '{ | |
| model: "openai/gpt-4.1", | |
| messages: [ | |
| { | |
| role: "system", | |
| content: "You are a code reviewer for a Go CLI project (mxcli) that reads/modifies Mendix application projects. Key patterns: ANTLR4 grammar → AST → visitor → executor → BSON writer. Generated ANTLR parser files (mdl/grammar/parser/) are noise — note but skip. Review thoroughly but concisely." | |
| }, | |
| { | |
| role: "user", | |
| content: ("Review this PR.\n\nPR Info:\n" + $pr_info + "\n\nProject context:\n" + $context + "\n\nProposals in repo:\n" + $proposals + "\n\n" + $truncation + "\n\nFocus on:\n1. Bugs, logic errors, race conditions, resource leaks\n2. Error handling gaps\n3. Security concerns (command injection, temp files, predictable paths)\n4. Scope — flag if PR bundles unrelated changes\n5. If proposals exist that match the PR topic, check alignment\n6. Check if PR claims to fix already-fixed issues\n\nStructure: Critical Issues, Moderate Issues, Minor Issues, What Looks Good, Recommendation (approve/request changes).\n\nDiff:\n```\n" + $diff + "\n```") | |
| } | |
| ], | |
| max_tokens: 4000 | |
| }' | |
| )") | |
| # Extract the review text | |
| REVIEW=$(echo "$RESPONSE" | jq -r '.choices[0].message.content // empty') | |
| if [ -z "$REVIEW" ]; then | |
| echo "::warning::AI review failed. Response: $(echo "$RESPONSE" | head -c 500)" | |
| exit 0 | |
| fi | |
| # Post as PR comment | |
| gh pr comment ${{ github.event.pull_request.number }} --body "$(cat <<EOF | |
| ## AI Code Review | |
| $REVIEW | |
| --- | |
| *Automated review by GitHub Models API (GPT-4.1) — [workflow source](${{ github.server_url }}/${{ github.repository }}/blob/main/.github/workflows/ai-review.yml)* | |
| EOF | |
| )" | |