tasks
This commit is contained in:
parent
249683ab5f
commit
ff52bbeb9e
2 changed files with 129 additions and 64 deletions
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue