Skip to content

chore(deps): bump husky-rs from 0.1.5 to 0.3.3 #1191

chore(deps): bump husky-rs from 0.1.5 to 0.3.3

chore(deps): bump husky-rs from 0.1.5 to 0.3.3 #1191

name: Claude Code Review
on:
pull_request:
types: [opened, reopened, ready_for_review]
issue_comment:
types: [created]
workflow_dispatch:
inputs:
pr_number:
description: "PR number to review"
required: true
type: number
permissions:
contents: read
pull-requests: write
issues: write
id-token: write
actions: read
jobs:
pre-check:
name: Pre-Check
runs-on: ubuntu-latest
outputs:
should_review: ${{ steps.check.outputs.should_review }}
pr_number: ${{ steps.check.outputs.pr_number }}
steps:
- name: Determine if review should run
id: check
uses: actions/github-script@v9
with:
script: |
let prNumber;
let shouldReview = false;
if (context.eventName === 'workflow_dispatch') {
prNumber = context.payload.inputs.pr_number;
shouldReview = true;
} else if (context.eventName === 'issue_comment') {
const comment = context.payload.comment.body;
if (!comment.includes('@claude-review')) {
core.setOutput('should_review', 'false');
return;
}
prNumber = context.payload.issue.number;
shouldReview = true;
} else {
prNumber = context.payload.pull_request.number;
const pr = context.payload.pull_request;
if (pr.draft) {
core.info('Skipping draft PR');
core.setOutput('should_review', 'false');
return;
}
const skipBots = ['dependabot[bot]', 'renovate[bot]'];
if (pr.user.type === 'Bot' && skipBots.includes(pr.user.login)) {
core.info(`Skipping dependency bot PR from ${pr.user.login}`);
core.setOutput('should_review', 'false');
return;
}
shouldReview = true;
}
if (shouldReview) {
const { data: pr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber
});
const { data: files } = await github.rest.pulls.listFiles({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber,
per_page: 100
});
core.info(`PR has ${files.length} files and ${pr.additions + pr.deletions} changed lines`);
}
core.setOutput('should_review', String(shouldReview));
core.setOutput('pr_number', String(prNumber));
review:
name: AI Code Review
needs: pre-check
if: needs.pre-check.outputs.should_review == 'true'
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
issues: write
id-token: write
actions: read
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y libgl1-mesa-dev libglu1-mesa-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libxxf86vm-dev libasound2-dev
- name: Run Claude Code Review
uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
allowed_bots: "claude[bot]"
track_progress: true
prompt: |
REPO: ${{ github.repository }}
PR NUMBER: ${{ needs.pre-check.outputs.pr_number }}
You are reviewing a PR for GoudEngine, a Rust game engine with C# and Python SDKs.
Read the root AGENTS.md for full project context.
Perform a 7-phase review:
## Phase 1: Context Gathering
- Read AGENTS.md for project conventions
- Identify which layers are touched (Core, FFI, SDK, Examples)
- Note the PR type (feature, fix, refactor, etc.)
## Phase 2: Architecture Validation
- Verify dependency flow is downward only (libs -> engine -> ffi -> sdks -> examples)
- Check that no logic is implemented in SDKs (Rust-first principle)
- Verify no raw OpenGL calls outside graphics/backend module
- Check file sizes (flag files exceeding 500 lines)
## Phase 3: Anti-Pattern Scan
Check for these blockers:
- Missing #[no_mangle] or #[repr(C)] on FFI exports
- unsafe blocks without // SAFETY: comments
- FFI changes without corresponding C# AND Python SDK updates
- todo!() or unimplemented!() in production code
- unwrap()/expect() in library code (should use Result)
- Duplicated logic between Rust and SDK layers
## Phase 4: Quality Assessment
- Code clarity and naming conventions
- Error handling completeness
- Test coverage for new code
- Documentation on public APIs
## Phase 5: Security Review (if FFI/unsafe changes)
- Null pointer checks on all FFI pointer parameters
- Memory ownership documented (who allocates, who frees)
- Buffer bounds validation
- No use-after-free potential
## Phase 6: Scope Verification
- Changes match the PR description
- No unrelated changes smuggled in
- Version bump included if needed
## Phase 7: Review Output
Produce a structured review with:
- Verdict: APPROVED | CHANGES REQUESTED | BLOCKED
- BLOCKERS table (must fix before merge)
- WARNINGS table (should fix, non-blocking)
- Positive callouts (good patterns observed)
Provide detailed feedback using inline comments for specific issues.
Use top-level comments for general observations.
claude_args: |
--allowedTools "Bash(cargo check:*),Bash(cargo fmt:*),Bash(cargo clippy:*),Bash(cargo test:*),Bash(cargo deny:*),Bash(wc -l:*),Bash(rg:*),Read,Glob,Grep"
agent-feedback:
name: Agent Feedback Loop
needs: [pre-check, review]
if: >-
vars.AGENT_REVIEW_FEEDBACK_ENABLED == 'true' &&
needs.pre-check.outputs.should_review == 'true'
runs-on: ubuntu-latest
permissions:
pull-requests: write
issues: write
steps:
- name: Generate App token
id: app-token
uses: actions/create-github-app-token@v3
with:
app-id: ${{ secrets.AGENT_APP_ID }}
private-key: ${{ secrets.AGENT_APP_PRIVATE_KEY }}
- name: Trigger agent feedback if needed
uses: actions/github-script@v9
with:
github-token: ${{ steps.app-token.outputs.token }}
script: |
const prNumber = ${{ needs.pre-check.outputs.pr_number }};
const { data: pr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber
});
// Only trigger feedback for agent-created PRs (branch starts with agent/)
const isAgentPR = pr.head.ref.startsWith('agent/');
if (!isAgentPR) {
core.info('Not an agent PR, skipping feedback loop');
return;
}
// Count existing review rounds to prevent infinite loops
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber
});
const reviewRounds = comments.filter(c =>
c.body.includes('<!-- agent-review-round')
).length;
if (reviewRounds >= 2) {
core.info(`Already completed ${reviewRounds} review rounds, leaving for human review`);
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: `<!-- agent-review-round: ${reviewRounds + 1} -->\n\nThis agent PR has completed ${reviewRounds} automated review rounds. Remaining issues require human review.`
});
return;
}
const round = reviewRounds + 1;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: `<!-- agent-review-round: ${round} -->\n\n@goudengine-agent The automated code review above has completed (round ${round}/2). Please address any issues found in the review and push fixes to this PR.`
});
core.info(`Posted agent feedback trigger (round ${round})`);