import { StrictMode, useCallback, useEffect, useMemo, useState } from 'react' import { createRoot } from 'react-dom/client' import { invoke } from '@tauri-apps/api/core' import './design-tokens.css' import './styles.css' type ThemeId = 'night' | 'dawn' | 'nebula' | 'candle' | 'clear' type Panel = 'channel' | 'receipts' | 'updates' | 'settings' | null interface HomeStatus { schema: string directLocalBrokerState: string directConnectionCount: number resumableSessionCount: number codeRepositoryMountCount: number pnccReceiptCount: number updateState: string automaticUpstreamUpdates: boolean mcpRole: string } interface DiscoveryTicketReceipt { schema: string state: string accountKey: string laneId: string clientInstanceId: string discoveryTicket: string issuedAtUnixMs: number receiptId: string } interface ReceiptEvent { sequence: number kind: string observedAtUnixMs: number eventHash: string } interface ReceiptProjection { events: ReceiptEvent[] returnedEventCount: number lastSequence: number } interface RepositoryInspection { personaId: string humanResponsibilitySubject: string repositoryPath: string gitHead: string repositoryClean: boolean currentCheckpoint: { relativePath: string; sha256: string } modelInferenceStarted: boolean realityExecutionAllowed: boolean } interface RepositoryCandidate { schema: string state: string candidateId: string confirmationToken: string expiresAtUnixMs: number inspection: RepositoryInspection } interface ReleaseCandidate { candidateId: string confirmationToken: string releaseId: string currentVersion: string version: string notes: string features: string[] fixes: string[] minimumVersion: string dataMigrationRequired: boolean compatibilityNotes?: string restartMessage?: string rollbackSupported: boolean previousVersion?: string expiresAtUnixMs: number } interface ReleaseCheckReceipt { state: string candidate?: ReleaseCandidate } const themes: Array<{ id: ThemeId; name: string }> = [ { id: 'night', name: '夜湖星光' }, { id: 'dawn', name: '晨湖曦光' }, { id: 'nebula', name: '星云紫夜' }, { id: 'candle', name: '烛畔暖湖' }, { id: 'clear', name: '清浅澄湖' }, ] const previewStatus: HomeStatus = { schema: 'hololake.home-status/preview', directLocalBrokerState: 'PREVIEW', directConnectionCount: 0, resumableSessionCount: 0, codeRepositoryMountCount: 0, pnccReceiptCount: 0, updateState: 'UNPROVISIONED_FAIL_CLOSED', automaticUpstreamUpdates: false, mcpRole: 'DISCOVERY_RECOVERY_COMPATIBILITY_ONLY', } function getOrCreateLocalId(key: string, prefix: string) { const existing = window.localStorage.getItem(key) if (existing) return existing const generated = `${prefix}-${crypto.randomUUID()}` window.localStorage.setItem(key, generated) return generated } function Icon({ name }: { name: 'settings' | 'arrow' | 'receipt' | 'close' | 'copy' }) { const paths = { settings: <>, arrow: <>, receipt: <>, close: <>, copy: <>, } return } function HoloLakeApp() { const [theme, setTheme] = useState(() => (window.localStorage.getItem('hololake-theme') as ThemeId) || 'night') const [status, setStatus] = useState(previewStatus) const [panel, setPanel] = useState(null) const [ticket, setTicket] = useState(null) const [receipts, setReceipts] = useState([]) const [repositoryCandidate, setRepositoryCandidate] = useState(null) const [repositoryBusy, setRepositoryBusy] = useState(false) const [repositoryMessage, setRepositoryMessage] = useState('') const [releaseCandidate, setReleaseCandidate] = useState(null) const [releaseBusy, setReleaseBusy] = useState(false) const [releaseMessage, setReleaseMessage] = useState('') const [message, setMessage] = useState('') const refreshStatus = useCallback(async () => { try { setStatus(await invoke('get_hololake_home_status')) } catch { setStatus(previewStatus) } }, []) useEffect(() => { void refreshStatus() const timer = window.setInterval(() => void refreshStatus(), 3000) return () => window.clearInterval(timer) }, [refreshStatus]) useEffect(() => { document.documentElement.dataset.theme = theme window.localStorage.setItem('hololake-theme', theme) }, [theme]) const connectionState = useMemo(() => { if (status.directConnectionCount > 0) return { label: '已连接', detail: `${status.directConnectionCount} 个直连通道在线`, tone: 'ready' } if (status.resumableSessionCount > 0) return { label: '可续接', detail: `${status.resumableSessionCount} 个会话等待续接`, tone: 'waiting' } return { label: '等待连接', detail: '本机直连核心已就绪', tone: 'quiet' } }, [status]) const openReceipts = async () => { setPanel('receipts') await loadReceipts() } const loadReceipts = async () => { try { const projection = await invoke('query_pncc_receipt_projection', { input: { afterSequence: 0, limit: 25 } }) setReceipts(projection.events) } catch { setReceipts([]) } } const chooseRepository = async () => { setRepositoryBusy(true) setRepositoryMessage('') try { const candidate = await invoke('select_pncc_repository_candidate') setRepositoryCandidate(candidate) if (!candidate) setRepositoryMessage('已取消选择,没有写入任何绑定。') } catch (error) { setRepositoryCandidate(null) setRepositoryMessage(`这个文件夹不能作为代码通道:${String(error)}`) } finally { setRepositoryBusy(false) } } const confirmRepository = async () => { if (!repositoryCandidate) return setRepositoryBusy(true) setRepositoryMessage('') try { await invoke('confirm_pncc_repository_mount', { input: { candidateId: repositoryCandidate.candidateId, confirmationToken: repositoryCandidate.confirmationToken, }, }) setRepositoryCandidate(null) setRepositoryMessage('代码仓库已按当前固定提交绑定为只读通道。') await Promise.all([refreshStatus(), loadReceipts()]) } catch (error) { setRepositoryMessage(`绑定没有写入:${String(error)}`) } finally { setRepositoryBusy(false) } } const checkUpdate = async () => { setReleaseBusy(true) setReleaseMessage('') try { const receipt = await invoke('check_hololake_update') setReleaseCandidate(receipt.candidate || null) if (!receipt.candidate) setReleaseMessage('当前已经是最新版本。') } catch (error) { const reason = String(error) setReleaseCandidate(null) setReleaseMessage(reason.includes('UNPROVISIONED_NO_NETWORK_REQUEST') ? '京东主控的正式发布地址和更新公钥还没有登记。HoloLake 保持离线,不会向任何上游检查更新。' : `更新检查没有完成:${reason}`) } finally { setReleaseBusy(false) } } const confirmUpdateInstall = async () => { if (!releaseCandidate) return setReleaseBusy(true) setReleaseMessage('正在重新核对广播并验证安装包;完成后由你手动重启 HoloLake。') try { await invoke('confirm_hololake_update_install', { input: { candidateId: releaseCandidate.candidateId, confirmationToken: releaseCandidate.confirmationToken, }, }) setReleaseCandidate(null) setReleaseMessage('签名安装包已验证并安装。请在准备好后手动重启 HoloLake。') } catch (error) { setReleaseMessage(`更新没有安装:${String(error)}`) } finally { setReleaseBusy(false) } } const issueInvitation = async () => { setMessage('') try { const receipt = await invoke('issue_direct_local_discovery_ticket', { input: { accountId: getOrCreateLocalId('hololake-local-account', 'human-local'), laneId: 'personal-channel', clientInstanceId: getOrCreateLocalId('hololake-external-ai-client', 'external-ai'), }, }) setTicket(receipt) setMessage('连接邀请已生成。它只在这台电脑上有效。') } catch (error) { setMessage(`暂时无法生成连接邀请:${String(error)}`) } } const invitationText = ticket ? JSON.stringify({ schema: 'hololake.direct-local-invitation/v1', transport: 'INSTALLED_HOLOLAKE_EXECUTABLE_WITH_CONNECTOR_FLAG', connectorArgument: '--connector', openSession: { operation: 'OPEN_SESSION', input: { accountId: window.localStorage.getItem('hololake-local-account'), laneId: ticket.laneId, clientInstanceId: ticket.clientInstanceId, discoveryTicket: ticket.discoveryTicket, }, }, mcpRole: 'DISCOVERY_RECOVERY_COMPATIBILITY_ONLY', }, null, 2) : '' const copyInvitation = async () => { try { await navigator.clipboard.writeText(invitationText) setMessage('已复制。把它交给桌面上的编程 AI 即可。') } catch { setMessage('复制没有成功,请选中下方邀请内容后复制。') } } return (