diff --git a/README.md b/README.md index 4b67ab8..c5a9655 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# MissionControl — Autonomous DevOps Incident Response Agent +# MissionControl — Autonomous DevOps Incident Response Agent > **Hackathon submission** — WeMakeDevs "The Agent Harness" (Double-O track, TrueFoundry sponsor) @@ -105,7 +105,7 @@ python scripts/trigger_incident.py api-gateway outage "gateway down" ## TrueForge Agent Setup 1. Start TrueForge: `npx @truefoundry/trueforge` (in a separate terminal) -2. Open `http://localhost:3000` +2. Open `http://localhost:8790` 3. **Add model provider** → paste your `OPENAI_API_KEY` 4. **Add MCP server** → URL: `http://localhost:8000/mcp` (name: `demo-infra`) 5. **Create agent** named `missioncontrol`: @@ -139,8 +139,8 @@ python scripts/trigger_incident.py api-gateway outage "gateway down" | Variable | Default | Description | |----------|---------|-------------| | `OPENAI_API_KEY` | *required* | OpenAI API key for TrueForge | -| `TRUEFORGE_URL` | `http://localhost:3000` | TrueForge UI URL | -| `NEXT_PUBLIC_TRUEFORGE_URL` | `http://localhost:3000` | Browser-side TrueForge URL | +| `TRUEFORGE_URL` | `http://localhost:8790` | TrueForge UI URL | +| `NEXT_PUBLIC_TRUEFORGE_URL` | `http://localhost:8790` | Browser-side TrueForge URL | | `MCP_ENDPOINT` | `http://localhost:8000/mcp` | MCP streamable-HTTP endpoint | | `DEMO_INFRA_API_URL` | `http://localhost:8001` | REST sidecar URL | | `DEMO_INFRA_TOKEN` | `local-demo-token` | Shared token for mutating POSTs | @@ -165,7 +165,7 @@ npm run build ## Security Notes -- **CORS**: Restricted to `localhost:3000/3001` only +- **CORS**: Restricted to `localhost:8790/3001` only - **Mutation auth**: All state-mutating POSTs require `Authorization: Bearer ` - **Default token**: `local-demo-token` (override via `DEMO_INFRA_TOKEN` in `.env`) - **MCP approval**: Agent tools `rollback_deploy` / `restart_service` require TrueForge human approval diff --git a/Submissions List/01-PUBLIC-REPOSITORY.md b/Submissions List/01-PUBLIC-REPOSITORY.md index 7528d23..0e857e6 100644 --- a/Submissions List/01-PUBLIC-REPOSITORY.md +++ b/Submissions List/01-PUBLIC-REPOSITORY.md @@ -304,7 +304,7 @@ chmod +x scripts/setup.sh # 5. Start TrueForge (in a separate terminal / WSL) npx @truefoundry/trueforge -# 6. In TrueForge UI (http://localhost:3000): +# 6. In TrueForge UI (http://localhost:8790): # a. Connect your model provider (OpenAI key from .env) # b. Add an MCP server -> URL: http://localhost:8000/mcp # c. Create an agent named 'missioncontrol' @@ -368,7 +368,7 @@ pkill -f trueforge | Port | Service | |---|---| -| 3000 | TrueForge UI | +| 8790 | TrueForge UI | | 3001 | MissionControl Dashboard | | 4000 | LiteLLM proxy | | 5432 | PostgreSQL | diff --git a/Submissions List/03-PROJECT-WRITEUP.md b/Submissions List/03-PROJECT-WRITEUP.md index ff13ffa..d0c9820 100644 --- a/Submissions List/03-PROJECT-WRITEUP.md +++ b/Submissions List/03-PROJECT-WRITEUP.md @@ -141,7 +141,7 @@ TrueForge is the agent harness that: - Runs the AI agent (GPT-4o-mini) - Manages MCP server connections - Handles human-in-the-loop approval -- Provides the agent UI at `http://localhost:3000` +- Provides the agent UI at `http://localhost:8790` **How we use it:** - Agent system prompt defines MissionControl's personality and rules @@ -222,7 +222,7 @@ WSL launchers (`scripts/wsl/start-trueforge.sh`, `scripts/wsl/start-litellm.sh`) | Agent Runtime | Runs GPT-4o-mini with our system prompt and skill | | MCP Server Connection | Connects to our FastMCP server at `http://localhost:8000/mcp` | | Approval Mechanism | Requires human approval before `rollback_deploy` / `restart_service` | -| Agent UI | Provides `http://localhost:3000` for agent interaction | +| Agent UI | Provides `http://localhost:8790` for agent interaction | | Skill System | Loads `incident-response/SKILL.md` for specialized behavior | | System Prompt | Loads `agent/system-prompt.md` for personality and rules | diff --git a/apps/dashboard/app/api/webhook/route.ts b/apps/dashboard/app/api/webhook/route.ts index 28e91c4..d7cad28 100644 --- a/apps/dashboard/app/api/webhook/route.ts +++ b/apps/dashboard/app/api/webhook/route.ts @@ -19,7 +19,7 @@ export async function POST(request: NextRequest) { const baseUrl = process.env.TRUEFORGE_URL || process.env.NEXT_PUBLIC_TRUEFORGE_URL || - 'http://localhost:3000' + 'http://localhost:8790' const token = process.env.TRUEFORGE_API_KEY const client = new TrueForge({ @@ -63,7 +63,7 @@ Alert type: ${alert_type}` return NextResponse.json( { error: 'Failed to trigger incident response', - hint: `Is TrueForge running at ${process.env.TRUEFORGE_URL || process.env.NEXT_PUBLIC_TRUEFORGE_URL || 'http://localhost:3000'} with an agent named "missioncontrol"?`, + hint: `Is TrueForge running at ${process.env.TRUEFORGE_URL || process.env.NEXT_PUBLIC_TRUEFORGE_URL || 'http://localhost:8790'} with an agent named "missioncontrol"?`, details: String(error), }, { status: 502 } diff --git a/apps/dashboard/components/agent-chat.tsx b/apps/dashboard/components/agent-chat.tsx index 86f5ccf..e577a66 100644 --- a/apps/dashboard/components/agent-chat.tsx +++ b/apps/dashboard/components/agent-chat.tsx @@ -16,7 +16,7 @@ const TrueforgeUI = dynamic(() => import('@truefoundry/trueforge-ui').then((m) = export function AgentChat({ sessionId }: { sessionId?: string }) { const [error, setError] = useState(null) - const baseUrl = process.env.NEXT_PUBLIC_TRUEFORGE_URL || 'http://localhost:3000' + const baseUrl = process.env.NEXT_PUBLIC_TRUEFORGE_URL || 'http://localhost:8790' const token = process.env.NEXT_PUBLIC_TRUEFORGE_TOKEN if (error) { diff --git a/mcp-servers/demo-infra/http_api.py b/mcp-servers/demo-infra/http_api.py index 8780ed7..a48ef6b 100644 --- a/mcp-servers/demo-infra/http_api.py +++ b/mcp-servers/demo-infra/http_api.py @@ -40,9 +40,9 @@ def _authorized(headers: Any, client_addr: str) -> bool: # Browser traffic reaches this API only via the Next.js server-side proxy, # so CORS is a convenience for local debugging, not an authorization layer. CORS_ALLOWED_ORIGINS = { - "http://localhost:3000", + "http://localhost:8790", "http://localhost:3001", - "http://127.0.0.1:3000", + "http://127.0.0.1:8790", "http://127.0.0.1:3001", } diff --git a/scripts/setup.ps1 b/scripts/setup.ps1 index 55877a7..627ac28 100644 --- a/scripts/setup.ps1 +++ b/scripts/setup.ps1 @@ -84,7 +84,7 @@ Write-Host " Run in a separate terminal:" -ForegroundColor Cyan Write-Host "" Write-Host " npx @truefoundry/trueforge" -ForegroundColor White Write-Host "" -Write-Host " Then in the TrueForge UI (http://localhost:3000):" +Write-Host " Then in the TrueForge UI (http://localhost:8790):" Write-Host " a. Connect your model provider (OpenAI key from .env)" Write-Host " b. Add an MCP server -> URL: http://localhost:8000/mcp" Write-Host " c. Create an agent named 'missioncontrol' using agent/system-prompt.md" @@ -96,7 +96,7 @@ Write-Host "=========================================" -ForegroundColor Cyan Write-Host " MissionControl is ready!" Write-Host "=========================================" Write-Host "" -Write-Host " TrueForge UI: http://localhost:3000 (after 'npx @truefoundry/trueforge')" +Write-Host " TrueForge UI: http://localhost:8790 (after 'npx @truefoundry/trueforge')" Write-Host " Dashboard: http://localhost:3001" Write-Host " MCP endpoint: http://localhost:8000/mcp" Write-Host " REST API: http://localhost:8001" diff --git a/scripts/setup.sh b/scripts/setup.sh index 7c0b3e4..0fd52c4 100644 --- a/scripts/setup.sh +++ b/scripts/setup.sh @@ -10,7 +10,7 @@ echo "" echo "[1/6] Checking prerequisites..." command -v docker >/dev/null 2>&1 || { echo "Error: docker is required. Install Docker Desktop."; exit 1; } -if command -v node >/dev/null 2>&1; then echo " - Node: $(node --version)"; else echo "Error: node 18+ is required."; exit 1; fi +if command -v node >/dev/null 2>&1; then echo " - Node: $(node --version)"; else echo "Error: node 22+ is required."; exit 1; fi PYTHON_BIN="$(command -v python3 || command -v python)" [ -n "$PYTHON_BIN" ] || { echo "Error: python 3.10+ is required."; exit 1; } echo " - Python: $($PYTHON_BIN --version)" @@ -64,7 +64,7 @@ echo "" echo "[5/6] Building and starting the dashboard (background)..." (cd apps/dashboard && npm run build) -(cd apps/dashboard && nohup npm run dev >/tmp/missioncontrol-dashboard.log 2>&1 &) +(cd apps/dashboard && NEXT_PUBLIC_TRUEFORGE_URL="http://localhost:8790" TRUEFORGE_URL="http://localhost:8790" nohup npm run dev >/tmp/missioncontrol-dashboard.log 2>&1 &) sleep 5 echo " Dashboard built and starting on http://localhost:3001 (log: /tmp/missioncontrol-dashboard.log)" echo "" @@ -72,9 +72,9 @@ echo "" echo "[6/6] Starting TrueForge agent runtime..." if command -v npx >/dev/null 2>&1; then echo " Starting TrueForge in background..." - nohup npx @truefoundry/trueforge >/tmp/missioncontrol-trueforge.log 2>&1 & + nohup npx -y @truefoundry/trueforge >/tmp/missioncontrol-trueforge.log 2>&1 & sleep 3 - echo " TrueForge starting on http://localhost:3000 (log: /tmp/missioncontrol-trueforge.log)" + echo " TrueForge starting on http://localhost:8790 (log: /tmp/missioncontrol-trueforge.log)" else echo " npx not found - run 'npx @truefoundry/trueforge' manually" fi @@ -84,7 +84,7 @@ echo "=========================================" echo " MissionControl is ready!" echo "=========================================" echo "" -echo " TrueForge UI: http://localhost:3000 (after 'npx @truefoundry/trueforge')" +echo " TrueForge UI: http://localhost:8790 (after 'npx @truefoundry/trueforge')" echo " Dashboard: http://localhost:3001" echo " MCP endpoint: http://localhost:8000/mcp" echo " REST API: http://localhost:8001" diff --git a/scripts/start-all.ps1 b/scripts/start-all.ps1 index 43c173f..0676908 100644 --- a/scripts/start-all.ps1 +++ b/scripts/start-all.ps1 @@ -55,20 +55,20 @@ if ($out -eq "200") { Write-Host " LiteLLM: UP" -ForegroundColor Green } else { Write-Host " LiteLLM: FAILED to start (check WSL ~/litellm.log)" -ForegroundColor Red } # ---------------------------------------------------------------- [4/8] -Write-Host "[4/8] Starting TrueForge (WSL :3000)..." +Write-Host "[4/8] Starting TrueForge (WSL :8790)..." $out = "" -try { $out = (wsl -e bash -lc "curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:3000 --max-time 4") } catch { $out = "000" } +try { $out = (wsl -e bash -lc "curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8790 --max-time 4") } catch { $out = "000" } if ($out -ne "200") { wsl -e bash -lc "setsid -f -- bash '$tfRunScript' $tfLog 2>&1" $up = $false foreach ($i in 1..24) { Start-Sleep -Seconds 5 - $out = wsl -e bash -lc "curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:3000 --max-time 4" + $out = wsl -e bash -lc "curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8790 --max-time 4" if ($out -eq "200") { $up = $true; break } } if (-not $up) { Write-Host " TrueForge: FAILED (check WSL ~/tf.log)" -ForegroundColor Red } } -$out = wsl -e bash -lc "curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:3000 --max-time 4" +$out = wsl -e bash -lc "curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8790 --max-time 4" if ($out -eq "200") { Write-Host " TrueForge: UP" -ForegroundColor Green } # ---------------------------------------------------------------- [5/8] @@ -94,7 +94,7 @@ if ($conn) { # ---------------------------------------------------------------- [6/8] Write-Host "[6/8] Keeping TrueForge MCP registration pointed at this machine..." try { - $mcp = Invoke-RestMethod "http://${wslIp}:3000/api/v1/settings/mcp-servers" -TimeoutSec 10 + $mcp = Invoke-RestMethod "http://${wslIp}:8790/api/v1/settings/mcp-servers" -TimeoutSec 10 $current = ($mcp | ConvertTo-Json -Depth 6) $want = "http://${gw}:8000/mcp" if ($current -notmatch [regex]::Escape($want)) { @@ -102,7 +102,7 @@ try { type = "remote"; name = "demo-infra"; url = $want description = "Simulated production infra: 4 services with metrics, logs, deploys, chaos injection and approval-gated rollback/restart tools." } } | ConvertTo-Json -Depth 6 - Invoke-RestMethod -Method Put -Uri "http://${wslIp}:3000/api/v1/settings/mcp-servers" ` + Invoke-RestMethod -Method Put -Uri "http://${wslIp}:8790/api/v1/settings/mcp-servers" ` -ContentType "application/json" -Body $body -TimeoutSec 15 | Out-Null Write-Host " MCP registration updated -> $want" -ForegroundColor Yellow } else { @@ -127,7 +127,7 @@ if (Test-Path $envFile) { # when a variable is missing. The replacement loop emits only the new # value so stale lines are replaced, never duplicated. foreach ($key in @("TRUEFORGE_URL", "NEXT_PUBLIC_TRUEFORGE_URL")) { - $newVal = "${key}=http://${wslIp}:3000" + $newVal = "${key}=http://${wslIp}:8790" if ($newTxt -notmatch [regex]::Escape($newVal)) { if ($newTxt -match "^${key}=") { $newTxt = (($newTxt -split "`r?`n") | ForEach-Object { @@ -179,7 +179,7 @@ try { Write-Host "" Write-Host "=== READY ===" -ForegroundColor Cyan -$tfUrl = "http://${wslIp}:3000" +$tfUrl = "http://${wslIp}:8790" Write-Host " Dashboard : http://localhost:3001" Write-Host " TrueForge UI : ${tfUrl}" Write-Host " MCP endpoint : http://localhost:8000/mcp" diff --git a/scripts/wsl/start-trueforge.sh b/scripts/wsl/start-trueforge.sh index 55e4a2c..4efc1f5 100644 --- a/scripts/wsl/start-trueforge.sh +++ b/scripts/wsl/start-trueforge.sh @@ -27,4 +27,4 @@ fi cd "$HOME" export HOST=0.0.0.0 -exec npx -y @truefoundry/trueforge --port 3000 \ No newline at end of file +exec npx -y @truefoundry/trueforge \ No newline at end of file diff --git a/start.ps1 b/start.ps1 index 98b8281..d64152b 100644 --- a/start.ps1 +++ b/start.ps1 @@ -8,7 +8,7 @@ Write-Host "=========================================" Write-Host "" # Step 1: Check Docker -Write-Host "[1/6] Checking Docker..." -ForegroundColor Yellow +Write-Host "[1/7] Checking Docker..." -ForegroundColor Yellow try { docker info > $null 2>&1 if ($LASTEXITCODE -ne 0) { throw } @@ -24,12 +24,12 @@ try { } # Step 2: Start containers -Write-Host "[2/6] Starting containers..." -ForegroundColor Yellow +Write-Host "[2/7] Starting containers..." -ForegroundColor Yellow docker compose up -d --build 2>&1 | Out-Null Write-Host " PostgreSQL, Redis, MCP server started" -ForegroundColor Green # Step 3: Wait for health -Write-Host "[3/6] Waiting for MCP server..." -ForegroundColor Yellow +Write-Host "[3/7] Waiting for MCP server..." -ForegroundColor Yellow $retries = 0 while ($retries -lt 15) { try { @@ -46,53 +46,49 @@ if ($retries -ge 15) { } # Step 4: Start dashboard -Write-Host "[4/6] Starting dashboard..." -ForegroundColor Yellow +Write-Host "[4/7] Starting dashboard..." -ForegroundColor Yellow $dashboardDir = Join-Path $PSScriptRoot "apps\dashboard" if (-not (Test-Path "$dashboardDir\node_modules")) { Push-Location $dashboardDir npm install --silent 2>&1 | Out-Null Pop-Location } -Start-Process powershell -ArgumentList "-NoExit", "-Command", "cd '$dashboardDir'; npm run dev" +Start-Process powershell -ArgumentList "-NoExit", "-Command", "`$env:NEXT_PUBLIC_TRUEFORGE_URL='http://localhost:8790'; `$env:TRUEFORGE_URL='http://localhost:8790'; cd '$dashboardDir'; npm run dev" Write-Host " Dashboard starting on http://localhost:3001" -ForegroundColor Green -# Step 5: Setup WSL - install Linux-native Node.js -Write-Host "[5/6] Setting up WSL..." -ForegroundColor Yellow -$wslLinuxNode = wsl -d Ubuntu -- bash -c 'test -f /usr/bin/node && echo ok || echo missing' -if ($wslLinuxNode -match "missing") { - Write-Host " Installing Node.js 22 in WSL (first time only)..." -ForegroundColor Yellow - wsl -d Ubuntu -- bash -c 'curl -fsSL https://deb.nodesource.com/setup_22.x -o /tmp/ns.sh' - wsl -d Ubuntu -- bash -c 'sudo bash /tmp/ns.sh' - wsl -d Ubuntu -- bash -c 'sudo apt-get install -y nodejs' - Write-Host " Node.js installed in WSL" -ForegroundColor Green +# Step 5: Setup WSL - install Linux-native Node.js 22 locally +Write-Host "[5/7] Setting up WSL..." -ForegroundColor Yellow +$localNode = wsl -d Ubuntu -- bash -c 'if [ -x ~/.local/node/bin/node ]; then ~/.local/node/bin/node -v; fi' +if ($localNode -match "v22") { + Write-Host " WSL Node.js 22 already installed locally" } else { - Write-Host " WSL Node.js already installed" -ForegroundColor Green + Write-Host " Installing Node.js 22 in WSL (~/.local/node)..." + wsl -d Ubuntu -- bash -c 'mkdir -p ~/.local/node && curl -fsSL https://nodejs.org/dist/v22.14.0/node-v22.14.0-linux-x64.tar.gz | tar -xz -C ~/.local/node --strip-components=1' } # Step 6: Install TrueForge in WSL -Write-Host "[6/6] Setting up TrueForge in WSL..." -ForegroundColor Yellow -$wslTf = wsl -d Ubuntu -- bash -c 'command -v trueforge 2>/dev/null || echo missing' -if ($wslTf -match "missing") { - Write-Host " Installing TrueForge in WSL (first time only)..." -ForegroundColor Yellow - wsl -d Ubuntu -- bash -c 'export PATH=/usr/bin:/usr/local/bin:$PATH && npm install -g @truefoundry/trueforge' - Write-Host " TrueForge installed in WSL" -ForegroundColor Green -} else { +Write-Host "[6/7] Setting up TrueForge in WSL..." -ForegroundColor Yellow +$tfInstalled = wsl -d Ubuntu -- bash -c 'export PATH=~/.local/node/bin:"$PATH" && npm list -g @truefoundry/trueforge >/dev/null 2>&1 && echo "yes" || echo "no"' +if ($tfInstalled -match "yes") { Write-Host " TrueForge already installed in WSL" -ForegroundColor Green +} else { + Write-Host " Installing @truefoundry/trueforge in WSL..." + wsl -d Ubuntu -- bash -c 'export PATH=~/.local/node/bin:"$PATH" && npm install -g @truefoundry/trueforge' + Write-Host " TrueForge installed in WSL" -ForegroundColor Green } +# Step 7: Start TrueForge +Write-Host "[7/7] Starting TrueForge in WSL..." -ForegroundColor Yellow +Start-Process powershell -ArgumentList "-NoExit", "-Command", "wsl -- bash -c 'cd `"/mnt/c/Users/adity/Documents/Mission Control/scripts/wsl`" && bash start-trueforge.sh'" +Write-Host " TrueForge starting on http://localhost:8790" -ForegroundColor Green + # Done Write-Host "" Write-Host "=========================================" -ForegroundColor Green Write-Host " Everything is running!" -ForegroundColor Green Write-Host "=========================================" -ForegroundColor Green Write-Host "" -Write-Host " Now start TrueForge manually:" -ForegroundColor Cyan -Write-Host " 1. Open a NEW terminal" -ForegroundColor White -Write-Host " 2. Type: wsl" -ForegroundColor White -Write-Host " 3. Type: cd ~" -ForegroundColor White -Write-Host " 4. Type: npx @truefoundry/trueforge" -ForegroundColor White -Write-Host "" -Write-Host " Then in TrueForge UI (http://localhost:3000):" -ForegroundColor Cyan +Write-Host " Then in TrueForge UI (http://localhost:8790):" -ForegroundColor Cyan Write-Host " 1. Add your OpenAI API key" -ForegroundColor White Write-Host " 2. Add MCP server -> http://localhost:8000/mcp" -ForegroundColor White Write-Host " 3. Create agent 'missioncontrol'" -ForegroundColor White