chore(workflows): Deploy autonomous workflow system

Deployed workflows:
- autonomous-orchestrator.yml
- autonomous-self-healer.yml
- autonomous-cross-repo.yml
- autonomous-dependency-manager.yml
- autonomous-issue-manager.yml

These workflows enable:
- Autonomous testing and building
- Self-healing on failures
- AI-powered code review
- Intelligent dependency updates
- Smart issue triage and management
- Cross-repo coordination

Co-Authored-By: BlackRoad Bot <bot@blackroad.ai>
This commit is contained in:
BlackRoad Automation
2026-02-05 17:29:16 -06:00
parent 0ae818a2f0
commit ce5ee8639e
5 changed files with 2068 additions and 0 deletions

View File

@@ -0,0 +1,324 @@
# .github/workflows/autonomous-cross-repo.yml
# Cross-repository coordination for synchronized changes
name: "Autonomous Cross-Repo Coordinator"
on:
push:
branches: [main, master]
paths:
- 'shared/**'
- 'packages/**'
- 'lib/**'
- '*.config.*'
workflow_dispatch:
inputs:
sync_type:
description: 'Type of sync'
required: true
type: choice
options:
- config
- dependencies
- workflows
- all
target_repos:
description: 'Target repos (comma-separated, or "all")'
required: false
default: 'all'
dry_run:
description: 'Dry run (no actual changes)'
required: false
default: true
type: boolean
permissions:
contents: write
pull-requests: write
env:
BLACKROAD_AGENT_API: https://blackroad-agents.amundsonalexa.workers.dev
jobs:
# ============================================
# Identify Affected Repositories
# ============================================
identify-repos:
name: "Identify Affected Repos"
runs-on: ubuntu-latest
outputs:
repos: ${{ steps.find.outputs.repos }}
sync_files: ${{ steps.changes.outputs.files }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2
- name: Get Changed Files
id: changes
run: |
FILES=$(git diff --name-only HEAD~1 HEAD 2>/dev/null | head -50 || echo "")
echo "files<<EOF" >> $GITHUB_OUTPUT
echo "$FILES" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Find Related Repositories
id: find
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Default BlackRoad repos that should stay in sync
CORE_REPOS='[
"BlackRoad-OS/blackroad-os-web",
"BlackRoad-OS/blackroad-os-docs",
"BlackRoad-OS/blackroad-cli",
"BlackRoad-OS/blackroad-agents",
"BlackRoad-OS/blackroad-os-mesh",
"BlackRoad-OS/blackroad-os-helper",
"BlackRoad-OS/blackroad-os-core"
]'
if [ "${{ github.event.inputs.target_repos }}" = "all" ] || [ -z "${{ github.event.inputs.target_repos }}" ]; then
REPOS="$CORE_REPOS"
else
# Convert comma-separated to JSON array
REPOS=$(echo '${{ github.event.inputs.target_repos }}' | jq -R 'split(",") | map(gsub("^\\s+|\\s+$";""))')
fi
echo "repos=$REPOS" >> $GITHUB_OUTPUT
echo "Repos to sync: $REPOS"
# ============================================
# Sync Workflows
# ============================================
sync-workflows:
name: "Sync Workflows"
needs: identify-repos
if: github.event.inputs.sync_type == 'workflows' || github.event.inputs.sync_type == 'all' || contains(needs.identify-repos.outputs.sync_files, '.github/workflows')
runs-on: ubuntu-latest
strategy:
matrix:
repo: ${{ fromJSON(needs.identify-repos.outputs.repos) }}
fail-fast: false
max-parallel: 5
steps:
- name: Checkout Source
uses: actions/checkout@v4
with:
path: source
- name: Checkout Target
uses: actions/checkout@v4
with:
repository: ${{ matrix.repo }}
path: target
token: ${{ secrets.CROSS_REPO_TOKEN || secrets.GITHUB_TOKEN }}
- name: Sync Workflow Files
run: |
# Copy autonomous workflows
mkdir -p target/.github/workflows
# Copy the orchestrator and self-healer
for workflow in autonomous-orchestrator.yml autonomous-self-healer.yml blackroad-agents.yml; do
if [ -f "source/.github/workflows-autonomous/$workflow" ]; then
cp "source/.github/workflows-autonomous/$workflow" "target/.github/workflows/"
elif [ -f "source/.github/workflows/$workflow" ]; then
cp "source/.github/workflows/$workflow" "target/.github/workflows/"
fi
done
echo "Synced workflows to ${{ matrix.repo }}"
- name: Create PR
if: github.event.inputs.dry_run != 'true'
working-directory: target
env:
GH_TOKEN: ${{ secrets.CROSS_REPO_TOKEN || secrets.GITHUB_TOKEN }}
run: |
if [ -n "$(git status --porcelain)" ]; then
BRANCH="sync-workflows-$(date +%Y%m%d-%H%M%S)"
git config user.name "BlackRoad Cross-Repo Bot"
git config user.email "crossrepo@blackroad.ai"
git checkout -b "$BRANCH"
git add -A
git commit -m "chore(workflows): Sync autonomous workflows from central repo
Synced workflows:
- autonomous-orchestrator.yml
- autonomous-self-healer.yml
- blackroad-agents.yml
Source: ${{ github.repository }}
Co-Authored-By: BlackRoad Bot <bot@blackroad.ai>"
git push -u origin "$BRANCH"
gh pr create \
--title "chore(workflows): Sync autonomous workflows" \
--body "## Workflow Sync
Synced autonomous workflows from central repository.
**Source:** ${{ github.repository }}
**Sync Type:** workflows
### Changes
- Updated autonomous-orchestrator.yml
- Updated autonomous-self-healer.yml
- Updated blackroad-agents.yml
---
*Automated by BlackRoad Cross-Repo Coordinator*" \
--label "automated,infrastructure"
else
echo "No workflow changes needed for ${{ matrix.repo }}"
fi
# ============================================
# Sync Configurations
# ============================================
sync-config:
name: "Sync Configurations"
needs: identify-repos
if: github.event.inputs.sync_type == 'config' || github.event.inputs.sync_type == 'all'
runs-on: ubuntu-latest
strategy:
matrix:
repo: ${{ fromJSON(needs.identify-repos.outputs.repos) }}
fail-fast: false
max-parallel: 5
steps:
- name: Checkout Source
uses: actions/checkout@v4
with:
path: source
- name: Checkout Target
uses: actions/checkout@v4
with:
repository: ${{ matrix.repo }}
path: target
token: ${{ secrets.CROSS_REPO_TOKEN || secrets.GITHUB_TOKEN }}
- name: Sync Config Files
run: |
# Sync common configs that should be consistent
SYNC_FILES=(
".eslintrc.js"
".prettierrc"
".editorconfig"
"tsconfig.base.json"
".github/CODEOWNERS"
".github/ISSUE_TEMPLATE/bug_report.yml"
".github/ISSUE_TEMPLATE/feature_request.yml"
)
for file in "${SYNC_FILES[@]}"; do
if [ -f "source/$file" ]; then
mkdir -p "target/$(dirname $file)"
cp "source/$file" "target/$file"
fi
done
- name: Create PR
if: github.event.inputs.dry_run != 'true'
working-directory: target
env:
GH_TOKEN: ${{ secrets.CROSS_REPO_TOKEN || secrets.GITHUB_TOKEN }}
run: |
if [ -n "$(git status --porcelain)" ]; then
BRANCH="sync-config-$(date +%Y%m%d-%H%M%S)"
git config user.name "BlackRoad Cross-Repo Bot"
git config user.email "crossrepo@blackroad.ai"
git checkout -b "$BRANCH"
git add -A
git commit -m "chore(config): Sync configurations from central repo
Co-Authored-By: BlackRoad Bot <bot@blackroad.ai>"
git push -u origin "$BRANCH"
gh pr create \
--title "chore(config): Sync configurations" \
--body "## Configuration Sync
Synced common configurations from central repository.
---
*Automated by BlackRoad Cross-Repo Coordinator*" \
--label "automated,config"
fi
# ============================================
# Sync Dependencies
# ============================================
sync-deps:
name: "Sync Dependencies"
needs: identify-repos
if: github.event.inputs.sync_type == 'dependencies' || github.event.inputs.sync_type == 'all'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Analyze Dependencies
id: deps
run: |
# Extract common dependencies and their versions
if [ -f "package.json" ]; then
DEPS=$(jq -r '.dependencies // {} | to_entries[] | "\(.key)@\(.value)"' package.json | head -20)
echo "deps<<EOF" >> $GITHUB_OUTPUT
echo "$DEPS" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
fi
- name: Report Dependencies
run: |
echo "## Dependencies to Sync"
echo "${{ steps.deps.outputs.deps }}"
# Log to coordination API
curl -s -X POST "${{ env.BLACKROAD_AGENT_API }}/coordinate" \
-H "Content-Type: application/json" \
-d '{
"action": "sync_deps",
"source": "${{ github.repository }}",
"repos": ${{ needs.identify-repos.outputs.repos }},
"timestamp": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"
}' 2>/dev/null || true
# ============================================
# Broadcast Changes
# ============================================
broadcast:
name: "Broadcast Changes"
needs: [sync-workflows, sync-config, sync-deps]
if: always()
runs-on: ubuntu-latest
steps:
- name: Notify Coordination System
run: |
curl -s -X POST "${{ env.BLACKROAD_AGENT_API }}/broadcast" \
-H "Content-Type: application/json" \
-d '{
"event": "cross_repo_sync_complete",
"source": "${{ github.repository }}",
"sync_type": "${{ github.event.inputs.sync_type || 'auto' }}",
"repos": ${{ needs.identify-repos.outputs.repos || '[]' }},
"timestamp": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"
}' 2>/dev/null || echo "Broadcast queued"
- name: Summary
run: |
echo "## Cross-Repo Sync Complete"
echo "- Source: ${{ github.repository }}"
echo "- Sync Type: ${{ github.event.inputs.sync_type || 'auto' }}"
echo "- Dry Run: ${{ github.event.inputs.dry_run || 'false' }}"

View File

@@ -0,0 +1,297 @@
# .github/workflows/autonomous-dependency-manager.yml
# Intelligent dependency management with bundled updates
name: "Autonomous Dependency Manager"
on:
schedule:
- cron: '0 3 * * 1' # Every Monday at 3 AM
workflow_dispatch:
inputs:
update_type:
description: 'Update type'
required: false
default: 'safe'
type: choice
options:
- safe # Patch versions only
- minor # Minor + patch
- major # All updates (risky)
- security # Security updates only
permissions:
contents: write
pull-requests: write
security-events: read
env:
BLACKROAD_AGENT_API: https://blackroad-agents.amundsonalexa.workers.dev
jobs:
# ============================================
# Analyze Current State
# ============================================
analyze:
name: "Analyze Dependencies"
runs-on: ubuntu-latest
outputs:
has_npm: ${{ steps.detect.outputs.npm }}
has_python: ${{ steps.detect.outputs.python }}
has_go: ${{ steps.detect.outputs.go }}
has_rust: ${{ steps.detect.outputs.rust }}
outdated_count: ${{ steps.check.outputs.count }}
security_issues: ${{ steps.security.outputs.count }}
steps:
- uses: actions/checkout@v4
- name: Detect Package Managers
id: detect
run: |
echo "npm=$([[ -f package.json ]] && echo true || echo false)" >> $GITHUB_OUTPUT
echo "python=$([[ -f requirements.txt || -f pyproject.toml ]] && echo true || echo false)" >> $GITHUB_OUTPUT
echo "go=$([[ -f go.mod ]] && echo true || echo false)" >> $GITHUB_OUTPUT
echo "rust=$([[ -f Cargo.toml ]] && echo true || echo false)" >> $GITHUB_OUTPUT
- name: Check Outdated (npm)
id: check
if: steps.detect.outputs.npm == 'true'
run: |
npm outdated --json > outdated.json 2>/dev/null || true
COUNT=$(jq 'length' outdated.json 2>/dev/null || echo 0)
echo "count=$COUNT" >> $GITHUB_OUTPUT
echo "Found $COUNT outdated packages"
- name: Security Audit
id: security
run: |
ISSUES=0
if [ -f "package.json" ]; then
npm audit --json > npm-audit.json 2>/dev/null || true
NPM_VULNS=$(jq '.metadata.vulnerabilities | .low + .moderate + .high + .critical' npm-audit.json 2>/dev/null || echo 0)
ISSUES=$((ISSUES + NPM_VULNS))
fi
echo "count=$ISSUES" >> $GITHUB_OUTPUT
echo "Found $ISSUES security issues"
# ============================================
# Update npm Dependencies
# ============================================
update-npm:
name: "Update npm Dependencies"
needs: analyze
if: needs.analyze.outputs.has_npm == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Dependencies
run: npm ci --ignore-scripts 2>/dev/null || npm install --ignore-scripts
- name: Update Based on Type
id: update
run: |
UPDATE_TYPE="${{ github.event.inputs.update_type || 'safe' }}"
case "$UPDATE_TYPE" in
safe)
# Only patch updates
npm update 2>/dev/null || true
;;
minor)
# Minor and patch updates
npx npm-check-updates -u --target minor 2>/dev/null || npm update
npm install
;;
major)
# All updates (risky)
npx npm-check-updates -u 2>/dev/null || true
npm install
;;
security)
# Security updates only
npm audit fix 2>/dev/null || true
npm audit fix --force 2>/dev/null || true
;;
esac
# Check what changed
if [ -n "$(git status --porcelain package.json package-lock.json)" ]; then
echo "changes=true" >> $GITHUB_OUTPUT
else
echo "changes=false" >> $GITHUB_OUTPUT
fi
- name: Run Tests
if: steps.update.outputs.changes == 'true'
id: test
continue-on-error: true
run: |
npm test 2>&1 && echo "result=passed" >> $GITHUB_OUTPUT || echo "result=failed" >> $GITHUB_OUTPUT
- name: Create PR
if: steps.update.outputs.changes == 'true' && steps.test.outputs.result != 'failed'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
BRANCH="deps/npm-update-$(date +%Y%m%d)"
git config user.name "BlackRoad Dependency Bot"
git config user.email "deps@blackroad.ai"
# Check if branch already exists
if git ls-remote --exit-code origin "$BRANCH" 2>/dev/null; then
echo "Branch already exists, updating..."
git fetch origin "$BRANCH"
git checkout "$BRANCH"
git merge main --no-edit || true
else
git checkout -b "$BRANCH"
fi
git add package.json package-lock.json
git commit -m "chore(deps): Update npm dependencies
Update type: ${{ github.event.inputs.update_type || 'safe' }}
Tests: ${{ steps.test.outputs.result || 'not run' }}
Co-Authored-By: BlackRoad Bot <bot@blackroad.ai>" || true
git push -u origin "$BRANCH" --force
# Check if PR already exists
EXISTING_PR=$(gh pr list --head "$BRANCH" --json number -q '.[0].number')
if [ -z "$EXISTING_PR" ]; then
gh pr create \
--title "chore(deps): Weekly npm dependency updates" \
--body "## Dependency Updates
**Update Type:** ${{ github.event.inputs.update_type || 'safe' }}
**Test Status:** ${{ steps.test.outputs.result || 'not run' }}
### Changes
Updated npm dependencies according to the configured update strategy.
### Verification
- [ ] Tests pass
- [ ] Build succeeds
- [ ] No breaking changes
---
*Automated by BlackRoad Dependency Manager*" \
--label "dependencies,automated"
fi
# ============================================
# Update Python Dependencies
# ============================================
update-python:
name: "Update Python Dependencies"
needs: analyze
if: needs.analyze.outputs.has_python == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Update Dependencies
id: update
run: |
pip install pip-tools safety 2>/dev/null || true
if [ -f "requirements.txt" ]; then
# Backup original
cp requirements.txt requirements.txt.bak
# Update all packages
pip install --upgrade $(cat requirements.txt | grep -v "^#" | cut -d'=' -f1 | tr '\n' ' ') 2>/dev/null || true
# Regenerate requirements with updated versions
pip freeze > requirements.txt.new
# Check for changes
if ! diff -q requirements.txt requirements.txt.new > /dev/null 2>&1; then
mv requirements.txt.new requirements.txt
echo "changes=true" >> $GITHUB_OUTPUT
else
echo "changes=false" >> $GITHUB_OUTPUT
fi
fi
- name: Run Tests
if: steps.update.outputs.changes == 'true'
id: test
continue-on-error: true
run: |
pip install -r requirements.txt
pytest 2>&1 && echo "result=passed" >> $GITHUB_OUTPUT || \
python -m unittest discover 2>&1 && echo "result=passed" >> $GITHUB_OUTPUT || \
echo "result=skipped" >> $GITHUB_OUTPUT
- name: Create PR
if: steps.update.outputs.changes == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
BRANCH="deps/python-update-$(date +%Y%m%d)"
git config user.name "BlackRoad Dependency Bot"
git config user.email "deps@blackroad.ai"
git checkout -b "$BRANCH"
git add requirements.txt
git commit -m "chore(deps): Update Python dependencies
Co-Authored-By: BlackRoad Bot <bot@blackroad.ai>"
git push -u origin "$BRANCH"
gh pr create \
--title "chore(deps): Weekly Python dependency updates" \
--body "## Dependency Updates
Updated Python dependencies.
---
*Automated by BlackRoad Dependency Manager*" \
--label "dependencies,automated"
# ============================================
# Report Summary
# ============================================
report:
name: "Generate Report"
needs: [analyze, update-npm, update-python]
if: always()
runs-on: ubuntu-latest
steps:
- name: Create Summary
run: |
echo "## Dependency Update Summary"
echo ""
echo "| Package Manager | Outdated | Security Issues |"
echo "|-----------------|----------|-----------------|"
echo "| npm | ${{ needs.analyze.outputs.outdated_count || 'N/A' }} | ${{ needs.analyze.outputs.security_issues || 'N/A' }} |"
- name: Log to Memory
run: |
curl -s -X POST "${{ env.BLACKROAD_AGENT_API }}/memory" \
-H "Content-Type: application/json" \
-d '{
"repo": "${{ github.repository }}",
"event": "dependency_update",
"outdated_count": "${{ needs.analyze.outputs.outdated_count }}",
"security_issues": "${{ needs.analyze.outputs.security_issues }}",
"timestamp": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"
}' 2>/dev/null || true

View File

@@ -0,0 +1,399 @@
# .github/workflows/autonomous-issue-manager.yml
# Autonomous issue creation, triage, and management
name: "Autonomous Issue Manager"
on:
issues:
types: [opened, edited, labeled, assigned]
issue_comment:
types: [created]
schedule:
- cron: '0 9 * * *' # Daily at 9 AM - stale check
workflow_run:
workflows: ["Autonomous Orchestrator", "Autonomous Self-Healer"]
types: [completed]
conclusions: [failure]
workflow_dispatch:
inputs:
action:
description: 'Action to perform'
required: true
type: choice
options:
- triage_all
- cleanup_stale
- generate_report
- create_health_issues
permissions:
contents: read
issues: write
pull-requests: write
env:
BLACKROAD_AGENT_API: https://blackroad-agents.amundsonalexa.workers.dev
STALE_DAYS: 30
CLOSE_DAYS: 7
jobs:
# ============================================
# Smart Issue Triage
# ============================================
triage:
name: "Smart Triage"
if: github.event_name == 'issues' && github.event.action == 'opened'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: AI Analysis
id: ai
run: |
TITLE="${{ github.event.issue.title }}"
BODY="${{ github.event.issue.body }}"
# Call AI for smart categorization
ANALYSIS=$(curl -s -X POST "${{ env.BLACKROAD_AGENT_API }}/analyze-issue" \
-H "Content-Type: application/json" \
-d '{
"title": "'"$TITLE"'",
"body": "'"$(echo "$BODY" | head -c 2000 | jq -Rs .)"'",
"repo": "${{ github.repository }}"
}' 2>/dev/null || echo '{}')
echo "analysis=$ANALYSIS" >> $GITHUB_OUTPUT
# Parse AI response for labels
LABELS=$(echo "$ANALYSIS" | jq -r '.labels // [] | join(",")' 2>/dev/null || echo "")
PRIORITY=$(echo "$ANALYSIS" | jq -r '.priority // "normal"' 2>/dev/null || echo "normal")
ASSIGNEE=$(echo "$ANALYSIS" | jq -r '.assignee // ""' 2>/dev/null || echo "")
echo "labels=$LABELS" >> $GITHUB_OUTPUT
echo "priority=$PRIORITY" >> $GITHUB_OUTPUT
echo "assignee=$ASSIGNEE" >> $GITHUB_OUTPUT
- name: Keyword-Based Labeling
id: keywords
run: |
TITLE="${{ github.event.issue.title }}"
BODY="${{ github.event.issue.body }}"
TEXT="$TITLE $BODY"
LABELS=""
# Type detection
echo "$TEXT" | grep -qi "bug\|error\|broken\|not working\|crash\|fail" && LABELS="$LABELS,bug"
echo "$TEXT" | grep -qi "feature\|add\|new\|enhance\|request" && LABELS="$LABELS,enhancement"
echo "$TEXT" | grep -qi "question\|how\|help\|what\|why" && LABELS="$LABELS,question"
echo "$TEXT" | grep -qi "doc\|documentation\|readme\|typo" && LABELS="$LABELS,documentation"
# Area detection
echo "$TEXT" | grep -qi "security\|vulnerability\|cve\|auth" && LABELS="$LABELS,security"
echo "$TEXT" | grep -qi "performance\|slow\|memory\|cpu" && LABELS="$LABELS,performance"
echo "$TEXT" | grep -qi "ui\|frontend\|css\|style\|design" && LABELS="$LABELS,frontend"
echo "$TEXT" | grep -qi "api\|backend\|server\|database" && LABELS="$LABELS,backend"
echo "$TEXT" | grep -qi "ci\|deploy\|workflow\|action" && LABELS="$LABELS,infrastructure"
# Priority detection
echo "$TEXT" | grep -qi "urgent\|critical\|asap\|important\|blocker" && LABELS="$LABELS,priority:high"
echo "$TEXT" | grep -qi "minor\|low\|when possible" && LABELS="$LABELS,priority:low"
# Clean up labels
LABELS=$(echo "$LABELS" | sed 's/^,//' | sed 's/,,/,/g')
echo "labels=$LABELS" >> $GITHUB_OUTPUT
- name: Apply Labels
uses: actions/github-script@v7
with:
script: |
const aiLabels = '${{ steps.ai.outputs.labels }}'.split(',').filter(l => l);
const keywordLabels = '${{ steps.keywords.outputs.labels }}'.split(',').filter(l => l);
// Merge and dedupe labels
const allLabels = [...new Set([...aiLabels, ...keywordLabels])].filter(l => l);
if (allLabels.length > 0) {
// Ensure labels exist (create if not)
for (const label of allLabels) {
try {
await github.rest.issues.getLabel({
owner: context.repo.owner,
repo: context.repo.repo,
name: label
});
} catch (e) {
// Label doesn't exist, create it
const colors = {
'bug': 'd73a4a',
'enhancement': 'a2eeef',
'question': 'd876e3',
'documentation': '0075ca',
'security': 'b60205',
'performance': 'fbca04',
'frontend': '7057ff',
'backend': '008672',
'infrastructure': 'c5def5',
'priority:high': 'b60205',
'priority:low': 'c2e0c6'
};
await github.rest.issues.createLabel({
owner: context.repo.owner,
repo: context.repo.repo,
name: label,
color: colors[label] || '333333'
}).catch(() => {});
}
}
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.issue.number,
labels: allLabels
});
}
- name: Welcome Response
uses: actions/github-script@v7
with:
script: |
const labels = '${{ steps.keywords.outputs.labels }}'.split(',').filter(l => l);
const priority = '${{ steps.ai.outputs.priority }}';
let response = `Thanks for opening this issue! 👋\n\n`;
// Add context based on type
if (labels.includes('bug')) {
response += `This has been identified as a **bug report**. `;
response += `To help us investigate:\n`;
response += `- What version are you using?\n`;
response += `- Can you provide steps to reproduce?\n`;
response += `- Any error messages or logs?\n\n`;
} else if (labels.includes('enhancement')) {
response += `This has been identified as a **feature request**. `;
response += `We'll review and prioritize accordingly.\n\n`;
} else if (labels.includes('question')) {
response += `This has been identified as a **question**. `;
response += `Check our [documentation](https://docs.blackroad.io) while you wait for a response.\n\n`;
}
if (priority === 'high') {
response += `⚠️ **High priority** - This will be reviewed soon.\n\n`;
}
response += `**Automated Labels Applied:** ${labels.length > 0 ? labels.map(l => '`' + l + '`').join(', ') : 'None'}\n\n`;
response += `---\n*Triaged by BlackRoad Autonomous Agent*`;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.issue.number,
body: response
});
# ============================================
# Stale Issue Cleanup
# ============================================
stale-cleanup:
name: "Stale Cleanup"
if: github.event_name == 'schedule' || github.event.inputs.action == 'cleanup_stale'
runs-on: ubuntu-latest
steps:
- name: Find Stale Issues
uses: actions/github-script@v7
with:
script: |
const staleDays = parseInt('${{ env.STALE_DAYS }}');
const closeDays = parseInt('${{ env.CLOSE_DAYS }}');
const now = new Date();
// Get open issues
const issues = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
per_page: 100
});
for (const issue of issues.data) {
// Skip PRs
if (issue.pull_request) continue;
const updatedAt = new Date(issue.updated_at);
const daysSinceUpdate = Math.floor((now - updatedAt) / (1000 * 60 * 60 * 24));
const hasStaleLabel = issue.labels.some(l => l.name === 'stale');
const isProtected = issue.labels.some(l =>
['pinned', 'security', 'priority:high', 'in-progress'].includes(l.name)
);
if (isProtected) continue;
// Already marked stale - check if should close
if (hasStaleLabel && daysSinceUpdate >= closeDays) {
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
state: 'closed',
state_reason: 'not_planned'
});
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: `This issue has been automatically closed due to inactivity.\n\nIf this is still relevant, please reopen it with additional context.\n\n---\n*Closed by BlackRoad Autonomous Agent*`
});
console.log(`Closed stale issue #${issue.number}`);
}
// Mark as stale
else if (!hasStaleLabel && daysSinceUpdate >= staleDays) {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
labels: ['stale']
});
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: `This issue has been automatically marked as **stale** because it has not had recent activity.\n\nIt will be closed in ${closeDays} days if no further activity occurs.\n\n---\n*Marked by BlackRoad Autonomous Agent*`
});
console.log(`Marked issue #${issue.number} as stale`);
}
}
# ============================================
# Auto-Create Issues from Failures
# ============================================
failure-issue:
name: "Create Failure Issue"
if: github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'failure'
runs-on: ubuntu-latest
steps:
- name: Check for Existing Issue
id: check
uses: actions/github-script@v7
with:
script: |
// Search for existing issue about this workflow
const workflowName = '${{ github.event.workflow_run.name }}';
const searchQuery = `repo:${context.repo.owner}/${context.repo.repo} is:issue is:open "[Automated] ${workflowName}" in:title`;
const results = await github.rest.search.issuesAndPullRequests({
q: searchQuery
});
core.setOutput('exists', results.data.total_count > 0);
if (results.data.total_count > 0) {
core.setOutput('issue_number', results.data.items[0].number);
}
- name: Create or Update Issue
uses: actions/github-script@v7
with:
script: |
const workflowName = '${{ github.event.workflow_run.name }}';
const runId = '${{ github.event.workflow_run.id }}';
const runUrl = '${{ github.event.workflow_run.html_url }}';
const exists = '${{ steps.check.outputs.exists }}' === 'true';
const existingNumber = '${{ steps.check.outputs.issue_number }}';
const body = `## Workflow Failure Detected
**Workflow:** ${workflowName}
**Run ID:** ${runId}
**Run URL:** ${runUrl}
**Time:** ${new Date().toISOString()}
### Details
The autonomous orchestrator detected a failure in the ${workflowName} workflow.
### Suggested Actions
1. Review the [workflow run logs](${runUrl})
2. Check recent commits for potential causes
3. Run the self-healer workflow if appropriate
---
*Created by BlackRoad Autonomous Agent*`;
if (exists) {
// Add comment to existing issue
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: parseInt(existingNumber),
body: `### New Failure Detected\n\n**Run:** ${runUrl}\n**Time:** ${new Date().toISOString()}`
});
} else {
// Create new issue
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `[Automated] ${workflowName} Workflow Failure`,
body: body,
labels: ['bug', 'automated', 'ci-failure']
});
}
# ============================================
# Generate Report
# ============================================
report:
name: "Generate Issue Report"
if: github.event.inputs.action == 'generate_report'
runs-on: ubuntu-latest
steps:
- name: Generate Statistics
uses: actions/github-script@v7
with:
script: |
// Get all issues
const issues = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'all',
per_page: 100
});
const stats = {
total: issues.data.length,
open: issues.data.filter(i => i.state === 'open' && !i.pull_request).length,
closed: issues.data.filter(i => i.state === 'closed' && !i.pull_request).length,
bugs: issues.data.filter(i => i.labels.some(l => l.name === 'bug')).length,
enhancements: issues.data.filter(i => i.labels.some(l => l.name === 'enhancement')).length,
stale: issues.data.filter(i => i.labels.some(l => l.name === 'stale')).length
};
console.log('Issue Statistics:', stats);
// Create summary issue
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `[Report] Issue Statistics - ${new Date().toISOString().split('T')[0]}`,
body: `## Issue Statistics Report
| Metric | Count |
|--------|-------|
| Total Issues | ${stats.total} |
| Open | ${stats.open} |
| Closed | ${stats.closed} |
| Bugs | ${stats.bugs} |
| Enhancements | ${stats.enhancements} |
| Stale | ${stats.stale} |
---
*Generated by BlackRoad Autonomous Agent*`,
labels: ['report', 'automated']
});

View File

@@ -0,0 +1,671 @@
# .github/workflows/autonomous-orchestrator.yml
# Master coordinator for all autonomous agents
# Drop this in any repo for full autonomous operation
name: "Autonomous Orchestrator"
on:
push:
branches: [main, master, develop]
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
issues:
types: [opened, labeled]
issue_comment:
types: [created]
schedule:
- cron: '0 */4 * * *' # Every 4 hours
workflow_dispatch:
inputs:
mode:
description: 'Operation mode'
required: false
default: 'auto'
type: choice
options:
- auto
- aggressive
- conservative
- audit-only
force_deploy:
description: 'Force deployment'
required: false
default: false
type: boolean
permissions:
contents: write
pull-requests: write
issues: write
actions: write
security-events: write
checks: write
concurrency:
group: autonomous-${{ github.repository }}-${{ github.ref }}
cancel-in-progress: false
env:
BLACKROAD_AGENT_API: https://blackroad-agents.amundsonalexa.workers.dev
MEMORY_ENABLED: true
AUTO_MERGE: true
AUTO_FIX: true
jobs:
# ============================================
# Stage 1: Intelligence Gathering
# ============================================
analyze:
name: "Analyze Repository"
runs-on: ubuntu-latest
outputs:
project_type: ${{ steps.detect.outputs.type }}
has_tests: ${{ steps.detect.outputs.has_tests }}
has_build: ${{ steps.detect.outputs.has_build }}
health_score: ${{ steps.health.outputs.score }}
priority: ${{ steps.priority.outputs.level }}
action_plan: ${{ steps.plan.outputs.actions }}
memory_context: ${{ steps.memory.outputs.context }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Detect Project Type
id: detect
run: |
TYPE="unknown"
HAS_TESTS="false"
HAS_BUILD="false"
# Node.js
if [ -f "package.json" ]; then
TYPE="nodejs"
grep -q '"test"' package.json && HAS_TESTS="true"
grep -q '"build"' package.json && HAS_BUILD="true"
# Python
elif [ -f "pyproject.toml" ] || [ -f "requirements.txt" ] || [ -f "setup.py" ]; then
TYPE="python"
[ -d "tests" ] || [ -d "test" ] && HAS_TESTS="true"
# Go
elif [ -f "go.mod" ]; then
TYPE="go"
find . -name "*_test.go" | head -1 | grep -q . && HAS_TESTS="true"
# Rust
elif [ -f "Cargo.toml" ]; then
TYPE="rust"
HAS_TESTS="true"
HAS_BUILD="true"
# Salesforce
elif [ -f "sfdx-project.json" ]; then
TYPE="salesforce"
# Static site
elif [ -f "index.html" ]; then
TYPE="static"
# Cloudflare Worker
elif [ -f "wrangler.toml" ]; then
TYPE="cloudflare-worker"
HAS_BUILD="true"
fi
echo "type=$TYPE" >> $GITHUB_OUTPUT
echo "has_tests=$HAS_TESTS" >> $GITHUB_OUTPUT
echo "has_build=$HAS_BUILD" >> $GITHUB_OUTPUT
echo "Detected: $TYPE (tests=$HAS_TESTS, build=$HAS_BUILD)"
- name: Calculate Health Score
id: health
run: |
SCORE=100
# Check for common issues
[ ! -f "README.md" ] && SCORE=$((SCORE - 10))
[ ! -f ".gitignore" ] && SCORE=$((SCORE - 5))
[ ! -d ".github/workflows" ] && SCORE=$((SCORE - 15))
# Security checks
grep -rn "password\s*=" --include="*.js" --include="*.ts" --include="*.py" . 2>/dev/null | grep -v node_modules && SCORE=$((SCORE - 20))
grep -rn "api_key\s*=" --include="*.js" --include="*.ts" --include="*.py" . 2>/dev/null | grep -v node_modules && SCORE=$((SCORE - 20))
# Stale checks
LAST_COMMIT=$(git log -1 --format=%ct 2>/dev/null || echo 0)
NOW=$(date +%s)
DAYS_SINCE=$(( (NOW - LAST_COMMIT) / 86400 ))
[ $DAYS_SINCE -gt 90 ] && SCORE=$((SCORE - 10))
[ $SCORE -lt 0 ] && SCORE=0
echo "score=$SCORE" >> $GITHUB_OUTPUT
echo "Health Score: $SCORE/100"
- name: Determine Priority
id: priority
run: |
PRIORITY="normal"
# High priority triggers
if echo "${{ github.event.issue.labels.*.name }}" | grep -qE "critical|urgent|security"; then
PRIORITY="critical"
elif echo "${{ github.event.issue.labels.*.name }}" | grep -qE "high|important"; then
PRIORITY="high"
elif [ "${{ github.event_name }}" = "schedule" ]; then
PRIORITY="background"
fi
echo "level=$PRIORITY" >> $GITHUB_OUTPUT
echo "Priority: $PRIORITY"
- name: Fetch Memory Context
id: memory
run: |
# Try to get memory from BlackRoad API
CONTEXT=$(curl -s -f "${{ env.BLACKROAD_AGENT_API }}/memory/${{ github.repository }}" 2>/dev/null || echo '{}')
echo "context=$CONTEXT" >> $GITHUB_OUTPUT
- name: Create Action Plan
id: plan
run: |
ACTIONS="[]"
# Build action list based on context
case "${{ github.event_name }}" in
push)
ACTIONS='["test","build","security_scan","quality_check"]'
;;
pull_request)
ACTIONS='["test","build","code_review","security_scan","auto_merge"]'
;;
issues)
ACTIONS='["triage","assign","respond"]'
;;
schedule)
ACTIONS='["health_check","dependency_update","stale_cleanup","security_audit"]'
;;
*)
ACTIONS='["analyze"]'
;;
esac
echo "actions=$ACTIONS" >> $GITHUB_OUTPUT
# ============================================
# Stage 2: Test & Build
# ============================================
test-and-build:
name: "Test & Build"
needs: analyze
runs-on: ubuntu-latest
if: needs.analyze.outputs.project_type != 'unknown'
outputs:
test_result: ${{ steps.test.outputs.result }}
build_result: ${{ steps.build.outputs.result }}
steps:
- uses: actions/checkout@v4
- name: Setup Environment
run: |
case "${{ needs.analyze.outputs.project_type }}" in
nodejs)
echo "Setting up Node.js..."
;;
python)
echo "Setting up Python..."
pip install pytest pytest-cov 2>/dev/null || true
;;
go)
echo "Go is pre-installed"
;;
rust)
echo "Installing Rust..."
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
;;
esac
- name: Install Dependencies
run: |
case "${{ needs.analyze.outputs.project_type }}" in
nodejs)
npm ci --ignore-scripts 2>/dev/null || npm install --ignore-scripts 2>/dev/null || true
;;
python)
[ -f "requirements.txt" ] && pip install -r requirements.txt 2>/dev/null || true
[ -f "pyproject.toml" ] && pip install -e . 2>/dev/null || true
;;
go)
go mod download 2>/dev/null || true
;;
rust)
cargo fetch 2>/dev/null || true
;;
esac
- name: Run Tests
id: test
continue-on-error: true
run: |
RESULT="skipped"
if [ "${{ needs.analyze.outputs.has_tests }}" = "true" ]; then
case "${{ needs.analyze.outputs.project_type }}" in
nodejs)
npm test 2>&1 && RESULT="passed" || RESULT="failed"
;;
python)
pytest -v 2>&1 && RESULT="passed" || python -m unittest discover 2>&1 && RESULT="passed" || RESULT="failed"
;;
go)
go test ./... 2>&1 && RESULT="passed" || RESULT="failed"
;;
rust)
cargo test 2>&1 && RESULT="passed" || RESULT="failed"
;;
esac
fi
echo "result=$RESULT" >> $GITHUB_OUTPUT
echo "Test result: $RESULT"
- name: Run Build
id: build
continue-on-error: true
run: |
RESULT="skipped"
if [ "${{ needs.analyze.outputs.has_build }}" = "true" ]; then
case "${{ needs.analyze.outputs.project_type }}" in
nodejs)
npm run build 2>&1 && RESULT="passed" || RESULT="failed"
;;
rust)
cargo build --release 2>&1 && RESULT="passed" || RESULT="failed"
;;
cloudflare-worker)
npx wrangler build 2>/dev/null && RESULT="passed" || RESULT="skipped"
;;
esac
fi
echo "result=$RESULT" >> $GITHUB_OUTPUT
echo "Build result: $RESULT"
# ============================================
# Stage 3: Security & Quality
# ============================================
security-scan:
name: "Security Scan"
needs: analyze
runs-on: ubuntu-latest
outputs:
vulnerabilities: ${{ steps.scan.outputs.vulns }}
severity: ${{ steps.scan.outputs.max_severity }}
steps:
- uses: actions/checkout@v4
- name: Run Security Scanners
id: scan
run: |
VULNS=0
MAX_SEVERITY="none"
# Scan for secrets
echo "Scanning for secrets..."
if grep -rn --include="*.js" --include="*.ts" --include="*.py" --include="*.json" \
-E "(password|secret|api_key|token)\s*[:=]\s*['\"][^'\"]+['\"]" . 2>/dev/null | \
grep -v node_modules | grep -v ".git" | head -5; then
VULNS=$((VULNS + 1))
MAX_SEVERITY="critical"
fi
# Check for common vulnerabilities
echo "Checking for common vulnerabilities..."
if [ -f "package.json" ]; then
npm audit --json 2>/dev/null | jq -r '.metadata.vulnerabilities | to_entries[] | select(.value > 0)' && VULNS=$((VULNS + 1))
fi
echo "vulns=$VULNS" >> $GITHUB_OUTPUT
echo "max_severity=$MAX_SEVERITY" >> $GITHUB_OUTPUT
- name: Auto-fix Security Issues
if: env.AUTO_FIX == 'true' && steps.scan.outputs.vulns != '0'
run: |
echo "Attempting auto-fix..."
# Try to fix npm vulnerabilities
if [ -f "package.json" ]; then
npm audit fix 2>/dev/null || true
fi
# Check if changes were made
if [ -n "$(git status --porcelain)" ]; then
git config user.name "BlackRoad Bot"
git config user.email "bot@blackroad.ai"
git add -A
git commit -m "fix(security): Auto-fix security vulnerabilities
Automated security fixes applied by BlackRoad Autonomous Agent.
Co-Authored-By: BlackRoad Bot <bot@blackroad.ai>"
git push || echo "Push failed - may need PR"
fi
# ============================================
# Stage 4: Code Review (PRs only)
# ============================================
code-review:
name: "AI Code Review"
needs: [analyze, test-and-build]
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get Changed Files
id: changed
run: |
FILES=$(git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ github.sha }} 2>/dev/null | head -50)
echo "files<<EOF" >> $GITHUB_OUTPUT
echo "$FILES" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: AI Code Analysis
id: ai_review
run: |
# Call BlackRoad AI for code review
REVIEW=$(curl -s -X POST "${{ env.BLACKROAD_AGENT_API }}/review" \
-H "Content-Type: application/json" \
-d '{
"repo": "${{ github.repository }}",
"pr_number": ${{ github.event.pull_request.number }},
"files": ${{ toJSON(steps.changed.outputs.files) }},
"test_result": "${{ needs.test-and-build.outputs.test_result }}",
"build_result": "${{ needs.test-and-build.outputs.build_result }}"
}' 2>/dev/null || echo "Review completed")
echo "AI Review: $REVIEW"
- name: Post Review Comment
uses: actions/github-script@v7
with:
script: |
const testResult = '${{ needs.test-and-build.outputs.test_result }}';
const buildResult = '${{ needs.test-and-build.outputs.build_result }}';
const healthScore = '${{ needs.analyze.outputs.health_score }}';
let status = '';
if (testResult === 'passed' && buildResult !== 'failed') {
status = '### Status: Ready to Merge';
} else if (testResult === 'failed') {
status = '### Status: Tests Failing - Needs Fix';
} else {
status = '### Status: Review Needed';
}
const body = `## Autonomous Agent Review
${status}
| Check | Result |
|-------|--------|
| Tests | ${testResult === 'passed' ? 'Passed' : testResult === 'failed' ? 'Failed' : 'Skipped'} |
| Build | ${buildResult === 'passed' ? 'Passed' : buildResult === 'failed' ? 'Failed' : 'Skipped'} |
| Health Score | ${healthScore}/100 |
---
*Autonomous review by BlackRoad Agent*`;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
body: body
});
# ============================================
# Stage 5: Auto-Merge
# ============================================
auto-merge:
name: "Auto-Merge"
needs: [analyze, test-and-build, security-scan, code-review]
if: |
github.event_name == 'pull_request' &&
needs.test-and-build.outputs.test_result != 'failed' &&
needs.test-and-build.outputs.build_result != 'failed' &&
needs.security-scan.outputs.severity != 'critical'
runs-on: ubuntu-latest
steps:
- name: Enable Auto-Merge
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "Enabling auto-merge for PR #${{ github.event.pull_request.number }}"
# Try multiple merge strategies
gh pr merge ${{ github.event.pull_request.number }} \
--repo ${{ github.repository }} \
--auto \
--squash \
--delete-branch 2>/dev/null || \
gh pr merge ${{ github.event.pull_request.number }} \
--repo ${{ github.repository }} \
--squash 2>/dev/null || \
echo "Auto-merge queued - waiting for required checks"
# ============================================
# Stage 6: Auto-Deploy
# ============================================
auto-deploy:
name: "Auto-Deploy"
needs: [analyze, test-and-build, security-scan]
if: |
github.event_name == 'push' &&
github.ref == 'refs/heads/main' &&
needs.test-and-build.outputs.test_result != 'failed' &&
needs.security-scan.outputs.severity != 'critical'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Determine Deploy Target
id: target
run: |
TARGET="none"
# Check for deployment configs
[ -f "wrangler.toml" ] && TARGET="cloudflare"
[ -f "vercel.json" ] && TARGET="vercel"
[ -f "railway.toml" ] && TARGET="railway"
[ -f "Dockerfile" ] && TARGET="docker"
echo "target=$TARGET" >> $GITHUB_OUTPUT
- name: Deploy to Cloudflare
if: steps.target.outputs.target == 'cloudflare'
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
run: |
if [ -n "$CLOUDFLARE_API_TOKEN" ]; then
npx wrangler deploy 2>/dev/null || echo "Cloudflare deploy skipped"
fi
- name: Deploy to Vercel
if: steps.target.outputs.target == 'vercel'
env:
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
run: |
if [ -n "$VERCEL_TOKEN" ]; then
npx vercel --prod --token=$VERCEL_TOKEN 2>/dev/null || echo "Vercel deploy skipped"
fi
# ============================================
# Stage 7: Memory Persistence
# ============================================
persist-memory:
name: "Persist Memory"
needs: [test-and-build, security-scan]
if: always()
runs-on: ubuntu-latest
steps:
- name: Save Run Memory
run: |
curl -s -X POST "${{ env.BLACKROAD_AGENT_API }}/memory" \
-H "Content-Type: application/json" \
-d '{
"repo": "${{ github.repository }}",
"run_id": "${{ github.run_id }}",
"event": "${{ github.event_name }}",
"results": {
"test": "${{ needs.test-and-build.outputs.test_result }}",
"build": "${{ needs.test-and-build.outputs.build_result }}",
"security": "${{ needs.security-scan.outputs.severity }}"
},
"timestamp": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"
}' 2>/dev/null || echo "Memory save queued"
# ============================================
# Stage 8: Issue Triage (Issues only)
# ============================================
issue-triage:
name: "Issue Triage"
needs: analyze
if: github.event_name == 'issues' && github.event.action == 'opened'
runs-on: ubuntu-latest
steps:
- name: AI Issue Analysis
id: analyze
run: |
TITLE="${{ github.event.issue.title }}"
BODY="${{ github.event.issue.body }}"
# Determine labels based on content
LABELS=""
echo "$TITLE $BODY" | grep -qi "bug\|error\|broken\|fix" && LABELS="$LABELS,bug"
echo "$TITLE $BODY" | grep -qi "feature\|add\|new\|enhance" && LABELS="$LABELS,enhancement"
echo "$TITLE $BODY" | grep -qi "question\|how\|help" && LABELS="$LABELS,question"
echo "$TITLE $BODY" | grep -qi "security\|vulnerability\|cve" && LABELS="$LABELS,security"
echo "$TITLE $BODY" | grep -qi "urgent\|critical\|asap" && LABELS="$LABELS,priority:high"
LABELS=$(echo "$LABELS" | sed 's/^,//')
echo "labels=$LABELS" >> $GITHUB_OUTPUT
- name: Apply Labels
if: steps.analyze.outputs.labels != ''
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
for label in $(echo "${{ steps.analyze.outputs.labels }}" | tr ',' ' '); do
gh issue edit ${{ github.event.issue.number }} --add-label "$label" 2>/dev/null || true
done
- name: Auto-Respond
uses: actions/github-script@v7
with:
script: |
const labels = '${{ steps.analyze.outputs.labels }}'.split(',').filter(l => l);
let response = `Thanks for opening this issue!\n\n`;
response += `**Automated Triage:**\n`;
if (labels.length > 0) {
response += `- Labels applied: ${labels.map(l => '`' + l + '`').join(', ')}\n`;
}
response += `\nA team member will review this shortly. In the meantime:\n`;
response += `- Check if there's a similar issue already open\n`;
response += `- Provide additional context if available\n\n`;
response += `*Triaged by BlackRoad Autonomous Agent*`;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.issue.number,
body: response
});
# ============================================
# Stage 9: Scheduled Maintenance
# ============================================
maintenance:
name: "Scheduled Maintenance"
needs: analyze
if: github.event_name == 'schedule'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Update Dependencies
run: |
if [ -f "package.json" ]; then
# Check for outdated packages
npm outdated --json > outdated.json 2>/dev/null || true
# Auto-update patch versions
npm update 2>/dev/null || true
if [ -n "$(git status --porcelain package-lock.json)" ]; then
git config user.name "BlackRoad Bot"
git config user.email "bot@blackroad.ai"
git add package.json package-lock.json
git commit -m "chore(deps): Auto-update dependencies
Automated dependency updates by BlackRoad Agent.
Co-Authored-By: BlackRoad Bot <bot@blackroad.ai>"
git push || echo "Would create PR for updates"
fi
fi
- name: Clean Stale Branches
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# List merged branches older than 30 days
git fetch --all --prune
for branch in $(git branch -r --merged origin/main | grep -v main | grep -v HEAD); do
LAST_COMMIT=$(git log -1 --format=%ct "$branch" 2>/dev/null || echo 0)
NOW=$(date +%s)
DAYS_OLD=$(( (NOW - LAST_COMMIT) / 86400 ))
if [ $DAYS_OLD -gt 30 ]; then
BRANCH_NAME=$(echo "$branch" | sed 's|origin/||')
echo "Deleting stale branch: $BRANCH_NAME ($DAYS_OLD days old)"
git push origin --delete "$BRANCH_NAME" 2>/dev/null || true
fi
done
- name: Health Report
uses: actions/github-script@v7
with:
script: |
const healthScore = '${{ needs.analyze.outputs.health_score }}';
// Only create issue if health is poor
if (parseInt(healthScore) < 70) {
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `[Automated] Repository Health Alert (Score: ${healthScore}/100)`,
body: `## Repository Health Report
**Current Health Score:** ${healthScore}/100
The autonomous agent has detected potential issues with this repository.
### Recommended Actions
- Review and address any security warnings
- Update outdated dependencies
- Add missing documentation
---
*Generated by BlackRoad Autonomous Agent*`,
labels: ['maintenance', 'automated']
});
}

View File

@@ -0,0 +1,377 @@
# .github/workflows/autonomous-self-healer.yml
# Self-healing agent that automatically fixes common issues
name: "Autonomous Self-Healer"
on:
workflow_run:
workflows: ["Autonomous Orchestrator", "CI", "Test"]
types: [completed]
conclusions: [failure]
schedule:
- cron: '30 */6 * * *' # Every 6 hours, offset from orchestrator
workflow_dispatch:
inputs:
fix_type:
description: 'Type of fix to attempt'
required: false
default: 'all'
type: choice
options:
- all
- tests
- build
- lint
- deps
- security
permissions:
contents: write
pull-requests: write
actions: read
checks: read
env:
BLACKROAD_AGENT_API: https://blackroad-agents.amundsonalexa.workers.dev
MAX_FIX_ATTEMPTS: 3
jobs:
# ============================================
# Diagnose the Failure
# ============================================
diagnose:
name: "Diagnose Failure"
runs-on: ubuntu-latest
outputs:
failure_type: ${{ steps.analyze.outputs.type }}
failure_details: ${{ steps.analyze.outputs.details }}
fixable: ${{ steps.analyze.outputs.fixable }}
fix_strategy: ${{ steps.strategy.outputs.approach }}
steps:
- uses: actions/checkout@v4
- name: Get Failed Run Logs
id: logs
if: github.event.workflow_run.id
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Download workflow run logs
gh run view ${{ github.event.workflow_run.id }} --log 2>/dev/null > run_logs.txt || true
echo "logs_retrieved=true" >> $GITHUB_OUTPUT
- name: Analyze Failure
id: analyze
run: |
TYPE="unknown"
DETAILS=""
FIXABLE="false"
if [ -f "run_logs.txt" ]; then
# Test failures
if grep -qi "test.*fail\|jest.*fail\|pytest.*fail\|assertion.*error" run_logs.txt; then
TYPE="test_failure"
DETAILS=$(grep -i "fail\|error" run_logs.txt | head -10)
FIXABLE="maybe"
# Build failures
elif grep -qi "build.*fail\|compile.*error\|typescript.*error" run_logs.txt; then
TYPE="build_failure"
DETAILS=$(grep -i "error" run_logs.txt | head -10)
FIXABLE="maybe"
# Lint failures
elif grep -qi "lint.*error\|eslint.*error\|prettier" run_logs.txt; then
TYPE="lint_failure"
FIXABLE="true"
# Dependency failures
elif grep -qi "npm.*err\|pip.*error\|dependency.*not found\|module.*not found" run_logs.txt; then
TYPE="dependency_failure"
DETAILS=$(grep -i "not found\|missing" run_logs.txt | head -5)
FIXABLE="true"
# Security failures
elif grep -qi "vulnerability\|security\|cve-" run_logs.txt; then
TYPE="security_failure"
FIXABLE="true"
fi
fi
echo "type=$TYPE" >> $GITHUB_OUTPUT
echo "details<<EOF" >> $GITHUB_OUTPUT
echo "$DETAILS" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
echo "fixable=$FIXABLE" >> $GITHUB_OUTPUT
echo "Diagnosed: $TYPE (fixable=$FIXABLE)"
- name: Determine Fix Strategy
id: strategy
run: |
APPROACH="manual"
case "${{ steps.analyze.outputs.type }}" in
lint_failure)
APPROACH="auto_lint_fix"
;;
dependency_failure)
APPROACH="reinstall_deps"
;;
security_failure)
APPROACH="security_patch"
;;
test_failure)
APPROACH="ai_assisted_fix"
;;
build_failure)
APPROACH="ai_assisted_fix"
;;
esac
echo "approach=$APPROACH" >> $GITHUB_OUTPUT
# ============================================
# Auto-Fix: Lint Issues
# ============================================
fix-lint:
name: "Fix Lint Issues"
needs: diagnose
if: needs.diagnose.outputs.fix_strategy == 'auto_lint_fix'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.workflow_run.head_branch || github.ref }}
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Dependencies
run: npm ci --ignore-scripts 2>/dev/null || npm install --ignore-scripts
- name: Run Lint Fix
run: |
# Try multiple linting tools
npm run lint:fix 2>/dev/null || \
npx eslint . --fix 2>/dev/null || \
npx prettier --write . 2>/dev/null || \
echo "No lint fix available"
- name: Commit Fixes
run: |
if [ -n "$(git status --porcelain)" ]; then
git config user.name "BlackRoad Self-Healer"
git config user.email "healer@blackroad.ai"
git add -A
git commit -m "fix(lint): Auto-fix linting issues
Automated lint fixes applied by BlackRoad Self-Healing Agent.
Co-Authored-By: BlackRoad Bot <bot@blackroad.ai>"
git push
echo "Lint fixes committed successfully"
else
echo "No lint issues to fix"
fi
# ============================================
# Auto-Fix: Dependencies
# ============================================
fix-deps:
name: "Fix Dependencies"
needs: diagnose
if: needs.diagnose.outputs.fix_strategy == 'reinstall_deps'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.workflow_run.head_branch || github.ref }}
- name: Fix Node Dependencies
if: hashFiles('package.json') != ''
run: |
# Remove node_modules and lock file, reinstall
rm -rf node_modules package-lock.json 2>/dev/null || true
npm install
# Dedupe and fix
npm dedupe 2>/dev/null || true
npm audit fix 2>/dev/null || true
- name: Fix Python Dependencies
if: hashFiles('requirements.txt') != '' || hashFiles('pyproject.toml') != ''
run: |
pip install --upgrade pip
[ -f "requirements.txt" ] && pip install -r requirements.txt
[ -f "pyproject.toml" ] && pip install -e .
- name: Commit Fixes
run: |
if [ -n "$(git status --porcelain)" ]; then
git config user.name "BlackRoad Self-Healer"
git config user.email "healer@blackroad.ai"
git add -A
git commit -m "fix(deps): Reinstall and fix dependencies
Dependency issues resolved by BlackRoad Self-Healing Agent.
Co-Authored-By: BlackRoad Bot <bot@blackroad.ai>"
git push
fi
# ============================================
# Auto-Fix: Security Issues
# ============================================
fix-security:
name: "Fix Security Issues"
needs: diagnose
if: needs.diagnose.outputs.fix_strategy == 'security_patch'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.workflow_run.head_branch || github.ref }}
- name: Fix npm Security Issues
if: hashFiles('package.json') != ''
run: |
npm audit fix 2>/dev/null || true
npm audit fix --force 2>/dev/null || true
- name: Fix Python Security Issues
if: hashFiles('requirements.txt') != ''
run: |
pip install safety pip-audit 2>/dev/null || true
pip-audit --fix 2>/dev/null || true
- name: Create Security PR
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
if [ -n "$(git status --porcelain)" ]; then
BRANCH="security-fix-$(date +%Y%m%d-%H%M%S)"
git config user.name "BlackRoad Self-Healer"
git config user.email "healer@blackroad.ai"
git checkout -b "$BRANCH"
git add -A
git commit -m "fix(security): Auto-patch security vulnerabilities
Security vulnerabilities patched by BlackRoad Self-Healing Agent.
Co-Authored-By: BlackRoad Bot <bot@blackroad.ai>"
git push -u origin "$BRANCH"
gh pr create \
--title "fix(security): Auto-patch security vulnerabilities" \
--body "## Security Patch
This PR was automatically generated by the BlackRoad Self-Healing Agent.
### Changes
- Applied security patches via npm audit fix / pip-audit
### Verification
- Automated tests will verify compatibility
- Please review before merging
---
*Generated by BlackRoad Autonomous Agent*" \
--label "security,automated"
fi
# ============================================
# AI-Assisted Fix
# ============================================
ai-fix:
name: "AI-Assisted Fix"
needs: diagnose
if: needs.diagnose.outputs.fix_strategy == 'ai_assisted_fix'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.workflow_run.head_branch || github.ref }}
- name: Request AI Fix
id: ai
run: |
# Send failure details to AI for analysis and fix
RESPONSE=$(curl -s -X POST "${{ env.BLACKROAD_AGENT_API }}/fix" \
-H "Content-Type: application/json" \
-d '{
"repo": "${{ github.repository }}",
"failure_type": "${{ needs.diagnose.outputs.failure_type }}",
"details": ${{ toJSON(needs.diagnose.outputs.failure_details) }},
"run_id": "${{ github.event.workflow_run.id }}"
}' 2>/dev/null || echo '{"status":"queued"}')
echo "AI Response: $RESPONSE"
echo "response=$RESPONSE" >> $GITHUB_OUTPUT
- name: Create Issue for Manual Review
if: needs.diagnose.outputs.fixable == 'maybe'
uses: actions/github-script@v7
with:
script: |
const failureType = '${{ needs.diagnose.outputs.failure_type }}';
const details = `${{ needs.diagnose.outputs.failure_details }}`;
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `[Self-Healer] ${failureType.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase())} Needs Review`,
body: `## Automated Failure Analysis
**Failure Type:** ${failureType}
**Run ID:** ${{ github.event.workflow_run.id || 'N/A' }}
### Error Details
\`\`\`
${details.substring(0, 2000)}
\`\`\`
### AI Analysis
The self-healing agent attempted to analyze this issue but requires human review.
### Suggested Actions
1. Review the error logs above
2. Check recent changes that may have caused this
3. Apply appropriate fix
---
*Created by BlackRoad Self-Healing Agent*`,
labels: ['bug', 'automated', 'needs-triage']
});
# ============================================
# Report Results
# ============================================
report:
name: "Report Results"
needs: [diagnose, fix-lint, fix-deps, fix-security, ai-fix]
if: always()
runs-on: ubuntu-latest
steps:
- name: Summarize Healing Attempt
run: |
echo "## Self-Healing Summary"
echo "Failure Type: ${{ needs.diagnose.outputs.failure_type }}"
echo "Fix Strategy: ${{ needs.diagnose.outputs.fix_strategy }}"
echo "Fixable: ${{ needs.diagnose.outputs.fixable }}"
# Log to memory
curl -s -X POST "${{ env.BLACKROAD_AGENT_API }}/memory" \
-H "Content-Type: application/json" \
-d '{
"repo": "${{ github.repository }}",
"event": "self_heal_attempt",
"failure_type": "${{ needs.diagnose.outputs.failure_type }}",
"strategy": "${{ needs.diagnose.outputs.fix_strategy }}",
"timestamp": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"
}' 2>/dev/null || true