diff --git a/.github/workflows/email-cleanup.yml b/.github/workflows/email-cleanup.yml new file mode 100644 index 00000000..fbabe220 --- /dev/null +++ b/.github/workflows/email-cleanup.yml @@ -0,0 +1,77 @@ +name: 📧 Email Notification Cleanup + +on: + schedule: + # Ejecutar cada hora + - cron: "0 * * * *" + workflow_dispatch: + inputs: + max_emails: + description: "Maximum emails to process" + required: false + default: "50" + type: string + +permissions: + contents: read + +jobs: + cleanup-notifications: + runs-on: ubuntu-latest + + steps: + - name: 🔍 Checkout + uses: actions/checkout@v4 + + - name: 🐍 Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + cache: "pip" + + - name: 📦 Install Dependencies + run: | + cd tools/email-handler + pip install -r requirements.txt + + - name: 🔐 Setup Gmail Credentials + env: + GMAIL_CREDENTIALS: ${{ secrets.GMAIL_CREDENTIALS }} + GMAIL_TOKEN: ${{ secrets.GMAIL_TOKEN }} + run: | + cd tools/email-handler + + # Crear credentials.json desde secret + echo "$GMAIL_CREDENTIALS" > credentials.json + + # Crear token.json desde secret si existe + if [ -n "$GMAIL_TOKEN" ]; then + echo "$GMAIL_TOKEN" > token.json + fi + + - name: 📧 Process Notifications + env: + GH_TOKEN: ${{ github.token }} + MAX_EMAILS: ${{ github.event.inputs.max_emails || '50' }} + run: | + cd tools/email-handler + python src/main.py --max-emails $MAX_EMAILS + + - name: 💾 Update Token (if refreshed) + if: always() + run: | + cd tools/email-handler + if [ -f token.json ]; then + echo "Token file exists, should be updated in secrets manually" + # Note: GitHub Actions cannot update secrets automatically + # User must copy the new token.json content to GMAIL_TOKEN secret + fi + + - name: 📊 Summary + if: always() + run: | + echo "## 📧 Email Cleanup Summary" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "✅ Email handler executed" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "Check logs for details on processed emails." >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/global-self-healing.yml b/.github/workflows/global-self-healing.yml new file mode 100644 index 00000000..d6790900 --- /dev/null +++ b/.github/workflows/global-self-healing.yml @@ -0,0 +1,89 @@ +name: Global Self-Healing Monitor + +on: + schedule: + - cron: '*/30 * * * *' + workflow_dispatch: + +permissions: + contents: read + issues: write # Required to create/update issues + pull-requests: read # Required to read PR status + +jobs: + monitor-repos: + runs-on: ubuntu-latest + + strategy: + matrix: + repo: + - iberi22/Git-Core-Protocol + - iberi22/software-factory + - iberi22/domus-otec + - iberi22/less-colegio + - iberi22/synapse-protocol + - iberi22/gara-g + - iberi22/AI-Chef + - iberi22/contratafacil + - iberi22/bestof-opensorce + - iberi22/obs-studio-agent + - iberi22/pocket_cerebro + fail-fast: false + max-parallel: 3 + + steps: + - name: Check Failures + id: check + env: + GH_TOKEN: ${{ secrets.MULTI_REPO_TOKEN || github.token }} + run: | + echo "Checking ${{ matrix.repo }} for failures..." + + # Check the last 10 runs to find any recent failures + RUN_ID=$(gh run list \ + --repo ${{ matrix.repo }} \ + --limit 10 \ + --json databaseId,conclusion \ + --jq 'map(select(.conclusion == "failure")) | .[0].databaseId' 2>/dev/null || echo "") + + if [ -z "$RUN_ID" ] || [ "$RUN_ID" = "null" ]; then + echo "No failures found in last 10 runs" + echo "has_failure=false" >> $GITHUB_OUTPUT + else + echo "Found failure: Run ID $RUN_ID" + echo "has_failure=true" >> $GITHUB_OUTPUT + echo "run_id=$RUN_ID" >> $GITHUB_OUTPUT + fi + + - name: Create Issue + if: steps.check.outputs.has_failure == 'true' + env: + GH_TOKEN: ${{ secrets.MULTI_REPO_TOKEN || github.token }} + run: | + RUN_ID="${{ steps.check.outputs.run_id }}" + REPO="${{ matrix.repo }}" + + WORKFLOW_NAME=$(gh run view $RUN_ID \ + --repo $REPO \ + --json name \ + --jq '.name' 2>/dev/null || echo "Unknown Workflow") + + EXISTING=$(gh issue list \ + --repo $REPO \ + --label "bug" \ + --search "in:title $WORKFLOW_NAME" \ + --state open \ + --json number \ + --jq '.[0].number' 2>/dev/null || echo "") + + if [ -n "$EXISTING" ] && [ "$EXISTING" != "null" ]; then + echo "Updating issue #$EXISTING" + gh issue comment $EXISTING --repo $REPO --body "New failure: https://github.com/$REPO/actions/runs/$RUN_ID" + else + echo "Creating new issue" + gh issue create \ + --repo $REPO \ + --title "CI Failure: $WORKFLOW_NAME" \ + --body "Workflow failed. Run: https://github.com/$REPO/actions/runs/$RUN_ID" \ + --label "bug,ai-plan" || echo "Could not create issue" + fi diff --git a/.github/workflows/protocol-propagation.yml b/.github/workflows/protocol-propagation.yml new file mode 100644 index 00000000..61cafaa2 --- /dev/null +++ b/.github/workflows/protocol-propagation.yml @@ -0,0 +1,167 @@ +name: Protocol Propagation + +on: + push: + tags: + - "v*.*.*" + workflow_dispatch: + inputs: + update_type: + description: "Update type" + required: true + type: choice + options: + - workflows + - agents + - scripts + - full + default: "workflows" + +permissions: + contents: read + +jobs: + detect-changes: + runs-on: ubuntu-latest + outputs: + version: ${{ steps.version.outputs.version }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Get Version + id: version + run: | + if [ -f VERSION ]; then + VERSION=$(cat VERSION) + else + VERSION=${GITHUB_REF#refs/tags/v} + fi + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "Version: $VERSION" + + propagate: + needs: detect-changes + runs-on: ubuntu-latest + + strategy: + matrix: + repo: + - iberi22/software-factory + - iberi22/domus-otec + - iberi22/less-colegio + - iberi22/synapse-protocol + - iberi22/gara-g + - iberi22/AI-Chef + - iberi22/contratafacil + - iberi22/bestof-opensorce + - iberi22/obs-studio-agent + - iberi22/pocket_cerebro + fail-fast: false + max-parallel: 3 + + steps: + - name: Checkout Protocol Repo + uses: actions/checkout@v4 + + - name: Clone Target Repo + env: + GH_TOKEN: ${{ secrets.MULTI_REPO_TOKEN || secrets.GITHUB_TOKEN }} + run: | + # Configure git to use the token for authentication + git config --global credential.helper store + echo "https://x-access-token:${GH_TOKEN}@github.com" > ~/.git-credentials + + # Clone using https with token + git clone https://github.com/${{ matrix.repo }}.git target-repo || { + echo "Cannot access ${{ matrix.repo }}, skipping..." + exit 0 + } + + - name: Prepare Update + id: package + run: | + UPDATE_TYPE="${{ github.event.inputs.update_type || 'workflows' }}" + VERSION="${{ needs.detect-changes.outputs.version }}" + + cd target-repo + + BRANCH_NAME="protocol-update-v${VERSION}" + git checkout -b "$BRANCH_NAME" 2>/dev/null || git checkout "$BRANCH_NAME" + + case "$UPDATE_TYPE" in + workflows) + echo "Updating workflows..." + mkdir -p .github/workflows + cp -r ../.github/workflows/* .github/workflows/ 2>/dev/null || true + ;; + agents) + echo "Updating agent configs..." + cp ../AGENTS.md . 2>/dev/null || true + cp ../.cursorrules . 2>/dev/null || true + cp -r ../.github/copilot-instructions.md .github/ 2>/dev/null || true + ;; + scripts) + echo "Updating scripts..." + mkdir -p scripts + cp -r ../scripts/* scripts/ 2>/dev/null || true + ;; + full) + echo "Full protocol update..." + cp ../AGENTS.md . 2>/dev/null || true + cp ../.cursorrules . 2>/dev/null || true + mkdir -p .github/workflows scripts + cp -r ../.github/workflows/* .github/workflows/ 2>/dev/null || true + cp -r ../.github/copilot-instructions.md .github/ 2>/dev/null || true + cp -r ../scripts/* scripts/ 2>/dev/null || true + ;; + esac + + if git diff --quiet; then + echo "has_changes=false" >> $GITHUB_OUTPUT + echo "No changes detected" + else + echo "has_changes=true" >> $GITHUB_OUTPUT + echo "Changes detected" + + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add . + git commit -m "chore: update Git-Core Protocol to v${VERSION}" + fi + + echo "branch=$BRANCH_NAME" >> $GITHUB_OUTPUT + + - name: Push Changes + if: steps.package.outputs.has_changes == 'true' + env: + GH_TOKEN: ${{ secrets.MULTI_REPO_TOKEN || secrets.GITHUB_TOKEN }} + run: | + cd target-repo + git push -u origin ${{ steps.package.outputs.branch }} --force + + - name: Create PR + if: steps.package.outputs.has_changes == 'true' + env: + GH_TOKEN: ${{ secrets.MULTI_REPO_TOKEN || secrets.GITHUB_TOKEN }} + run: | + cd target-repo + + VERSION="${{ needs.detect-changes.outputs.version }}" + UPDATE_TYPE="${{ github.event.inputs.update_type || 'workflows' }}" + REPO="${{ matrix.repo }}" + + # Try to create PR without labels first, then add labels if they exist + gh pr create \ + --title "Git-Core Protocol v${VERSION} Update" \ + --body "Updates from Git-Core Protocol v${VERSION}. Type: ${UPDATE_TYPE}. See: https://github.com/iberi22/Git-Core-Protocol/releases/tag/v${VERSION}" \ + --base main \ + --head ${{ steps.package.outputs.branch }} || echo "PR may already exist" + + # Try to add labels (ignore if they don't exist) + PR_NUMBER=$(gh pr list --head ${{ steps.package.outputs.branch }} --json number --jq '.[0].number' 2>/dev/null || echo "") + if [ -n "$PR_NUMBER" ]; then + gh pr edit $PR_NUMBER --add-label "dependencies" 2>/dev/null || true + gh pr edit $PR_NUMBER --add-label "protocol-update" 2>/dev/null || true + fi diff --git a/.github/workflows/self-healing.yml b/.github/workflows/self-healing.yml new file mode 100644 index 00000000..87d0d7f7 --- /dev/null +++ b/.github/workflows/self-healing.yml @@ -0,0 +1,89 @@ +name: Self-Healing Workflow + +on: + workflow_run: + workflows: ["*"] + types: + - completed + +permissions: + contents: write + pull-requests: write + issues: write + +jobs: + self-heal: + runs-on: ubuntu-latest + if: ${{ github.event.workflow_run.conclusion == 'failure' }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Get Workflow Info + id: info + env: + GH_TOKEN: ${{ github.token }} + run: | + RUN_ID="${{ github.event.workflow_run.id }}" + WORKFLOW_NAME="${{ github.event.workflow_run.name }}" + + echo "workflow_name=$WORKFLOW_NAME" >> $GITHUB_OUTPUT + echo "run_id=$RUN_ID" >> $GITHUB_OUTPUT + echo "run_url=https://github.com/${{ github.repository }}/actions/runs/$RUN_ID" >> $GITHUB_OUTPUT + + - name: Classify Error + id: classify + env: + GH_TOKEN: ${{ github.token }} + run: | + RUN_ID="${{ steps.info.outputs.run_id }}" + + LOGS=$(gh run view $RUN_ID --log 2>&1 || echo "") + + if echo "$LOGS" | grep -qiE "ETIMEDOUT|ECONNRESET|429|rate limit"; then + echo "error_type=transient" >> $GITHUB_OUTPUT + elif echo "$LOGS" | grep -qiE "npm ERR|yarn error|pip.*failed"; then + echo "error_type=dependency" >> $GITHUB_OUTPUT + elif echo "$LOGS" | grep -qiE "lint|prettier|eslint"; then + echo "error_type=lint" >> $GITHUB_OUTPUT + elif echo "$LOGS" | grep -qiE "test.*failed|FAIL|AssertionError"; then + echo "error_type=test" >> $GITHUB_OUTPUT + else + echo "error_type=unknown" >> $GITHUB_OUTPUT + fi + + - name: Auto-Retry Transient Errors + if: steps.classify.outputs.error_type == 'transient' + env: + GH_TOKEN: ${{ github.token }} + run: | + echo "Retrying transient error..." + gh run rerun ${{ steps.info.outputs.run_id }} --failed || echo "Could not rerun" + + - name: Create Issue for Non-Transient Errors + if: steps.classify.outputs.error_type != 'transient' + env: + GH_TOKEN: ${{ github.token }} + run: | + WORKFLOW_NAME="${{ steps.info.outputs.workflow_name }}" + ERROR_TYPE="${{ steps.classify.outputs.error_type }}" + RUN_URL="${{ steps.info.outputs.run_url }}" + + EXISTING=$(gh issue list \ + --label "bug" \ + --search "in:title $WORKFLOW_NAME" \ + --state open \ + --json number \ + --jq '.[0].number' 2>/dev/null || echo "") + + if [ -n "$EXISTING" ] && [ "$EXISTING" != "null" ]; then + echo "Updating issue #$EXISTING" + gh issue comment $EXISTING --body "New failure: $RUN_URL (Type: $ERROR_TYPE)" + else + echo "Creating new issue" + gh issue create \ + --title "CI Failure: $WORKFLOW_NAME" \ + --body "Workflow failed. Run: $RUN_URL. Error type: $ERROR_TYPE" \ + --label "bug,ai-plan" || echo "Could not create issue" + fi diff --git a/.github/workflows/setup-labels.yml b/.github/workflows/setup-labels.yml index 213af278..0c3af823 100644 --- a/.github/workflows/setup-labels.yml +++ b/.github/workflows/setup-labels.yml @@ -14,60 +14,71 @@ jobs: create-labels: name: "🏷️ Create Git-Core Protocol Labels" runs-on: ubuntu-latest - + steps: - name: Create Dependency Lifecycle Labels env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | REPO="${{ github.repository }}" - + # Function to create or update label create_label() { local name="$1" local color="$2" local description="$3" - + # Try to create, if exists, update gh label create "$name" --color "$color" --description "$description" --repo "$REPO" 2>/dev/null || \ gh label edit "$name" --color "$color" --description "$description" --repo "$REPO" 2>/dev/null || \ echo "Label '$name' already exists with same config" } - + echo "🏷️ Creating Git-Core Protocol labels..." - + # Dependency Lifecycle Labels create_label "quarantine" "FFA500" "Dependency in 14-day quarantine period" create_label "ready-to-adopt" "28A745" "Dependency passed quarantine, ready for adoption" create_label "implementation-plan" "0366D6" "Implementation plan awaiting review" create_label "awaiting-review" "FBCA04" "Awaiting user review before proceeding" create_label "post-quarantine" "6F42C1" "Post-quarantine analysis in progress" - + # AI Agent Labels create_label "copilot" "0969DA" "Assigned to GitHub Copilot" create_label "copilot-implementing" "1D76DB" "Copilot is implementing changes" create_label "jules" "EA4335" "Assigned to Google Jules" create_label "ai-agent" "8250DF" "For AI agent auto-assignment" create_label "ai-review-requested" "C5DEF5" "AI code review requested" - + # Automation Labels create_label "auto-implementation" "FF6B6B" "Scheduled for automatic implementation" create_label "scheduled" "BFD4F2" "Scheduled automation task" create_label "living-context" "7057FF" "Part of Living Context Protocol" - + # Review Labels create_label "gemini-review" "4285F4" "Gemini Code Assist review" create_label "coderabbit" "FF69B4" "CodeRabbit review" create_label "codex-review" "9B59B6" "Codex AI review" - + # Status Labels create_label "in-progress" "0E8A16" "Work in progress" create_label "blocked" "D93F0B" "Blocked by dependency" create_label "needs-info" "FBCA04" "Needs more information" - + # Report Labels create_label "weekly-summary" "BFD4F2" "Weekly summary report" create_label "documentation" "0075CA" "Documentation update" create_label "e2e-report" "1D7DBA" "E2E test report" - + + # Protocol v3.0 Labels (Full Autonomy) + create_label "high-stakes" "D73A4A" "Requires human review - no auto-merge" + create_label "needs-human" "FF0000" "Guardian Agent escalated to human" + create_label "auto-merged" "28A745" "Merged by Guardian Agent" + create_label "ai-plan" "2EA44F" "AI planning/roadmap issue" + create_label "automation" "0052CC" "Automation related" + create_label "protocol" "5319E7" "Git-Core Protocol changes" + create_label "planner-generated" "7057FF" "Generated by Planner Agent" + + + echo "✅ All labels created/updated successfully!"