feat(hololake): project resident PNCC state

This commit is contained in:
冰朔 2026-08-16 02:52:55 +08:00
commit 9736563262
13 changed files with 325 additions and 11 deletions

View file

@ -5,7 +5,7 @@ import './design-tokens.css'
import './styles.css'
type ThemeId = 'night' | 'dawn' | 'nebula' | 'candle' | 'clear'
type Panel = 'channel' | 'receipts' | 'updates' | 'settings' | null
type Panel = 'channel' | 'pncc' | 'receipts' | 'updates' | 'settings' | null
interface HomeStatus {
schema: string
@ -87,6 +87,27 @@ interface ReleaseCheckReceipt {
candidate?: ReleaseCandidate
}
interface ServerPnccProjection {
schema: string
state: string
personaId: string
humanResponsibilitySubject: string
nodeId: string
bootId: string
gitHead: string
carrierBindingState: string
personaCarrierBound: boolean
modelInferenceStarted: boolean
realityExecutionAllowed: boolean
primaryLeaseHeld: boolean
eventCount: number
eventChainHead: string
observedAtUnixMs: number
transport: string
repositoryContentExposed: boolean
writeAuthority: boolean
}
const themes: Array<{ id: ThemeId; name: string }> = [
{ id: 'night', name: '夜湖星光' },
{ id: 'dawn', name: '晨湖曦光' },
@ -157,6 +178,9 @@ function HoloLakeApp() {
const [releaseBusy, setReleaseBusy] = useState(false)
const [releaseMessage, setReleaseMessage] = useState('')
const [message, setMessage] = useState('')
const [serverPncc, setServerPncc] = useState<ServerPnccProjection | null>(null)
const [serverPnccBusy, setServerPnccBusy] = useState(false)
const [serverPnccReadback, setServerPnccReadback] = useState<'WAITING' | 'LIVE' | 'UNAVAILABLE'>('WAITING')
const refreshStatus = useCallback(async () => {
try {
@ -172,6 +196,26 @@ function HoloLakeApp() {
return () => window.clearInterval(timer)
}, [refreshStatus])
const refreshServerPncc = useCallback(async () => {
setServerPnccBusy(true)
try {
const projection = await invoke<ServerPnccProjection>('query_jd_pncc_server_projection')
setServerPncc(projection)
setServerPnccReadback('LIVE')
} catch {
setServerPncc(null)
setServerPnccReadback('UNAVAILABLE')
} finally {
setServerPnccBusy(false)
}
}, [])
useEffect(() => {
void refreshServerPncc()
const timer = window.setInterval(() => void refreshServerPncc(), 15000)
return () => window.clearInterval(timer)
}, [refreshServerPncc])
useEffect(() => {
document.documentElement.dataset.theme = theme
window.localStorage.setItem('hololake-theme', theme)
@ -378,10 +422,10 @@ function HoloLakeApp() {
<span className={`status-light ${connectionState.tone}`} aria-hidden="true" />
<div><h2></h2><p>{connectionState.detail}</p></div>
</article>
<article className="status-item">
<span className={`status-light ${status.codeRepositoryMountCount > 0 ? 'ready' : 'quiet'}`} aria-hidden="true" />
<div><h2></h2><p>{status.codeRepositoryMountCount > 0 ? `已验证 · ${status.codeRepositoryMountCount} 个仓库` : '等待人类确认绑定'}</p></div>
</article>
<button className="status-item status-button" type="button" onClick={() => setPanel('pncc')}>
<span className={`status-light ${serverPnccReadback === 'LIVE' ? 'ready' : serverPnccReadback === 'WAITING' ? 'waiting' : 'quiet'}`} aria-hidden="true" />
<div><h2></h2><p>{serverPnccReadback === 'LIVE' ? '京东主控已驻留 · 载体保持分离' : serverPnccReadback === 'WAITING' ? '正在回读京东主控' : '主控暂时不可回读'}</p></div>
</button>
<button className="status-item status-button" type="button" onClick={() => setPanel('updates')}>
<span className={`status-light ${releaseRecoveryNeedsAttention ? 'waiting' : status.updateState.startsWith('READY') ? 'ready' : 'quiet'}`} aria-hidden="true" />
<div><h2>广</h2><p>{releaseRecoveryNeedsAttention ? '更新结果等待你的确认' : status.updateState.startsWith('READY') ? '仅接收光湖签名广播' : '信任根未配置 · 已关闭联网'}</p></div>
@ -415,6 +459,28 @@ function HoloLakeApp() {
{message && <p className="panel-message" aria-live="polite">{message}</p>}
<p className="boundary-note"></p>
</>}
{panel === 'pncc' && <>
<p className="panel-kicker"></p>
<h2 id="panel-title"></h2>
<p className="panel-intro">HoloLake 访</p>
{serverPncc ? <div className="pncc-live-card">
<div className="candidate-heading"><span className="status-light ready" /><div><b></b><span>{new Date(serverPncc.observedAtUnixMs).toLocaleString('zh-CN')}</span></div></div>
<dl className="candidate-facts pncc-facts">
<div><dt></dt><dd>{serverPncc.personaId}</dd></div>
<div><dt></dt><dd>{serverPncc.humanResponsibilitySubject}</dd></div>
<div><dt></dt><dd>{serverPncc.nodeId}</dd></div>
<div><dt></dt><dd>{serverPncc.gitHead.slice(0, 12)}</dd></div>
<div><dt></dt><dd>{serverPncc.primaryLeaseHeld ? '已持有' : '未持有'}</dd></div>
<div><dt></dt><dd>{serverPncc.personaCarrierBound ? '已验证绑定' : '未绑定 · 等待证据'}</dd></div>
<div><dt></dt><dd>{serverPncc.modelInferenceStarted ? '已启动' : '未启动'}</dd></div>
<div><dt></dt><dd>{serverPncc.realityExecutionAllowed ? '已授权' : '未授权'}</dd></div>
<div><dt></dt><dd>{serverPncc.eventCount} · {serverPncc.eventChainHead.slice(0, 12)}</dd></div>
</dl>
<p> OS Codex 访</p>
</div> : <div className="empty-state compact"><i /><b></b><span>HoloLake 线</span></div>}
<button className="secondary-action panel-action" type="button" disabled={serverPnccBusy} onClick={() => void refreshServerPncc()}>{serverPnccBusy ? '正在回读…' : '重新回读主控'}</button>
<p className="boundary-note"> SSH 127.0.0.1 PNCC </p>
</>}
{panel === 'receipts' && <>
<p className="panel-kicker"></p>
<h2 id="panel-title"></h2>