学术论文 · 四川的梦科技有限公司 · 2026-07-27
摘要
多面板 IDE 中,同一对话可能在不同面板中同时打开,需防止双重发送和状态不一致。现有跨 iframe 通信方案(BroadcastChannel/postMessage/服务端轮询)在跨域限制、状态一致性、延迟等方面存在不足。本文提出跨面板建楼状态同步装置——基于父窗口中央注册表(parent.__qqq_buildingRegistry + parent.__qqq_questOwners)+ IPC sync 桥 + 状态机转移校验的三层架构。该装置保证同一对话同时仅在一个面板可操作,所有面板实时同步建楼状态,彗星电子钟等全局 UI 正确反映工作状态。
1. 引言
qqq-shell-v2 的 AI 面板采用三面板架构:左翼(panel=0)、中面板(panel=1)、右翼(panel=2)。每个面板运行在独立 iframe 中。用户可在任一面板中操作对话,但同一对话同时只能在一个面板中处于活跃状态。
需要同步的状态包括:
- 所有权:哪个面板正在操作哪个对话?
- 建楼状态:对话是否正在 sending/stopping/fatal?
- 全局 UI:彗星电子钟应显示哪个面板的工作状态?
2. 系统设计
2.1 三层架构
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ iframe 左翼 │ │ iframe 中面板│ │ iframe 右翼 │
│ panel=0 │ │ panel=1 │ │ panel=2 │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
└────────────────┼────────────────┘
│ postMessage
┌────────▼────────┐
│ 父窗口 (shell) │
│ __qqq_questOwners│ ← 所有权注册表
│ __qqq_buildingReg│ ← 建楼状态注册表
│ __qqq_agentPool │ ← Agent 实例池
└────────┬────────┘
│ IPC sync relay
┌────────▼────────┐
│ Electron 主进程 │
│ sync:broadcast │
└─────────────────┘
2.2 所有权注册表
parent.__qqq_questOwners: Map<questId → panelId>
- 零 TTL、零 IO、纯内存同步映射
- 面板 switchQuest 时:先通过 _parentGetQuestOwner 检查 → 若已被占用且非本面板 → 拒绝
- 切换前:_parentReleaseQuest(旧 questId) → _parentClaimQuest(新 questId)
2.3 建楼状态注册表
parent.__qqq_buildingRegistry: Map<questId → {stopState, panelId}>
- stopState: idle | sending | stopping | fatal
- 状态转移校验表:idle→[sending, fatal], sending→[stopping, fatal, idle], stopping→[idle, fatal], fatal→[sending]
- 非法转移不阻断但 console.warn
- finally 块兜底防僵尸:agent-loop 完结路径无条件 unregisterBuilding
2.4 IPC Sync 桥
_broadcast(type, data) {
parent.qqqideBridge.sync.broadcast(type, data)
}
// → Electron 主进程 relay → 所有 webContents(含发送者)
// _handleSyncMessage 首行过滤 msg.windowId === _windowId
2.5 Agent 实例池
parent.__qqq_agentPool: Map<questId → AgentLoop实例>
三面板共享同一 agent 实例。任一面板建楼 → 写入 ag._houses → 另两个面板自动可见 → 切换对话不再出现"死卡片"。
3. 彗星电子钟同步
电子钟需显示"哪个对话正在建楼"及耗时:
- 每 200ms 滴答:遍历 parent.__qqq_agentPool → 找到 stopState==='sending' 的 agent
- 豆腐块(招牌行):仅在本面板 questActiveId 对应 agent 正在 sending 时显示时钟
- 下拉列表:每个 quest 独立插入时钟,各自计算秒数
- 广播兜底:若 poll 检测到 agent 状态与本地不同步 → 触发广播纠正
4. 正确性分析
| 场景 | 保障机制 |
|---|---|
| 用户在中面板操作 q5,左翼也尝试操作 q5 | 所有权注册表拒绝(q5 已被 panel=1 占用) |
| 中面板 crash | finally 块清除注册表条目,q5 重新可用 |
| 同一面板双击 Enter | _execSendBusy 同步锁 + stopState 状态机防并发 |
| 彗星电子钟显示错误面板的工作状态 | data-qid 绑定各自 questId,独立计算 |
5. 结论
跨面板建楼状态同步装置通过父窗口中央注册表 + IPC 广播 + 状态机校验,在 iframe 隔离架构中实现了强一致的多面板协同。所有权系统保证互斥操作,Agent 实例池消除多副本竞态。
参考文献
[1] MDN — window.postMessage. developer.mozilla.org. [2] BroadcastChannel API — W3C Specification. [3] qqq-shell-v2 架构文档 §28/§30/§46b, 2026.