diff --git a/.github/workflows/claude-review.yml b/.github/workflows/claude-review.yml index 9dccd59..d80ece9 100644 --- a/.github/workflows/claude-review.yml +++ b/.github/workflows/claude-review.yml @@ -1,39 +1,43 @@ name: Claude PR Review on: pull_request: - -# Cancel in-progress reviews for the same PR when a new push arrives. concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number }} cancel-in-progress: true - jobs: claude-review: name: Claude PR Review runs-on: ubuntu-latest - - # Prevent running on fork PRs where secrets are unavailable if: ${{ github.event.pull_request.head.repo.full_name == github.repository }} - permissions: contents: read pull-requests: write - id-token: write # OIDC token for Claude GitHub App auth - + issues: write steps: - uses: actions/checkout@v4 - - uses: anthropics/claude-code-action@v1 with: anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} - prompt: "/review" - # Pre-loads full PR context and shows a progress tracker. - track_progress: true - # Only include comments from trusted team members in Claude's context (prompt injection mitigation). - include_comments_by_actor: "mmiermans" - # Update the same comment on each push instead of creating new ones. - use_sticky_comment: true - # Inline code comments, PR comments, reading PR diffs, and git log for commit messages. - # gh pr view is excluded to prevent Claude from fetching PR comments (prompt injection risk). + github_token: ${{ github.token }} + prompt: | + You are an automated code reviewer for pull request #${{ github.event.pull_request.number }} in ${{ github.repository }}. + Read the changes: gh pr diff ${{ github.event.pull_request.number }}. Review concisely for bugs, security, performance, quality, tests, docs. Do not invent issues. + Write the review to review.md. Its FIRST line must be the exact hidden marker (an invisible HTML comment): + + followed immediately by one collapsed details block: +
+ 🤖 Claude has reviewed this PR — expand after forming your own opinion + + (your full review) + +
+ Nothing VISIBLE may appear outside the details block (the marker renders invisibly). + STICKY DELIVERY — keep ONE comment across runs. Find any prior review comment carrying the marker: + ID=$(gh api repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments --jq '[.[] | select(.user.login=="github-actions[bot]" and (.body | contains("")))] | last | .id // empty') + If ID is non-empty, UPDATE that comment: + gh api -X PATCH repos/${{ github.repository }}/issues/comments/$ID -f body="$(cat review.md)" + Otherwise create a new comment: + gh pr comment ${{ github.event.pull_request.number }} --body-file review.md + No inline comments, no approve/request-changes, no AI attribution. claude_args: | - --allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(git log:*)" + --allowedTools "Bash(gh pr diff:*),Bash(gh pr comment:*),Bash(gh api:*)" diff --git a/webclient/resources/js/exp-stick-marker.js b/webclient/resources/js/exp-stick-marker.js new file mode 100644 index 0000000..afefc8d --- /dev/null +++ b/webclient/resources/js/exp-stick-marker.js @@ -0,0 +1,4 @@ +// helper for sticky-review experiment +function pct(part, total) { + return (part / total) * 100; // no guard for total === 0 +}