fix(education): ship 0.2.1 drag and Forgejo truth state
This commit is contained in:
parent
84a631d886
commit
28f68fa9ac
15 changed files with 171 additions and 17 deletions
47
deployment/receipts/GH-EDU-DESKTOP-0.2.1-20260808-001.json
Normal file
47
deployment/receipts/GH-EDU-DESKTOP-0.2.1-20260808-001.json
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
{
|
||||
"schema": "guanghu.education-desktop-correction/v1",
|
||||
"receipt_id": "GH-EDU-DESKTOP-0.2.1-20260808-001",
|
||||
"development_id": "DEV-20260808-002",
|
||||
"state": "PASS_100",
|
||||
"product": {
|
||||
"name": "光湖分域 · 教育",
|
||||
"version": "0.2.1",
|
||||
"bundle_identifier": "com.guanghulab.subdomain.education",
|
||||
"source_path": "product-source/guanghu-education-industry-os/",
|
||||
"local_source_commit": "1ab2f7903dcae073bd7847004c4b9548e18414cd"
|
||||
},
|
||||
"corrections": {
|
||||
"window_drag": {
|
||||
"state": "PASS_100",
|
||||
"implementation": "fixed native drag handle plus Tauri startDragging permission",
|
||||
"desktop_skill_observation": "accessibility tree exposes 拖动窗口 and drag action completed without runtime error"
|
||||
},
|
||||
"code_channel_identity": {
|
||||
"state": "PASS_100",
|
||||
"runtime": "Forgejo 16.0.1+gitea-1.22.0",
|
||||
"display": "Forgejo 16.0.1",
|
||||
"compatibility_suffix_hidden": "gitea-1.22.0"
|
||||
},
|
||||
"agent_truth_state": {
|
||||
"state": "NOT_INTEGRATED",
|
||||
"display": "未接入",
|
||||
"research_candidates": 12
|
||||
}
|
||||
},
|
||||
"application": {
|
||||
"desktop_path": "/Users/bingshuolingdianyuanhe/Desktop/光湖分域 · 教育.app",
|
||||
"mac_binary_sha256": "3e6573348237730cf7c80706415afa14722097eb79c38ee7bea69a72420058d0",
|
||||
"signature_verification": "PASS",
|
||||
"release_backup": "/Volumes/JZAO/HoloLake/development/education-industry-os-DEV-20260808-001/releases/0.2.1/光湖分域 · 教育.app"
|
||||
},
|
||||
"tests": {
|
||||
"vitest": "7 passed",
|
||||
"vite_build": "PASS",
|
||||
"cargo_check_locked_offline": "PASS",
|
||||
"tauri_release_build": "PASS",
|
||||
"desktop_launch": "PASS",
|
||||
"server_key_login": "PASS",
|
||||
"forgejo_and_agent_status_readback": "PASS"
|
||||
},
|
||||
"verified_at": "2026-08-08T09:53:28+08:00"
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"schema": "guanghu.desktop-package-audit/v1",
|
||||
"receipt_id": "GH-HOLOLAKE-DESKTOP-0.5.0-AUDIT-20260808-001",
|
||||
"development_id": "DEV-20260808-002",
|
||||
"target": {
|
||||
"path": "/Users/bingshuolingdianyuanhe/Desktop/HoloLake Era.app",
|
||||
"version": "0.5.0",
|
||||
"bundle_identifier": "com.guanghu.hololake-desktop",
|
||||
"bundle_mtime": "2026-08-08T09:39:48+08:00",
|
||||
"binary_sha256": "b999c4dc1afbef2261c7749f731fec8d982bebd41197874629403796ce93f21a",
|
||||
"packaged_main_sha256": "fdb0384977bc2b32d1c433742e2faf2a339b6ff4e3bc1f68a6246f2923586313"
|
||||
},
|
||||
"result": "FAIL_0_PACKAGE_NOT_RUNNABLE",
|
||||
"evidence": {
|
||||
"diagnostic_reports_observed": 6,
|
||||
"first_crash": "DYLD library validation rejected libffmpeg.dylib because the mapped file and process had different Team IDs",
|
||||
"current_packaged_main": "production path spawns process.execPath with server-bundle.js and recursively launches Electron instead of Node",
|
||||
"runtime_reproduction": "repeated KB Server Error output and child-process fanout",
|
||||
"repository_fix_commit": "84a631d886a23aa60c65bf68f6394834ac3a8946",
|
||||
"repository_fix_is_in_desktop_bundle": false
|
||||
},
|
||||
"capability_truth": {
|
||||
"outline_runtime": false,
|
||||
"outline_component_analysis_cards": true,
|
||||
"forgejo_runtime_or_remote_integration": false,
|
||||
"forgejo_declaration_and_offline_manifest_only": true,
|
||||
"local_markdown_git_engine_code": true,
|
||||
"agent_code_shell": true,
|
||||
"agent_operational_runtime": false,
|
||||
"agent_without_external_model_key": "offline fixed response"
|
||||
},
|
||||
"mutation": "NONE_DIAGNOSTIC_ONLY",
|
||||
"verified_at": "2026-08-08T09:53:28+08:00"
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"schema": "hololake.module-registry/v1",
|
||||
"registry_id": "HL-MODULE-REGISTRY-0001",
|
||||
"version": "2026.08.08.1",
|
||||
"version": "2026.08.08.2",
|
||||
"authority_rule": "A module entry maps a stable id to a real path and provenance; it grants no execution authority. Pulling a module does not equal being online.",
|
||||
"modules": [
|
||||
{
|
||||
|
|
@ -124,7 +124,7 @@
|
|||
{
|
||||
"id": "GH-EDU-MODULE-REGISTRY-0001",
|
||||
"name": "guanghu-education-industry-os",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.1",
|
||||
"state": "LIVE_STAGE_1",
|
||||
"path": "product-source/guanghu-education-industry-os/",
|
||||
"registry_path": "product-source/guanghu-education-industry-os/protocol/module-registry.json",
|
||||
|
|
@ -145,7 +145,7 @@
|
|||
],
|
||||
"execution_boundary": "XX-GZ-001 holds identity and channel data; desktop app renders and edits; server contains protocol release but no product source",
|
||||
"update_authority": "guanghu-only",
|
||||
"receipt": "deployment/receipts/GH-EDU-STAGE1-20260808-001.json"
|
||||
"receipt": "deployment/receipts/GH-EDU-DESKTOP-0.2.1-20260808-001.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
# 教育桌面端 0.2.1 纠正与 HoloLake 0.5.0 包审计
|
||||
|
||||
## 教育桌面端 0.2.1
|
||||
|
||||
- 窗口顶部新增独立原生拖动区域,并显式调用 Tauri `startDragging`。
|
||||
- 能力清单增加 `core:window:allow-start-dragging`。
|
||||
- Forgejo API 返回的兼容版本串 `16.0.1+gitea-1.22.0` 只在界面显示为 `Forgejo 16.0.1`,避免把 Forgejo 数据面误认成 Gitea 部署。
|
||||
- 首页明确显示人格体 Agent 尚未接入;当前只有 12 个 `RESEARCH_ONLY` 候选。
|
||||
- 桌面 App、JZAO 发行备份、测试和签名校验均已回读。
|
||||
|
||||
## 桌面 HoloLake Era 0.5.0 只读审计
|
||||
|
||||
桌面包不是当前可交付运行物。系统已有 6 份崩溃报告;旧签名包先出现 `libffmpeg.dylib` 团队标识不一致,当前桌面包中的主进程又在生产模式使用 Electron 可执行文件启动 `server-bundle.js`,形成递归 Electron 拉起。
|
||||
|
||||
线上 `84a631d` 已把源码改成在主进程内加载后端,但桌面包生成时间早于该提交,包内仍是旧逻辑,不能用“源码已修”证明桌面 App 已修。
|
||||
|
||||
能力边界:
|
||||
|
||||
- Outline:只有拆解分析卡,没有 Outline 运行时。
|
||||
- Forgejo:只有集成声明、离线包清单和未来 remote 方案,没有实际 remote/API/同步实现。
|
||||
- Agent:有聊天路由、文档工具桥和模型调用代码壳;当前桌面包无法正常启动,未配置模型时只返回离线固定文本,不能登记为可运行 Agent。
|
||||
- 知识库:实际实现是本地 Markdown + Git 的轻量知识库,不是完整 Outline,也未接入 Forgejo 数据面。
|
||||
|
||||
审计未修改 Qoder 生成的 `HoloLake Era.app`。
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "guanghu-education-industry-os",
|
||||
"private": true,
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.1",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --host 127.0.0.1 --port 5216",
|
||||
|
|
|
|||
|
|
@ -1171,7 +1171,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "guanghu-education-industry-os"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "guanghu-education-industry-os"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
description = "Guanghu Education Subdomain operating system client"
|
||||
authors = ["Guanghu"]
|
||||
license = "LicenseRef-Guanghu"
|
||||
|
|
|
|||
|
|
@ -3,5 +3,5 @@
|
|||
"identifier": "default",
|
||||
"description": "Base window capability for the Guanghu education workspace",
|
||||
"windows": ["main"],
|
||||
"permissions": ["core:default"]
|
||||
"permissions": ["core:default", "core:window:allow-start-dragging"]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
{"default":{"identifier":"default","description":"Base window capability for the Guanghu education workspace","local":true,"windows":["main"],"permissions":["core:default"]}}
|
||||
{"default":{"identifier":"default","description":"Base window capability for the Guanghu education workspace","local":true,"windows":["main"],"permissions":["core:default","core:window:allow-start-dragging"]}}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
||||
"productName": "光湖分域 · 教育",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.1",
|
||||
"identifier": "com.guanghulab.subdomain.education",
|
||||
"build": {
|
||||
"frontendDist": "../dist",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
import { invoke } from '@tauri-apps/api/core'
|
||||
import { useMemo, useState } from 'react'
|
||||
import { getCurrentWindow } from '@tauri-apps/api/window'
|
||||
import { useMemo, useState, type MouseEvent } from 'react'
|
||||
import {
|
||||
bundledModules,
|
||||
formatForgejoVersion,
|
||||
parseSheetMetrics,
|
||||
routeInstruction,
|
||||
type InstructionRoute,
|
||||
|
|
@ -72,6 +74,21 @@ function LakeMark() {
|
|||
return <span className="lake-mark" aria-hidden="true"><i /><b /></span>
|
||||
}
|
||||
|
||||
function WindowDragHandle() {
|
||||
const startDragging = (event: MouseEvent<HTMLDivElement>) => {
|
||||
if (event.button !== 0) return
|
||||
event.preventDefault()
|
||||
void getCurrentWindow().startDragging()
|
||||
}
|
||||
|
||||
return <div
|
||||
className="native-drag-handle"
|
||||
data-tauri-drag-region
|
||||
aria-label="拖动窗口"
|
||||
onMouseDown={startDragging}
|
||||
/>
|
||||
}
|
||||
|
||||
function LoginGate({
|
||||
error,
|
||||
loading,
|
||||
|
|
@ -82,8 +99,8 @@ function LoginGate({
|
|||
onConnect: () => void
|
||||
}) {
|
||||
return <main className="login-gate">
|
||||
<WindowDragHandle />
|
||||
<section className="login-window">
|
||||
<div className="window-drag" data-tauri-drag-region />
|
||||
<LakeMark />
|
||||
<p>光湖分域 · 教育行业</p>
|
||||
<h1>进入自己的初始化频道</h1>
|
||||
|
|
@ -117,6 +134,8 @@ function StatusCard({ label, value, detail, tone = 'green' }: {
|
|||
|
||||
function ChannelHome({ snapshot, modules }: { snapshot: ChannelSnapshot; modules: ModuleEntry[] }) {
|
||||
const live = modules.filter((module) => module.state === 'LIVE_STAGE_1').length
|
||||
const brainCandidates = modules.filter((module) => module.group === 'persona-brain').length
|
||||
const liveAgent = modules.some((module) => module.group === 'persona-brain' && module.state === 'LIVE_STAGE_1')
|
||||
const mounted = snapshot.channel.mountedModules?.length ?? 0
|
||||
const repositoryCount = snapshot.codeChannel.repositories?.data?.length ?? 0
|
||||
return <div className="page-stack">
|
||||
|
|
@ -129,7 +148,8 @@ function ChannelHome({ snapshot, modules }: { snapshot: ChannelSnapshot; modules
|
|||
<StatusCard label="个人服务器" value={String(snapshot.node.state ?? '已连接')} detail="身份与现实数据锚点 · XX-GZ-001" />
|
||||
<StatusCard label="第五域协议" value={String(snapshot.fifthDomainLink.state ?? '未知')} detail="上游导航 · JD-FD-PRIMARY" tone="blue" />
|
||||
<StatusCard label="真实能力" value={`${live} 个`} detail={`模板已装配 ${mounted} 个模块地址`} tone="amber" />
|
||||
<StatusCard label="代码频道" value={snapshot.codeChannel.version?.version ?? '未知'} detail={`${repositoryCount} 个服务器内仓库`} tone="blue" />
|
||||
<StatusCard label="代码频道" value={formatForgejoVersion(snapshot.codeChannel.version?.version)} detail={`${repositoryCount} 个服务器内仓库 · Forgejo 数据面`} tone="blue" />
|
||||
<StatusCard label="人格体 Agent" value={liveAgent ? '已接入' : '未接入'} detail={`仅登记 ${brainCandidates} 个研究候选`} tone="amber" />
|
||||
</section>
|
||||
<section className="work-grid">
|
||||
<article className="work-panel">
|
||||
|
|
@ -303,6 +323,7 @@ function App() {
|
|||
if (!snapshot) return <LoginGate error={error} loading={connecting} onConnect={connect} />
|
||||
|
||||
return <main className="education-os">
|
||||
<WindowDragHandle />
|
||||
<aside className="side-rail">
|
||||
<div className="brand"><LakeMark /><span><strong>光湖分域 · 教育</strong><small>EDUCATION SUBDOMAIN OS</small></span></div>
|
||||
<nav>{navigation.map((item) => <button key={item.id} className={surface === item.id ? 'active' : ''} onClick={() => setSurface(item.id)}>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { describe, expect, it } from 'vitest'
|
||||
import { bundledModules, parseSheetMetrics, routeInstruction } from './guanghuKernel'
|
||||
import { bundledModules, formatForgejoVersion, parseSheetMetrics, routeInstruction } from './guanghuKernel'
|
||||
|
||||
describe('Guanghu Education Subdomain kernel', () => {
|
||||
it.each([
|
||||
|
|
@ -24,4 +24,9 @@ describe('Guanghu Education Subdomain kernel', () => {
|
|||
{ label: '周子航', value: 65 },
|
||||
])
|
||||
})
|
||||
|
||||
it('presents the Forgejo release without exposing the Gitea compatibility suffix as product identity', () => {
|
||||
expect(formatForgejoVersion('16.0.1+gitea-1.22.0')).toBe('Forgejo 16.0.1')
|
||||
expect(formatForgejoVersion()).toBe('Forgejo')
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -54,6 +54,11 @@ export function bundledModules(): ModuleEntry[] {
|
|||
return registry.modules as ModuleEntry[]
|
||||
}
|
||||
|
||||
export function formatForgejoVersion(rawVersion?: string): string {
|
||||
const release = rawVersion?.match(/^(?:forgejo\s+version\s+)?([0-9]+(?:\.[0-9]+){2})/i)?.[1]
|
||||
return release ? `Forgejo ${release}` : 'Forgejo'
|
||||
}
|
||||
|
||||
export function parseSheetMetrics(content: string): Array<{ label: string; value: number }> {
|
||||
return content
|
||||
.trim()
|
||||
|
|
|
|||
|
|
@ -10,6 +10,18 @@ body { margin: 0; min-width: 900px; min-height: 100vh; overflow: hidden; }
|
|||
button, input, textarea { font: inherit; }
|
||||
button { color: inherit; }
|
||||
|
||||
.native-drag-handle {
|
||||
position: fixed;
|
||||
z-index: 1000;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 82px;
|
||||
height: 34px;
|
||||
cursor: grab;
|
||||
-webkit-app-region: drag;
|
||||
}
|
||||
.native-drag-handle:active { cursor: grabbing; }
|
||||
|
||||
.login-gate {
|
||||
display: grid;
|
||||
min-height: 100vh;
|
||||
|
|
@ -29,7 +41,6 @@ button { color: inherit; }
|
|||
box-shadow: 0 30px 90px rgba(0, 0, 0, .38), inset 0 1px rgba(255,255,255,.025);
|
||||
text-align: center;
|
||||
}
|
||||
.window-drag { position: absolute; inset: 0 0 auto; height: 42px; border-radius: 18px 18px 0 0; }
|
||||
.login-window > .lake-mark { width: 58px; height: 58px; margin-bottom: 18px; transform: scale(1.65); }
|
||||
.login-window > p { margin: 0 0 8px; color: #6ec2f4; font-size: 12px; letter-spacing: .18em; }
|
||||
.login-window h1 { margin: 0; color: #f0f7fc; font-size: 31px; font-weight: 650; letter-spacing: -.03em; }
|
||||
|
|
@ -115,7 +126,7 @@ button { color: inherit; }
|
|||
.page-intro { padding: 2px 2px 9px; }.page-intro p, .editor-page header p { margin: 0 0 7px; color: #4aa9e8; font-size: 9px; letter-spacing: .08em; }
|
||||
.page-intro h2, .editor-page h2 { margin: 0; color: #edf5fa; font-size: 25px; font-weight: 650; letter-spacing: -.025em; }
|
||||
.page-intro span, .editor-page header span { display: block; margin-top: 7px; color: #6c8395; font-size: 11px; }
|
||||
.status-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; }
|
||||
.status-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 10px; }
|
||||
.status-card { display: grid; gap: 7px; min-height: 112px; padding: 15px 16px; border: 1px solid var(--line); background: linear-gradient(180deg, rgba(10, 27, 42, .9), rgba(7, 21, 33, .9)); }
|
||||
.status-card span { color: #71899b; font-size: 9px; }.status-card strong { color: #62d0bc; font-size: 20px; }.status-card small { color: #526b7f; font-size: 8px; }
|
||||
.status-card--blue strong { color: #64b8ef; }.status-card--amber strong { color: #d5b463; }
|
||||
|
|
|
|||
|
|
@ -1,4 +1,11 @@
|
|||
import { defineConfig } from 'vite'
|
||||
import { defineConfig } from 'vitest/config'
|
||||
import react from '@vitejs/plugin-react'
|
||||
|
||||
export default defineConfig({ plugins: [react()], clearScreen: false, server: { strictPort: true } })
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
clearScreen: false,
|
||||
server: { strictPort: true },
|
||||
test: {
|
||||
exclude: ['**/node_modules/**', '**/dist/**', '**/._*'],
|
||||
},
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in a new issue