diff --git a/.forgejo/workflows/agent-planning.yml b/.forgejo/workflows/agent-planning.yml index 54e4c35..c2d2cf7 100644 --- a/.forgejo/workflows/agent-planning.yml +++ b/.forgejo/workflows/agent-planning.yml @@ -3,14 +3,6 @@ name: AI Agent - Planning on: workflow_dispatch: inputs: - component: - description: 'Component to plan for' - required: true - type: choice - options: - - web_v2 - - backend - - common llm_model: description: 'LLM Model' required: true @@ -49,10 +41,11 @@ jobs: - name: Set up Python and bash run: | 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 pip3 --version bash --version || echo "bash check failed" + jq --version || echo "jq check failed" - name: Install Cursor CLI run: | @@ -88,7 +81,7 @@ jobs: git config --global user.name "AI Agent" git config --global user.email "ai-agent@mnemo-cards.com" - - name: Run Planning Agent + - name: Run Planning Agent for All Components env: CURSOR_API_KEY: ${{ secrets.CURSOR_API_KEY }} CURSOR_MODEL: ${{ inputs.llm_model || secrets.CURSOR_MODEL }} @@ -132,26 +125,40 @@ jobs: fi 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() id: parse_tasks run: | - COMPONENT="${{ inputs.component }}" - TASK_LIST_PATH="ai_docs/agent/${COMPONENT}/task_list.json" + COMPONENTS=("web_v2" "backend" "common") - if [ ! -f "$TASK_LIST_PATH" ]; then - echo "Task list not found" - exit 0 - fi - - # Parse JSON with Python - python3 << 'EOF' + for COMPONENT in "${COMPONENTS[@]}"; do + TASK_LIST_PATH="ai_docs/agent/${COMPONENT}/task_list.json" + + if [ ! -f "$TASK_LIST_PATH" ]; then + echo "⚠️ Task list not found for $COMPONENT, skipping..." + continue + fi + + echo "📊 Parsing task list for $COMPONENT..." + + # Parse JSON with Python + python3 << EOF import json import os - component = os.environ.get('COMPONENT', 'unknown') + component = "$COMPONENT" task_list_path = f"ai_docs/agent/{component}/task_list.json" try: @@ -186,61 +193,119 @@ jobs: body += "\\n---\\n*Generated by AI Planning Agent*" - # Save to file for next step - with open('/tmp/issue_body.txt', 'w') as f: + # Save to file for next step (component-specific) + with open(f'/tmp/issue_body_{component}.txt', 'w') as f: f.write(body) 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) - 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: - print(f"Error: {e}") - exit(1) + print(f"❌ Error processing {component}: {e}") + import traceback + traceback.print_exc() EOF + done + + echo "✅ All task lists parsed" + + - name: Create Issues via Forgejo API + if: success() env: - COMPONENT: ${{ inputs.component }} - - - name: Create Issue via Forgejo API - if: success() + FORGEJO_TOKEN: ${{ secrets.FORGEJO_TOKEN }} + API_URL: ${{ github.api_url }}/repos/${{ github.repository }}/issues run: | - COMPONENT="${{ inputs.component }}" + COMPONENTS=("web_v2" "backend" "common") - if [ ! -f "/tmp/issue_body.txt" ] || [ ! -f "/tmp/issue_title.txt" ]; then - echo "Issue files not found, skipping issue creation" - exit 0 - fi + for COMPONENT in "${COMPONENTS[@]}"; do + if [ ! -f "/tmp/issue_body_${COMPONENT}.txt" ] || [ ! -f "/tmp/issue_title_${COMPONENT}.txt" ]; then + echo "⚠️ Issue files not found for $COMPONENT, skipping..." + 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) - BODY=$(cat /tmp/issue_body.txt) + component = "$COMPONENT" + api_url = os.environ.get('API_URL') + token = os.environ.get('FORGEJO_TOKEN') - # Forgejo API endpoint (adjust to your Forgejo instance) - API_URL="${{ github.api_url }}/repos/${{ github.repository }}/issues" + if not all([component, api_url, token]): + print("❌ Missing required environment variables") + sys.exit(1) - # Create issue using curl - curl -X POST "$API_URL" \ - -H "Authorization: token ${{ secrets.FORGEJO_TOKEN }}" \ - -H "Content-Type: application/json" \ - -d @- << EOF - { - "title": "$TITLE", - "body": $(echo "$BODY" | jq -Rs .), - "labels": ["ai-agent", "planning", "$COMPONENT"] + # Read title and body + try: + with open(f'/tmp/issue_title_{component}.txt', 'r') as f: + title = f.read().strip() + + with open(f'/tmp/issue_body_{component}.txt', 'r') as f: + body = f.read() + except Exception as e: + 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() run: | - COMPONENT="${{ inputs.component }}" - - # Trigger via Forgejo API + COMPONENTS=("web_v2" "backend" "common") API_URL="${{ github.api_url }}/repos/${{ github.repository }}/actions/workflows/agent-development.yml/dispatches" - curl -X POST "$API_URL" \ - -H "Authorization: token ${{ secrets.FORGEJO_TOKEN }}" \ - -H "Content-Type: application/json" \ - -d "{\"ref\":\"master\",\"inputs\":{\"component\":\"$COMPONENT\"}}" + for COMPONENT in "${COMPONENTS[@]}"; do + echo "🚀 Triggering development workflow for $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 diff --git a/tools/agent/planning_agent.py b/tools/agent/planning_agent.py index db32de4..458b1f9 100644 --- a/tools/agent/planning_agent.py +++ b/tools/agent/planning_agent.py @@ -153,10 +153,12 @@ Start planning now! """Gather context from existing files.""" 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" 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(): with open(tasks_md, 'r') as f: @@ -166,10 +168,8 @@ Start planning now! content = content[:10000] + "\n... (truncated)" 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" - if not workflow_state.exists(): - workflow_state = self.config.project_root / "mnemo_cards_web_v2" / "workflow_state.md" if workflow_state.exists(): with open(workflow_state, 'r') as f: