import { StrictMode, useCallback, useEffect, useMemo, useRef, useState } from 'react' import { createRoot } from 'react-dom/client' import { invoke } from '@tauri-apps/api/core' import { splitFrontmatter, documentOutline, jumpToHeading, MarkdownDocument, markdownHtml } from './modules/knowledge-render' import nightLake from './assets/hololake-night-lake.png' const TAG_TINTS = ['tag-lavender', 'tag-sky', 'tag-mint', 'tag-amber', 'tag-rose', 'tag-slate'] // 编号自动补齐:人只敲字母与数字,杠由系统按已登记文法自动出。 // ICE 系(ICE-GL∞ / ICE-P-ZY001)、GLS 系(GLS-LA-20260720-003);认不出的文法只在字母数字交界处补杠。 function formatGateNumber(raw: string): string { const up = raw.toUpperCase() if (up.startsWith('ICE')) { const rest = up.slice(3) if (!rest) return 'ICE' if (rest.startsWith('P')) { const body = rest.slice(1) return body ? `ICE-P-${body}` : 'ICE-P' } return `ICE-${rest}` } if (up.startsWith('GLS')) { const rest = up.slice(3) if (!rest) return 'GLS' const letters = rest.match(/^[A-Z]*/)?.[0] ?? '' const digits = rest.slice(letters.length) if (!digits) return `GLS-${letters}` const d1 = digits.slice(0, 8) const d2 = digits.slice(8, 11) return `GLS-${letters}-${d1}${d2 ? `-${d2}` : ''}` } return up.replace(/([A-Z]+)([0-9])/g, '$1-$2').replace(/([0-9]+)([A-Z])/g, '$1-$2') } function tagTint(tag: string) { let hash = 0 for (const char of tag) hash = (hash * 31 + (char.codePointAt(0) || 0)) % 997 return TAG_TINTS[hash % TAG_TINTS.length] } import './design-tokens.css' import './styles.css' type ThemeId = 'night' | 'dawn' | 'nebula' | 'candle' | 'clear' type ViewId = 'overview' | 'knowledge' | 'code' | 'receipts' | 'system' type KnowledgeSource = 'native' | 'legacy' interface HomeStatus { directLocalBrokerState: string directConnectionCount: number resumableSessionCount: number codeRepositoryMountCount: number pnccReceiptCount: number updateState: string releaseRecoveryState: string mcpRole: string } interface PersonalChannelIdentity { humanSubjectId: string; displayName: string; channelId: string; createdAtUnixMs: number } interface LoginSession { username: string; host: string; domain: string; signedInAtUnixMs: number } interface LoginReceipt { username: string; email: string; host: string; domain: string } interface UserPnccChannelSnapshot { state: string repositoryId: string channelId: string userNumber: string domain: string accountUsername: string accountHost: string localPath: string branch: string gitHead: string repositoryClean: boolean createdAtUnixMs: number gitEngine: string humanProjection: string forgejoAdapterState: string remoteRepositoryUrl?: string personaBindingClaimed: boolean authority: string } interface PersonalChannelEvent { sequence: number; eventId: string; kind: string; summary: string; occurredAtUnixMs: number; receiptId: string; receiptHash: string } interface PersonalChannelSnapshot { state: string; identity?: PersonalChannelIdentity; recentEvents: PersonalChannelEvent[]; integrity: { state: string; eventCount: number; receiptCount: number } } interface KnowledgeDocumentSummary { source: KnowledgeSource path: string title: string updatedAtUnixMs: number sizeBytes: number contentSha256: string duplicateCount: number } interface KnowledgeSnapshot { state: string nativeRoot: string legacyAvailable: boolean legacyRoot?: string documents: KnowledgeDocumentSummary[] rawDocumentCount: number uniqueDocumentCount: number duplicateDocumentCount: number truncated: boolean } interface KnowledgeDocument { source: KnowledgeSource path: string title: string body: string updatedAtUnixMs: number contentSha256: string writable: boolean } interface KnowledgeSearchResult { source: KnowledgeSource; path: string; title: string; snippet: string } interface KnowledgeImportResult { state: string sourceName: string importedDocuments: number importedAssets: number existingDocuments: number conflicts: number skipped: number firstDocument?: string gitCommit: string snapshot: KnowledgeSnapshot } interface KnowledgeSaveResult { state: string; gitCommit: string; document: KnowledgeDocument } interface CodeChannelEntry { channelId: string; name: string; sourceKind: string; localPath: string; remoteUrl?: string; gitHead: string; branch: string; repositoryClean: boolean; registeredAtUnixMs: number } interface CodeChannelSnapshot { state: string; channels: CodeChannelEntry[]; authority: string } interface CodeTreeEntry { path: string; name: string; kind: 'directory' | 'file'; sizeBytes: number } interface CodeTreeSnapshot { channelId: string; path: string; entries: CodeTreeEntry[]; truncated: boolean } interface CodeFileProjection { channelId: string; path: string; format: string; source: string; humanMarkdown: string; sizeBytes: number } interface ReceiptEvent { sequence: number; kind: string; observedAtUnixMs: number; eventHash: string } interface ReceiptProjection { events: ReceiptEvent[] } interface DiscoveryTicketReceipt { laneId: string; clientInstanceId: string; discoveryTicket: string } interface NearbyAiDiscoverySnapshot { state: string serviceName: string transport: string languageProtocol: string automaticSameDeviceDiscovery: boolean largeInvitationCopyRequired: boolean genericAiVisitor: string guanghuPersona: string localNetworkDiscovery: string authority: string } interface ReleaseCandidate { candidateId: string; confirmationToken: string; currentVersion: string; version: string; notes: string; features: string[]; fixes: string[]; dataMigrationRequired: boolean } interface ReleaseCheckReceipt { candidate?: ReleaseCandidate } interface ZeroPointSnapshot { route: string binding: string userNumber: string resolvedName: string resolvedDomain: string lastValidCheck: number graceDeadline: number protocol: { gracePeriodDays: number; lighthouseAnchorUrl: string; lighthouseResolveUrl: string; coreChannelSource: string; origin: string } syncNote: string } function domainDisplayName(domain: string): string { const names: Record = { FIFTH_DOMAIN: '第五域 · 光湖本源域', MAIN_DOMAIN: '光湖主域', BRANCH_DOMAIN: '光湖分域', ZERO_DOMAIN: '光湖零域', ZERO_SENSE_DOMAIN: '光湖零感域', } return names[domain] || '已登记光湖域' } function domainLightIndex(domain: string): number { return ({ MAIN_DOMAIN: 1, BRANCH_DOMAIN: 2, ZERO_DOMAIN: 3, ZERO_SENSE_DOMAIN: 4, FIFTH_DOMAIN: 5 } as Record)[domain] || 0 } function protocolOriginDisplayName(origin: string): string { return origin.startsWith('FACTORY_DEFAULT') ? '内置默认协议(签名发布通道尚未配置)' : origin } 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 previewStatus: HomeStatus = { directLocalBrokerState: 'UNVERIFIED', directConnectionCount: 0, resumableSessionCount: 0, codeRepositoryMountCount: 0, pnccReceiptCount: 0, updateState: 'UNPROVISIONED_FAIL_CLOSED', releaseRecoveryState: 'NONE', mcpRole: 'DISCOVERY_RECOVERY_COMPATIBILITY_ONLY' } const previewPersonal: PersonalChannelSnapshot = { state: 'UNAVAILABLE', recentEvents: [], integrity: { state: 'UNKNOWN', eventCount: 0, receiptCount: 0 } } const previewKnowledge: KnowledgeSnapshot = { state: 'UNAVAILABLE', nativeRoot: '', legacyAvailable: false, documents: [], rawDocumentCount: 0, uniqueDocumentCount: 0, duplicateDocumentCount: 0, truncated: false } const previewCode: CodeChannelSnapshot = { state: 'UNAVAILABLE', channels: [], authority: 'LOCAL_SOURCE_ACCESS_ONLY_NO_PUSH_OR_DEPLOY_AUTHORITY' } const themes: Array<{ id: ThemeId; name: string }> = [ { id: 'night', name: '夜湖星光' }, { id: 'dawn', name: '晨湖曦光' }, { id: 'nebula', name: '星云紫夜' }, { id: 'candle', name: '烛畔暖湖' }, { id: 'clear', name: '清浅澄湖' }, ] const viewLabels: Record = { overview: '个人频道', knowledge: '知识空间', code: '人格代码频道', receipts: '运行回执', system: '系统详情' } 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 humanError(error: unknown, context: 'knowledge' | 'code' | 'identity' | 'system' | 'login') { const value = String(error) if (value.includes('LOGIN_CREDENTIALS_INVALID')) return '账号或密码未被仓库接受。' if (value.includes('LOGIN_USERNAME_INVALID')) return '账号格式不合法(仅限字母、数字、连字符、下划线)。' if (value.includes('LOGIN_NETWORK_FAILED')) return '未能连通光湖代码频道服务器。' if (value.includes('LOGIN_KEYCHAIN_FAILED')) return '本机钥匙串写入失败,凭证未能安全保存。' if (value.includes('LOGIN_SESSION_CORRUPT')) return '登录会话已损坏,请重新登录。' if (value.includes('LOGIN_VERIFICATION_FAILED')) return '仓库验证未通过,请稍后再试。' if (value.includes('DOMAIN_LOGIN_NOT_PROVISIONED')) return '该域的企业服务器尚未接入,当前不能继续登录。' if (value.includes('DOMAIN_ROUTE_REQUIRED') || value.includes('ZP_DOMAIN_ROUTE_REQUIRED')) return '编号尚未解析到已登记域,不能开始登录。' if (value.includes('USER_PNCC_TRUSTED_SUBJECT_REQUIRED')) return '建立人格代码频道前,需要有效的用户编号与仓库账号登录。' if (value.includes('USER_PNCC_BINDING_MISMATCH')) return '本机频道绑定记录与当前账号不一致,系统已停止加载。' if (value.includes('HOST_NOT_TRUSTED')) return '该地址不属于已登记的光湖代码频道。' if (value.includes('URL_INVALID')) return '频道地址无效,请粘贴完整的 HTTPS 克隆地址。' if (value.includes('DESTINATION_EXISTS')) return '该代码频道已经存在,无需再次克隆。' if (value.includes('CLONE_FAILED')) return '代码频道克隆失败,请核对地址及读取权限。' if (value.includes('NO_SUPPORTED_FILES')) return '文件夹中没有可导入的知识文件。' if (value.includes('SAVE_CONFLICT')) return '页面已在别处更新,请重新打开后再编辑。' if (value.includes('FILE_UNSUPPORTED')) return '该文件不是当前可阅读的文本格式。' if (context === 'login') return '登录未完成。' if (context === 'identity') return '个人空间未能建立。' if (context === 'knowledge') return '知识操作未完成,原文件未被覆盖。' if (context === 'code') return '代码频道操作未完成。' return '系统操作未完成。' } function Icon({ name }: { name: ViewId | 'search' | 'import' | 'folder' | 'copy' | 'arrow' | 'chevron' | 'file' | 'edit' | 'save' | 'back' | 'download' | 'trash' | 'chevronDown' | 'settings' | 'more' | 'plus' }) { const paths: Record = { overview: <>, knowledge: <>, code: <>, receipts: <>, system: <>, search: <>, import: <>, download: <>, trash: <>, chevronDown: , settings: <>, more: <>, plus: , folder: , file: <>, copy: <>, arrow: <>, chevron: , edit: <>, save: <>, back: , } return } interface TreeNode { name: string; key: string; folders: Map; documents: KnowledgeDocumentSummary[] } function knowledgeTree(documents: KnowledgeDocumentSummary[]) { const root: TreeNode = { name: '知识', key: '', folders: new Map(), documents: [] } for (const document of documents) { const segments = document.path.split('/').filter(Boolean) const file = segments.pop() let cursor = root for (const segment of segments) { const key = cursor.key ? `${cursor.key}/${segment}` : segment if (!cursor.folders.has(segment)) cursor.folders.set(segment, { name: segment, key, folders: new Map(), documents: [] }) cursor = cursor.folders.get(segment)! } cursor.documents.push({ ...document, title: document.title || file || '未命名页面' }) } return root } function countTree(node: TreeNode): number { return node.documents.length + [...node.folders.values()].reduce((sum, child) => sum + countTree(child), 0) } function KnowledgeTree({ node, depth, expanded, active, onToggle, onOpen, onRemoveFolder, folderMenuKey, onFolderMenuToggle }: { node: TreeNode; depth: number; expanded: Set; active?: string; onToggle: (key: string) => void; onOpen: (item: KnowledgeDocumentSummary) => void; onRemoveFolder?: (folder: TreeNode) => void; folderMenuKey?: string | null; onFolderMenuToggle?: (key: string) => void }) { const folders = [...node.folders.values()].sort((a, b) => a.name.localeCompare(b.name, 'zh-CN')) const documents = [...node.documents].sort((a, b) => a.title.localeCompare(b.title, 'zh-CN')) return <> {folders.map((folder) => { const open = depth === 0 || expanded.has(folder.key) return
{onRemoveFolder && onFolderMenuToggle && {folderMenuKey === folder.key && }} {open && }
})} {documents.map((document) => )} } function HoloLakeApp() { const [theme, setTheme] = useState(() => (window.localStorage.getItem('hololake-theme') as ThemeId) || 'night') const [view, setView] = useState('knowledge') const [status, setStatus] = useState(previewStatus) const [personal, setPersonal] = useState(previewPersonal) const [knowledge, setKnowledge] = useState(previewKnowledge) const [codeChannels, setCodeChannels] = useState(previewCode) const [activeDocument, setActiveDocument] = useState(null) const [searchQuery, setSearchQuery] = useState('') const [searchResults, setSearchResults] = useState(null) const [knowledgeBusy, setKnowledgeBusy] = useState(false) const [knowledgeMessage, setKnowledgeMessage] = useState('') const [expanded, setExpanded] = useState>(() => new Set(['导入'])) const [editing, setEditing] = useState(false) const [draft, setDraft] = useState('') const [lastKnowledgeReceipt, setLastKnowledgeReceipt] = useState('') const [cloneUrl, setCloneUrl] = useState('') const [codeBusy, setCodeBusy] = useState(false) const [codeMessage, setCodeMessage] = useState('') const [activeChannel, setActiveChannel] = useState(null) const [codeTree, setCodeTree] = useState(null) const [activeCodeFile, setActiveCodeFile] = useState(null) const [codeMode, setCodeMode] = useState<'human' | 'source'>('human') const [sidebarCollapsed, setSidebarCollapsed] = useState(() => window.localStorage.getItem('hololake-sidebar-collapsed') === '1') const [inspectorOpen, setInspectorOpen] = useState(() => window.localStorage.getItem('hololake-inspector-open') !== '0') const toggleSidebar = () => setSidebarCollapsed((current) => { window.localStorage.setItem('hololake-sidebar-collapsed', current ? '0' : '1'); return !current }) const toggleInspector = () => setInspectorOpen((current) => { window.localStorage.setItem('hololake-inspector-open', current ? '0' : '1'); return !current }) const [activeHeadingId, setActiveHeadingId] = useState(null) const headingScrollTimer = useRef(null) const [settingsMenuOpen, setSettingsMenuOpen] = useState(false) const [folderMenuKey, setFolderMenuKey] = useState(null) const [displayName, setDisplayName] = useState('') const [identityBusy, setIdentityBusy] = useState(false) const [identityMessage, setIdentityMessage] = useState('') const [receipts, setReceipts] = useState([]) const [ticket, setTicket] = useState(null) const [nearbyDiscovery, setNearbyDiscovery] = useState(null) const [systemMessage, setSystemMessage] = useState('') const [releaseCandidate, setReleaseCandidate] = useState(null) const [repoLogin, setRepoLogin] = useState(null) const [userPncc, setUserPncc] = useState(null) const [userPnccBusy, setUserPnccBusy] = useState(false) const [userPnccMessage, setUserPnccMessage] = useState('') const [loginUsername, setLoginUsername] = useState('') const [loginPassword, setLoginPassword] = useState('') const [loginBusy, setLoginBusy] = useState(false) const [loginRising, setLoginRising] = useState(false) const [loginMessage, setLoginMessage] = useState('') const [gateStage, setGateStage] = useState<'number' | 'key'>('number') const [gateRaw, setGateRaw] = useState('') const [gateInf, setGateInf] = useState(false) const gateNumber = formatGateNumber(gateRaw) + (gateInf ? '∞' : '') const [gateOpen, setGateOpen] = useState(false) const gateInputRef = useRef(null) // 等待入口展开动画进入稳定阶段后再聚焦输入框,避免动画期间焦点跳转。 useEffect(() => { if (!gateOpen || gateStage !== 'number') return const timer = window.setTimeout(() => gateInputRef.current?.focus(), 640) return () => window.clearTimeout(timer) }, [gateOpen, gateStage]) const [gateBusy, setGateBusy] = useState(false) const [gateMessage, setGateMessage] = useState('') const [gateRising, setGateRising] = useState(false) const [systemBusy, setSystemBusy] = useState(false) const [zeroPoint, setZeroPoint] = useState(null) const [zpNumber, setZpNumber] = useState('') const [zpBusy, setZpBusy] = useState(false) const [zpMessage, setZpMessage] = useState('') const [serverPncc, setServerPncc] = useState(null) const [serverPnccBusy, setServerPnccBusy] = useState(false) const [serverPnccReadback, setServerPnccReadback] = useState<'WAITING' | 'LIVE' | 'UNAVAILABLE'>('WAITING') const refreshCore = useCallback(async () => { const [homeResult, personalResult, knowledgeResult, codeResult] = await Promise.allSettled([ invoke('get_hololake_home_status'), invoke('get_personal_channel_snapshot'), invoke('get_knowledge_snapshot'), invoke('get_code_channel_snapshot'), ]) if (homeResult.status === 'fulfilled') setStatus(homeResult.value) if (personalResult.status === 'fulfilled') setPersonal(personalResult.value) if (knowledgeResult.status === 'fulfilled') setKnowledge(knowledgeResult.value) if (codeResult.status === 'fulfilled') setCodeChannels(codeResult.value) }, []) const loadReceipts = useCallback(async () => { try { const projection = await invoke('query_pncc_receipt_projection', { input: { afterSequence: 0, limit: 25 } }) setReceipts(projection.events) } catch { setReceipts([]) } }, []) useEffect(() => { void refreshCore() const timer = window.setInterval(() => void refreshCore(), 3500) return () => window.clearInterval(timer) }, [refreshCore]) useEffect(() => { invoke('get_nearby_ai_discovery') .then(setNearbyDiscovery) .catch(() => setNearbyDiscovery(null)) }, []) const refreshServerPncc = useCallback(async () => { setServerPnccBusy(true) try { setServerPncc(await invoke('query_jd_pncc_server_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) }, [theme]) useEffect(() => { invoke('check_code_repo_login').then((session) => setRepoLogin(session)).catch(() => setRepoLogin(null)) }, []) const loadZeroPoint = useCallback(async () => { try { setZeroPoint(await invoke('zero_point_status')) } catch { /* 验证服务尚未就绪时保持空白状态。 */ } }, []) useEffect(() => { void loadZeroPoint() const timer = window.setInterval(() => void loadZeroPoint(), 10000) return () => window.clearInterval(timer) }, [loadZeroPoint]) // 已验证编号与已认证账号同时存在时,后端幂等建立或恢复该用户自己的 GH-PNCC。 useEffect(() => { if (!repoLogin || zeroPoint?.route !== 'verified') { setUserPncc(null) return } let active = true setUserPnccBusy(true) setUserPnccMessage('') invoke('ensure_user_pncc_channel') .then((snapshot) => { if (!active) return setUserPncc(snapshot) setUserPnccMessage('本机原生代码频道已就绪。') void refreshCore() }) .catch((error) => { if (active) setUserPnccMessage(humanError(error, 'code')) }) .finally(() => { if (active) setUserPnccBusy(false) }) return () => { active = false } }, [repoLogin, zeroPoint?.route, zeroPoint?.userNumber, refreshCore]) // 本机存在已绑定编号时自动回填,减少重复输入。 useEffect(() => { if (gateStage !== 'number' || gateRaw) return const bound = zeroPoint?.binding === 'bound' ? zeroPoint.userNumber : '' if (!bound) return setGateInf(bound.includes('∞')) setGateRaw(bound.toUpperCase().replace(/[^A-Z0-9]/g, '')) }, [zeroPoint, gateStage, gateRaw]) // 大门·编号门输入:只收字母数字(杠系统补、∞开关点),删到∞时开关跟着灭 const onGateInput = (value: string) => { if (gateInf && !value.includes('∞')) setGateInf(false) setGateRaw(value.toUpperCase().replace(/[^A-Z0-9]/g, '')) } // 大门·编号门:先报编号→灯塔查号→只答有效/无效→域浮起→才见钥匙门 const gateVerifyNumber = async () => { setGateBusy(true) setGateMessage('') try { await invoke('zero_point_bind', { input: { number: gateNumber } }) const snapshot = await invoke('zero_point_verify') setZeroPoint(snapshot) if (snapshot.route === 'verified') { setGateRising(true) window.setTimeout(() => { setGateRising(false); setGateStage('key') }, 2600) } else { setGateMessage('编号无效') } } catch (error) { setGateMessage(humanError(error, 'login')) } finally { setGateBusy(false) } } useEffect(() => { if (view === 'receipts') void loadReceipts() }, [loadReceipts, view]) const visibleDocuments = useMemo(() => { if (!searchResults) return knowledge.documents return searchResults.map((result) => knowledge.documents.find((item) => item.source === result.source && item.path === result.path)).filter(Boolean) as KnowledgeDocumentSummary[] }, [knowledge.documents, searchResults]) const tree = useMemo(() => knowledgeTree(visibleDocuments), [visibleDocuments]) const activeSummary = activeDocument ? knowledge.documents.find((item) => item.source === activeDocument.source && item.path === activeDocument.path) : undefined const parsedDocument = useMemo(() => activeDocument ? splitFrontmatter(activeDocument.body) : null, [activeDocument]) const outline = useMemo(() => activeDocument ? documentOutline(activeDocument.body) : [], [activeDocument]) const docStats = useMemo(() => { if (!activeDocument) return null const chars = activeDocument.body.replace(/\s+/g, '').length return { chars, minutes: Math.max(1, Math.ceil(chars / 400)) } }, [activeDocument]) useEffect(() => { setActiveHeadingId(null) }, [activeDocument?.path]) useEffect(() => { if (!activeHeadingId) return document.querySelector('.outline-list button.active')?.scrollIntoView({ block: 'nearest' }) }, [activeHeadingId]) const handleReaderScroll = (event: React.UIEvent) => { const container = event.currentTarget if (headingScrollTimer.current !== null) return headingScrollTimer.current = window.setTimeout(() => { headingScrollTimer.current = null const containerTop = container.getBoundingClientRect().top let current: string | null = null for (const heading of Array.from(container.querySelectorAll('h1[id], h2[id], h3[id], h4[id]'))) { if (heading.getBoundingClientRect().top - containerTop <= 28) current = heading.id else break } setActiveHeadingId(current) }, 100) } const connectionOnline = status.directConnectionCount > 0 const connectionLabel = connectionOnline ? '本地原生连接 · 客户端在线' : status.resumableSessionCount > 0 ? '原生会话可续接 · 当前离线' : '原生接口已驻留 · 尚无客户端' const openDocument = async (source: KnowledgeSource, path: string) => { setKnowledgeBusy(true) setKnowledgeMessage('') setEditing(false) try { const document = await invoke('read_knowledge_document', { input: { source, path } }) setActiveDocument(document) setDraft(document.body) } catch (error) { setKnowledgeMessage(humanError(error, 'knowledge')) } finally { setKnowledgeBusy(false) } } const openWiki = (target: string) => { const normalized = target.replace(/\.md$/i, '').toLowerCase() const match = knowledge.documents.find((item) => item.title.toLowerCase() === normalized || item.path.replace(/\.md$/i, '').toLowerCase().endsWith(normalized)) if (match) void openDocument(match.source, match.path) else setKnowledgeMessage(`未找到链接页面:${target}`) } const runSearch = async (event: React.FormEvent) => { event.preventDefault() if (!searchQuery.trim()) { setSearchResults(null); return } setKnowledgeBusy(true) try { setSearchResults(await invoke('search_knowledge', { input: { query: searchQuery } })) setActiveDocument(null) } catch (error) { setKnowledgeMessage(humanError(error, 'knowledge')) } finally { setKnowledgeBusy(false) } } const importKnowledge = async () => { setKnowledgeBusy(true) setKnowledgeMessage('') try { const result = await invoke('select_and_import_knowledge_folder') if (!result) return setKnowledge(result.snapshot) setSearchResults(null) setSearchQuery('') setLastKnowledgeReceipt(result.gitCommit) setKnowledgeMessage(`导入完成:新增 ${result.importedDocuments},已存在 ${result.existingDocuments},冲突 ${result.conflicts}。`) if (result.firstDocument) await openDocument('native', result.firstDocument) } catch (error) { setKnowledgeMessage(humanError(error, 'knowledge')) } finally { setKnowledgeBusy(false) } } const downloadDocument = async (format: 'md' | 'html') => { if (!activeDocument) return setKnowledgeBusy(true) setKnowledgeMessage('') try { let body = activeDocument.body if (format === 'html') { const parsed = splitFrontmatter(body) const article = markdownHtml(parsed.content) body = `${activeDocument.title}

${activeDocument.title}

${article}` } const receipt = await invoke<{ path: string; bytes: number } | null>('export_knowledge_document', { input: { title: activeDocument.title, extension: format, body } }) setKnowledgeMessage(receipt ? `已下载到 ${receipt.path}` : '已取消下载。') } catch (error) { setKnowledgeMessage(humanError(error, 'knowledge')) } finally { setKnowledgeBusy(false) } } const printDocument = async () => { setKnowledgeMessage('') try { await invoke('print_knowledge_document') setKnowledgeMessage('打印框里选「存储为 PDF」即可得到 PDF 文件。') } catch (error) { setKnowledgeMessage(humanError(error, 'knowledge')) } } const reloadKnowledge = async () => { const snapshot = await invoke('get_knowledge_snapshot') setKnowledge(snapshot) } const createDocument = async () => { setKnowledgeBusy(true) setKnowledgeMessage('') try { const receipt = await invoke<{ removed: string; pages: number }>('create_knowledge_document', { input: { title: '未命名页面' } }) setKnowledgeMessage(`已新建空白页「${receipt.removed.replace(/\.md$/, '')}」,正在编辑。`) setSearchResults(null) await reloadKnowledge() await openDocument('native', receipt.removed) setEditing(true) } catch (error) { setKnowledgeMessage(humanError(error, 'knowledge')) } finally { setKnowledgeBusy(false) } } const removeDocument = async () => { if (!activeDocument) return setKnowledgeBusy(true) setKnowledgeMessage('') try { const receipt = await invoke<{ removed: string; pages: number } | null>('delete_knowledge_document', { input: { source: activeDocument.source, path: activeDocument.path } }) if (receipt) { setKnowledgeMessage(`已移入回收站:${receipt.removed}(可找回)`) setActiveDocument(null) setSearchResults(null) await reloadKnowledge() } else setKnowledgeMessage('已取消删除。') } catch (error) { setKnowledgeMessage(humanError(error, 'knowledge')) } finally { setKnowledgeBusy(false) } } const removeFolder = async (folder: TreeNode) => { setKnowledgeBusy(true) setKnowledgeMessage('') try { const receipt = await invoke<{ removed: string; pages: number } | null>('delete_knowledge_folder', { input: { folder: folder.key } }) if (receipt) { setKnowledgeMessage(`文件夹「${folder.name}」(${receipt.pages} 页)已移入回收站(可找回)`) setActiveDocument(null) setSearchResults(null) await reloadKnowledge() } else setKnowledgeMessage('已取消删除。') } catch (error) { setKnowledgeMessage(humanError(error, 'knowledge')) } finally { setKnowledgeBusy(false) } } const saveDocument = async () => { if (!activeDocument?.writable) return setKnowledgeBusy(true) try { const result = await invoke('save_knowledge_document', { input: { path: activeDocument.path, body: draft, expectedContentSha256: activeDocument.contentSha256 }, }) setActiveDocument(result.document) setDraft(result.document.body) setEditing(false) setLastKnowledgeReceipt(result.gitCommit) setKnowledgeMessage(result.state === 'UNCHANGED' ? '内容没有变化。' : '页面已保存,并写入本机 Git 回执。') await refreshCore() } catch (error) { setKnowledgeMessage(humanError(error, 'knowledge')) } finally { setKnowledgeBusy(false) } } const cloneCodeChannel = async (event: React.FormEvent) => { event.preventDefault() if (!cloneUrl.trim()) return setCodeBusy(true) setCodeMessage('') try { const snapshot = await invoke('clone_code_channel', { input: { url: cloneUrl } }) setCodeChannels(snapshot) setCloneUrl('') setCodeMessage('代码频道已克隆并登记。') } catch (error) { setCodeMessage(humanError(error, 'code')) } finally { setCodeBusy(false) } } const selectLocalCodeChannel = async () => { setCodeBusy(true) setCodeMessage('') try { const snapshot = await invoke('select_local_code_channel') if (snapshot) { setCodeChannels(snapshot) setCodeMessage('本地代码频道已登记,原文件未移动。') } } catch (error) { setCodeMessage(humanError(error, 'code')) } finally { setCodeBusy(false) } } const browseChannel = async (channel: CodeChannelEntry, path = '') => { setCodeBusy(true) setActiveChannel(channel) setActiveCodeFile(null) try { setCodeTree(await invoke('browse_code_channel', { input: { channelId: channel.channelId, path } })) } catch (error) { setCodeMessage(humanError(error, 'code')) } finally { setCodeBusy(false) } } const openCodeEntry = async (entry: CodeTreeEntry) => { if (!activeChannel) return if (entry.kind === 'directory') { await browseChannel(activeChannel, entry.path); return } setCodeBusy(true) setCodeMode('human') try { setActiveCodeFile(await invoke('read_code_channel_file', { input: { channelId: activeChannel.channelId, path: entry.path }, })) } catch (error) { setCodeMessage(humanError(error, 'code')) } finally { setCodeBusy(false) } } const codeParent = () => codeTree?.path.split('/').filter(Boolean).slice(0, -1).join('/') || '' const performRepoLogin = async (event: React.FormEvent) => { event.preventDefault() setLoginBusy(true) setLoginMessage('') try { const receipt = await invoke('perform_code_repo_login', { username: loginUsername.trim(), password: loginPassword }) // 五湖开场:校验通过=第五域从湖面浮起,镜头沉入湖中再进场。 setLoginRising(true) await new Promise((resolve) => setTimeout(resolve, 1300)) setRepoLogin({ username: receipt.username, host: receipt.host, domain: receipt.domain, signedInAtUnixMs: Date.now() }) setLoginRising(false) setLoginPassword('') } catch (error) { setLoginMessage(humanError(error, 'login')) } finally { setLoginBusy(false) } } const signOutRepo = async () => { try { await invoke('sign_out_code_repo_login') } catch { /* 登出以本机清场为准 */ } setRepoLogin(null) } const initializeIdentity = async (event: React.FormEvent) => { event.preventDefault() setIdentityBusy(true) try { setPersonal(await invoke('initialize_personal_channel', { input: { displayName } })) setDisplayName('') } catch (error) { setIdentityMessage(humanError(error, 'identity')) } finally { setIdentityBusy(false) } } const issueInvitation = async () => { setSystemBusy(true) setSystemMessage('') try { setTicket(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'), }, })) setSystemMessage('一次性发现凭据已生成。连接成功后,状态条会显示真实在线数。') } catch (error) { setSystemMessage(humanError(error, 'system')) } finally { setSystemBusy(false) } } const invitationText = ticket ? JSON.stringify({ schema: 'hololake.direct-local-invitation/v1', connectorArgument: '--connector', openSession: { operation: 'OPEN_SESSION', input: { accountId: window.localStorage.getItem('hololake-local-account'), laneId: ticket.laneId, clientInstanceId: ticket.clientInstanceId, discoveryTicket: ticket.discoveryTicket, }, }, }, null, 2) : '' const copyInvitation = async () => { try { await navigator.clipboard.writeText(invitationText) setSystemMessage('连接凭据已复制。') } catch { setSystemMessage('复制失败,请手动选择凭据。') } } const checkUpdate = async () => { setSystemBusy(true) try { const result = await invoke('check_hololake_update') setReleaseCandidate(result.candidate || null) setSystemMessage(result.candidate ? '发现已签名更新。' : '当前没有可安装更新。') } catch (error) { setSystemMessage(humanError(error, 'system')) } finally { setSystemBusy(false) } } const installUpdate = async () => { if (!releaseCandidate) return setSystemBusy(true) try { await invoke('confirm_hololake_update_install', { input: { candidateId: releaseCandidate.candidateId, confirmationToken: releaseCandidate.confirmationToken }, }) setSystemMessage('更新安装已启动。') } catch (error) { setSystemMessage(humanError(error, 'system')) } finally { setSystemBusy(false) } } const bindZeroPoint = async () => { if (!zpNumber.trim()) return setZpBusy(true); setZpMessage('') try { const bound = await invoke('zero_point_bind', { input: { number: zpNumber.trim() } }) setZeroPoint(bound) const verified = await invoke('zero_point_verify') setZeroPoint(verified) setZpMessage(verified.route === 'verified' ? '编号验证通过。' : '编号未通过验证,受限功能保持关闭。') } catch (error) { setZpMessage(String(error)) } finally { setZpBusy(false) } } const verifyZeroPoint = async () => { setZpBusy(true); setZpMessage('') try { const snapshot = await invoke('zero_point_verify') setZeroPoint(snapshot) setZpMessage(snapshot.route === 'verified' ? '编号验证通过。' : '编号未通过验证,受限功能保持关闭。') } catch (error) { setZpMessage(String(error)) } finally { setZpBusy(false) } } const syncZeroPoint = async () => { setZpBusy(true); setZpMessage('') try { setZeroPoint(await invoke('zero_point_sync')) } catch (error) { setZpMessage(String(error)) } finally { setZpBusy(false) } } const renderOverview = () => (
PERSONAL CHANNEL

个人频道

统一访问本机知识、代码、运行状态与可核验回执。

最近知识

从真实页面继续阅读

{knowledge.documents.slice().sort((a, b) => b.updatedAtUnixMs - a.updatedAtUnixMs).slice(0, 7).map((item) => )}

运行状态

以下信息均来自当前进程与已登记运行源。

Unix 本地代理
{status.directLocalBrokerState}
在线客户端
{status.directConnectionCount}
可续接会话
{status.resumableSessionCount}
PNCC 投影回执
{status.pnccReceiptCount}
MCP
备用 / 恢复
) const renderKnowledge = () => (
{activeDocument ? <>
{activeDocument.source === 'legacy' ? 'HoloLake Era · 只读源' : '我的知识库'}/{activeDocument.path}
{editing ? <> : <>
{settingsMenuOpen &&
{activeDocument.writable && }{activeDocument.writable && }
}
}
{editing ?