feat(web): add Code Review Codex handoff board
This commit is contained in:
@@ -4,11 +4,16 @@ import { AppLayout } from '@/components/layout'
|
||||
import { IwoooSReadOnlyBridge } from '@/components/security/iwooos-read-only-bridge'
|
||||
import {
|
||||
Activity,
|
||||
ArrowRight,
|
||||
Bot,
|
||||
CheckCircle2,
|
||||
ClipboardList,
|
||||
Code2,
|
||||
ExternalLink,
|
||||
FileCheck2,
|
||||
GitBranch,
|
||||
Gauge,
|
||||
LockKeyhole,
|
||||
SearchCheck,
|
||||
ShieldCheck,
|
||||
} from 'lucide-react'
|
||||
@@ -33,6 +38,71 @@ const agentStateLabel: Record<string, string> = {
|
||||
standby: '待命',
|
||||
}
|
||||
|
||||
const codexHandoffLanes = [
|
||||
{
|
||||
icon: Code2,
|
||||
title: '可交給 Codex 起草',
|
||||
metric: '4 類',
|
||||
detail: '前端體驗、測試補洞、文件同步、低風險重構。',
|
||||
guard: '只建立草稿修正與驗證清單。',
|
||||
className: 'border-emerald-500/30 bg-emerald-500/10 text-emerald-100',
|
||||
iconClassName: 'text-emerald-300',
|
||||
},
|
||||
{
|
||||
icon: FileCheck2,
|
||||
title: '需人工批准後接手',
|
||||
metric: '3 類',
|
||||
detail: '高風險程式路徑、部署流程、跨專案設定。',
|
||||
guard: '先有人控範圍、回滾條件與證據。',
|
||||
className: 'border-amber-500/30 bg-amber-500/10 text-amber-100',
|
||||
iconClassName: 'text-amber-300',
|
||||
},
|
||||
{
|
||||
icon: LockKeyhole,
|
||||
title: '禁止自動轉工作',
|
||||
metric: '5 條',
|
||||
detail: 'Kali 主機變更、掃描、正式推版、主要來源切換、執行期閘門。',
|
||||
guard: '維持 Gate 0 與獨立人工批准。',
|
||||
className: 'border-rose-500/30 bg-rose-500/10 text-rose-100',
|
||||
iconClassName: 'text-rose-300',
|
||||
},
|
||||
]
|
||||
|
||||
const codexCandidateWork = [
|
||||
{
|
||||
id: 'CR-CX-01',
|
||||
track: '前端體驗',
|
||||
finding: '版面密度、手機寬度、文字層級',
|
||||
handoff: 'Codex 起草 UI 修正與截圖證據',
|
||||
gate: '人工確認 scope',
|
||||
state: '候選',
|
||||
},
|
||||
{
|
||||
id: 'CR-CX-02',
|
||||
track: '守門測試',
|
||||
finding: 'IwoooS 邊界、禁用動作、進度口徑',
|
||||
handoff: '補 guard / smoke test',
|
||||
gate: '不得碰 runtime',
|
||||
state: '候選',
|
||||
},
|
||||
{
|
||||
id: 'CR-CX-03',
|
||||
track: '繁中紀錄',
|
||||
finding: '部署證據、LOGBOOK、跨 Session 同步',
|
||||
handoff: '整理已驗證事實',
|
||||
gate: '不寫未驗證結論',
|
||||
state: '候選',
|
||||
},
|
||||
{
|
||||
id: 'CR-CX-04',
|
||||
track: '禁止轉派',
|
||||
finding: 'Kali 更新、掃描、GitHub primary、正式部署',
|
||||
handoff: '維持人工閘門',
|
||||
gate: '獨立批准',
|
||||
state: '封鎖',
|
||||
},
|
||||
]
|
||||
|
||||
export default function CodeReviewPage({ params }: { params: { locale: string } }) {
|
||||
const evidenceHref = `/${params.locale}/awooop/runs`
|
||||
|
||||
@@ -62,6 +132,102 @@ export default function CodeReviewPage({ params }: { params: { locale: string }
|
||||
|
||||
<IwoooSReadOnlyBridge variant="dark" />
|
||||
|
||||
<section
|
||||
id="code-review-codex-handoff-board"
|
||||
data-testid="code-review-codex-handoff-board"
|
||||
className="grid min-w-0 gap-4 rounded border border-gray-800 bg-gray-950 p-4 lg:grid-cols-[minmax(0,0.92fr)_minmax(0,1.08fr)]"
|
||||
>
|
||||
<div className="flex min-w-0 flex-col justify-between gap-5">
|
||||
<div className="min-w-0">
|
||||
<div className="flex items-center gap-2 text-xs font-mono uppercase text-sky-300">
|
||||
<ClipboardList className="h-4 w-4" />
|
||||
Code Review → Codex
|
||||
</div>
|
||||
<h2 className="mt-2 text-xl font-semibold text-white">審查後 Coding 工作橋接</h2>
|
||||
<p className="mt-2 max-w-xl text-sm leading-6 text-gray-400">
|
||||
審查結論先變成可追溯的 Codex 工作草稿;真正修改、推版、主機操作與來源切換仍留在人工閘門後面。
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid gap-2 text-xs font-mono text-gray-400 sm:grid-cols-2">
|
||||
<div className="min-w-0 break-all rounded border border-gray-800 bg-black/25 px-3 py-2">
|
||||
codex_handoff_mode=read_only_candidate
|
||||
</div>
|
||||
<div className="min-w-0 break-all rounded border border-gray-800 bg-black/25 px-3 py-2">
|
||||
codex_auto_coding_enabled=false
|
||||
</div>
|
||||
<div className="min-w-0 break-all rounded border border-gray-800 bg-black/25 px-3 py-2">
|
||||
runtime_execution_authorized=false
|
||||
</div>
|
||||
<div className="min-w-0 break-all rounded border border-gray-800 bg-black/25 px-3 py-2">
|
||||
production_deploy_authorized=false
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid min-w-0 gap-3 md:grid-cols-3">
|
||||
{codexHandoffLanes.map((lane, index) => {
|
||||
const Icon = lane.icon
|
||||
return (
|
||||
<div
|
||||
key={lane.title}
|
||||
className={`flex min-h-[12rem] min-w-0 flex-col rounded border p-3 ${lane.className}`}
|
||||
>
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<Icon className={`h-5 w-5 ${lane.iconClassName}`} />
|
||||
<span className="font-mono text-xl font-semibold">{lane.metric}</span>
|
||||
</div>
|
||||
<div className="mt-4 text-sm font-semibold text-white">{lane.title}</div>
|
||||
<p className="mt-2 text-sm leading-5 text-gray-300">{lane.detail}</p>
|
||||
<div className="mt-auto pt-4 text-xs leading-5 text-gray-400">{lane.guard}</div>
|
||||
{index < codexHandoffLanes.length - 1 ? (
|
||||
<ArrowRight className="mt-3 hidden h-4 w-4 self-end text-gray-600 md:block" />
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section
|
||||
data-testid="code-review-codex-candidate-work"
|
||||
className="min-w-0 rounded border border-gray-800 bg-gray-950"
|
||||
>
|
||||
<div className="grid min-w-0 gap-2 border-b border-gray-800 px-4 py-3 md:grid-cols-[minmax(0,1fr)_auto] md:items-center">
|
||||
<div className="min-w-0">
|
||||
<div className="break-words text-sm font-semibold text-white">Codex 工作候選佇列</div>
|
||||
<div className="mt-1 break-words text-xs text-gray-500">
|
||||
草稿、待批、封鎖分流;不是自動執行佇列。
|
||||
</div>
|
||||
</div>
|
||||
<div className="min-w-0 max-w-full break-all rounded border border-emerald-500/30 px-3 py-1 text-xs font-mono text-emerald-200 md:justify-self-end">
|
||||
action_buttons_allowed=false
|
||||
</div>
|
||||
</div>
|
||||
<div className="divide-y divide-gray-800">
|
||||
{codexCandidateWork.map((item) => (
|
||||
<div
|
||||
key={item.id}
|
||||
className="grid gap-3 px-4 py-3 text-sm md:grid-cols-[7rem_8rem_1.2fr_1.1fr_8rem_5rem] md:items-center"
|
||||
>
|
||||
<span className="min-w-0 break-words font-mono text-gray-500">{item.id}</span>
|
||||
<span className="min-w-0 break-words font-semibold text-white">{item.track}</span>
|
||||
<span className="min-w-0 break-words text-gray-400">{item.finding}</span>
|
||||
<span className="min-w-0 break-words text-gray-300">{item.handoff}</span>
|
||||
<span className="min-w-0 break-words text-gray-500">{item.gate}</span>
|
||||
<span
|
||||
className={
|
||||
item.state === '封鎖'
|
||||
? 'justify-self-start rounded bg-rose-500/10 px-2 py-1 text-xs font-mono text-rose-200'
|
||||
: 'justify-self-start rounded bg-emerald-500/10 px-2 py-1 text-xs font-mono text-emerald-200'
|
||||
}
|
||||
>
|
||||
{item.state}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="grid gap-3 md:grid-cols-4">
|
||||
<div className="rounded border border-gray-800 bg-gray-950 p-4">
|
||||
<div className="flex items-center gap-2 text-xs text-gray-400">
|
||||
|
||||
@@ -8297,6 +8297,24 @@ def validate(root: Path) -> None:
|
||||
source_text,
|
||||
'<IwoooSReadOnlyBridge variant="dark" />',
|
||||
)
|
||||
for text in [
|
||||
'data-testid="code-review-codex-handoff-board"',
|
||||
'data-testid="code-review-codex-candidate-work"',
|
||||
"審查後 Coding 工作橋接",
|
||||
"Codex 工作草稿",
|
||||
"可交給 Codex 起草",
|
||||
"需人工批准後接手",
|
||||
"禁止自動轉工作",
|
||||
"codex_handoff_mode=read_only_candidate",
|
||||
"codex_auto_coding_enabled=false",
|
||||
"runtime_execution_authorized=false",
|
||||
"production_deploy_authorized=false",
|
||||
"action_buttons_allowed=false",
|
||||
"CR-CX-04",
|
||||
"Kali 更新、掃描、GitHub primary、正式部署",
|
||||
"維持人工閘門",
|
||||
]:
|
||||
assert_text_contains("code_review_page.codex_handoff_read_only", code_review_page, text)
|
||||
assert_text_contains("iwooos_page.surface_connection_board", iwooos_projection_page, "surfaceConnectionStatuses")
|
||||
assert_text_contains("iwooos_page.surface_connection_testid", iwooos_projection_page, 'data-testid="iwooos-surface-connection-board"')
|
||||
assert_text_contains("iwooos_page.surface_connection_embedded", iwooos_projection_page, "embeddedBridge")
|
||||
|
||||
Reference in New Issue
Block a user