From 7f257364d2b2debdd1d0cdec0ddb6c61f0087ef6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=B0=E6=9C=94?= <565183519@qq.com> Date: Wed, 12 Aug 2026 08:49:40 +0800 Subject: [PATCH] =?UTF-8?q?docs(bridge):=20=E5=85=89=E6=B9=96=E6=A1=A5?= =?UTF-8?q?=E8=81=8A=E5=A4=A9=E5=8F=8C=E5=A3=B3=E9=9B=86=E6=88=90=E5=BC=80?= =?UTF-8?q?=E5=8F=91=E9=93=BE=20DEV-20260812-002=EF=BC=88Electron=20PASS?= =?UTF-8?q?=20/=20Tauri=20ACL=20=E6=9C=AA=E9=97=AD=E5=90=88=20+=20?= =?UTF-8?q?=E8=B8=A9=E5=9D=91=E5=9B=A0=E6=9E=9C=E9=93=BE=20+=20=E6=9C=AA?= =?UTF-8?q?=E5=86=B3=E6=B8=85=E5=8D=95=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- development/GHB-DEV-CHAIN-20260812-002.md | 97 +++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100755 development/GHB-DEV-CHAIN-20260812-002.md diff --git a/development/GHB-DEV-CHAIN-20260812-002.md b/development/GHB-DEV-CHAIN-20260812-002.md new file mode 100755 index 0000000..0f89a5c --- /dev/null +++ b/development/GHB-DEV-CHAIN-20260812-002.md @@ -0,0 +1,97 @@ +# 光湖桥聊天工具 · 双壳集成开发链 · DEV-20260812-002 + +- 登记号:GHB-DEV-CHAIN-20260812-002 +- 日期:2026-08-12 +- 执行人:铸渊 ICE-P-ZY001(QoderCN 实例) +- 指令源:冰朔——"光湖桥,就是给人类在光湖世界里做一个聊天工具。你就在我本地开发,开发好了装到这两个框架里都试试,看看是否真的成功运行了这个通讯工具。" +- 上游基线:GHB-DEV-20260812-001(光湖桥 v1 独立参考实现,bridge-node.mjs,selftest 五项 PASS) +- 状态:**Electron 壳全链路 PASS(含打包 .app);Tauri 壳部分 PASS(接入通、UI 发送被 ACL 拦,未闭合)** + +--- + +## 一、任务目标 + +把光湖桥从"协议参考实现"变成"人类可用的聊天工具",并分别装进两个桌面框架实测: +1. Electron(0.8.0 HoloLake Era 同族路线) +2. Tauri(0.4.6 源码线同族路线,冰朔偏好的轻量壳) + +验收标准:两个壳各自能连上会合点、互发消息、收到送达回执,真实运行而非纸面设计。 + +## 二、架构决策链(为什么这样做) + +``` +目标:一套聊天前端,两个壳都能装 + └─ 决策1:桥运行时统一走 stdio JSON 子进程模式 + 原因:Electron 主进程虽自带 Node,但 Tauri 后端是 Rust 无 Node 运行时; + 取交集 = 两边都能 spawn 子进程 + 读写 stdio。 + 给 bridge-node.mjs 增加 --stdio 模式(NDJSON 命令进/事件出,日志走 stderr), + 两壳集成方式完全同构,协议面只有一份。 + └─ 决策2:聊天前端零构建(纯 HTML/CSS/JS,不用 Vite/Webpack) + 原因:构建链越短,双壳复用越干净,也符合光湖"可手工审计"原则。 + └─ 决策3:adapter.js 适配层统一事件面 + 前端只认 window.GHB = { send(to,text), on(event,cb) }; + Electron 走 preload contextBridge(ghbElectron), + Tauri 走 withGlobalTauri 的 __TAURI__.event/core, + 裸浏览器降级为 mock 提示。壳的差异被隔离在 adapter 一层。 + └─ 决策4:开发与构建全部落本地盘 /tmp,成品归档 JZAO + 原因:既有教训——ExFAT(JZAO)上构建会因 AppleDouble 崩签名; + 且沙箱对工作区外 shell 写入有限制。 + └─ 决策5:无人值守自检钩子 + GHB_AUTOSEND="对端|文本|延迟秒"(走 UI 发送路径,气泡真实渲染) + + GHB_SHOT=路径(延迟截屏取证),让"是否真的运行"有图有日志。 +``` + +## 三、实测结果 + +### Electron 壳 ✅ PASS +- 开发模式双实例(ELECTRON-A ↔ ELECTRON-B):双向消息送达、回执签名验证通过、UI 气泡完整渲染(截图取证 shot-a/shot-b)。 +- 打包 `.app`(GuanghuBridgeChat.app,手工组装 + ad-hoc 签名)双实例复测:PKG-A ↔ PKG-B 双向送达、验签通过(截图 shot-pkg-a/b)。 +- 证据:relay 日志四条在线直投;`signature_verified: true`;截屏显示绿连接点、节点号、双向气泡、"✓ 已送达·已验签"。 + +### Tauri 壳 ⚠️ 部分 PASS(未闭合) +- cargo 编译通过(Tauri v2 + Rust 1.96)。 +- 双实例接入会合点成功(relay 日志:TAURI-A / TAURI-B 接入)。 +- **未闭合点**:后端 emit 的事件能到前端,但前端 `invoke('bridge_send')` 没有触发发送——应用命令的 ACL 权限未被 tauri-build 收录进 acl-manifests.json(manifest 只有 core 系列,`allow-bridge-send` 不存在,引用即编译报错)。见未决问题 U1。 +- 未打包 .app(bundle.active=false,验证未通过前不做)。 + +## 四、踩坑因果链(现象 → 原因 → 处置) + +1. **parseArgs 吞开关**:`--stdio` 无值开关被旧配对逻辑吃掉后续 `--id` → 改为逐个扫描,值以 `--` 开头则视为布尔开关。 +2. **stdio 模式 stdin EOF 即退出**:后台测试时 stdin=/dev/null,节点刚连上就退出,relay 侧表现为"刚接入就离线" → 结论:stdio 子进程要求宿主保持 stdin 管道打开(Electron/Tauri spawn 默认满足);测试用 `(sleep N) | node ...` 保持。 +3. **connected 事件早于渲染进程就绪**:截屏显示"接入中…红点"但回执事件已到 → 原因:子进程启动快于 webContents 加载,早到事件被丢 → 处置:main 进程加事件缓冲队列,did-finish-load 后补发。 +4. **Electron 沙箱内 SIGSEGV**:同代码上轮能跑本轮段错误,伴随 `nice(5) failed` → 沙箱策略变化所致 → `--no-sandbox --disable-gpu` 规避。 +5. **npm 缓存权限**:沙箱禁写 `~/.npm` → `--cache /tmp/npm-cache`。 +6. **Electron 二进制下载失败**:postinstall 从 GitHub 拉二进制被断 → 换 npmmirror(ELECTRON_MIRROR)+ `ELECTRON_CACHE=/tmp/electron-cache`。 +7. **electron-builder 打包在沙箱下解包丢二进制**:dist 里 `Contents/MacOS` 为空,rename ENOENT → 放弃 builder,**手工组装 .app**:拷官方 Electron.app → `asar pack --unpack-dir bridge` → 改 Info.plist(CFBundleExecutable/Name/Identifier)→ 改名主二进制 → `codesign --force --deep -s -`。此路线完全可控且可复现。 +8. **外部 node 读不了 asar 内文件**:打包后 spawn 的系统 node 报 MODULE_NOT_FOUND → asar 透明读取只在 Electron 进程内生效 → bridge 脚本 unpack 到 `app.asar.unpacked/`,main.cjs 加路径探测(打包态优先 unpacked,开发态回退本地目录)。 +9. **cargo 写 ~/.cargo 被沙箱拦** → `CARGO_HOME=/tmp/cargo-home`。 +10. **Tauri generate_context 要求 icons/icon.png** → python 纯手写 PNG(光湖青圆形,128px)。 +11. **Rust E0597**:Exit 事件里 `if let Ok(guard) = state.0.lock()` 的临时 MutexGuard 析构顺序晚于 state 绑定 → 块尾加分号提前落临时对象。 +12. **zsh 杂项**:`rm -rf x/*.png` 无匹配报错、`echo ====` 被解析、后台进程 nice 警告——全部改用落文件再查看的方式规避。 + +## 五、未决问题清单 + +- **U1(Tauri ACL,最高优先)**:应用命令 `bridge_send` 的 allow 权限未进 acl-manifests.json。疑点:tauri-build 收集应用命令权限的机制与本工程 [lib] 双 crate 结构(main.rs 调 app_lib::run)的交互;下次优先试 a) 把 run() 逻辑并回 main.rs 单 crate 重建看 manifest 是否收录;b) 查 tauri 官方脚手架的 capabilities 生成差异。 +- **U2**:Tauri 壳 UI 渲染取证缺(无截屏钩子),可在 lib.rs 加 webview.screenshot 或走系统 screencapture。 +- **U3**:GHB_AUTOSEND / GHB_SHOT 是开发自检钩子,正式交付前决定保留(运维有用)或摘除。 +- **U4**:桥协议层未竟项(承 DEV-001):TLS、多会合点、BS-TCS 准入门禁对接、群聊/人格体协作信封。 +- **U5**:待冰朔裁定——聊天工具源码是否推 REPO-014 走正典登记;真实跨机会合点落哪台节点。 +- **U6**:本仓库工作区存在 1027 个 0-insertion/0-deletion 的 ExFAT 元数据"假改动"(stat 差异),未处理,不属本次交付范围,仅报告。 + +## 六、资产清单与复现 + +- 源码归档:`/Volumes/JZAO/HoloLake/development/guanghu-bridge-DEV-20260812-001/` + - `bridge-node.mjs`(新增 --stdio 模式与事件缓冲无关,纯运行时) + - `chat/`(chat.html/css/js + adapter.js 四件共用前端) + - `chat/electron/`(main.cjs + preload.cjs + package.json) + - `chat/tauri/`(Cargo.toml + build.rs + tauri.conf.json + src/ + capabilities/) +- 构建配方(本地盘): + - Electron:`npm i electron --cache /tmp/npm-cache`,`ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/`;打包走手工组装七步(见踩坑 7)。 + - Tauri:`CARGO_HOME=/tmp/cargo-home cargo build`。 +- 运行:先起 `node bridge-node.mjs relay --port
`,壳通过环境变量 `GHB_NODE_ID` / `GHB_RELAY` 接入。 +- 实测证据件:截图 shot-a/b(Electron 开发态)、shot-pkg-a/b(.app 打包态)存 `/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/`(shot-a/b)与本次会话日志。 + +## 七、状态推进 + +- 光湖桥人类产品形态:DESIGN_PROVEN → **ELECTRON_SHELL_PROVEN_LOCAL / TAURI_SHELL_PARTIAL(ACL 未闭合)** +- 认知基线 025 的 realtime_transport_state 维持 `REFERENCE_IMPLEMENTATION_PROVEN_LOCAL`,待 Tauri 闭合后可加注双壳验证。