From 4f5a5cd752e91356ca5b05f4724c021ac96b1957 Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Sat, 29 Nov 2025 10:02:01 -0800 Subject: [PATCH] chore: Claude --- .github/workflows/ci-failure-auto-fix.yml | 97 +++++++++++++++++++++++ .github/workflows/claude.yml | 58 ++++++++++++++ CLAUDE.md | 59 ++++++++++++++ 3 files changed, 214 insertions(+) create mode 100644 .github/workflows/ci-failure-auto-fix.yml create mode 100644 .github/workflows/claude.yml create mode 100644 CLAUDE.md diff --git a/.github/workflows/ci-failure-auto-fix.yml b/.github/workflows/ci-failure-auto-fix.yml new file mode 100644 index 00000000..ff08a7a2 --- /dev/null +++ b/.github/workflows/ci-failure-auto-fix.yml @@ -0,0 +1,97 @@ +name: Auto Fix CI Failures + +on: + workflow_run: + workflows: ["CI"] + types: + - completed + +permissions: + contents: write + pull-requests: write + actions: read + issues: write + id-token: write # Required for OIDC token exchange + +jobs: + auto-fix: + if: | + github.event.workflow_run.conclusion == 'failure' && + github.event.workflow_run.pull_requests[0] && + !startsWith(github.event.workflow_run.head_branch, 'claude-auto-fix-ci-') + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v5 + with: + ref: ${{ github.event.workflow_run.head_branch }} + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Setup git identity + run: | + git config --global user.email "claude[bot]@users.noreply.github.com" + git config --global user.name "claude[bot]" + + - name: Create fix branch + id: branch + run: | + BRANCH_NAME="claude-auto-fix-ci-${{ github.event.workflow_run.head_branch }}-${{ github.run_id }}" + git checkout -b "$BRANCH_NAME" + echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT + + - name: Get CI failure details + id: failure_details + uses: actions/github-script@v7 + with: + script: | + const run = await github.rest.actions.getWorkflowRun({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: ${{ github.event.workflow_run.id }} + }); + + const jobs = await github.rest.actions.listJobsForWorkflowRun({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: ${{ github.event.workflow_run.id }} + }); + + const failedJobs = jobs.data.jobs.filter(job => job.conclusion === 'failure'); + + let errorLogs = []; + for (const job of failedJobs) { + const logs = await github.rest.actions.downloadJobLogsForWorkflowRun({ + owner: context.repo.owner, + repo: context.repo.repo, + job_id: job.id + }); + errorLogs.push({ + jobName: job.name, + logs: logs.data + }); + } + + return { + runUrl: run.data.html_url, + failedJobs: failedJobs.map(j => j.name), + errorLogs: errorLogs + }; + + - name: Fix CI failures with Claude + id: claude + uses: anthropics/claude-code-action@v1 + with: + prompt: | + /fix-ci + Failed CI Run: ${{ fromJSON(steps.failure_details.outputs.result).runUrl }} + Failed Jobs: ${{ join(fromJSON(steps.failure_details.outputs.result).failedJobs, ', ') }} + PR Number: ${{ github.event.workflow_run.pull_requests[0].number }} + Branch Name: ${{ steps.branch.outputs.branch_name }} + Base Branch: ${{ github.event.workflow_run.head_branch }} + Repository: ${{ github.repository }} + + Error logs: + ${{ toJSON(fromJSON(steps.failure_details.outputs.result).errorLogs) }} + anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} + claude_args: "--allowedTools 'Edit,MultiEdit,Write,Read,Glob,Grep,LS,Bash(git:*),Bash(bun:*),Bash(npm:*),Bash(npx:*),Bash(gh:*)'" \ No newline at end of file diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml new file mode 100644 index 00000000..c264a6a9 --- /dev/null +++ b/.github/workflows/claude.yml @@ -0,0 +1,58 @@ +name: Claude Code + +on: + issue_comment: + types: [created] + pull_request_review_comment: + types: [created] + issues: + types: [opened, assigned] + pull_request_review: + types: [submitted] + +jobs: + claude: + if: | + (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) || + (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) || + (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) || + (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude'))) + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + issues: write + id-token: write + actions: read # Required for Claude to read CI results on PRs + steps: + - name: Checkout repository + uses: actions/checkout@v5 + with: + fetch-depth: 1 + + - name: Run Claude Code + id: claude + uses: anthropics/claude-code-action@v1 + with: + anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} + + # Optional: Customize the trigger phrase (default: @claude) + # trigger_phrase: "/claude" + + # Optional: Trigger when specific user is assigned to an issue + # assignee_trigger: "claude-bot" + + # Optional: Configure Claude's behavior with CLI arguments + # claude_args: | + # --model claude-opus-4-1-20250805 + # --max-turns 10 + # --allowedTools "Bash(npm install),Bash(npm run build),Bash(npm run test:*),Bash(npm run lint:*)" + # --system-prompt "Follow our coding standards. Ensure all new code has tests. Use TypeScript for new files." + + # Optional: Advanced settings configuration + # settings: | + # { + # "env": { + # "NODE_ENV": "test" + # } + # } \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..85909ef4 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,59 @@ +# CLAUDE.md + +## Code Style + +- C++11 unless otherwise specified +- Boost C++ Libraries naming conventions (snake_case) +- 4-space indentation, no tabs +- Braces on their own line for classes/functions + +## Javadoc Documentation + +Follow Boost C++ Libraries Javadoc style: + +- Brief descriptions on first line after `/**` +- Functions returning values: brief starts with "Return" +- Use `@param` for function parameters +- Use `@tparam` for template parameters, except: + - Variadic args (`Args...`) — omit + - Types deduced from function parameters — omit (self-evident from `@param`) +- Use `@return` for return value details +- Use `@pre` for preconditions +- Use `@post` for postconditions +- Use `@throws` for exceptions +- Use `@note` for important notes +- Use `@see` for cross-references +- Use `@code` / `@endcode` for examples + +## Examples + +```cpp +/** Return the size of the buffer sequence. + + @param buffers The buffer sequence to measure. + + @return The total byte count. +*/ +template +std::size_t +buffer_size(BufferSequence const& buffers); +``` + +No `@tparam` needed—`BufferSequence` is evident from `@param buffers`. + +```cpp +/** Return the default value. + + @tparam T The value type. +*/ +template +T default_value(); +``` + +`@tparam` needed—`T` has no corresponding function parameter. + +## Preferences + +- Concise, dry answers +- Full files, not diffs +- Accurate, compiling C++ code