feat(hololake): project resident PNCC state
This commit is contained in:
parent
fa9c2043c1
commit
9736563262
13 changed files with 325 additions and 11 deletions
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -119,6 +119,8 @@ button:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 3px
|
|||
.repository-picker small { color: var(--content-faint); font-size: 10px; }
|
||||
.repository-picker svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.45; stroke-linecap: round; stroke-linejoin: round; }
|
||||
.candidate-card { margin-top: 26px; padding: 21px; border-radius: 21px; background: var(--primitive-glass); box-shadow: inset 0 1px var(--primitive-glass-top); }
|
||||
.pncc-live-card { margin: 26px 0 18px; padding: 21px; border: 1px solid var(--primitive-line); border-radius: 21px; background: var(--primitive-glass); box-shadow: inset 0 1px var(--primitive-glass-top); }
|
||||
.pncc-live-card > p { margin: 19px 0 0; color: var(--content-faint); font-size: 10.5px; line-height: 1.75; }
|
||||
.candidate-heading { display: flex; align-items: flex-start; gap: 14px; }
|
||||
.candidate-heading div { display: grid; gap: 5px; }
|
||||
.candidate-heading b { color: var(--content-secondary); font-size: 12.5px; }
|
||||
|
|
@ -127,6 +129,7 @@ button:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 3px
|
|||
.candidate-facts div { display: grid; grid-template-columns: 72px minmax(0, 1fr); gap: 12px; }
|
||||
.candidate-facts dt { color: var(--content-faint); font-size: 10px; }
|
||||
.candidate-facts dd { margin: 0; overflow: hidden; color: var(--content-secondary); font: 10.5px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.pncc-facts div { grid-template-columns: 78px minmax(0, 1fr); }
|
||||
.candidate-card > p { color: var(--content-faint); font-size: 10.5px; line-height: 1.7; }
|
||||
.candidate-actions { display: flex; align-items: center; gap: 16px; margin-top: 18px; }
|
||||
.candidate-actions .primary-action { min-height: 42px; padding-inline: 18px; font-size: 12px; }
|
||||
|
|
|
|||
Loading…
Reference in a new issue