diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index 4c22fe15e..b9da3fcbe 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -329,6 +329,12 @@ "quality": "品質閘門", "provider": "AI Provider", "km": "KM 健康" + }, + "swimlanes": { + "signals": "Signals / 收件", + "reasoning": "AI / MCP 判斷", + "execution": "PlayBook / Ansible", + "governance": "Approval / KM" } }, "homeProductMap": { diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index 4c22fe15e..b9da3fcbe 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -329,6 +329,12 @@ "quality": "品質閘門", "provider": "AI Provider", "km": "KM 健康" + }, + "swimlanes": { + "signals": "Signals / 收件", + "reasoning": "AI / MCP 判斷", + "execution": "PlayBook / Ansible", + "governance": "Approval / KM" } }, "homeProductMap": { diff --git a/apps/web/src/app/[locale]/page.tsx b/apps/web/src/app/[locale]/page.tsx index 64c872a26..387c46fdc 100644 --- a/apps/web/src/app/[locale]/page.tsx +++ b/apps/web/src/app/[locale]/page.tsx @@ -1879,6 +1879,55 @@ export default function Home({ params }: { params: { locale: string } }) { }), }, ] + const commandMapSwimlanes: Array<{ + key: string + label: string + summary: string + tone: HomepageWorkTone + stages: HomepageBlueprintStage[] + }> = [ + { + key: 'signals', + label: tDashboard('homeCommandMap.swimlanes.signals'), + summary: tDashboard('automationDiagrams.workspace.liveEvidence.signal.metric', { + sources: formatAutomationNumber(dossierCoverageSummary?.source_count, dossierCoverageLoaded), + refs: formatAutomationNumber(dossierCoverageSummary?.source_ref_total, dossierCoverageLoaded), + }), + tone: dossierCoverageLoaded ? 'live' : 'watching', + stages: automationFlowStages.filter(stage => stage.key === 'signal' || stage.key === 'intake'), + }, + { + key: 'reasoning', + label: tDashboard('homeCommandMap.swimlanes.reasoning'), + summary: tDashboard('automationDiagrams.workspace.values.aiRoute', { + lane: aiRouteLaneMode, + provider: aiRouteSelectedProvider, + }), + tone: hasAiRouteStatus ? 'live' : 'watching', + stages: automationFlowStages.filter(stage => stage.key === 'ai' || stage.key === 'mcp'), + }, + { + key: 'execution', + label: tDashboard('homeCommandMap.swimlanes.execution'), + summary: tDashboard('automationDiagrams.workspace.values.ansible', { + checkMode: formatAutomationNumber(executionBackend?.ansible_check_mode_total, automationQualityLoaded), + pending: formatAutomationNumber(executionBackend?.ansible_pending_check_mode_total, automationQualityLoaded), + blocker: ansibleRuntimeBlockerLabel, + }), + tone: ansibleRuntime?.can_run_check_mode ? 'live' : automationQualityAvailable ? 'blocked' : 'watching', + stages: automationFlowStages.filter(stage => stage.key === 'playbook' || stage.key === 'ansible'), + }, + { + key: 'governance', + label: tDashboard('homeCommandMap.swimlanes.governance'), + summary: tDashboard('automationDiagrams.workspace.liveEvidence.verify.metric', { + stale: formatAutomationNumber(kmStaleDisplayCount, kmGovernanceLoaded), + ratio: staleRatioLabel, + }), + tone: typeof kmStaleDisplayCount === 'number' && kmStaleDisplayCount > 0 ? 'progress' : hasKmStaleCandidates ? 'live' : 'watching', + stages: automationFlowStages.filter(stage => stage.key === 'approval' || stage.key === 'verify'), + }, + ] const productModuleRows: Array<{ key: string module: string @@ -2263,6 +2312,139 @@ export default function Home({ params }: { params: { locale: string } }) { })} +