Skip to content

docs(readme): trim to principles and cross-link docs #15

docs(readme): trim to principles and cross-link docs

docs(readme): trim to principles and cross-link docs #15

Workflow file for this run

name: AI Review Bot
on:
pull_request:
types: [opened, reopened, synchronize, ready_for_review]
issues:
types: [opened]
issue_comment:
types: [created]
workflow_dispatch:
inputs:
mode:
description: "Manual mode"
required: true
default: review
type: choice
options:
- review
- triage
- explain
permissions:
contents: read
pull-requests: write
issues: write
concurrency:
group: ai-review-${{ github.event.pull_request.number || github.event.issue.number || github.ref }}-${{ github.event_name }}
cancel-in-progress: true
jobs:
ai-review:
name: OpenCode2API AI review (gateway + CPA)
# Slash commands only run for collaborators (budget/abuse gate); automatic
# PR/issue events are unaffected.
if: >
github.event_name != 'issue_comment' ||
((
contains(github.event.comment.body, '/review') ||
contains(github.event.comment.body, '/triage') ||
contains(github.event.comment.body, '/explain')
) && contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association))
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
- name: Skip draft pull requests
id: gate
shell: bash
run: |
set -euo pipefail
if [[ "${{ github.event_name }}" == "pull_request" && "${{ github.event.pull_request.draft }}" == "true" ]]; then
echo "skip=true" >> "$GITHUB_OUTPUT"
echo "Skipping draft pull request"
else
echo "skip=false" >> "$GITHUB_OUTPUT"
fi
- name: Ensure LLM route is available
if: steps.gate.outputs.skip != 'true'
shell: bash
env:
GATEWAY_BASE_URL: ${{ secrets.GATEWAY_BASE_URL }}
CPA_BASE_URL: ${{ secrets.CPA_BASE_URL }}
CPA_API_KEY: ${{ secrets.CPA_API_KEY }}
run: |
set -euo pipefail
# Free models always have a route: an in-job no-auth gateway is
# started below unless an external GATEWAY_BASE_URL secret is set.
# CPA credentials are optional (fallback channel only).
if [[ -n "${GATEWAY_BASE_URL}" ]]; then
echo "Using external gateway (URL from secrets; value not printed)."
else
echo "No external gateway secret; starting in-job no-auth gateway."
fi
if [[ -z "${CPA_API_KEY}" || -z "${CPA_BASE_URL}" ]]; then
echo "::warning::No CPA credentials; CPA fallback channel disabled (gateway only)."
fi
- name: Check out repository
if: steps.gate.outputs.skip != 'true'
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0
persist-credentials: false
- name: Resolve PR head for comment-triggered runs
if: steps.gate.outputs.skip != 'true' && github.event_name == 'issue_comment' && github.event.issue.pull_request
id: pr_ref
shell: bash
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
pr_json="$(gh api "repos/${GITHUB_REPOSITORY}/pulls/${{ github.event.issue.number }}")"
base_sha="$(printf '%s' "$pr_json" | python3 -c 'import json,sys; print(json.load(sys.stdin)["base"]["sha"])')"
head_sha="$(printf '%s' "$pr_json" | python3 -c 'import json,sys; print(json.load(sys.stdin)["head"]["sha"])')"
git fetch --no-tags origin "pull/${{ github.event.issue.number }}/head:refs/bot/pr-${{ github.event.issue.number }}"
git checkout --force "refs/bot/pr-${{ github.event.issue.number }}"
{
echo "base_sha=${base_sha}"
echo "head_sha=${head_sha}"
} >> "$GITHUB_OUTPUT"
- name: Detect gateway source
id: gw
shell: bash
env:
GATEWAY_BASE_URL: ${{ secrets.GATEWAY_BASE_URL }}
run: |
set -euo pipefail
# secrets context is not allowed in step `if:`; expose via outputs.
# Always runs (trivial check) so downstream never reads an absent output.
if [[ -n "${GATEWAY_BASE_URL}" ]]; then
echo "external=true" >> "$GITHUB_OUTPUT"
else
echo "external=false" >> "$GITHUB_OUTPUT"
fi
- name: Set up Node
if: steps.gate.outputs.skip != 'true' && steps.gw.outputs.external != 'true'
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: 24
cache: npm
- name: Start in-job gateway (free models, no login needed)
if: steps.gate.outputs.skip != 'true' && steps.gw.outputs.external != 'true'
shell: bash
run: |
set -euo pipefail
npm ci
npm run build
# Pinned to track @opencode-ai/sdk ^1.18.29 used by this repo.
npm i -g opencode-ai@1.18.30
# No-auth localhost gateway: empty API_KEY = no auth; the gateway
# spawns its own backend (anonymous out-of-box free quota).
API_KEY= OPENCODE_PROXY_MANAGE_BACKEND=true OPENCODE_SERVER_PASSWORD=ci-local-only \
nohup node dist/index.js > /tmp/opencode-gateway.log 2>&1 &
ok=0
for i in $(seq 1 60); do
if curl -sf http://127.0.0.1:10000/health; then
echo
echo "gateway: /health 200"
ok=1
break
fi
sleep 5
done
if [[ "$ok" != "1" ]]; then
echo "gateway failed to start" >&2
tail -50 /tmp/opencode-gateway.log || true
exit 1
fi
- name: Set up Python
if: steps.gate.outputs.skip != 'true'
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
with:
python-version: "3.12"
- name: Determine bot mode
if: steps.gate.outputs.skip != 'true'
id: mode
shell: bash
run: |
set -euo pipefail
mode="review"
case "${{ github.event_name }}" in
issues)
mode="triage"
;;
issue_comment)
mode="comment"
;;
workflow_dispatch)
mode="${{ inputs.mode }}"
;;
pull_request)
mode="review"
;;
esac
echo "mode=${mode}" >> "$GITHUB_OUTPUT"
- name: Run AI bot
if: steps.gate.outputs.skip != 'true'
shell: bash
env:
GATEWAY_BASE_URL: ${{ secrets.GATEWAY_BASE_URL }}
GATEWAY_API_KEY: ${{ secrets.GATEWAY_API_KEY }}
OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
CPA_BASE_URL: ${{ secrets.CPA_BASE_URL }}
CPA_API_KEY: ${{ secrets.CPA_API_KEY }}
GITHUB_TOKEN: ${{ github.token }}
COMMENT_BODY: ${{ github.event.comment.body || '' }}
ISSUE_TITLE: ${{ github.event.issue.title || '' }}
ISSUE_BODY: ${{ github.event.issue.body || '' }}
PR_BASE_SHA: ${{ steps.pr_ref.outputs.base_sha || github.event.pull_request.base.sha || '' }}
PR_HEAD_SHA: ${{ steps.pr_ref.outputs.head_sha || github.event.pull_request.head.sha || '' }}
PYTHONPATH: github_bot/src
run: |
set -euo pipefail
# Default to the in-job no-auth gateway when no external URL secret.
export GATEWAY_BASE_URL="${GATEWAY_BASE_URL:-http://127.0.0.1:10000}"
python3 github_bot/src/github_runner.py --mode="${{ steps.mode.outputs.mode }}"