2025-11-20 21:28:55 +00:00
|
|
|
name: AI Agent - Development
|
|
|
|
|
|
|
|
|
|
on:
|
|
|
|
|
workflow_dispatch:
|
|
|
|
|
inputs:
|
|
|
|
|
component:
|
|
|
|
|
description: 'Component to develop'
|
|
|
|
|
required: true
|
|
|
|
|
type: choice
|
|
|
|
|
options:
|
|
|
|
|
- web_v2
|
|
|
|
|
- backend
|
|
|
|
|
- common
|
2025-11-21 00:37:57 +00:00
|
|
|
schedule:
|
|
|
|
|
# Run every 30 minutes
|
|
|
|
|
- cron: '*/30 * * * *'
|
|
|
|
|
|
|
|
|
|
# Other schedule options (uncomment to use):
|
|
|
|
|
# Run every 15 minutes
|
|
|
|
|
# - cron: '*/15 * * * *'
|
|
|
|
|
# Run every hour
|
|
|
|
|
# - cron: '0 * * * *'
|
|
|
|
|
# Run every 6 hours (at 2:00, 8:00, 14:00, 20:00 UTC)
|
|
|
|
|
# - cron: '0 */6 * * *'
|
|
|
|
|
# Run every day at 2:00 AM UTC (5:00 AM MSK)
|
|
|
|
|
# - cron: '0 2 * * *'
|
|
|
|
|
# Run every day at 9:00 AM UTC (12:00 PM MSK)
|
|
|
|
|
# - cron: '0 9 * * *'
|
2025-11-20 21:28:55 +00:00
|
|
|
|
|
|
|
|
jobs:
|
|
|
|
|
development:
|
|
|
|
|
runs-on: ubuntu-latest
|
2025-11-21 00:19:10 +00:00
|
|
|
container: ghcr.io/cirruslabs/flutter:3.35.5
|
2025-11-20 21:28:55 +00:00
|
|
|
timeout-minutes: 360 # 6 hours
|
2025-11-21 00:37:57 +00:00
|
|
|
# For scheduled runs, use matrix to run all components
|
|
|
|
|
# For manual runs, use input component
|
|
|
|
|
strategy:
|
|
|
|
|
matrix:
|
|
|
|
|
component: [web_v2, backend, common]
|
|
|
|
|
fail-fast: false
|
|
|
|
|
# Only use matrix for scheduled runs (when inputs.component is not set)
|
|
|
|
|
# For workflow_dispatch, matrix will be ignored and inputs.component will be used
|
|
|
|
|
env:
|
|
|
|
|
# Use input component if provided (workflow_dispatch), otherwise use matrix component (schedule)
|
|
|
|
|
COMPONENT: ${{ inputs.component || matrix.component }}
|
|
|
|
|
# For workflow_dispatch, only run the selected component
|
|
|
|
|
# For schedule, run all components (matrix will create jobs for all)
|
|
|
|
|
if: github.event_name == 'schedule' || inputs.component == '' || inputs.component == matrix.component
|
2025-11-20 21:28:55 +00:00
|
|
|
|
|
|
|
|
steps:
|
2025-11-21 00:21:48 +00:00
|
|
|
- name: Install Node.js
|
|
|
|
|
run: |
|
|
|
|
|
# Try to install nodejs if missing (required for actions)
|
|
|
|
|
if ! command -v node &> /dev/null; then
|
|
|
|
|
echo "Node.js not found, installing..."
|
|
|
|
|
# Check if running as root
|
|
|
|
|
if [ "$(id -u)" -eq 0 ]; then
|
|
|
|
|
apt-get update && apt-get install -y nodejs npm
|
|
|
|
|
else
|
|
|
|
|
sudo apt-get update && sudo apt-get install -y nodejs npm
|
|
|
|
|
fi
|
|
|
|
|
fi
|
|
|
|
|
|
2025-11-20 21:28:55 +00:00
|
|
|
- name: Checkout repository
|
2025-11-20 23:25:09 +00:00
|
|
|
uses: actions/checkout@v4
|
2025-11-20 21:28:55 +00:00
|
|
|
with:
|
|
|
|
|
fetch-depth: 0
|
2025-11-20 23:25:09 +00:00
|
|
|
submodules: recursive
|
|
|
|
|
|
2025-11-20 21:55:20 +00:00
|
|
|
- name: Set up Python and dependencies
|
2025-11-20 21:28:55 +00:00
|
|
|
run: |
|
2025-11-20 21:35:20 +00:00
|
|
|
apt-get update -qq
|
2025-11-20 23:21:57 +00:00
|
|
|
apt-get install -y -qq python3 python3-pip python3-venv jq bash git
|
2025-11-20 21:55:20 +00:00
|
|
|
python3 --version
|
|
|
|
|
pip3 --version
|
2025-11-20 22:15:47 +00:00
|
|
|
bash --version || echo "bash check failed"
|
2025-11-20 23:56:30 +00:00
|
|
|
|
2025-11-20 21:28:55 +00:00
|
|
|
- name: Install Cursor CLI
|
|
|
|
|
run: |
|
2025-11-20 22:15:47 +00:00
|
|
|
# bash should already be installed in previous step
|
2025-11-20 21:28:55 +00:00
|
|
|
curl https://cursor.com/install -fsS | bash
|
2025-11-20 22:12:32 +00:00
|
|
|
# Cursor installs to ~/.local/bin by default
|
|
|
|
|
export PATH="$HOME/.local/bin:$PATH"
|
|
|
|
|
echo "$HOME/.local/bin" >> $GITHUB_PATH
|
|
|
|
|
# Also check ~/.cursor/bin (older location)
|
|
|
|
|
if [ -d "$HOME/.cursor/bin" ]; then
|
|
|
|
|
export PATH="$HOME/.cursor/bin:$PATH"
|
|
|
|
|
echo "$HOME/.cursor/bin" >> $GITHUB_PATH
|
|
|
|
|
fi
|
2025-11-20 22:04:17 +00:00
|
|
|
# Verify installation
|
2025-11-20 22:12:32 +00:00
|
|
|
if [ -f "$HOME/.local/bin/cursor-agent" ]; then
|
|
|
|
|
echo "✅ Cursor CLI installed at $HOME/.local/bin/cursor-agent"
|
|
|
|
|
chmod +x "$HOME/.local/bin/cursor-agent"
|
|
|
|
|
"$HOME/.local/bin/cursor-agent" --version || echo "cursor-agent executable found but version check failed"
|
|
|
|
|
elif [ -f "$HOME/.cursor/bin/cursor-agent" ]; then
|
2025-11-20 22:04:17 +00:00
|
|
|
echo "✅ Cursor CLI installed at $HOME/.cursor/bin/cursor-agent"
|
|
|
|
|
chmod +x "$HOME/.cursor/bin/cursor-agent"
|
|
|
|
|
"$HOME/.cursor/bin/cursor-agent" --version || echo "cursor-agent executable found but version check failed"
|
|
|
|
|
else
|
2025-11-20 22:12:32 +00:00
|
|
|
echo "❌ Cursor CLI not found in expected locations"
|
|
|
|
|
echo "Checking PATH..."
|
|
|
|
|
command -v cursor-agent || echo "cursor-agent not in PATH"
|
|
|
|
|
find "$HOME" -name "cursor-agent" -type f 2>/dev/null | head -5 || echo "No cursor-agent found in $HOME"
|
2025-11-20 22:04:17 +00:00
|
|
|
exit 1
|
|
|
|
|
fi
|
2025-11-20 21:28:55 +00:00
|
|
|
|
|
|
|
|
- name: Configure Git
|
|
|
|
|
run: |
|
|
|
|
|
git config --global user.name "AI Agent"
|
|
|
|
|
git config --global user.email "ai-agent@mnemo-cards.com"
|
|
|
|
|
|
2025-11-21 00:37:57 +00:00
|
|
|
- name: Install Dependencies
|
2025-11-20 21:28:55 +00:00
|
|
|
run: |
|
2025-11-21 00:37:57 +00:00
|
|
|
COMPONENT="${{ env.COMPONENT }}"
|
|
|
|
|
if [ "$COMPONENT" == "web_v2" ]; then
|
|
|
|
|
cd mnemo_cards_web_v2
|
|
|
|
|
flutter pub get
|
|
|
|
|
elif [ "$COMPONENT" == "backend" ]; then
|
|
|
|
|
cd mnemo_cards_backend
|
|
|
|
|
dart pub get
|
|
|
|
|
elif [ "$COMPONENT" == "common" ]; then
|
|
|
|
|
cd mnemo_cards_common
|
|
|
|
|
dart pub get
|
|
|
|
|
fi
|
2025-11-20 21:28:55 +00:00
|
|
|
|
|
|
|
|
- name: Run Development Agent
|
|
|
|
|
env:
|
|
|
|
|
CURSOR_API_KEY: ${{ secrets.CURSOR_API_KEY }}
|
|
|
|
|
CURSOR_MODEL: ${{ secrets.CURSOR_MODEL }}
|
|
|
|
|
PROJECT_ROOT: ${{ github.workspace }}
|
|
|
|
|
MAX_ITERATIONS: 10
|
|
|
|
|
MAX_RETRIES: 3
|
|
|
|
|
TIMEOUT_HOURS: 6
|
|
|
|
|
run: |
|
2025-11-20 22:04:17 +00:00
|
|
|
# Verify cursor-agent is accessible
|
2025-11-21 00:29:06 +00:00
|
|
|
echo "Current PATH: $PATH"
|
|
|
|
|
|
2025-11-20 22:04:17 +00:00
|
|
|
if ! command -v cursor-agent &> /dev/null; then
|
|
|
|
|
echo "❌ cursor-agent not found in PATH"
|
|
|
|
|
echo "PATH: $PATH"
|
2025-11-20 22:12:32 +00:00
|
|
|
echo "Trying full paths..."
|
|
|
|
|
if [ -f "$HOME/.local/bin/cursor-agent" ]; then
|
|
|
|
|
export PATH="$HOME/.local/bin:$PATH"
|
|
|
|
|
echo "✅ Found at $HOME/.local/bin/cursor-agent"
|
|
|
|
|
elif [ -f "$HOME/.cursor/bin/cursor-agent" ]; then
|
2025-11-20 22:04:17 +00:00
|
|
|
export PATH="$HOME/.cursor/bin:$PATH"
|
2025-11-20 22:12:32 +00:00
|
|
|
echo "✅ Found at $HOME/.cursor/bin/cursor-agent"
|
2025-11-20 22:04:17 +00:00
|
|
|
else
|
2025-11-20 22:12:32 +00:00
|
|
|
echo "❌ cursor-agent not found in any expected location"
|
|
|
|
|
find "$HOME" -name "cursor-agent" -type f 2>/dev/null | head -5 || echo "No cursor-agent found"
|
2025-11-20 22:04:17 +00:00
|
|
|
exit 1
|
|
|
|
|
fi
|
2025-11-20 22:22:34 +00:00
|
|
|
else
|
|
|
|
|
echo "✅ cursor-agent found at: $(command -v cursor-agent)"
|
2025-11-20 22:04:17 +00:00
|
|
|
fi
|
|
|
|
|
|
2025-11-20 21:28:55 +00:00
|
|
|
cd ${{ github.workspace }}
|
2025-11-21 00:37:57 +00:00
|
|
|
python3 tools/agent/agent_orchestrator.py ${{ env.COMPONENT }}
|
2025-11-20 21:28:55 +00:00
|
|
|
|
|
|
|
|
- name: Create Summary Report
|
|
|
|
|
if: always()
|
|
|
|
|
run: |
|
2025-11-21 00:37:57 +00:00
|
|
|
COMPONENT="${{ env.COMPONENT }}"
|
2025-11-20 21:28:55 +00:00
|
|
|
STATE_FILE="ai_docs/agent/${COMPONENT}/agent_state.json"
|
|
|
|
|
|
|
|
|
|
echo "# Development Agent Summary" > /tmp/summary.md
|
|
|
|
|
echo "" >> /tmp/summary.md
|
|
|
|
|
echo "**Component:** ${COMPONENT}" >> /tmp/summary.md
|
|
|
|
|
echo "**Started:** $(date -u +"%Y-%m-%d %H:%M:%S UTC")" >> /tmp/summary.md
|
|
|
|
|
echo "" >> /tmp/summary.md
|
|
|
|
|
|
|
|
|
|
if [ -f "$STATE_FILE" ]; then
|
|
|
|
|
echo "## Agent State" >> /tmp/summary.md
|
|
|
|
|
echo "\`\`\`json" >> /tmp/summary.md
|
|
|
|
|
cat "$STATE_FILE" >> /tmp/summary.md
|
|
|
|
|
echo "\`\`\`" >> /tmp/summary.md
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
cat /tmp/summary.md
|
|
|
|
|
|
|
|
|
|
- name: Check if all tasks completed
|
|
|
|
|
id: check_completion
|
|
|
|
|
run: |
|
2025-11-21 00:37:57 +00:00
|
|
|
COMPONENT="${{ env.COMPONENT }}"
|
2025-11-20 21:28:55 +00:00
|
|
|
STATE_FILE="ai_docs/agent/${COMPONENT}/agent_state.json"
|
|
|
|
|
TASK_LIST="ai_docs/agent/${COMPONENT}/task_list.json"
|
|
|
|
|
|
|
|
|
|
if [ -f "$STATE_FILE" ] && [ -f "$TASK_LIST" ]; then
|
|
|
|
|
# Check if all tasks are completed
|
|
|
|
|
python3 << 'EOF'
|
|
|
|
|
import json
|
|
|
|
|
import os
|
|
|
|
|
import sys
|
|
|
|
|
|
|
|
|
|
component = os.environ.get('COMPONENT', 'unknown')
|
|
|
|
|
state_file = f"ai_docs/agent/{component}/agent_state.json"
|
|
|
|
|
task_list_file = f"ai_docs/agent/{component}/task_list.json"
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
with open(state_file, 'r') as f:
|
|
|
|
|
state = json.load(f)
|
|
|
|
|
|
|
|
|
|
with open(task_list_file, 'r') as f:
|
|
|
|
|
task_list = json.load(f)
|
|
|
|
|
|
|
|
|
|
tasks = task_list.get('tasks', [])
|
|
|
|
|
pending = [t for t in tasks if t.get('status') == 'pending']
|
|
|
|
|
|
|
|
|
|
# Check if status is completed or no pending tasks
|
|
|
|
|
if state.get('status') == 'completed' or len(pending) == 0:
|
|
|
|
|
print("all_completed=true")
|
|
|
|
|
else:
|
|
|
|
|
print("all_completed=false")
|
|
|
|
|
except Exception as e:
|
|
|
|
|
print(f"Error: {e}", file=sys.stderr)
|
|
|
|
|
print("all_completed=false")
|
|
|
|
|
EOF
|
|
|
|
|
else
|
|
|
|
|
echo "all_completed=false"
|
|
|
|
|
fi > /tmp/completion_status.txt
|
|
|
|
|
|
|
|
|
|
cat /tmp/completion_status.txt >> $GITHUB_OUTPUT
|
|
|
|
|
env:
|
2025-11-21 00:37:57 +00:00
|
|
|
COMPONENT: ${{ env.COMPONENT }}
|
2025-11-20 21:28:55 +00:00
|
|
|
|
|
|
|
|
- name: Trigger Planning Agent (if all completed)
|
|
|
|
|
if: contains(steps.check_completion.outputs.*, 'all_completed=true')
|
|
|
|
|
run: |
|
|
|
|
|
COMPONENT="${{ inputs.component }}"
|
|
|
|
|
|
|
|
|
|
echo "All tasks completed! Triggering planning agent for new tasks..."
|
|
|
|
|
|
|
|
|
|
# Trigger via Forgejo API
|
|
|
|
|
API_URL="${{ github.api_url }}/repos/${{ github.repository }}/actions/workflows/agent-planning.yml/dispatches"
|
|
|
|
|
|
|
|
|
|
curl -X POST "$API_URL" \
|
|
|
|
|
-H "Authorization: token ${{ secrets.FORGEJO_TOKEN }}" \
|
|
|
|
|
-H "Content-Type: application/json" \
|
|
|
|
|
-d "{\"ref\":\"master\",\"inputs\":{\"component\":\"$COMPONENT\"}}"
|
|
|
|
|
|