feat(phase-6.4g-6.5b): API Synaptic Integration + Dual-State WarRoom UI

Phase 6.4g (API 突觸對接):
- lewooogo-brain dependency binding in apps/api/pyproject.toml
- POST /api/v1/incidents/{id}/propose route (proposals.py)
- Guardrails integration (8/8 tests passed)

Phase 6.5a (視覺皮層建置):
- DualStateIncidentCard.tsx with Nothing.tech visual compliance
- Ping radar animation for alert state
- Tier-based decision layer UI (AI 執行中 / 等待親核)

Phase 6.5b (神經網路串接):
- Main warroom page integration (page.tsx)
- IncidentResponse → DualState mapper function
- Empty state: "系統穩定。0 活躍異常。"

Tests:
- test_guardrails.py (8/8)
- test_incident_engine.py (6/6)
- test_skill_loader.py (6/6)
- Frontend build: 0 errors

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
OG T
2026-03-23 11:58:28 +08:00
parent 8eaf2acb0d
commit cb5d0ecfe4
17 changed files with 2206 additions and 39 deletions

View File

@@ -0,0 +1,97 @@
'use client'
/**
* DualStateIncidentCard - Phase 6.5a 雙態戰情室卡片
* ==================================================
*
* Nothing.tech 視覺憲法:
* - 純白極簡 (bg-white/90)
* - 無深色模式
* - 嚴禁陰影 (shadow-none)
* - 細邊框 (border-[0.5px])
*
* 雙態設計:
* - normal: 淺灰邊框,靜態
* - alert: 紅色邊框,脈衝雷達動畫
*
* 統帥鐵律: 禁止假數據!
*/
import React from 'react'
export interface DualStateIncidentCardProps {
id: string
serviceName: string
status: 'normal' | 'alert'
tier?: 1 | 2 | 3
message: string
timestamp: string
}
export const DualStateIncidentCard: React.FC<DualStateIncidentCardProps> = ({
id,
serviceName,
status,
tier,
message,
timestamp,
}) => {
const isAlert = status === 'alert'
return (
<div
className={`
relative p-4 w-full max-w-md font-mono text-sm transition-all duration-300
bg-white/90 backdrop-blur-md
${isAlert ? 'border border-red-500' : 'border-[0.5px] border-neutral-200'}
shadow-none
`}
>
{/* 異常脈衝雷達 (Ping Animation) */}
{isAlert && (
<span className="absolute top-4 right-4 flex h-2.5 w-2.5">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-red-400 opacity-75"></span>
<span className="relative inline-flex rounded-full h-2.5 w-2.5 bg-red-600"></span>
</span>
)}
{/* 標頭資訊 */}
<div className="flex justify-between items-center mb-3">
<span className="text-neutral-400 text-xs">{id}</span>
<span
className={`px-2 py-0.5 text-xs tracking-wider border-[0.5px] ${
isAlert
? 'bg-red-50 text-red-600 border-red-200'
: 'bg-neutral-50 text-neutral-500 border-neutral-200'
}`}
>
{serviceName}
</span>
</div>
{/* 核心數據與訊息 */}
<div
className={`mt-2 font-bold tracking-wide ${isAlert ? 'text-red-600' : 'text-neutral-800'}`}
>
{message}
</div>
<div className="mt-1 text-xs text-neutral-400">{timestamp}</div>
{/* 大腦決策層 (Proposal UI) */}
{isAlert && tier && (
<div className="mt-4 pt-3 border-t-[0.5px] border-red-200 flex justify-between items-center">
<span className="text-xs text-neutral-500">
{tier === 1 ? '>_ AI 執行中 (Tier 1)' : `>_ 等待統帥親核 (Tier ${tier})`}
</span>
{tier > 1 && (
<button className="px-3 py-1 bg-neutral-900 text-white text-xs hover:bg-black transition-colors cursor-pointer">
[ Y / n ]
</button>
)}
</div>
)}
</div>
)
}
export default DualStateIncidentCard

View File

@@ -1,8 +1,12 @@
/**
* Incident Components - Phase 7
* Incident Components - Phase 7 + 6.5a
*/
export { IncidentCard, IncidentCardGrid, IncidentEmptyState } from './incident-card'
export {
DualStateIncidentCard,
type DualStateIncidentCardProps,
} from './dual-state-incident-card'
export {
ThinkingTerminal,
DEMO_DECISION_CHAIN,