fix: restore local bot api startup #257
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 Iteration | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| issue_number: | |
| description: 'Issue number to iterate' | |
| required: false | |
| pr_number: | |
| description: 'PR number to iterate' | |
| required: false | |
| pull_request: | |
| types: [opened, synchronize] | |
| issue_comment: | |
| types: [created] | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| issues: read | |
| id-token: write | |
| jobs: | |
| ai-iterate: | |
| if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && startsWith(github.head_ref, 'ai/issue-')) || (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@ai')) | |
| runs-on: windows-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 1 | |
| - name: Setup bun | |
| uses: oven-sh/setup-bun@v1 | |
| with: | |
| bun-version: latest | |
| - name: Get opencode version | |
| id: version | |
| run: | | |
| VERSION=$(curl -sf https://api.github.com/repos/anomalyco/opencode/releases/latest | grep -o '"tag_name": *"[^"]*"' | cut -d'"' -f4) | |
| echo "version=${VERSION:-latest}" >> $GITHUB_OUTPUT | |
| - name: Cache opencode | |
| id: cache | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.opencode/bin | |
| key: opencode-${{ runner.os }}-${{ runner.arch }}-${{ steps.version.outputs.version }} | |
| - name: Install opencode | |
| if: steps.cache.outputs.cache-hit != 'true' | |
| run: curl -fsSL https://opencode.ai/install | bash | |
| - name: Add opencode to PATH | |
| run: echo "$HOME/.opencode/bin" >> $GITHUB_PATH | |
| - name: Install oh-my-opencode | |
| run: | | |
| bunx oh-my-opencode install --no-tui --claude=no --gemini=no --copilot=no | |
| - name: Copy oh-my-opencode config | |
| env: | |
| MINIMAX_API_KEY: ${{ secrets.MINIMAX_API_KEY }} | |
| run: | | |
| New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.config\opencode" | Out-Null | |
| $content = Get-Content '.github/workflows/opencode.json' -Raw | |
| $content = $content -replace 'MINIMAX_API_KEY', $env:MINIMAX_API_KEY | |
| Set-Content -Path "$env:USERPROFILE\.config\opencode\opencode.json" -Value $content | |
| $content = Get-Content '.github/workflows/oh-my-opencode.json' -Raw | |
| $content = $content -replace 'MINIMAX_API_KEY', $env:MINIMAX_API_KEY | |
| Set-Content -Path "$env:USERPROFILE\.config\opencode\oh-my-opencode.json" -Value $content | |
| - name: Determine trigger type and get PR info | |
| id: determine | |
| uses: actions/github-script@v7 | |
| with: | |
| result-encoding: string | |
| script: | | |
| const isSchedule = context.eventName === 'schedule'; | |
| const isDispatch = context.eventName === 'workflow_dispatch'; | |
| const isPR = context.eventName === 'pull_request'; | |
| const isComment = context.eventName === 'issue_comment'; | |
| let issueNumber = null; | |
| let prNumber = null; | |
| let branchName = null; | |
| if (isDispatch && context.payload.inputs && context.payload.inputs.issue_number) { | |
| issueNumber = parseInt(context.payload.inputs.issue_number); | |
| prNumber = issueNumber; | |
| branchName = 'ai/issue-' + issueNumber; | |
| } else if (isPR) { | |
| const match = context.payload.pull_request.head.ref.match(/ai\/issue-(\d+)/); | |
| if (match) { | |
| issueNumber = parseInt(match[1]); | |
| prNumber = context.payload.pull_request.number; | |
| branchName = context.payload.pull_request.head.ref; | |
| } | |
| } else if (isComment) { | |
| const match = context.payload.issue.body.match(/#(\d+)/); | |
| if (context.payload.issue.pull_request) { | |
| prNumber = context.payload.issue.number; | |
| const prMatch = context.payload.issue.head.ref.match(/ai\/issue-(\d+)/); | |
| if (prMatch) { | |
| issueNumber = parseInt(prMatch[1]); | |
| branchName = context.payload.issue.head.ref; | |
| } | |
| } | |
| } else if (isSchedule) { | |
| const { data: prs } = await github.rest.pulls.list({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| state: 'open', | |
| head: 'ai/issue-' | |
| }); | |
| if (prs.length > 0) { | |
| const pr = prs[0]; | |
| const match = pr.head.ref.match(/ai\/issue-(\d+)/); | |
| issueNumber = parseInt(match[1]); | |
| prNumber = pr.number; | |
| branchName = pr.head.ref; | |
| } | |
| } | |
| return JSON.stringify({ issueNumber, prNumber, branchName, isSchedule }); | |
| - name: Set issue/PR number from dispatch/schedule | |
| id: set_issue_pr | |
| if: steps.determine.outputs.result != '{}' | |
| run: | | |
| node -e "const d=JSON.parse(process.env.RESULT); console.log('issueNumber='+(d.issueNumber||'')); console.log('prNumber='+(d.prNumber||'')); console.log('branchName='+(d.branchName||''))" >> %GITHUB_OUTPUT% | |
| env: | |
| RESULT: ${{ steps.determine.outputs.result }} | |
| - name: Skip if no PRs found | |
| if: steps.determine.outputs.result == '{}' || steps.set_issue_pr.outputs.branchName == '' | |
| run: | | |
| echo "SKIP=true" >> %GITHUB_OUTPUT% | |
| echo "No PRs found to iterate" | |
| - name: Checkout branch for schedule trigger | |
| if: steps.set_issue_pr.outputs.branchName != '' | |
| env: | |
| BRANCH: ${{ steps.set_issue_pr.outputs.branchName }} | |
| run: | | |
| git fetch origin %BRANCH% | |
| git checkout %BRANCH% | |
| - name: Set environment variables | |
| if: steps.set_issue_pr.outputs.branchName != '' | |
| run: | | |
| echo "ISSUE_NUM=${{ steps.set_issue_pr.outputs.issueNumber }}" >> %GITHUB_ENV% | |
| echo "PR_NUMBER=${{ steps.set_issue_pr.outputs.prNumber }}" >> %GITHUB_ENV% | |
| - name: Get PR comments | |
| if: steps.set_issue_pr.outputs.branchName != '' | |
| id: comments | |
| uses: actions/github-script@v7 | |
| with: | |
| result-encoding: string | |
| script: | | |
| const prNum = '${{ env.PR_NUMBER }}'; | |
| const { data: comments } = await github.rest.issues.listComments({ | |
| issue_number: parseInt(prNum), | |
| owner: context.repo.owner, | |
| repo: context.repo.repo | |
| }); | |
| const newComments = comments.filter(c => | |
| c.user.type !== 'Bot' && | |
| new Date(c.created_at) > new Date('${{ github.event.pull_request.updated_at || github.event.comment.created_at }}') | |
| ); | |
| return JSON.stringify(newComments.map(c => c.body)); | |
| - name: Prepare prompt for iteration | |
| if: steps.comments.outputs.result != '[]' && steps.comments.outputs.result != '' | |
| id: prepare_prompt | |
| env: | |
| COMMENTS_DATA: ${{ steps.comments.outputs.result }} | |
| run: | | |
| $comments = '${{ steps.comments.outputs.result }}' | |
| if ($comments -eq '' -or $comments -eq '[]') { | |
| Write-Host 'No new comments, skipping' | |
| exit 0 | |
| } | |
| $c = $comments | ConvertFrom-Json | |
| $prompt = Get-Content '.github/workflows/prompts/ai-iterate-prompt.txt' -Raw | |
| $prompt = $prompt -replace '{{issue_number}}', '${{ env.ISSUE_NUM }}' | |
| $prompt = $prompt -replace '{{pr_number}}', '${{ env.PR_NUMBER }}' | |
| $commentText = ($c | ForEach-Object { $_ }) -join "`n`n" | |
| $prompt = $prompt -replace '{{comments}}', $commentText | |
| # Write to temp file for opencode action | |
| $prompt | Out-File -FilePath "$env:TEMP\prompt.txt" -Encoding UTF8 | |
| # Also output as environment variable for action | |
| echo "PROMPT_CONTENT=$prompt" >> $env:GITHUB_ENV | |
| - name: Run OpenCode for changes | |
| if: steps.comments.outputs.result != '[]' && steps.comments.outputs.result != '' | |
| id: opencode | |
| run: opencode github run | |
| env: | |
| MINIMAX_API_KEY: ${{ secrets.MINIMAX_API_KEY }} | |
| MODEL: minimax-cn-coding-plan/MiniMax-M2.5 | |
| AGENT: sisyphus | |
| PROMPT: ${{ env.PROMPT_CONTENT }} | |
| - name: Check changes | |
| id: changes | |
| if: steps.opencode.outputs.result != '' | |
| run: | | |
| for /f %%a in ('git status --porcelain ^| find /c /v ""') do echo changed=%%a >> %GITHUB_OUTPUT% | |
| - name: Commit and push | |
| if: steps.changes.outputs.changed > 0 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| git config user.name "AI Agent" | |
| git config user.email "ai@github.local" | |
| git add -A | |
| git commit -m "AI: Iterate based on feedback" 2>nul | |
| git push origin "ai/issue-$env:ISSUE_NUM" 2>nul | |
| - name: Post iteration report | |
| if: steps.changes.outputs.changed > 0 | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const body = "## AI Iteration Report\n\nChanges made:\n- Applied requested changes from PR comments\n- Fixed identified issues\n\nFiles modified: See commit history\nTest results: See workflow logs"; | |
| await github.rest.issues.createComment({ | |
| issue_number: parseInt('${{ env.PR_NUMBER }}'), | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| body: body | |
| }); | |
| - name: Cleanup temp files | |
| if: always() | |
| run: | | |
| Remove-Item -Force "$env:TEMP\prompt.txt" -ErrorAction SilentlyContinue || true | |