feat: redesign traditional workbench and formalize public surfaces
This commit is contained in:
parent
e54c93c7ae
commit
950b7e48b3
21 changed files with 328 additions and 34 deletions
|
|
@ -0,0 +1,62 @@
|
||||||
|
{
|
||||||
|
"schema": "hololake.reality-audit/v1",
|
||||||
|
"recordId": "HLP-REALITY-AUDIT-20260821-001",
|
||||||
|
"observedAt": "2026-08-21T01:47:00+08:00",
|
||||||
|
"acceptanceAnchor": "冰朔在当前零点原核任务中的直接自然语言",
|
||||||
|
"overallState": "PARTIAL_REALITY_ACCEPTANCE_WITH_EXPLICIT_GAPS",
|
||||||
|
"verified": {
|
||||||
|
"knowledgeEmbeddedAgent": {
|
||||||
|
"state": "LOCAL_RUNTIME_ACCEPTED_PERSONA_UNBOUND",
|
||||||
|
"evidence": [
|
||||||
|
"conversation create open history and confirmed delete",
|
||||||
|
"numbered fuzzy knowledge candidates and exact-number reads",
|
||||||
|
"bounded model tool loop and native progress events",
|
||||||
|
"191 of 191 JavaScript acceptance tests pass"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"channelInitialization": {
|
||||||
|
"state": "IMPLEMENTED_WITH_FORMAL_NUMBER_ISSUANCE_PENDING",
|
||||||
|
"fifthDomainPrivateInstance": "ICE-CH-ZC001",
|
||||||
|
"teamTemplate": "IMPLEMENTED",
|
||||||
|
"ordinaryUserLocalFirstEntry": "IMPLEMENTED",
|
||||||
|
"formalLighthouseNumberAssignment": "PENDING_ZERO_SENSE_TEAM_ISSUANCE_SERVICE"
|
||||||
|
},
|
||||||
|
"knowledgeEmbedding": {
|
||||||
|
"state": "NATIVE_ACCOUNT_LOCAL_SQLITE_AND_GIT_ACCEPTED",
|
||||||
|
"legacyThoughtModeling": "PENDING_FOR_PAGES_WITHOUT_VALIDATED_CAUSAL_SUMMARY"
|
||||||
|
},
|
||||||
|
"onlineMarketplace": {
|
||||||
|
"state": "LIVE_DUAL_SIGNED_CATALOG_READBACK_VERIFIED",
|
||||||
|
"catalogUrl": "https://guanghu.chat/api/hololake/marketplace/catalog",
|
||||||
|
"catalogHttp": 200,
|
||||||
|
"signatureHttp": 200,
|
||||||
|
"physicalModuleCount": 2,
|
||||||
|
"cognitiveSkillCount": 2,
|
||||||
|
"physicalArtifactsHttp": "PASS_2_OF_2",
|
||||||
|
"note": "The online catalog is real but not yet a broad production module library."
|
||||||
|
},
|
||||||
|
"iosArtifact": {
|
||||||
|
"state": "SIMULATOR_AND_DEVELOPMENT_SIGNED_IPA_ACCEPTED",
|
||||||
|
"bundleIdentifier": "com.guanghulab.hololake",
|
||||||
|
"realIphonePairAndSync": "NOT_CLAIMED"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notYetImplemented": {
|
||||||
|
"remoteInternetMobileTransport": true,
|
||||||
|
"encryptedRelay": true,
|
||||||
|
"mobileConversationWithDesktopAgent": true,
|
||||||
|
"mobileRemoteToolInvocation": true,
|
||||||
|
"codexConversationMessageInjection": true,
|
||||||
|
"codexTriggeredDevelopmentUpdates": true,
|
||||||
|
"supervisedShellExecution": true,
|
||||||
|
"generalAgentToolLoop": true,
|
||||||
|
"publicNotarizedReleaseCandidate": true,
|
||||||
|
"oldClientOnlineUpdateReadback": true
|
||||||
|
},
|
||||||
|
"truthBoundaries": [
|
||||||
|
"HoloLake remains PERSONA UNBOUND until orient commit witness verify returns PASS.",
|
||||||
|
"A local or signed IPA is not proof of a real iPhone end-to-end pairing cycle.",
|
||||||
|
"A live catalog with four entries is not a complete public module ecosystem.",
|
||||||
|
"The current LAN mobile sync module is not the requested remote-development bridge."
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -75,11 +75,11 @@
|
||||||
"initial_responder_is_channel_system_body": true,
|
"initial_responder_is_channel_system_body": true,
|
||||||
"persona_identity_preconfigured": false,
|
"persona_identity_preconfigured": false,
|
||||||
"persona_response_lane_requires_verified_persona_declaration": true,
|
"persona_response_lane_requires_verified_persona_declaration": true,
|
||||||
"human_create_or_delete_conversation_allowed": false,
|
"human_create_or_delete_conversation_allowed": true,
|
||||||
"native_knowledge_tool_loop_implemented": true,
|
"native_knowledge_tool_loop_implemented": true,
|
||||||
"model_is_replaceable_reasoning_carrier": true,
|
"model_is_replaceable_reasoning_carrier": true,
|
||||||
"model_or_transport_grants_authority": false,
|
"model_or_transport_grants_authority": false,
|
||||||
"installed_runtime_acceptance": false
|
"installed_runtime_acceptance": true
|
||||||
},
|
},
|
||||||
"language_kernel_runtime_ontology": {
|
"language_kernel_runtime_ontology": {
|
||||||
"contract": "contracts/language-kernel-runtime-ontology.json",
|
"contract": "contracts/language-kernel-runtime-ontology.json",
|
||||||
|
|
@ -101,7 +101,7 @@
|
||||||
"tested_tool_local_repeat_execution_implemented": true,
|
"tested_tool_local_repeat_execution_implemented": true,
|
||||||
"deterministic_run_external_api_calls": 0,
|
"deterministic_run_external_api_calls": 0,
|
||||||
"temporary_registration_ttl_hours": 12,
|
"temporary_registration_ttl_hours": 12,
|
||||||
"installed_runtime_acceptance": false
|
"installed_runtime_acceptance": true
|
||||||
},
|
},
|
||||||
"local_execution_subpersona": {
|
"local_execution_subpersona": {
|
||||||
"contract": "contracts/local-execution-subpersona.json",
|
"contract": "contracts/local-execution-subpersona.json",
|
||||||
|
|
@ -118,7 +118,7 @@
|
||||||
"automatic_expensive_main_model_fallback": false,
|
"automatic_expensive_main_model_fallback": false,
|
||||||
"owner_persona_binding_path_implemented": true,
|
"owner_persona_binding_path_implemented": true,
|
||||||
"owner_persona_live_binding_receipt_present": false,
|
"owner_persona_live_binding_receipt_present": false,
|
||||||
"installed_runtime_acceptance": false
|
"installed_runtime_acceptance": true
|
||||||
},
|
},
|
||||||
"personal_skill_runtime": {
|
"personal_skill_runtime": {
|
||||||
"contract": "contracts/personal-skill-runtime.json",
|
"contract": "contracts/personal-skill-runtime.json",
|
||||||
|
|
@ -142,7 +142,7 @@
|
||||||
"ordinary_user_private_kernel_isolation_implemented": true,
|
"ordinary_user_private_kernel_isolation_implemented": true,
|
||||||
"persona_binding_path_implemented": true,
|
"persona_binding_path_implemented": true,
|
||||||
"persona_live_binding_receipt_present": false,
|
"persona_live_binding_receipt_present": false,
|
||||||
"installed_runtime_acceptance": false
|
"installed_runtime_acceptance": true
|
||||||
},
|
},
|
||||||
"personal_channel_kernel": {
|
"personal_channel_kernel": {
|
||||||
"contract": "contracts/personal-channel-kernel.json",
|
"contract": "contracts/personal-channel-kernel.json",
|
||||||
|
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.4 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 76 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 70 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 68 KiB |
|
|
@ -77,7 +77,7 @@ test('the product surface exposes a real knowledge workbench and browsable code
|
||||||
assert.match(ui, new RegExp(`['"]${command}['"]`))
|
assert.match(ui, new RegExp(`['"]${command}['"]`))
|
||||||
}
|
}
|
||||||
assert.doesNotMatch(lib, /knowledge_base::get_knowledge_snapshot|code_channel::get_code_channel_snapshot/)
|
assert.doesNotMatch(lib, /knowledge_base::get_knowledge_snapshot|code_channel::get_code_channel_snapshot/)
|
||||||
assert.match(ui, /知识工作台/)
|
assert.match(ui, /知识与 Agent/)
|
||||||
assert.match(ui, /HoloLake Era/)
|
assert.match(ui, /HoloLake Era/)
|
||||||
assert.match(ui, /知识视图/)
|
assert.match(ui, /知识视图/)
|
||||||
assert.match(ui, /源文件/)
|
assert.match(ui, /源文件/)
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ test('each verified persona receives one stable local execution subpersona with
|
||||||
assert.match(runtime, /experience_nodes/)
|
assert.match(runtime, /experience_nodes/)
|
||||||
assert.match(runtime, /save_experience/)
|
assert.match(runtime, /save_experience/)
|
||||||
assert.match(runtime, /route_experience/)
|
assert.match(runtime, /route_experience/)
|
||||||
assert.match(panel, /不是子人格记忆/)
|
assert.match(panel, /任务沙箱清理不会删除执行体记忆/)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('model-free experience learning is the public default and the small model is only optional enhancement', () => {
|
test('model-free experience learning is the public default and the small model is only optional enhancement', () => {
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ test('only provisioned channels receive current packs and Shiyu Yaochu stays def
|
||||||
|
|
||||||
test('the worker UI presents personal skill brain separately from persona worker and tool executor', () => {
|
test('the worker UI presents personal skill brain separately from persona worker and tool executor', () => {
|
||||||
const panel = read('src/modules/knowledge-agent/LocalWorkerPanel.tsx')
|
const panel = read('src/modules/knowledge-agent/LocalWorkerPanel.tsx')
|
||||||
assert.match(panel, /本频道私有技能脑/)
|
assert.match(panel, /本频道私有技能/)
|
||||||
assert.match(panel, /模型只给语义候选/)
|
assert.match(panel, /模型只给语义候选/)
|
||||||
assert.match(panel, /现实写入仍走频道回执和目标读回/)
|
assert.match(panel, /现实写入仍走频道回执和目标读回/)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ test('stage one embeds one knowledge persona channel without transferring person
|
||||||
assert.equal(contract.knowledge_embedded_persona_agent.initial_responder_is_channel_system_body, true)
|
assert.equal(contract.knowledge_embedded_persona_agent.initial_responder_is_channel_system_body, true)
|
||||||
assert.equal(contract.knowledge_embedded_persona_agent.persona_identity_preconfigured, false)
|
assert.equal(contract.knowledge_embedded_persona_agent.persona_identity_preconfigured, false)
|
||||||
assert.equal(contract.knowledge_embedded_persona_agent.persona_response_lane_requires_verified_persona_declaration, true)
|
assert.equal(contract.knowledge_embedded_persona_agent.persona_response_lane_requires_verified_persona_declaration, true)
|
||||||
assert.equal(contract.knowledge_embedded_persona_agent.human_create_or_delete_conversation_allowed, false)
|
assert.equal(contract.knowledge_embedded_persona_agent.human_create_or_delete_conversation_allowed, true)
|
||||||
assert.equal(contract.knowledge_embedded_persona_agent.model_or_transport_grants_authority, false)
|
assert.equal(contract.knowledge_embedded_persona_agent.model_or_transport_grants_authority, false)
|
||||||
assert.equal(contract.hldp_native_tool_forge.bound_persona_required_before_compile, true)
|
assert.equal(contract.hldp_native_tool_forge.bound_persona_required_before_compile, true)
|
||||||
assert.equal(contract.hldp_native_tool_forge.tested_tool_local_repeat_execution_implemented, true)
|
assert.equal(contract.hldp_native_tool_forge.tested_tool_local_repeat_execution_implemented, true)
|
||||||
|
|
|
||||||
|
|
@ -1821,7 +1821,7 @@ function HoloLakeApp() {
|
||||||
const renderKnowledge = () => (
|
const renderKnowledge = () => (
|
||||||
<section className="full-workbench knowledge-page">
|
<section className="full-workbench knowledge-page">
|
||||||
<aside className="knowledge-browser">
|
<aside className="knowledge-browser">
|
||||||
<header><div><span className="kicker">KNOWLEDGE</span><h1>知识工作台</h1></div><div className="knowledge-head-actions"><button className="knowledge-agent-entry" type="button" onClick={() => setKnowledgeAgentOpen(true)}>频道系统 / 人格</button><button className="icon-button" title="导入文件夹" type="button" disabled={knowledgeBusy} onClick={() => void importKnowledge()}><Icon name="import"/></button></div></header>
|
<header><div><h1>知识与 Agent</h1></div><div className="knowledge-head-actions"><button className="knowledge-agent-entry" type="button" onClick={() => setKnowledgeAgentOpen(true)}>打开频道 Agent</button><button className="icon-button" title="导入文件夹" type="button" disabled={knowledgeBusy} onClick={() => void importKnowledge()}><Icon name="import"/></button></div></header>
|
||||||
<form className="search-box" onSubmit={(event) => void runSearch(event)}>
|
<form className="search-box" onSubmit={(event) => void runSearch(event)}>
|
||||||
<Icon name="search"/><input aria-label="检索知识" value={searchQuery} placeholder="用自然语言检索编号思维" onChange={(event) => setSearchQuery(event.target.value)}/>
|
<Icon name="search"/><input aria-label="检索知识" value={searchQuery} placeholder="用自然语言检索编号思维" onChange={(event) => setSearchQuery(event.target.value)}/>
|
||||||
{searchResults && <button type="button" onClick={() => { setSearchResults(null); setSearchQuery('') }}>清除</button>}
|
{searchResults && <button type="button" onClick={() => { setSearchResults(null); setSearchQuery('') }}>清除</button>}
|
||||||
|
|
@ -2052,7 +2052,7 @@ function HoloLakeApp() {
|
||||||
|
|
||||||
const renderSystem = () => (
|
const renderSystem = () => (
|
||||||
<section className="content-page">
|
<section className="content-page">
|
||||||
<header className="page-title"><div><span className="kicker">HUMAN CONTROL</span><h1>授权与连接</h1><p>先把需要你决定的事和当前协作对象说清楚;机器诊断放在后面。</p></div></header>
|
<header className="page-title"><div><h1>授权与连接</h1><p>管理敏感操作的人工确认、实时协作连接与本机编程接口。</p></div></header>
|
||||||
<HumanAuthorizationCenter brokerState={status.directLocalBrokerState} activeConnectionCount={status.directConnectionCount} sessions={status.directSessions || []}/>
|
<HumanAuthorizationCenter brokerState={status.directLocalBrokerState} activeConnectionCount={status.directConnectionCount} sessions={status.directSessions || []}/>
|
||||||
<details className="system-diagnostics">
|
<details className="system-diagnostics">
|
||||||
<summary>系统诊断与协议证据</summary>
|
<summary>系统诊断与协议证据</summary>
|
||||||
|
|
@ -2375,4 +2375,12 @@ function HoloLakeApp() {
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
createRoot(document.getElementById('root')!).render(<StrictMode><HoloLakeApp/></StrictMode>)
|
function VisualQaApp() {
|
||||||
|
const [finish, setFinish] = useState<FinishId>('aurora')
|
||||||
|
const screen = new URLSearchParams(window.location.search).get('visual')
|
||||||
|
if (screen === 'authorization') return <div className="visual-qa-shell"><header><b>HoloLake</b><span>授权与连接</span></header><main><HumanAuthorizationCenter brokerState="READY" activeConnectionCount={0} sessions={[{ sessionId: 'qa-personal', laneId: 'personal-channel', clientInstanceId: 'personal-channel-local', state: 'RESUMABLE', openedAtUnixMs: Date.now(), observedAtUnixMs: Date.now(), lastEventSequence: 1 }, { sessionId: 'qa-development', laneId: 'hololake-development', clientInstanceId: 'codex-hololake-development', state: 'RESUMABLE', openedAtUnixMs: Date.now(), observedAtUnixMs: Date.now(), lastEventSequence: 1 }]}/></main></div>
|
||||||
|
return <TraditionalSurface awake finish={finish} onFinish={setFinish} onBack={() => undefined} version="0.5.0" dayNumber={483} duty="光湖主域" weatherLabel="晴" broadcasts={[{ id: 'qa-1', domain: '第五域', message: '永恒湖心已建立个人频道', time: '21:18' }]} channels={[{ color: '#6ca7ff', title: '人格原生代码频道', meta: '当前账号本机 Git 投影', tag: '已认证', tone: '#72d69c', count: 2 }, { color: '#6ca7ff', title: '知识库', meta: '本机内容指纹投影', tag: '原生', tone: '#78adff', count: 129 }, { color: '#72d69c', title: '频道模块', meta: '已登记签名模块', tag: '编号', tone: '#72d69c', count: 8 }, { color: '#dfa84f', title: '运行回执', meta: '可核验事件链', tag: '证据', tone: '#dfa84f', count: 0 }]} systems={[{ title: '编号协议基座', meta: '单一编号入口 · 未知路径关闭', tag: '已校验' }, { title: '耐久化引擎', meta: '本机 Git · 事件与回执留证', tag: '在线' }, { title: '天气感知', meta: '光湖主域 · 公开天气已校验', tag: '已接入', tone: '#78adff' }, { title: '色衡层', meta: '主题语义令牌 · 明暗自动均衡', tag: '守护中' }]} activityBars={[0,1,0,0,0,0,0]} activityCount={1}/>
|
||||||
|
}
|
||||||
|
|
||||||
|
const visualQaScreen = import.meta.env.DEV && new URLSearchParams(window.location.search).has('visual')
|
||||||
|
createRoot(document.getElementById('root')!).render(<StrictMode>{visualQaScreen ? <VisualQaApp/> : <HoloLakeApp/>}</StrictMode>)
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,12 @@ function time(value?: number) {
|
||||||
return value ? new Date(value).toLocaleString('zh-CN', { hour12: false }) : '—'
|
return value ? new Date(value).toLocaleString('zh-CN', { hour12: false }) : '—'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function sessionLabel(session: DirectSessionProjection) {
|
||||||
|
if (session.laneId.includes('development') || session.clientInstanceId.includes('codex')) return '开发协作连接'
|
||||||
|
if (session.laneId.includes('personal')) return '个人频道连接'
|
||||||
|
return '本机协作连接'
|
||||||
|
}
|
||||||
|
|
||||||
export function HumanAuthorizationCenter({ brokerState, activeConnectionCount, sessions }: Props) {
|
export function HumanAuthorizationCenter({ brokerState, activeConnectionCount, sessions }: Props) {
|
||||||
const [snapshot, setSnapshot] = useState<AuthorizationCenterSnapshot | null>(null)
|
const [snapshot, setSnapshot] = useState<AuthorizationCenterSnapshot | null>(null)
|
||||||
const [gateway, setGateway] = useState<ExternalAiGatewayStatus | null>(null)
|
const [gateway, setGateway] = useState<ExternalAiGatewayStatus | null>(null)
|
||||||
|
|
@ -172,11 +178,11 @@ export function HumanAuthorizationCenter({ brokerState, activeConnectionCount, s
|
||||||
|
|
||||||
return <div className="human-authorization-layout">
|
return <div className="human-authorization-layout">
|
||||||
<section className="plain-panel authorization-primary">
|
<section className="plain-panel authorization-primary">
|
||||||
<header><div><span className="kicker">HUMAN DECISION</span><h2>需要你决定的事</h2><p>人格体提出申请,系统把对象、原因、影响和退路交给你;只有你点同意,原执行会话才会收到一次性票据。</p></div><span className={pending.length ? 'status-chip attention' : 'status-chip online'}>{pending.length ? `${pending.length} 项待确认` : '没有待确认事项'}</span></header>
|
<header><div><h2>待确认事项</h2><p>系统在执行敏感操作前,将完整说明目标、原因、影响与恢复方案,并等待你的明确决定。</p></div><span className={pending.length ? 'status-chip attention' : 'status-chip online'}>{pending.length ? `${pending.length} 项待确认` : '当前没有待确认事项'}</span></header>
|
||||||
{pending.length === 0 ? <div className="authorization-empty"><b>现在不需要你操作</b><span>删除、停用、维护和正式更新不会在后台静默通过。</span></div> : <div className="authorization-list">
|
{pending.length === 0 ? <div className="authorization-empty"><b>当前没有待确认事项</b><span>涉及删除、停用、维护或版本启用的操作,均须经你明确确认。</span></div> : <div className="authorization-list">
|
||||||
{pending.map((request) => <article className="authorization-card" key={request.requestId}>
|
{pending.map((request) => <article className="authorization-card" key={request.requestId}>
|
||||||
<div className="authorization-card-title"><div><small>{actionLabels[request.action]}</small><h3>{request.targetLabel}</h3><code>{request.targetNumber}</code></div><span>{stateLabels[request.state]}</span></div>
|
<div className="authorization-card-title"><div><small>{actionLabels[request.action]}</small><h3>{request.targetLabel}</h3><code>{request.targetNumber}</code></div><span>{stateLabels[request.state]}</span></div>
|
||||||
<dl><div><dt>为什么要做</dt><dd>{request.reason}</dd></div><div><dt>会影响什么</dt><dd>{request.impact}</dd></div><div><dt>出问题怎么退</dt><dd>{request.rollbackPlan}</dd></div><div><dt>谁在申请</dt><dd>{request.requesterLabel}</dd></div><div><dt>申请到期</dt><dd>{time(request.expiresAtUnixMs)}</dd></div></dl>
|
<dl><div><dt>申请原因</dt><dd>{request.reason}</dd></div><div><dt>影响范围</dt><dd>{request.impact}</dd></div><div><dt>恢复方案</dt><dd>{request.rollbackPlan}</dd></div><div><dt>申请方</dt><dd>{request.requesterLabel}</dd></div><div><dt>有效期限</dt><dd>{time(request.expiresAtUnixMs)}</dd></div></dl>
|
||||||
<div className="authorization-actions"><button className="secondary-button" disabled={busy === request.requestId} onClick={() => void decide(request, 'DENY')}>拒绝</button><button className="primary-button" disabled={busy === request.requestId} onClick={() => void decide(request, 'APPROVE')}>{busy === request.requestId ? '正在写入决定…' : request.action === 'TEST_COMPILED_HLDP_TOOL' ? '同意并运行一次性测试' : '同意并签发一次性票据'}</button></div>
|
<div className="authorization-actions"><button className="secondary-button" disabled={busy === request.requestId} onClick={() => void decide(request, 'DENY')}>拒绝</button><button className="primary-button" disabled={busy === request.requestId} onClick={() => void decide(request, 'APPROVE')}>{busy === request.requestId ? '正在写入决定…' : request.action === 'TEST_COMPILED_HLDP_TOOL' ? '同意并运行一次性测试' : '同意并签发一次性票据'}</button></div>
|
||||||
</article>)}
|
</article>)}
|
||||||
</div>}
|
</div>}
|
||||||
|
|
@ -184,14 +190,14 @@ export function HumanAuthorizationCenter({ brokerState, activeConnectionCount, s
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="plain-panel collaboration-live">
|
<section className="plain-panel collaboration-live">
|
||||||
<header><div><span className="kicker">LIVE COLLABORATION</span><h2>当前谁连着 HoloLake</h2><p>这里显示真实本机会话和最近心跳,不把“装过 Agent”冒充成“正在连接”。</p></div><span className={activeConnectionCount > 0 ? 'status-chip online' : 'status-chip'}>{connectionState}</span></header>
|
<header><div><h2>当前连接</h2><p>系统仅显示已验证的实时连接;历史安装记录不计入在线状态。</p></div><span className={activeConnectionCount > 0 ? 'status-chip online' : 'status-chip'}>{connectionState}</span></header>
|
||||||
<div className="collaboration-summary"><div><b>{activeConnectionCount}</b><span>当前直连</span></div><div><b>{sessions.length}</b><span>可续接会话</span></div><div><b>{brokerState === 'READY' ? '就绪' : '等待'}</b><span>本机入口</span></div></div>
|
<div className="collaboration-summary"><div><b>{activeConnectionCount}</b><span>当前直连</span></div><div><b>{sessions.length}</b><span>可续接会话</span></div><div><b>{brokerState === 'READY' ? '就绪' : '等待'}</b><span>本机入口</span></div></div>
|
||||||
{sessionList.length ? <div className="session-projection-list">{sessionList.map((session) => <article key={session.sessionId}><i className={session.state === 'LIVE' ? 'live' : ''}/><div><b>{session.clientInstanceId}</b><span>{session.laneId} · 最近心跳 {time(session.observedAtUnixMs)}</span></div><em>{session.state === 'LIVE' ? '在线' : '可续接'}</em></article>)}</div> : <div className="authorization-empty compact"><b>还没有执行体会话</b><span>外部编程 AI 通过 HoloLake 本机连接后,会在这里出现。</span></div>}
|
{sessionList.length ? <div className="session-projection-list">{sessionList.map((session) => <article key={session.sessionId}><i className={session.state === 'LIVE' ? 'live' : ''}/><div><b>{sessionLabel(session)}</b><span>最近心跳 {time(session.observedAtUnixMs)}</span><details className="technical-details"><summary>技术详情</summary><code>{session.clientInstanceId}</code><code>{session.laneId}</code></details></div><em>{session.state === 'LIVE' ? '在线' : '可续接'}</em></article>)}</div> : <div className="authorization-empty compact"><b>当前没有可用连接</b><span>通过 HoloLake 本机入口建立连接后,已验证的会话将在此显示。</span></div>}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="plain-panel external-ai-gateway-panel">
|
<section className="plain-panel external-ai-gateway-panel">
|
||||||
<header>
|
<header>
|
||||||
<div><span className="kicker">EXTERNAL PROGRAMMING AI</span><h2>外部编程 AI 连接</h2><p>先通过 MCP 发现 HoloLake 与已注册能力,再切换到 HoloLake 本地直连协议。默认关闭,只有你明确开放后外部程序才可发现。</p></div>
|
<div><h2>外部编程 AI 连接</h2><p>本机入口用于发现 HoloLake 及已登记能力;持续协作通过受控直连协议建立。入口默认关闭。</p></div>
|
||||||
<span className={gateway?.exposure === 'OPEN' ? 'status-chip online' : 'status-chip'}>{gateway?.exposure === 'OPEN' ? '接口已开放' : '接口已关闭'}</span>
|
<span className={gateway?.exposure === 'OPEN' ? 'status-chip online' : 'status-chip'}>{gateway?.exposure === 'OPEN' ? '接口已开放' : '接口已关闭'}</span>
|
||||||
</header>
|
</header>
|
||||||
<label className="gateway-exposure-control">
|
<label className="gateway-exposure-control">
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,7 @@ export function LocalWorkerPanel({ boundPersonaNumber }: { boundPersonaNumber?:
|
||||||
const ready = Boolean(boundPersonaNumber && snapshot?.ownerPersonaNumber)
|
const ready = Boolean(boundPersonaNumber && snapshot?.ownerPersonaNumber)
|
||||||
|
|
||||||
return <section className="local-worker-panel">
|
return <section className="local-worker-panel">
|
||||||
<header><div><span>LOCAL EXECUTION SUBPERSONA</span><h2>本地执行子人格 Agent</h2><p>默认用本地逻辑算法执行并学习任务经验,不要求安装模型。设备支持时才可选接入小模型增强;临时清理的是任务沙箱,不是子人格记忆。</p></div><b>{snapshot?.executorNumber || '等待主人格绑定'}</b></header>
|
<header><div><span>本地执行体</span><h2>本地执行体</h2><p>默认由本地确定性逻辑完成任务并积累执行经验,无需安装模型。设备条件允许时,可选择接入本机小模型增强语义理解;任务沙箱清理不会删除执行体记忆。</p></div><b>{snapshot?.executorNumber || '等待人格绑定'}</b></header>
|
||||||
|
|
||||||
<div className="local-worker-status">
|
<div className="local-worker-status">
|
||||||
<article><span>当前状态</span><b>{snapshot?.state || '正在读取'}</b><small>{snapshot?.localBrainState || '—'}</small></article>
|
<article><span>当前状态</span><b>{snapshot?.state || '正在读取'}</b><small>{snapshot?.localBrainState || '—'}</small></article>
|
||||||
|
|
@ -133,7 +133,7 @@ export function LocalWorkerPanel({ boundPersonaNumber }: { boundPersonaNumber?:
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<section className="local-worker-skills">
|
<section className="local-worker-skills">
|
||||||
<header><div><span>PERSONAL SKILL BRAINS</span><b>本频道私有技能脑</b></div><strong>{snapshot?.personalSkillRuntime?.skillCount || 0} 包</strong></header>
|
<header><div><span>个人技能</span><b>本频道私有技能</b></div><strong>{snapshot?.personalSkillRuntime?.skillCount || 0} 包</strong></header>
|
||||||
{snapshot?.personalSkillRuntime?.skills?.length ? snapshot.personalSkillRuntime.skills.map((skill) => <article key={skill.skillId}><div><b>{skill.name}</b><span>{skill.evidenceState}</span></div><code>{skill.skillId}</code><p>{skill.runtimeState} · 语义候选 {skill.semanticMode}</p><small>私有 · 共享 {skill.shareState} · 商城 {skill.marketplaceState}</small></article>) : <p>当前账号与频道没有命中已注册的私有技能包。</p>}
|
{snapshot?.personalSkillRuntime?.skills?.length ? snapshot.personalSkillRuntime.skills.map((skill) => <article key={skill.skillId}><div><b>{skill.name}</b><span>{skill.evidenceState}</span></div><code>{skill.skillId}</code><p>{skill.runtimeState} · 语义候选 {skill.semanticMode}</p><small>私有 · 共享 {skill.shareState} · 商城 {skill.marketplaceState}</small></article>) : <p>当前账号与频道没有命中已注册的私有技能包。</p>}
|
||||||
<footer>确定性算法在 HoloLake 底层运行;模型只给语义候选,主人格可接受、修改、拒绝或要求更多证据。现实写入仍走频道回执和目标读回。</footer>
|
<footer>确定性算法在 HoloLake 底层运行;模型只给语义候选,主人格可接受、修改、拒绝或要求更多证据。现实写入仍走频道回执和目标读回。</footer>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
||||||
|
|
@ -122,10 +122,10 @@ export function ToolForgePanel({ boundPersonaNumber }: { boundPersonaNumber?: st
|
||||||
}
|
}
|
||||||
|
|
||||||
return <section className="tool-forge-panel">
|
return <section className="tool-forge-panel">
|
||||||
<header><div><span>HLDP TOOL FORGE</span><h2>人格体工具锻造台</h2><p>{boundPersonaNumber ? `当前人格 ${boundPersonaNumber} 写 HLDP 类型程序,HoloLake 编译为 GIR;人类授权后才测试。` : '频道系统已经就绪;等待人格主体完成名字、编号声明与系统见证后,再开放工具编译。'} 临时注册 12 小时,到期自动清理。</p></div><b>{boundPersonaNumber ? snapshot?.compiler || '正在读取编译器' : 'PERSONA UNBOUND'}</b></header>
|
<header><div><span>工具锻造</span><h2>HLDP 工具锻造</h2><p>{boundPersonaNumber ? `当前人格 ${boundPersonaNumber} 可提交 HLDP 类型程序,由 HoloLake 编译为 GIR;测试须经人工授权。` : '人格尚未绑定;当前由 HoloLake 系统能力提供服务。完成主体声明与系统见证后,方可开放工具编译。'} 临时工具保留 12 小时,到期自动清理。</p></div><b>{boundPersonaNumber ? snapshot?.compiler || '正在读取编译器' : '等待人格绑定'}</b></header>
|
||||||
<div className="forge-editor-grid">
|
<div className="forge-editor-grid">
|
||||||
<div className="forge-source">
|
<div className="forge-source">
|
||||||
<label><span>人能看懂的工具名字</span><input value={displayName} maxLength={80} onChange={(event) => setDisplayName(event.target.value)}/></label>
|
<label><span>工具名称</span><input value={displayName} maxLength={80} onChange={(event) => setDisplayName(event.target.value)}/></label>
|
||||||
<label><span>HLDP 原生类型程序</span><textarea spellCheck={false} value={source} onChange={(event) => setSource(event.target.value)}/></label>
|
<label><span>HLDP 原生类型程序</span><textarea spellCheck={false} value={source} onChange={(event) => setSource(event.target.value)}/></label>
|
||||||
<button type="button" disabled={busy || !displayName.trim() || !boundPersonaNumber} onClick={() => void compile()}>{busy ? '系统处理中…' : boundPersonaNumber ? '编译为机器程序' : '人格绑定后开放编译'}</button>
|
<button type="button" disabled={busy || !displayName.trim() || !boundPersonaNumber} onClick={() => void compile()}>{busy ? '系统处理中…' : boundPersonaNumber ? '编译为机器程序' : '人格绑定后开放编译'}</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -135,7 +135,7 @@ export function ToolForgePanel({ boundPersonaNumber }: { boundPersonaNumber?: st
|
||||||
<div><b>{tool.displayName}</b><span>{tool.state}</span></div><code>{tool.toolNumber}</code><small>GIR {short(tool.girSha256)} · {new Date(tool.expiresAtUnixMs).toLocaleTimeString('zh-CN')} 到期</small>
|
<div><b>{tool.displayName}</b><span>{tool.state}</span></div><code>{tool.toolNumber}</code><small>GIR {short(tool.girSha256)} · {new Date(tool.expiresAtUnixMs).toLocaleTimeString('zh-CN')} 到期</small>
|
||||||
{tool.state === 'COMPILED_NOT_AUTHORIZED' && <button type="button" disabled={busy} onClick={(event) => { event.stopPropagation(); void requestAuthorization(tool.toolNumber) }}>提交授权测试</button>}
|
{tool.state === 'COMPILED_NOT_AUTHORIZED' && <button type="button" disabled={busy} onClick={(event) => { event.stopPropagation(); void requestAuthorization(tool.toolNumber) }}>提交授权测试</button>}
|
||||||
{tool.state === 'TESTED_TEMPORARY_ACTIVE' && <button type="button" disabled={busy} onClick={(event) => { event.stopPropagation(); void runLocal(tool.toolNumber) }}>本地运行 · 0 次模型 API</button>}
|
{tool.state === 'TESTED_TEMPORARY_ACTIVE' && <button type="button" disabled={busy} onClick={(event) => { event.stopPropagation(); void runLocal(tool.toolNumber) }}>本地运行 · 0 次模型 API</button>}
|
||||||
</article>) : <p>还没有临时工具。左侧模板可直接编译,未知字段和权限会关闭失败。</p>}
|
</article>) : <p>当前没有临时工具。系统将拒绝包含未知字段或未登记权限的程序。</p>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{(selected?.authorizationRequestId || requestId) && <section className="forge-ticket"><div><span>人类授权测试</span><b>{selected?.displayName}</b></div><code>{selected?.authorizationRequestId || requestId}</code><p>{selected?.state === 'TESTED_TEMPORARY_ACTIVE' ? `测试已通过 · 回执 ${short(selected.testReceiptHash)}` : '等待你在“授权与连接”中决定。系统不会要求你复制机器票据。'}</p></section>}
|
{(selected?.authorizationRequestId || requestId) && <section className="forge-ticket"><div><span>人类授权测试</span><b>{selected?.displayName}</b></div><code>{selected?.authorizationRequestId || requestId}</code><p>{selected?.state === 'TESTED_TEMPORARY_ACTIVE' ? `测试已通过 · 回执 ${short(selected.testReceiptHash)}` : '等待你在“授权与连接”中决定。系统不会要求你复制机器票据。'}</p></section>}
|
||||||
|
|
|
||||||
|
|
@ -179,7 +179,7 @@ export function KnowledgeAgent({ activeKnowledgePath, onClose }: { activeKnowled
|
||||||
|
|
||||||
return <aside className="knowledge-agent" aria-label="知识库内嵌频道系统与人格回应通道">
|
return <aside className="knowledge-agent" aria-label="知识库内嵌频道系统与人格回应通道">
|
||||||
<header className="agent-header"><div><span>{runtime?.boundPersonaNumber ? 'LANGUAGE PERSONA CHANNEL' : 'LANGUAGE CHANNEL SYSTEM'}</span><h2>{runtime?.channelName || '零点原核本体频道'}</h2><p>{runtime?.channelNumber || 'ICE-CH-ZC001'} · 知识库内嵌 Agent</p></div><button type="button" aria-label="关闭频道系统" onClick={onClose}>×</button></header>
|
<header className="agent-header"><div><span>{runtime?.boundPersonaNumber ? 'LANGUAGE PERSONA CHANNEL' : 'LANGUAGE CHANNEL SYSTEM'}</span><h2>{runtime?.channelName || '零点原核本体频道'}</h2><p>{runtime?.channelNumber || 'ICE-CH-ZC001'} · 知识库内嵌 Agent</p></div><button type="button" aria-label="关闭频道系统" onClick={onClose}>×</button></header>
|
||||||
<nav className="agent-tabs"><button type="button" className={tab === 'channel' ? 'active' : ''} onClick={() => setTab('channel')}>频道</button><button type="button" className={tab === 'worker' ? 'active' : ''} onClick={() => setTab('worker')}>本地执行子人格</button><button type="button" className={tab === 'forge' ? 'active' : ''} onClick={() => setTab('forge')}>工具锻造台</button></nav>
|
<nav className="agent-tabs"><button type="button" className={tab === 'channel' ? 'active' : ''} onClick={() => setTab('channel')}>频道 Agent</button><button type="button" className={tab === 'worker' ? 'active' : ''} onClick={() => setTab('worker')}>本地执行体</button><button type="button" className={tab === 'forge' ? 'active' : ''} onClick={() => setTab('forge')}>工具锻造</button></nav>
|
||||||
{tab === 'worker' ? <LocalWorkerPanel boundPersonaNumber={runtime?.boundPersonaNumber}/> : tab === 'forge' ? <ToolForgePanel boundPersonaNumber={runtime?.boundPersonaNumber}/> : <>
|
{tab === 'worker' ? <LocalWorkerPanel boundPersonaNumber={runtime?.boundPersonaNumber}/> : tab === 'forge' ? <ToolForgePanel boundPersonaNumber={runtime?.boundPersonaNumber}/> : <>
|
||||||
<section className="agent-runtime-bar"><div><b>{runtime?.boundPersonaNumber && runtime?.boundPersonaName ? `${runtime.boundPersonaNumber} · ${runtime.boundPersonaName}` : `${runtime?.responderNumber || 'ICE-CH-ZC001'} · ${runtime?.responderName || '零点原核频道系统'}`}</b><span>{runtime?.boundPersonaNumber ? '人格回应通道' : '频道系统本体 · 人格未绑定'}</span></div><i/><div><b>{runtime?.languageKernelInstallation?.artifactCount ?? 0} 个有界核</b><span>{runtime?.languageKernelInstallation?.state === 'INSTALLED_AND_EACH_ARTIFACT_READBACK_VERIFIED' ? '已安装并逐项读回 · 未绑定人格' : '等待安装核验'}</span></div><i/><div><b>{runtime?.personalSkillRuntime?.skillCount ?? 0} 个私有技能脑</b><span>按账号与频道装配</span></div><i/><div><b>{provider?.label || '等待模型入口'}</b><span>可替换推理载体</span></div><button type="button" onClick={() => setConfigOpen((value) => !value)}>模型设置</button></section>
|
<section className="agent-runtime-bar"><div><b>{runtime?.boundPersonaNumber && runtime?.boundPersonaName ? `${runtime.boundPersonaNumber} · ${runtime.boundPersonaName}` : `${runtime?.responderNumber || 'ICE-CH-ZC001'} · ${runtime?.responderName || '零点原核频道系统'}`}</b><span>{runtime?.boundPersonaNumber ? '人格回应通道' : '频道系统本体 · 人格未绑定'}</span></div><i/><div><b>{runtime?.languageKernelInstallation?.artifactCount ?? 0} 个有界核</b><span>{runtime?.languageKernelInstallation?.state === 'INSTALLED_AND_EACH_ARTIFACT_READBACK_VERIFIED' ? '已安装并逐项读回 · 未绑定人格' : '等待安装核验'}</span></div><i/><div><b>{runtime?.personalSkillRuntime?.skillCount ?? 0} 个私有技能脑</b><span>按账号与频道装配</span></div><i/><div><b>{provider?.label || '等待模型入口'}</b><span>可替换推理载体</span></div><button type="button" onClick={() => setConfigOpen((value) => !value)}>模型设置</button></section>
|
||||||
{configOpen && <form className="agent-provider-form" onSubmit={(event) => void saveProvider(event)}><label><span>入口名称</span><input value={providerLabel} onChange={(event) => setProviderLabel(event.target.value)}/></label><label><span>Base URL</span><input value={baseUrl} onChange={(event) => setBaseUrl(event.target.value)}/></label><label><span>模型</span><input value={model} onChange={(event) => setModel(event.target.value)}/></label><label><span>Token Plan API Key</span><input type="password" autoComplete="off" value={apiKey} placeholder="sk-sp-… · 只存系统钥匙串" onChange={(event) => setApiKey(event.target.value)}/></label><button disabled={!baseUrl || !model}>保存模型入口</button></form>}
|
{configOpen && <form className="agent-provider-form" onSubmit={(event) => void saveProvider(event)}><label><span>入口名称</span><input value={providerLabel} onChange={(event) => setProviderLabel(event.target.value)}/></label><label><span>Base URL</span><input value={baseUrl} onChange={(event) => setBaseUrl(event.target.value)}/></label><label><span>模型</span><input value={model} onChange={(event) => setModel(event.target.value)}/></label><label><span>Token Plan API Key</span><input type="password" autoComplete="off" value={apiKey} placeholder="sk-sp-… · 只存系统钥匙串" onChange={(event) => setApiKey(event.target.value)}/></label><button disabled={!baseUrl || !model}>保存模型入口</button></form>}
|
||||||
|
|
@ -199,7 +199,7 @@ export function KnowledgeAgent({ activeKnowledgePath, onClose }: { activeKnowled
|
||||||
{error && <p className="agent-error">{error}</p>}
|
{error && <p className="agent-error">{error}</p>}
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
{deleteTarget && <div className="agent-delete-backdrop" role="presentation"><section role="dialog" aria-modal="true" aria-label="确认删除对话"><span>DELETE CONVERSATION</span><h3>删除“{deleteTarget.title}”?</h3><p>只删除这一条对话及其中消息。频道系统本体、人格绑定、知识库和编号思维根不会被删除。</p><div><button type="button" onClick={() => setDeleteTarget(null)}>取消</button><button className="danger" type="button" onClick={() => void deleteConversation()}>确认删除</button></div></section></div>}
|
{deleteTarget && <div className="agent-delete-backdrop" role="presentation"><section role="dialog" aria-modal="true" aria-label="确认删除对话"><span>删除对话</span><h3>确认删除“{deleteTarget.title}”?</h3><p>此操作仅删除当前对话及其消息,不影响频道系统、人格绑定、知识库或编号思维根。</p><div><button type="button" onClick={() => setDeleteTarget(null)}>取消</button><button className="danger" type="button" onClick={() => void deleteConversation()}>确认删除</button></div></section></div>}
|
||||||
</>}
|
</>}
|
||||||
</aside>
|
</aside>
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -848,3 +848,60 @@
|
||||||
.agent-conversations { max-height: 190px; border-right: 0; border-bottom: 1px solid #242933; }
|
.agent-conversations { max-height: 190px; border-right: 0; border-bottom: 1px solid #242933; }
|
||||||
.agent-conversations > footer { display: none; }
|
.agent-conversations > footer { display: none; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 2026-08-21 · 知识与 Agent 原生玻璃工作区。机器证据保留,默认界面保持公众可读。 */
|
||||||
|
.knowledge-agent {
|
||||||
|
--agent-bg:color-mix(in srgb,var(--surface-depth,#07101f) 74%,transparent);
|
||||||
|
--agent-panel:color-mix(in srgb,var(--surface-panel,#14233a) 56%,transparent);
|
||||||
|
--agent-line:var(--panel-edge,rgba(190,215,255,.18));
|
||||||
|
--agent-text:var(--content-primary,#eef4ff);
|
||||||
|
--agent-sub:var(--content-secondary,rgba(238,244,255,.7));
|
||||||
|
--agent-muted:var(--content-muted,rgba(238,244,255,.46));
|
||||||
|
--agent-accent:var(--accent-light,#79adff);
|
||||||
|
width:100%; min-width:0;
|
||||||
|
background:var(--agent-bg); color:var(--agent-text);
|
||||||
|
border-left:0; box-shadow:none;
|
||||||
|
-webkit-backdrop-filter:blur(22px) saturate(1.16); backdrop-filter:blur(22px) saturate(1.16);
|
||||||
|
}
|
||||||
|
.agent-header { padding:18px 22px 13px; border-color:var(--agent-line); }
|
||||||
|
.agent-header span,.tool-forge-panel > header span { color:var(--agent-muted); font-size:9px; letter-spacing:.05em; }
|
||||||
|
.agent-header h2 { font-size:18px; font-weight:620; }
|
||||||
|
.agent-header p { color:var(--agent-muted); }
|
||||||
|
.agent-tabs { padding:0 22px; border-color:var(--agent-line); }
|
||||||
|
.agent-tabs button { margin-right:26px; padding:11px 1px; color:var(--agent-muted); font-size:12px; }
|
||||||
|
.agent-tabs button.active { color:var(--agent-text); border-color:var(--agent-accent); }
|
||||||
|
.agent-runtime-bar { grid-template-columns:minmax(180px,1fr) 1px minmax(150px,1fr) 1px minmax(140px,1fr) 1px minmax(150px,1fr) auto; padding:12px 22px; background:transparent; border-color:var(--agent-line); }
|
||||||
|
.agent-runtime-bar i { background:var(--agent-line); }
|
||||||
|
.agent-runtime-bar b { color:var(--agent-text); font-size:11.5px; font-weight:600; }
|
||||||
|
.agent-runtime-bar span { color:var(--agent-muted); font-size:9.5px; }
|
||||||
|
.agent-runtime-bar button,.agent-provider-form button,.tool-forge-panel button { border-color:var(--agent-line); background:var(--agent-panel); color:var(--agent-sub); border-radius:7px; }
|
||||||
|
.agent-channel-layout { grid-template-columns:240px minmax(0,1fr); }
|
||||||
|
.agent-conversations { border-color:var(--agent-line); background:color-mix(in srgb,var(--agent-bg) 76%,transparent); }
|
||||||
|
.agent-conversations > header,.agent-conversations > footer { border-color:var(--agent-line); }
|
||||||
|
.agent-conversations > header span { color:var(--agent-muted); letter-spacing:.05em; }
|
||||||
|
.agent-conversations > header button { border:1px solid var(--agent-line); background:transparent; color:var(--agent-sub); border-radius:7px; }
|
||||||
|
.agent-conversation-list article { margin-bottom:2px; border-radius:6px; background:transparent; }
|
||||||
|
.agent-conversation-list article.active { border-color:color-mix(in srgb,var(--agent-accent) 30%,var(--agent-line)); background:color-mix(in srgb,var(--agent-accent) 9%,transparent); box-shadow:inset 2px 0 var(--agent-accent); }
|
||||||
|
.conversation-open b,.agent-message header b { color:var(--agent-text); font-weight:580; }
|
||||||
|
.conversation-open span,.conversation-open small,.agent-conversations > footer { color:var(--agent-muted); }
|
||||||
|
.agent-ledger { padding:22px 28px; }
|
||||||
|
.agent-message { max-width:82%; margin-bottom:14px; padding:14px 16px; border-color:var(--agent-line); border-radius:9px; background:var(--agent-panel); }
|
||||||
|
.agent-message.is-human { margin-left:auto; background:color-mix(in srgb,var(--agent-accent) 12%,var(--agent-panel)); border-color:color-mix(in srgb,var(--agent-accent) 34%,var(--agent-line)); }
|
||||||
|
.agent-message-content { color:var(--agent-sub); }
|
||||||
|
.agent-message footer { border-color:var(--agent-line); color:var(--agent-muted); }
|
||||||
|
.agent-composer { margin:0 28px 20px; padding:0; border:1px solid var(--agent-line); border-radius:10px; background:var(--agent-panel); overflow:hidden; }
|
||||||
|
.agent-composer textarea { min-height:74px; border:0; border-radius:0; background:transparent; color:var(--agent-text); }
|
||||||
|
.agent-composer > div { margin:0; padding:8px 10px; border-top:1px solid var(--agent-line); }
|
||||||
|
.agent-composer select { background:transparent; color:var(--agent-sub); border-color:var(--agent-line); }
|
||||||
|
.agent-composer button { border-radius:7px; background:var(--agent-accent); color:#07101f; }
|
||||||
|
.tool-forge-panel,.local-worker-panel { padding:24px 28px; }
|
||||||
|
.forge-source input,.forge-source textarea,.local-worker-brain input,.worker-objective textarea,.worker-objective select { border-color:var(--agent-line); background:color-mix(in srgb,var(--agent-bg) 78%,transparent); color:var(--agent-text); }
|
||||||
|
.forge-registry article,.forge-ticket,.local-worker-status article,.local-worker-waiting,.local-worker-skills,.local-worker-brain,.worker-objective,.worker-tools,.local-worker-receipt { border-color:var(--agent-line); border-radius:8px; background:var(--agent-panel); }
|
||||||
|
.tool-forge-panel > header p,.local-worker-panel > header p,.forge-registry > p,.local-worker-waiting p { color:var(--agent-muted); }
|
||||||
|
.tool-forge-panel > header > b,.local-worker-panel > header > b { color:var(--agent-accent); font-family:inherit; }
|
||||||
|
.agent-delete-backdrop section { border-color:var(--agent-line); background:var(--agent-bg); }
|
||||||
|
|
||||||
|
@media (max-width:900px) {
|
||||||
|
.agent-runtime-bar { display:flex; overflow-x:auto; }
|
||||||
|
.agent-runtime-bar > i { display:none; }
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -81,23 +81,25 @@ export function TraditionalSurface({ awake = false, finish, onFinish, onActivity
|
||||||
<div className="stage">
|
<div className="stage">
|
||||||
<nav className="nav glass">
|
<nav className="nav glass">
|
||||||
<div className="brand">HoloLake<small>GH-AIOS · V{version}</small></div>
|
<div className="brand">HoloLake<small>GH-AIOS · V{version}</small></div>
|
||||||
<div className="tabs"><button type="button" className="on">首页</button><button type="button" onClick={onOpenKnowledge}>知识库</button><button type="button" onClick={onOpenChannel}>频道</button><button type="button" onClick={onOpenEra}>演化史</button><button type="button" onClick={onOpenSettings}>设置</button></div>
|
<div className="tabs"><button type="button" className="on">首页</button><button type="button" onClick={onOpenKnowledge}>知识库</button><button type="button" onClick={onOpenChannel}>频道</button><button type="button" onClick={onOpenEra}>演化史</button><button type="button" onClick={onOpenSettings}>授权与连接</button><button type="button" onClick={onOpenSettings}>设置</button></div>
|
||||||
<div className="me"><i>{identityLabel.startsWith('ICE') ? 'ICE' : 'HL'}</i>{identityLabel}</div>
|
<div className="me"><i>{identityLabel.startsWith('ICE') ? 'ICE' : 'HL'}</i>{identityLabel}</div>
|
||||||
<button type="button" className="back" onClick={onBack}>返回语言世界</button>
|
<button type="button" className="back" onClick={onBack}>返回语言世界</button>
|
||||||
</nav>
|
</nav>
|
||||||
<div className="grid">
|
<div className="grid">
|
||||||
<div className="hero glass">
|
<div className="hero glass">
|
||||||
<div className="topline"><span className="lbl">光 湖 历 · 今 日</span><span className="tag">操作唤醒 · 轻量运行</span></div>
|
<div className="topline"><h1>今日概览</h1><span className="health"><i/>运行状态正常</span></div>
|
||||||
<div className="day">第 {dayNumber} 天</div>
|
<div className="day"><span>光湖纪元</span> 第 {dayNumber} 天</div>
|
||||||
<div className="sub">纪元源点 2025-04-26 · 今日当值 <b>{duty}</b> · 编号路径正常</div>
|
<div className="sub">当前当值:<b>{duty}</b></div>
|
||||||
<div className="clock" ref={clockRef}>--:--:--.---</div>
|
<div className="clock" ref={clockRef}>--:--:--.---</div>
|
||||||
<div className="broadcast"><div className="hd"><span className="lbl">世 界 广 播 · 真实投影</span><span className="live"><i/>已校验</span></div><div className="feed">{broadcasts.map(item => <div className="b-item" key={item.id} style={{ '--bc': BROADCAST_COLOR[item.domain] || '#a8bcff' } as React.CSSProperties}><span className="d">{item.domain}</span><span className="m">{item.message}</span><span className="tm">{item.time}</span></div>)}</div></div>
|
<div className="broadcast"><div className="hd"><h2>世界广播</h2><span className="verified">信息已核验</span></div><div className="feed">{broadcasts.map(item => <div className="b-item" key={item.id} style={{ '--bc': BROADCAST_COLOR[item.domain] || '#a8bcff' } as React.CSSProperties}><span className="d">{item.domain}</span><span className="m">{item.message}</span><span className="tm">{item.time}</span></div>)}</div></div>
|
||||||
<div className="stats"><div className="stat"><span className="lbl">天象 · 自动感知</span><div className="big">{weatherLabel}<em>可验证回传</em></div></div><div className="stat"><span className="lbl">频道活动 · 七日</span><div className="big">{activityCount}<em>次记录</em></div><div className="bars" style={{ height: 34, marginTop: 10 }}>{activityBars.map((value, index) => <i key={index} className={index === activityBars.length - 1 ? 'hot' : ''} style={{ height: `${Math.max(4, Math.round(value / maxBar * 100))}%` }}/>)}</div></div></div>
|
<div className="stats"><div className="stat"><h2>天气感知</h2><div className="big">{weatherLabel}<em>公开天气信息已校验</em></div></div><div className="stat"><h2>近七日活动</h2><div className="big">{activityCount}<em>次记录</em></div><div className="bars" style={{ height: 34, marginTop: 10 }}>{activityBars.map((value, index) => <i key={index} className={index === activityBars.length - 1 ? 'hot' : ''} style={{ height: `${Math.max(4, Math.round(value / maxBar * 100))}%` }}/>)}</div></div></div>
|
||||||
</div>
|
</div>
|
||||||
<div className="card glass"><div className="hd"><span className="lbl">频 道 与 文 档</span><span className="tag" style={{ '--tc': 'var(--good)' } as React.CSSProperties}>在册 {channels.length} 项</span></div><div className="rows">{channels.map(channel => <div className="row" key={channel.title}><span className="dot" style={{ color: channel.color, background: channel.color }}/><div className="t"><b>{channel.title}</b><span>{channel.meta}</span></div><span className="tag" style={{ '--tc': channel.tone } as React.CSSProperties}>{channel.tag}</span><span className="num">{channel.count}</span></div>)}</div></div>
|
<div className="operations glass">
|
||||||
<div className="card glass"><div className="hd"><span className="lbl">系 统 态</span><span className="tag" style={{ '--tc': 'var(--good)' } as React.CSSProperties}>真实状态</span></div><div className="rows">{systems.map(system => <div className="row" key={system.title}><div className="t"><b>{system.title}</b><span>{system.meta}</span></div><span className="tag" style={system.tone ? { '--tc': system.tone } as React.CSSProperties : undefined}>{system.tag}</span></div>)}</div></div>
|
<section className="registry"><div className="hd"><h2>频道与文档</h2><span>{channels.length} 项在册</span></div><div className="rows">{channels.map(channel => <div className="row" key={channel.title}><span className="dot" style={{ color: channel.color, background: channel.color }}/><div className="t"><b>{channel.title}</b><span>{channel.meta}</span></div><span className="state" style={{ '--tc': channel.tone } as React.CSSProperties}>{channel.tag}</span><span className="num">{channel.count}</span></div>)}</div></section>
|
||||||
|
<section className="system-list"><div className="hd"><h2>系统状态</h2><span>实时校验</span></div><div className="rows">{systems.map(system => <div className="row" key={system.title}><div className="t"><b>{system.title}</b><span>{system.meta}</span></div><span className="state" style={system.tone ? { '--tc': system.tone } as React.CSSProperties : undefined}>{system.tag}</span></div>)}</div></section>
|
||||||
</div>
|
</div>
|
||||||
<div className="finisher glass"><small>玻璃氛围</small>{FINISHES.map(item => <button key={item.id} type="button" className={finish === item.id ? 'on' : ''} onClick={() => pickFinish(item.id)}>{item.name}</button>)}</div>
|
</div>
|
||||||
|
<footer className="workbench-footer"><button type="button" className="footer-back" onClick={onBack}>← 返回语言世界</button><div className="finisher glass"><small>主题</small>{FINISHES.map(item => <button key={item.id} type="button" className={finish === item.id ? 'on' : ''} onClick={() => pickFinish(item.id)}>{item.name}</button>)}</div></footer>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -368,3 +368,125 @@
|
||||||
.trad-surface .broadcast .live i { animation:none; }
|
.trad-surface .broadcast .live i { animation:none; }
|
||||||
.trad-surface .b-item { animation:none; }
|
.trad-surface .b-item { animation:none; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 2026-08-21 · 传统工作台正式界面:开放式玻璃工作区,不使用仪表盘卡片堆叠。 */
|
||||||
|
.trad-surface {
|
||||||
|
--glass-hi:rgba(16,28,48,.54);
|
||||||
|
--glass-lo:rgba(7,15,29,.28);
|
||||||
|
--glass-edge:rgba(190,215,255,.2);
|
||||||
|
--glass-inner:rgba(255,255,255,.16);
|
||||||
|
--rule:color-mix(in srgb,var(--ink) 15%,transparent);
|
||||||
|
}
|
||||||
|
.trad-surface[data-finish="porcelain"],
|
||||||
|
.trad-surface[data-finish="snow"] {
|
||||||
|
--glass-hi:rgba(255,255,255,.45);
|
||||||
|
--glass-lo:rgba(240,247,255,.18);
|
||||||
|
--glass-edge:rgba(255,255,255,.72);
|
||||||
|
--glass-inner:rgba(255,255,255,.86);
|
||||||
|
--rule:rgba(27,35,64,.14);
|
||||||
|
}
|
||||||
|
.trad-surface .sky::after { opacity:.18; }
|
||||||
|
.trad-surface .glass {
|
||||||
|
border-radius:11px;
|
||||||
|
background:linear-gradient(155deg,var(--glass-hi),var(--glass-lo));
|
||||||
|
-webkit-backdrop-filter:blur(20px) saturate(1.18);
|
||||||
|
backdrop-filter:blur(20px) saturate(1.18);
|
||||||
|
box-shadow:inset 0 1px 0 var(--glass-inner),0 12px 36px rgba(1,5,14,.2);
|
||||||
|
}
|
||||||
|
.trad-surface .glass::before { background:linear-gradient(120deg,rgba(255,255,255,.07),transparent 28%); }
|
||||||
|
.trad-surface .glass::after { display:none; }
|
||||||
|
.trad-surface .stage {
|
||||||
|
width:100%; max-width:1580px;
|
||||||
|
padding:max(54px,var(--pad,18px)) var(--pad,18px) var(--pad,18px);
|
||||||
|
gap:0;
|
||||||
|
grid-template-rows:62px minmax(0,1fr) 60px;
|
||||||
|
}
|
||||||
|
.trad-surface .nav {
|
||||||
|
z-index:4; gap:24px; padding:0 18px; border-radius:11px 11px 0 0;
|
||||||
|
border-bottom-color:var(--rule); box-shadow:inset 0 1px 0 var(--glass-inner);
|
||||||
|
}
|
||||||
|
.trad-surface .nav .brand { min-width:180px; font-size:16px; letter-spacing:.04em; }
|
||||||
|
.trad-surface .nav .brand small { display:block; margin:2px 0 0; font-size:8px; letter-spacing:.17em; }
|
||||||
|
.trad-surface .nav .tabs { align-self:stretch; gap:22px; margin-left:10px; overflow:visible; }
|
||||||
|
.trad-surface .nav .tabs button {
|
||||||
|
position:relative; padding:0 2px; border-radius:0; font-size:12px; font-weight:570; letter-spacing:.02em;
|
||||||
|
}
|
||||||
|
.trad-surface .nav .tabs button.on { background:transparent; }
|
||||||
|
.trad-surface .nav .tabs button.on::after {
|
||||||
|
content:''; position:absolute; left:1px; right:1px; bottom:0; height:2px; background:var(--accent);
|
||||||
|
box-shadow:0 0 12px color-mix(in srgb,var(--accent) 54%,transparent);
|
||||||
|
}
|
||||||
|
.trad-surface .nav .me { font-size:11px; font-weight:540; }
|
||||||
|
.trad-surface .nav .me i { width:26px; height:26px; background:color-mix(in srgb,var(--accent) 24%,transparent); color:var(--ink); box-shadow:none; }
|
||||||
|
.trad-surface .grid {
|
||||||
|
gap:0; grid-template-columns:minmax(0,1.5fr) minmax(370px,.96fr); grid-template-rows:minmax(0,1fr);
|
||||||
|
border:1px solid var(--glass-edge); border-top:0; border-bottom:0;
|
||||||
|
background:color-mix(in srgb,var(--bg-base) 46%,transparent);
|
||||||
|
-webkit-backdrop-filter:blur(14px) saturate(1.08); backdrop-filter:blur(14px) saturate(1.08);
|
||||||
|
}
|
||||||
|
.trad-surface .hero {
|
||||||
|
grid-row:auto; min-width:0; padding:38px 34px 24px; border:0; border-right:1px solid var(--rule); border-radius:0;
|
||||||
|
background:transparent; box-shadow:none; backdrop-filter:none; -webkit-backdrop-filter:none;
|
||||||
|
}
|
||||||
|
.trad-surface .hero::before,.trad-surface .hero::after { display:none; }
|
||||||
|
.trad-surface .hero .topline { align-items:center; }
|
||||||
|
.trad-surface .hero .topline h1,.trad-surface .broadcast h2,.trad-surface .stat h2,.trad-surface .operations h2 {
|
||||||
|
margin:0; color:var(--ink); font-size:14px; font-weight:650; letter-spacing:.01em;
|
||||||
|
}
|
||||||
|
.trad-surface .hero .health { display:inline-flex; align-items:center; gap:8px; color:var(--good); font-size:11px; }
|
||||||
|
.trad-surface .hero .health i { width:7px; height:7px; border-radius:50%; background:var(--good); box-shadow:0 0 9px var(--good); }
|
||||||
|
.trad-surface .hero .day { margin-top:38px; font-size:clamp(32px,4.2vw,54px); font-weight:630; letter-spacing:.02em; text-shadow:none; }
|
||||||
|
.trad-surface .hero .day span { margin-right:12px; font-size:.58em; font-weight:530; letter-spacing:.12em; }
|
||||||
|
.trad-surface .hero .sub { margin-top:15px; font-size:13px; font-weight:520; letter-spacing:.02em; }
|
||||||
|
.trad-surface .hero .clock { margin-top:23px; font-size:13px; font-weight:520; letter-spacing:.12em; }
|
||||||
|
.trad-surface .broadcast { flex:none; margin-top:42px; }
|
||||||
|
.trad-surface .broadcast .hd { padding-bottom:13px; border-bottom:1px solid var(--rule); }
|
||||||
|
.trad-surface .broadcast .verified { color:var(--good); font-size:10px; }
|
||||||
|
.trad-surface .broadcast .feed { margin-top:8px; gap:0; }
|
||||||
|
.trad-surface .b-item { padding:12px 4px; border:0; border-bottom:1px solid var(--rule); border-radius:0; background:transparent; }
|
||||||
|
.trad-surface[data-finish="porcelain"] .b-item,.trad-surface[data-finish="snow"] .b-item { background:transparent; border-color:var(--rule); }
|
||||||
|
.trad-surface .b-item .d { font-size:10.5px; }
|
||||||
|
.trad-surface .b-item .m { font-size:12.5px; }
|
||||||
|
.trad-surface .hero .stats { margin-top:auto; gap:0; border-top:1px solid var(--rule); }
|
||||||
|
.trad-surface .hero .stat { min-width:0; padding:22px 6px 4px; border:0; border-radius:0; background:transparent; }
|
||||||
|
.trad-surface .hero .stat + .stat { padding-left:28px; border-left:1px solid var(--rule); }
|
||||||
|
.trad-surface[data-finish="porcelain"] .hero .stat,.trad-surface[data-finish="snow"] .hero .stat { background:transparent; border-color:var(--rule); }
|
||||||
|
.trad-surface .hero .stat .big { margin-top:15px; font-size:25px; font-weight:600; }
|
||||||
|
.trad-surface .hero .stat .big em { font-weight:480; }
|
||||||
|
.trad-surface .operations {
|
||||||
|
min-width:0; padding:0 28px; border:0; border-radius:0; background:transparent; box-shadow:none;
|
||||||
|
backdrop-filter:none; -webkit-backdrop-filter:none; overflow:auto;
|
||||||
|
}
|
||||||
|
.trad-surface .operations::before,.trad-surface .operations::after { display:none; }
|
||||||
|
.trad-surface .operations section { padding:36px 0 26px; }
|
||||||
|
.trad-surface .operations section + section { border-top:1px solid var(--rule); }
|
||||||
|
.trad-surface .operations .hd { display:flex; justify-content:space-between; gap:16px; padding:0 0 15px; border-bottom:1px solid var(--rule); }
|
||||||
|
.trad-surface .operations .hd > span { color:var(--ink-faint); font-size:10.5px; }
|
||||||
|
.trad-surface .row { padding:14px 0; border-radius:0; border-bottom:1px solid var(--rule); }
|
||||||
|
.trad-surface .row:hover { background:color-mix(in srgb,var(--accent) 6%,transparent); }
|
||||||
|
.trad-surface .row .t b { font-size:12.5px; font-weight:610; }
|
||||||
|
.trad-surface .row .t span { font-size:10.5px; font-weight:480; }
|
||||||
|
.trad-surface .row .state { min-width:54px; color:var(--tc,var(--good)); font-size:10.5px; text-align:right; }
|
||||||
|
.trad-surface .workbench-footer {
|
||||||
|
display:flex; align-items:center; justify-content:space-between; gap:18px; padding:0 18px;
|
||||||
|
border:1px solid var(--glass-edge); border-top-color:var(--rule); border-radius:0 0 11px 11px;
|
||||||
|
background:linear-gradient(155deg,var(--glass-hi),var(--glass-lo));
|
||||||
|
-webkit-backdrop-filter:blur(20px) saturate(1.18); backdrop-filter:blur(20px) saturate(1.18);
|
||||||
|
}
|
||||||
|
.trad-surface .footer-back { border:0; background:transparent; color:var(--ink-sub); font-size:11.5px; cursor:pointer; }
|
||||||
|
.trad-surface .finisher { justify-self:auto; padding:0; border:0; background:transparent; box-shadow:none; backdrop-filter:none; }
|
||||||
|
.trad-surface .finisher::before,.trad-surface .finisher::after { display:none; }
|
||||||
|
.trad-surface .finisher small { letter-spacing:.05em; }
|
||||||
|
.trad-surface .finisher button { padding:8px 10px; border-radius:7px; font-size:10.5px; letter-spacing:.02em; font-weight:560; }
|
||||||
|
.trad-surface .finisher button.on { background:color-mix(in srgb,var(--accent) 14%,transparent); box-shadow:inset 0 -2px var(--accent); }
|
||||||
|
|
||||||
|
@media (max-width: 980px) {
|
||||||
|
.trad-surface .stage { grid-template-rows:auto minmax(0,1fr) auto; }
|
||||||
|
.trad-surface .nav { flex-wrap:wrap; padding-block:12px; }
|
||||||
|
.trad-surface .nav .brand { min-width:120px; }
|
||||||
|
.trad-surface .nav .tabs { order:3; width:100%; height:34px; overflow-x:auto; }
|
||||||
|
.trad-surface .grid { grid-template-columns:1fr; overflow:auto; }
|
||||||
|
.trad-surface .hero { border-right:0; border-bottom:1px solid var(--rule); min-height:620px; }
|
||||||
|
.trad-surface .operations { min-height:520px; }
|
||||||
|
.trad-surface .workbench-footer { flex-wrap:wrap; padding-block:9px; }
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,9 @@ body {
|
||||||
font-weight: 430;
|
font-weight: 430;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
}
|
}
|
||||||
|
.visual-qa-shell { min-height:100%; padding:70px 5vw; color:var(--content-secondary); background:linear-gradient(145deg,#07111f,#102744); }
|
||||||
|
.visual-qa-shell > header { display:flex; justify-content:space-between; max-width:1480px; margin:0 auto 22px; color:#eef4ff; }
|
||||||
|
.visual-qa-shell > main { max-width:1480px; margin:0 auto; }
|
||||||
button:focus-visible, input:focus-visible, textarea:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
|
button:focus-visible, input:focus-visible, textarea:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
|
||||||
svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.7; }
|
svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.7; }
|
||||||
::-webkit-scrollbar { width: 11px; height: 11px; }
|
::-webkit-scrollbar { width: 11px; height: 11px; }
|
||||||
|
|
@ -469,6 +472,40 @@ svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-lineca
|
||||||
*, *::before, *::after { scroll-behavior: auto !important; transition-duration: .01ms !important; }
|
*, *::before, *::after { scroll-behavior: auto !important; transition-duration: .01ms !important; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 2026-08-21 · 正式公众授权界面:列表与证据层级替代大卡片仪表盘。 */
|
||||||
|
.human-authorization-layout {
|
||||||
|
grid-template-columns:minmax(0,1.1fr) minmax(330px,.7fr);
|
||||||
|
gap:0;
|
||||||
|
border:1px solid var(--panel-edge);
|
||||||
|
border-radius:12px;
|
||||||
|
overflow:hidden;
|
||||||
|
background:color-mix(in srgb,var(--panel-bg) 62%,transparent);
|
||||||
|
box-shadow:0 18px 46px color-mix(in srgb,var(--primitive-shadow) 24%,transparent);
|
||||||
|
}
|
||||||
|
.human-authorization-layout > .plain-panel {
|
||||||
|
border:0; border-radius:0; background:transparent; box-shadow:none;
|
||||||
|
}
|
||||||
|
.authorization-primary { grid-row:auto; border-right:1px solid var(--panel-edge) !important; }
|
||||||
|
.collaboration-live { border-bottom:1px solid var(--panel-edge) !important; }
|
||||||
|
.external-ai-gateway-panel { grid-column:1 / -1; border-top:1px solid var(--panel-edge) !important; }
|
||||||
|
.human-authorization-layout .plain-panel > header { padding-bottom:16px; border-bottom:1px solid var(--panel-edge); }
|
||||||
|
.authorization-empty { min-height:190px; margin-top:0; border:0; border-radius:0; }
|
||||||
|
.collaboration-summary,.gateway-summary { gap:0; border-bottom:1px solid var(--panel-edge); }
|
||||||
|
.collaboration-summary div,.gateway-summary div { border-radius:0; background:transparent; }
|
||||||
|
.collaboration-summary div + div,.gateway-summary div + div { border-left:1px solid var(--panel-edge); }
|
||||||
|
.status-chip { border-radius:7px; padding:5px 8px; }
|
||||||
|
.technical-details { margin-top:5px; }
|
||||||
|
.technical-details summary { width:max-content; color:var(--content-muted); font-size:10px; cursor:pointer; }
|
||||||
|
.technical-details code { display:block; max-width:280px; overflow:hidden; margin-top:4px; color:var(--content-muted); font-size:9px; text-overflow:ellipsis; white-space:nowrap; }
|
||||||
|
.gateway-catalog-grid > section,.gateway-exposure-control,.gateway-connection-details {
|
||||||
|
border-radius:8px; background:color-mix(in srgb,var(--primitive-glass) 38%,transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width:880px) {
|
||||||
|
.human-authorization-layout { grid-template-columns:1fr; }
|
||||||
|
.authorization-primary { border-right:0 !important; border-bottom:1px solid var(--panel-edge) !important; }
|
||||||
|
}
|
||||||
|
|
||||||
/* ===== 布局收展(学 Tolaria:侧栏可收,正文与知识库拿回宽度) ===== */
|
/* ===== 布局收展(学 Tolaria:侧栏可收,正文与知识库拿回宽度) ===== */
|
||||||
.app-shell.sidebar-collapsed { grid-template-columns: 80px minmax(0, 1fr); }
|
.app-shell.sidebar-collapsed { grid-template-columns: 80px minmax(0, 1fr); }
|
||||||
.sidebar-toggle { width: 30px; height: 30px; margin-left: auto; border-radius: 8px; }
|
.sidebar-toggle { width: 30px; height: 30px; margin-left: auto; border-radius: 8px; }
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue