This commit is contained in:
Dmitry 2025-11-22 02:26:25 +03:00
parent 249683ab5f
commit ff52bbeb9e
2 changed files with 129 additions and 64 deletions

View file

@ -3,14 +3,6 @@ name: AI Agent - Planning
on: on:
workflow_dispatch: workflow_dispatch:
inputs: inputs:
component:
description: 'Component to plan for'
required: true
type: choice
options:
- web_v2
- backend
- common
llm_model: llm_model:
description: 'LLM Model' description: 'LLM Model'
required: true required: true
@ -49,10 +41,11 @@ jobs:
- name: Set up Python and bash - name: Set up Python and bash
run: | run: |
apt-get update -qq apt-get update -qq
apt-get install -y -qq python3 python3-pip python3-venv bash apt-get install -y -qq python3 python3-pip python3-venv bash jq
python3 --version python3 --version
pip3 --version pip3 --version
bash --version || echo "bash check failed" bash --version || echo "bash check failed"
jq --version || echo "jq check failed"
- name: Install Cursor CLI - name: Install Cursor CLI
run: | run: |
@ -88,7 +81,7 @@ jobs:
git config --global user.name "AI Agent" git config --global user.name "AI Agent"
git config --global user.email "ai-agent@mnemo-cards.com" git config --global user.email "ai-agent@mnemo-cards.com"
- name: Run Planning Agent - name: Run Planning Agent for All Components
env: env:
CURSOR_API_KEY: ${{ secrets.CURSOR_API_KEY }} CURSOR_API_KEY: ${{ secrets.CURSOR_API_KEY }}
CURSOR_MODEL: ${{ inputs.llm_model || secrets.CURSOR_MODEL }} CURSOR_MODEL: ${{ inputs.llm_model || secrets.CURSOR_MODEL }}
@ -132,26 +125,40 @@ jobs:
fi fi
cd ${{ github.workspace }} cd ${{ github.workspace }}
python3 tools/agent/planning_agent.py ${{ inputs.component }}
# Plan for all components
COMPONENTS=("web_v2" "backend" "common")
for COMPONENT in "${COMPONENTS[@]}"; do
echo "📋 Planning for component: $COMPONENT"
python3 tools/agent/planning_agent.py "$COMPONENT" || {
echo "⚠️ Planning failed for $COMPONENT, continuing with other components..."
}
done
echo "✅ Planning completed for all components"
- name: Parse Task List and Create Summary - name: Parse Task Lists and Create Summaries
if: success() if: success()
id: parse_tasks id: parse_tasks
run: | run: |
COMPONENT="${{ inputs.component }}" COMPONENTS=("web_v2" "backend" "common")
TASK_LIST_PATH="ai_docs/agent/${COMPONENT}/task_list.json"
if [ ! -f "$TASK_LIST_PATH" ]; then for COMPONENT in "${COMPONENTS[@]}"; do
echo "Task list not found" TASK_LIST_PATH="ai_docs/agent/${COMPONENT}/task_list.json"
exit 0
fi if [ ! -f "$TASK_LIST_PATH" ]; then
echo "⚠️ Task list not found for $COMPONENT, skipping..."
# Parse JSON with Python continue
python3 << 'EOF' fi
echo "📊 Parsing task list for $COMPONENT..."
# Parse JSON with Python
python3 << EOF
import json import json
import os import os
component = os.environ.get('COMPONENT', 'unknown') component = "$COMPONENT"
task_list_path = f"ai_docs/agent/{component}/task_list.json" task_list_path = f"ai_docs/agent/{component}/task_list.json"
try: try:
@ -186,61 +193,119 @@ jobs:
body += "\\n---\\n*Generated by AI Planning Agent*" body += "\\n---\\n*Generated by AI Planning Agent*"
# Save to file for next step # Save to file for next step (component-specific)
with open('/tmp/issue_body.txt', 'w') as f: with open(f'/tmp/issue_body_{component}.txt', 'w') as f:
f.write(body) f.write(body)
title = f"📋 Planning: {component} - {len(tasks)} tasks ({total_hours:.1f}h)" title = f"📋 Planning: {component} - {len(tasks)} tasks ({total_hours:.1f}h)"
with open('/tmp/issue_title.txt', 'w') as f: with open(f'/tmp/issue_title_{component}.txt', 'w') as f:
f.write(title) f.write(title)
print(f"Tasks: {len(tasks)}, High: {high}, Medium: {medium}, Low: {low}") print(f"✅ {component}: Tasks: {len(tasks)}, High: {high}, Medium: {medium}, Low: {low}")
except Exception as e: except Exception as e:
print(f"Error: {e}") print(f"❌ Error processing {component}: {e}")
exit(1) import traceback
traceback.print_exc()
EOF EOF
done
echo "✅ All task lists parsed"
- name: Create Issues via Forgejo API
if: success()
env: env:
COMPONENT: ${{ inputs.component }} FORGEJO_TOKEN: ${{ secrets.FORGEJO_TOKEN }}
API_URL: ${{ github.api_url }}/repos/${{ github.repository }}/issues
- name: Create Issue via Forgejo API
if: success()
run: | run: |
COMPONENT="${{ inputs.component }}" COMPONENTS=("web_v2" "backend" "common")
if [ ! -f "/tmp/issue_body.txt" ] || [ ! -f "/tmp/issue_title.txt" ]; then for COMPONENT in "${COMPONENTS[@]}"; do
echo "Issue files not found, skipping issue creation" if [ ! -f "/tmp/issue_body_${COMPONENT}.txt" ] || [ ! -f "/tmp/issue_title_${COMPONENT}.txt" ]; then
exit 0 echo "⚠️ Issue files not found for $COMPONENT, skipping..."
fi continue
fi
echo "📝 Creating issue for $COMPONENT..."
# Create issue using Python for proper JSON escaping
python3 << PYTHON_SCRIPT
import json
import sys
import os
import subprocess
TITLE=$(cat /tmp/issue_title.txt) component = "$COMPONENT"
BODY=$(cat /tmp/issue_body.txt) api_url = os.environ.get('API_URL')
token = os.environ.get('FORGEJO_TOKEN')
# Forgejo API endpoint (adjust to your Forgejo instance) if not all([component, api_url, token]):
API_URL="${{ github.api_url }}/repos/${{ github.repository }}/issues" print("❌ Missing required environment variables")
sys.exit(1)
# Create issue using curl # Read title and body
curl -X POST "$API_URL" \ try:
-H "Authorization: token ${{ secrets.FORGEJO_TOKEN }}" \ with open(f'/tmp/issue_title_{component}.txt', 'r') as f:
-H "Content-Type: application/json" \ title = f.read().strip()
-d @- << EOF
{ with open(f'/tmp/issue_body_{component}.txt', 'r') as f:
"title": "$TITLE", body = f.read()
"body": $(echo "$BODY" | jq -Rs .), except Exception as e:
"labels": ["ai-agent", "planning", "$COMPONENT"] print(f"❌ Error reading files: {e}")
sys.exit(1)
# Create JSON payload
payload = {
"title": title,
"body": body,
"labels": ["ai-agent", "planning", component]
} }
EOF
# Make API request
json_payload = json.dumps(payload)
curl_cmd = [
"curl", "-X", "POST", api_url,
"-H", f"Authorization: token {token}",
"-H", "Content-Type: application/json",
"-d", json_payload,
"-f", "-s", "-S"
]
result = subprocess.run(curl_cmd, capture_output=True, text=True)
if result.returncode == 0:
print(f"✅ Issue created for {component}")
if result.stdout:
print(f"Response: {result.stdout[:200]}")
else:
print(f"❌ Failed to create issue for {component}")
print(f"Error: {result.stderr}")
if result.stdout:
print(f"Response: {result.stdout}")
sys.exit(1)
PYTHON_SCRIPT
if [ $? -ne 0 ]; then
echo "⚠️ Failed to create issue for $COMPONENT, continuing..."
fi
done
- name: Trigger Development Workflow - name: Trigger Development Workflow for All Components
if: success() if: success()
run: | run: |
COMPONENT="${{ inputs.component }}" COMPONENTS=("web_v2" "backend" "common")
# Trigger via Forgejo API
API_URL="${{ github.api_url }}/repos/${{ github.repository }}/actions/workflows/agent-development.yml/dispatches" API_URL="${{ github.api_url }}/repos/${{ github.repository }}/actions/workflows/agent-development.yml/dispatches"
curl -X POST "$API_URL" \ for COMPONENT in "${COMPONENTS[@]}"; do
-H "Authorization: token ${{ secrets.FORGEJO_TOKEN }}" \ echo "🚀 Triggering development workflow for $COMPONENT..."
-H "Content-Type: application/json" \
-d "{\"ref\":\"master\",\"inputs\":{\"component\":\"$COMPONENT\"}}" curl -X POST "$API_URL" \
-H "Authorization: token ${{ secrets.FORGEJO_TOKEN }}" \
-H "Content-Type: application/json" \
-d "{\"ref\":\"master\",\"inputs\":{\"component\":\"$COMPONENT\"}}" || {
echo "⚠️ Failed to trigger workflow for $COMPONENT, continuing..."
}
echo "✅ Development workflow triggered for $COMPONENT"
done

View file

@ -153,10 +153,12 @@ Start planning now!
"""Gather context from existing files.""" """Gather context from existing files."""
context = "" context = ""
# Read tasks.md if exists # Read tasks.md - check multiple locations
# Priority: component-specific > global agent tasks.md
tasks_md = self.config.component_root / "tasks.md" tasks_md = self.config.component_root / "tasks.md"
if not tasks_md.exists(): if not tasks_md.exists():
tasks_md = self.config.project_root / "mnemo_cards_web_v2" / "tasks.md" # Fallback to global agent tasks.md
tasks_md = self.config.project_root / "ai_docs" / "agent" / "tasks.md"
if tasks_md.exists(): if tasks_md.exists():
with open(tasks_md, 'r') as f: with open(tasks_md, 'r') as f:
@ -166,10 +168,8 @@ Start planning now!
content = content[:10000] + "\n... (truncated)" content = content[:10000] + "\n... (truncated)"
context += f"### tasks.md:\n```\n{content}\n```\n\n" context += f"### tasks.md:\n```\n{content}\n```\n\n"
# Read workflow_state.md if exists # Read workflow_state.md - component-specific only
workflow_state = self.config.component_root / "workflow_state.md" workflow_state = self.config.component_root / "workflow_state.md"
if not workflow_state.exists():
workflow_state = self.config.project_root / "mnemo_cards_web_v2" / "workflow_state.md"
if workflow_state.exists(): if workflow_state.exists():
with open(workflow_state, 'r') as f: with open(workflow_state, 'r') as f: