Files
awoooi/scripts/verify-sse.js
OG T 7478dc0254 feat(phase6-9): Complete modular architecture and Agent Teams
Phase 6.4 - Modular Architecture:
- Add lewooogo-brain adapters for LLM providers
- Add lewooogo-data dual memory (Redis + PostgreSQL)
- Implement consensus engine for multi-agent decisions
- Add incident memory service for historical context

Phase 9 - Agent Teams (Claude Agent SDK):
- Add base agent class with Claude Sonnet 4 integration
- Implement action planner, blast radius, and security agents
- Add agent API endpoints and proposal workflow
- Integrate ADR-009 OpenClaw Agent Teams architecture

DevOps & CI/CD:
- Add GitHub Actions CI/CD workflows (ci.yaml, cd.yaml)
- Add pre-commit hooks and secrets baseline
- Add docker-compose for local development
- Update Kubernetes network policies

Frontend Improvements:
- Add auto-healing error boundary component
- Update i18n messages for agent features
- Enhance dual-state incident card with execution feedback

Documentation:
- Add 7 ADRs covering MCP, design system, architecture decisions
- Update ARCHITECTURE_MEMORY.md with modular design
- Add GLOBAL_RULES.md and SOUL.md for project identity

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-23 18:40:36 +08:00

158 lines
4.5 KiB
JavaScript

#!/usr/bin/env node
/**
* AWOOOI 自動化 QA 腳本 - verify-sse.js
* =====================================
* 自動驗證 SSE 連線,禁止人工 QA
*
* 驗證項目:
* 1. 後端 SSE 端點 200 OK
* 2. SSE 數據流 (connected, heartbeat)
* 3. 前端頁面可訪問
*
* 用法: node scripts/verify-sse.js
*/
const http = require('http')
const API_URL = 'http://localhost:8000'
const FRONTEND_URL = 'http://localhost:3000'
// ANSI Colors
const GREEN = '\x1b[32m'
const RED = '\x1b[31m'
const YELLOW = '\x1b[33m'
const RESET = '\x1b[0m'
function log(status, message) {
const icon = status === 'pass' ? `${GREEN}${RESET}` : status === 'fail' ? `${RED}${RESET}` : `${YELLOW}${RESET}`
console.log(`${icon} ${message}`)
}
// Test 1: Backend SSE Endpoint
async function testBackendSSE() {
return new Promise((resolve) => {
log('info', '測試後端 SSE 端點...')
const req = http.get(`${API_URL}/api/v1/dashboard/stream`, (res) => {
if (res.statusCode !== 200) {
log('fail', `後端 SSE: HTTP ${res.statusCode}`)
resolve(false)
return
}
let data = ''
let gotConnected = false
let gotHeartbeat = false
res.on('data', (chunk) => {
data += chunk.toString()
if (data.includes('event: connected')) gotConnected = true
if (data.includes('event: heartbeat') || data.includes('event: host_update')) gotHeartbeat = true
// Stop after receiving both events
if (gotConnected && gotHeartbeat) {
req.destroy()
log('pass', '後端 SSE: connected + data events 收到')
resolve(true)
}
})
// Timeout after 10 seconds
setTimeout(() => {
req.destroy()
if (gotConnected) {
log('pass', '後端 SSE: connected 收到')
resolve(true)
} else {
log('fail', '後端 SSE: 超時未收到事件')
resolve(false)
}
}, 10000)
})
req.on('error', (err) => {
log('fail', `後端 SSE: ${err.message}`)
resolve(false)
})
})
}
// Test 2: Frontend Accessible
async function testFrontend() {
return new Promise((resolve) => {
log('info', '測試前端頁面...')
http.get(`${FRONTEND_URL}/zh-TW`, (res) => {
if (res.statusCode === 200 || res.statusCode === 307) {
log('pass', `前端頁面: HTTP ${res.statusCode}`)
resolve(true)
} else {
log('fail', `前端頁面: HTTP ${res.statusCode}`)
resolve(false)
}
}).on('error', (err) => {
log('fail', `前端頁面: ${err.message}`)
resolve(false)
})
})
}
// Test 3: API Health Check
async function testAPIHealth() {
return new Promise((resolve) => {
log('info', '測試 API 健康狀態...')
http.get(`${API_URL}/api/v1/health`, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => {
try {
const json = JSON.parse(data)
if (json.status === 'healthy') {
log('pass', `API 健康: ${json.status}`)
resolve(true)
} else {
log('fail', `API 健康: ${json.status}`)
resolve(false)
}
} catch (e) {
log('fail', `API 健康: 無法解析 JSON`)
resolve(false)
}
})
}).on('error', (err) => {
log('fail', `API 健康: ${err.message}`)
resolve(false)
})
})
}
// Main
async function main() {
console.log('\n========================================')
console.log(' AWOOOI 自動化 QA - SSE 驗證腳本')
console.log('========================================\n')
const results = {
apiHealth: await testAPIHealth(),
backendSSE: await testBackendSSE(),
frontend: await testFrontend(),
}
console.log('\n========================================')
console.log(' 驗證結果')
console.log('========================================')
console.log(`API 健康: ${results.apiHealth ? GREEN + 'PASS' + RESET : RED + 'FAIL' + RESET}`)
console.log(`後端 SSE: ${results.backendSSE ? GREEN + 'PASS' + RESET : RED + 'FAIL' + RESET}`)
console.log(`前端頁面: ${results.frontend ? GREEN + 'PASS' + RESET : RED + 'FAIL' + RESET}`)
const allPassed = Object.values(results).every(Boolean)
console.log(`\n總結: ${allPassed ? GREEN + '全部通過' + RESET : RED + '有失敗項目' + RESET}`)
console.log('========================================\n')
process.exit(allPassed ? 0 : 1)
}
main().catch(console.error)