fix: add Toggle Case and Remove Blank Lines to shortcuts docs #923
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: Claude Code | |
| on: | |
| # Audit-fix pipeline reacts to [audit]-labeled issues; general issues are not auto-processed. | |
| issues: | |
| types: [opened, reopened] | |
| # Review Claude-proposed PRs | |
| pull_request: | |
| types: [opened, synchronize] | |
| # Trigger audit-fix after the audit workflow creates issues | |
| # (github-actions[bot] events don't trigger 'issues' — this is the workaround) | |
| workflow_run: | |
| workflows: ["Claude Periodic Audit"] | |
| types: [completed] | |
| # Manual trigger to run audit-fix without re-auditing | |
| workflow_dispatch: | |
| inputs: | |
| max_issues: | |
| description: "Max issues to fix (0 = use default cap of 6)" | |
| required: false | |
| default: "0" | |
| permissions: | |
| contents: write | |
| issues: write | |
| pull-requests: write | |
| id-token: write | |
| jobs: | |
| # Collect open audit issues into a matrix — one job per issue | |
| # Skips issues labeled 'fix-attempted' (failed in a previous run). | |
| # Caps at 6 issues per run to control cost (~$5/issue × 6 = ~$30 max). | |
| audit-collect: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| concurrency: | |
| group: audit-collect | |
| cancel-in-progress: true | |
| if: >- | |
| (github.event_name == 'issues' && contains(github.event.issue.labels.*.name, 'audit')) || | |
| (github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success') || | |
| (github.event_name == 'workflow_dispatch') | |
| outputs: | |
| matrix: ${{ steps.collect.outputs.matrix }} | |
| has_issues: ${{ steps.collect.outputs.has_issues }} | |
| steps: | |
| - name: Collect audit issues | |
| id: collect | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| EVENT_NAME: ${{ github.event_name }} | |
| ISSUE_NUMBER: ${{ github.event.issue.number }} | |
| INPUT_MAX: ${{ github.event.inputs.max_issues || '0' }} | |
| run: | | |
| # Default cap: 6 issues per run (override via workflow_dispatch input) | |
| MAX_ISSUES="${INPUT_MAX:-0}" | |
| if [ "$MAX_ISSUES" = "0" ]; then | |
| MAX_ISSUES=6 | |
| fi | |
| if [ "$EVENT_NAME" = "issues" ]; then | |
| # Single issue trigger — no cap, no skip check | |
| NUMBERS="$ISSUE_NUMBER" | |
| else | |
| # Batch mode: get open audit issues, EXCLUDE 'fix-attempted' label | |
| # Sort by issue number (oldest first) so we process in order | |
| NUMBERS=$(gh issue list --repo "$GITHUB_REPOSITORY" \ | |
| --state open --label audit \ | |
| --json number,labels \ | |
| --jq '[.[] | select(.labels | map(.name) | index("fix-attempted") | not)] | sort_by(.number) | .[].number' \ | |
| | head -n "$MAX_ISSUES" \ | |
| | tr '\n' ' ') | |
| fi | |
| if [ -z "$NUMBERS" ]; then | |
| echo "has_issues=false" >> "$GITHUB_OUTPUT" | |
| echo 'matrix={"issue":[]}' >> "$GITHUB_OUTPUT" | |
| echo "No eligible issues found (fix-attempted issues are skipped)" | |
| else | |
| # Build JSON array: "123 456" -> [123,456] | |
| JSON=$(echo "$NUMBERS" | xargs -n1 | jq -R 'tonumber' | jq -sc '.') | |
| COUNT=$(echo "$JSON" | jq 'length') | |
| echo "has_issues=true" >> "$GITHUB_OUTPUT" | |
| echo "matrix={\"issue\":$JSON}" >> "$GITHUB_OUTPUT" | |
| echo "Will fix $COUNT issues (cap=$MAX_ISSUES): $NUMBERS" | |
| fi | |
| # Fix one audit issue per matrix job — independent branches, PRs, and Claude sessions | |
| audit-fix: | |
| needs: audit-collect | |
| if: needs.audit-collect.outputs.has_issues == 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 45 | |
| concurrency: | |
| group: audit-fix-${{ matrix.issue }} | |
| cancel-in-progress: false | |
| strategy: | |
| fail-fast: false | |
| max-parallel: 3 | |
| matrix: ${{ fromJSON(needs.audit-collect.outputs.matrix) }} | |
| steps: | |
| # Checkout with PAT so git push creates events that trigger CI | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 1 | |
| token: ${{ secrets.PAT_TOKEN }} | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version: 22 | |
| - uses: dtolnay/rust-toolchain@stable | |
| - uses: ./.github/actions/setup-tauri-deps | |
| - name: Install dependencies | |
| run: npm install -g pnpm && pnpm install --frozen-lockfile | |
| - name: Fix issue #${{ matrix.issue }} | |
| id: fix | |
| uses: anthropics/claude-code-action@v1 | |
| env: | |
| # Claude's gh/git commands use PAT so PRs trigger CI | |
| GH_TOKEN: ${{ secrets.PAT_TOKEN }} | |
| with: | |
| allowed_bots: "claude[bot]" | |
| claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} | |
| github_token: ${{ secrets.PAT_TOKEN }} | |
| claude_args: "--model opus --max-turns 25 --allowedTools Bash Read Write Edit Glob Grep MultiEdit" | |
| show_full_output: true | |
| prompt: | | |
| You are fixing a single audit finding in the VMark codebase. | |
| VMark is a Tauri v2 + React 19 + Zustand v5 desktop Markdown editor. | |
| ## Step 1: Understand the issue | |
| Run: `gh issue view ${{ matrix.issue }}` | |
| Read the ENTIRE issue body carefully. It contains: | |
| - **Problem**: what's wrong | |
| - **Location**: exact file paths and line numbers | |
| - **Suggested Fix**: step-by-step instructions | |
| - **Scope Guard**: what NOT to touch | |
| - **Verification**: how to confirm the fix | |
| Follow the suggested fix closely. Do not deviate unless it's clearly wrong. | |
| ## Step 2: Plan before coding | |
| Before writing any code, read the files listed in "Location". | |
| Verify the problem exists at the stated lines (code may have shifted). | |
| If the issue is outdated or already fixed, comment on the issue and stop. | |
| ## Step 3: Fix | |
| - Create a branch: `git checkout -b fix/audit-${{ matrix.issue }}` | |
| - Make ONLY the changes described in the issue | |
| - Stay within the files listed in "Location" — do not touch unrelated files | |
| - If the fix requires a new test, write it next to the source file | |
| - If the fix removes code, also remove its tests (don't leave dead test code) | |
| ## Step 4: Verify | |
| - Run `pnpm check:all` (lint + test + build) | |
| - If Rust code changed: `cargo check --manifest-path src-tauri/Cargo.toml` | |
| - Run the specific verification from the issue body | |
| - If tests fail, fix them — but only for code you changed | |
| ## Step 5: Ship | |
| - Commit: `fix: <concise description> (Closes #${{ matrix.issue }})` | |
| - Push and create PR: | |
| `gh pr create --title "fix: <title>" --body "Closes #${{ matrix.issue }}" --label audit` | |
| ## Anti-patterns (DO NOT) | |
| - Do NOT refactor surrounding code | |
| - Do NOT add features beyond the fix | |
| - Do NOT update documentation unless the issue says to | |
| - Do NOT enable auto-merge (verification step handles that) | |
| - Do NOT spend more than 3 turns debugging a single test failure — | |
| if stuck, comment on the issue with what you tried and stop | |
| ## If unfixable | |
| Comment on the issue explaining: | |
| 1. What you tried | |
| 2. What went wrong | |
| 3. What a human would need to do differently | |
| # Label issue as fix-attempted on failure so next run skips it | |
| - name: Label fix-attempted on failure | |
| if: failure() | |
| env: | |
| GH_TOKEN: ${{ secrets.PAT_TOKEN }} | |
| run: | | |
| gh issue edit "${{ matrix.issue }}" --repo "$GITHUB_REPOSITORY" --add-label "fix-attempted" 2>&1 || true | |
| echo "Labeled #${{ matrix.issue }} as fix-attempted — will be skipped on next run" | |
| # Find the PR created by the fix step | |
| - name: Find created PR | |
| id: find-pr | |
| if: success() | |
| env: | |
| GH_TOKEN: ${{ secrets.PAT_TOKEN }} | |
| run: | | |
| PR=$(gh pr list --repo "$GITHUB_REPOSITORY" --head "fix/audit-${{ matrix.issue }}" --json number --jq '.[0].number // empty') | |
| if [ -n "$PR" ]; then | |
| echo "number=$PR" >> "$GITHUB_OUTPUT" | |
| echo "Found PR #$PR" | |
| else | |
| echo "No PR found for fix/audit-${{ matrix.issue }}" | |
| fi | |
| # Verify the fix in a separate read-only Claude session | |
| - name: Verify fix for #${{ matrix.issue }} | |
| if: steps.find-pr.outputs.number | |
| uses: anthropics/claude-code-action@v1 | |
| with: | |
| claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} | |
| github_token: ${{ secrets.PAT_TOKEN }} | |
| claude_args: "--model opus --max-turns 10 --allowedTools Bash Read Glob Grep" | |
| prompt: | | |
| You are an audit-fix VERIFIER — not an open-ended reviewer. | |
| Your ONLY job is to check whether PR #${{ steps.find-pr.outputs.number }} actually resolves audit issue #${{ matrix.issue }}. | |
| Steps: | |
| 1. Read the issue: `gh issue view ${{ matrix.issue }} --repo "$GITHUB_REPOSITORY"` | |
| 2. Read the PR diff: `gh pr diff ${{ steps.find-pr.outputs.number }} --repo "$GITHUB_REPOSITORY"` | |
| 3. Answer THREE questions: | |
| a. Does the diff address the specific finding described in the issue? | |
| b. Does the fix introduce any obvious regressions (wrong logic, removed unrelated code)? | |
| c. Is the fix minimal and focused (no scope creep)? | |
| Output format — use EXACTLY one of: | |
| - ✅ **VERIFIED** — The audit finding is resolved. [1-sentence explanation] | |
| - ❌ **NOT VERIFIED** — The finding is NOT resolved. [specific reason] | |
| - ⚠️ **PARTIAL** — The finding is partially addressed. [what's missing] | |
| Post your verification as a comment on PR #${{ steps.find-pr.outputs.number }}: | |
| `gh pr comment ${{ steps.find-pr.outputs.number }} --repo "$GITHUB_REPOSITORY" --body "<your output>"` | |
| Rules: | |
| - Do NOT do open-ended code review. Only verify the specific finding. | |
| - Do NOT suggest improvements beyond the finding. | |
| - If you cannot determine the finding, say so. | |
| # Auto-merge after verification | |
| - name: Enable auto-merge | |
| if: steps.find-pr.outputs.number | |
| env: | |
| GH_TOKEN: ${{ secrets.PAT_TOKEN }} | |
| PR_NUMBER: ${{ steps.find-pr.outputs.number }} | |
| run: gh pr merge "$PR_NUMBER" --repo "$GITHUB_REPOSITORY" --auto --squash 2>&1 || echo "Auto-merge not available" | |
| # Fallback: verify audit PRs created externally (PAT/App token that triggers workflows) | |
| # Primary verification now runs inline in audit-fix above. | |
| audit-verify: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| concurrency: | |
| group: audit-verify-${{ github.event.pull_request.number }} | |
| cancel-in-progress: true | |
| if: >- | |
| github.event_name == 'pull_request' && | |
| contains(github.event.pull_request.labels.*.name, 'audit') && | |
| (github.event.pull_request.user.login == 'claude[bot]' || | |
| github.event.pull_request.user.login == 'github-actions[bot]') | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 1 | |
| - uses: anthropics/claude-code-action@v1 | |
| id: verify | |
| with: | |
| claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} | |
| github_token: ${{ github.token }} | |
| claude_args: "--model opus --max-turns 10 --allowedTools Bash Read Glob Grep" | |
| use_sticky_comment: true | |
| prompt: | | |
| You are an audit-fix VERIFIER — not an open-ended reviewer. | |
| Your ONLY job is to check whether this PR actually resolves the linked audit issue. | |
| Steps: | |
| 1. Read the PR description to find the linked issue number (look for "Closes #N") | |
| 2. Read that issue: `gh issue view <N>` | |
| 3. Read the PR diff: `gh pr diff ${{ github.event.pull_request.number }}` | |
| 4. Answer THREE questions: | |
| a. Does the diff address the specific finding described in the issue? | |
| b. Does the fix introduce any obvious regressions (wrong logic, removed unrelated code)? | |
| c. Is the fix minimal and focused (no scope creep)? | |
| Output format — use EXACTLY one of: | |
| - ✅ **VERIFIED** — The audit finding is resolved. [1-sentence explanation] | |
| - ❌ **NOT VERIFIED** — The finding is NOT resolved. [specific reason] | |
| - ⚠️ **PARTIAL** — The finding is partially addressed. [what's missing] | |
| Rules: | |
| - Do NOT do open-ended code review. Only verify the specific finding. | |
| - Do NOT suggest improvements beyond the finding. | |
| - Do NOT approve or request changes — just report verification status. | |
| - If you cannot determine the linked issue, say so. | |
| - name: Enable auto-merge on verification pass | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| PR_NUMBER: ${{ github.event.pull_request.number }} | |
| run: gh pr merge "$PR_NUMBER" --auto --squash 2>&1 || echo "Auto-merge not available for this PR" | |
| # Review and auto-merge Claude-proposed PRs (non-audit) | |
| claude: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| concurrency: | |
| group: claude-${{ github.event.pull_request.number || github.run_id }} | |
| cancel-in-progress: true | |
| if: >- | |
| github.event_name == 'pull_request' && | |
| !contains(github.event.pull_request.labels.*.name, 'audit') && | |
| (github.event.pull_request.user.login == 'claude[bot]' || | |
| github.event.pull_request.user.login == 'github-actions[bot]') | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 1 | |
| - uses: anthropics/claude-code-action@v1 | |
| id: claude | |
| with: | |
| claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} | |
| github_token: ${{ github.token }} | |
| claude_args: "--model opus --max-turns 15" | |
| use_sticky_comment: true | |
| - name: Enable auto-merge | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| PR_NUMBER: ${{ github.event.pull_request.number }} | |
| run: gh pr merge "$PR_NUMBER" --auto --squash 2>&1 || echo "Auto-merge not available for this PR" |