Files
Haocode/docs/agent-handoff/PLATFORM_PLAN.md
T
sorrow404null bc0b92bcdc docs: add agent handoff docs, verification guide, and repair evidence
Add docs/agent-handoff (backlog, execution state, verification, platform plan, per-task evidence), repo AGENTS.md, and architecture notes updated for the dual-renderer design.
2026-09-17 16:40:06 +08:00

12 KiB
Raw Blame History

Windows / Linux 源码运行契约

触发条件:修改启动、浏览器、shell、进程取消、系统热键、截图、路径、依赖或平台测试前读取。本文定义目标行为,不代表这些能力已经实现。只有完成本文验收矩阵后,才能把对应环境标为“已验证”。

支持矩阵

环境 Python 浏览器后端 系统集成 状态定义
Windows x64 现有 Python 3.10 基线 WebView2 首选;失败或 profile 被占用时回落 QtWebEngine 现有 Windows 原生全局热键和截图 必须保持现有产品行为
Ubuntu 22.04/24.04 x64 + X11 Python 3.103.12 仅 QtWebEngine X11 原生全局热键;现有截图交互的 X11 实现 本阶段 Linux 主支持目标
Ubuntu 22.04/24.04 x64 + Wayland Python 3.103.12 仅 QtWebEngine xdg-desktop-portal 全局快捷键/截图能力 portal 缺失或桌面不支持时明确报错
QT_QPA_PLATFORM=offscreen 同对应系统 QtWebEngine 测试路径;Windows 跳过 WebView2 不验证真实全局热键和桌面截图 只用于自动化测试,不算桌面支持证据

其他 Linux 发行版可以尝试源码运行,但必须标记“未验证”。Linux 不引入 WebKitGTK、WebKitGTK 的 Qt 包装层或第二套网页 UI。

平台选择原则

平台能力通过小型适配器隔离,不建立通用插件框架,也不移动现有模块。适配器至少覆盖以下三类能力:

  • 浏览器选择:Windows 尝试 WebView2 后回落 QtWebEngine;非 Windows 直接进入 QtWebEngine。
  • shell 生命周期:生成固定 shell argv、设置进程组选项、取消和超时时终止完整命令树。
  • 桌面集成:注册/注销 Alt+S,启动截图并以现有 Qt 信号返回结果或错误。

Windows 专用模块和 Linux 专用模块只在平台选择完成后延迟导入。Linux 启动链不得先访问 ctypes.WinDLL、Windows HWND、taskkill 或 WebView2 DLLWindows 启动链不得依赖 DBus、portal 或 X11 包。

浏览器后端

Windows

  1. 保持 WebView2 为首选,初始化失败时显示可诊断日志并回落 QtWebEngine,主窗口仍可使用。
  2. 保持现有实例锁语义。同一 WebView2 profile 已由另一个实例使用时,新实例回落 QtWebEngine,不与其争用 profile,也不结束对方进程。
  3. WebView2 原生子窗口继续使用现有包装层;修复弹层时只调整已确认的遮挡案例。
  4. 强制 QtWebEngine 回落必须有测试入口,以便在 Windows 上验证两条渲染路径。

Linux 与 QtWebEngine 回落

  1. 非 Windows 平台不探测、不导入、不加载 WebView2。
  2. 每个 QtWebEngine 应用实例使用独立 profile/storage 目录,避免多个 Chromium 实例争用同一 profile。源码阶段目录仍位于项目 data/ 范围;自动化测试使用临时目录。
  3. 保持离线加载 ui/web/ 资源;路径拼接必须兼容大小写敏感文件系统。
  4. QtWebEngine 必须在 QApplication 创建前完成项目所需的导入和 Chromium 环境设置。
  5. 保留现有软件渲染/GPU 配置入口。无效可选配置应输出明确警告并回落可启动默认值,不能让源码运行因可选渲染配置直接失败。

Linux 源码运行(最小步骤,Ubuntu 22.04/24.04 x64):

# 1) 依赖(pythonnet/clr_loader 带 sys_platform == "win32" markerLinux 自动跳过)
python3.10 -m venv .venv && . .venv/bin/activate
pip install -r requirements.txt
sudo apt install -y libnss3 libxkbcommon0 libfontconfig1 libdbus-1-3 libgl1 libegl1 libasound2t64
#    22.04 无 t64 后缀,用 libasound2

# 2) 运行(普通用户;只走 QtWebEngine;每实例独立 profiledata/webengine/profile_<pid>_*
python3.10 main.py

# 3) 仅当 root/容器启动且页面空白时,才显式禁用沙箱(启动会打印高可见风险警告):
QTWEBENGINE_CHROMIUM_FLAGS="--no-sandbox" python3.10 main.py

# 4) 离屏自动化测试:
QT_QPA_PLATFORM=offscreen HAOCODE_RENDER=software QTWEBENGINE_CHROMIUM_FLAGS=--disable-gpu \
  python3.10 tests/smoke_offscreen.py

实现锚点:core/renderer_backend.py(后端解析 / profile 目录 / sandbox 标志处理);main.py 在导入 PyQt6 前调用 sanitize_chromium_flagsui/views/main_window.pysys.platform == "win32" 门控 core.webview2 导入(非 Windows 永不导入,不触达 pythonnet/Win32/WebView2 DLL/taskkill);CustomWebPage(profile, parent) 接收本实例独立 QWebEngineProfile

Chromium sandbox

Chromium sandbox 与 agent 命令权限是两件事。默认保留 Chromium sandbox,项目代码不得普遍追加 --no-sandbox。仅当运行者明确为 root/容器场景配置现有 QTWEBENGINE_CHROMIUM_FLAGS,且启动代码确认处于该场景时才接受该标志,同时输出高可见警告。普通 Windows/Linux 桌面运行不得关闭 sandbox。

Shell 和进程生命周期

“bash 工具”保留产品名称,但执行契约按平台固定:

平台 argv Popen 要求 取消/超时
Windows cmd.exe /d /s /c <command> shell=False;保持现有流式 stdout/stderr 终止该命令的完整 Windows 进程树
Linux /bin/bash -lc <command> shell=Falsestart_new_session=True;保持流式 stdout/stderr 向进程组发 SIGTERM,短暂宽限后仍存活则发 SIGKILL

实现必须满足:

  • 取消、超时、窗口退出三条路径复用同一个幂等终止函数。
  • Linux 以 os.getpgid(proc.pid) 定位本次命令进程组,不按进程名杀进程,也不遗留孙进程。
  • 正常退出不进入强杀路径;进程已经结束时重复取消不抛出用户可见异常。
  • cwd、环境变量、编码和分块输出保持现有工具语义。命令字符串不在 Python 中按 ;&& 或管道自行拆分。
  • 平台 shell 名称进入诊断日志,避免把 Linux /bin/sh 误报成 bash。

系统提示词

只维护根目录一份 SYSTEM_PROMPT.md。每次请求继续重新读取公共正文,再由运行时生成一段短的平台信息并插入请求,不创建 Windows/Linux 两份完整提示词。

运行时段至少声明:

  • 当前操作系统和 shellWindows cmd.exe 或 Linux /bin/bash -lc
  • 路径格式和路径分隔符;Linux 文件名大小写敏感。
  • 对应 shell 的环境变量、命令连接和引号规则。
  • agent 没有额外 shell 沙盒或命令审批层,不要虚构这些能力。

平台段是请求构造的一部分,不写入会话历史,不参与压缩持久化。契约测试应验证公共提示词只有一份,且不同平台只改变运行时段。

配置和路径

  1. 所有配置读取入口统一尊重 HAOCODE_CONFIG_FILE;测试在导入 UI/LLM 模块前把它指向临时文件。真实凭据文件按 README.md 的边界处理。
  2. 所有自动化测试同时把默认数据库改到临时目录,不能依赖开发机已有数据库或附件。
  3. 源码运行阶段继续使用项目内 data/。AppData、XDG Base Directory、安装器写入权限和配置迁移全部留到打包阶段。
  4. 使用 pathlibos.path 组合路径,不拼接平台分隔符;资源存在性检查覆盖 Linux 大小写差异。
  5. WebView2 DLL、Windows 锁文件和 Windows 进程命令不成为 Linux 配置校验项。Linux portal/X11 依赖缺失也不能阻止不相关的聊天和 shell 功能启动。

Linux 桌面集成

X11

  • 为现有 Alt+S 截图快捷键实现 X11 原生注册/注销,保持 GlobalHotkeyThread 对上层的信号语义。
  • 注册失败时返回具体原因并保留窗口内截图按钮或应用内快捷键;不得后台忙等键盘状态。
  • 屏幕像素获取走 X11 可用的原生抓屏路径;区域选择 UI 可以继续使用 Qt。
  • 截图继续提供现有 QImage 返回语义,覆盖多显示器和负坐标桌面布局。

Wayland

  • 使用 xdg-desktop-portal 提供的桌面协议请求全局快捷键和截图,不使用 X11 API 假装支持 Wayland。
  • portal 请求必须异步处理授权、拒绝、取消和桌面不支持四种结果;UI 只禁用受影响能力,主程序继续运行。
  • 无法提供全局快捷键时给出明确、可操作的错误,不能静默降级成“看似注册成功”。窗口内按钮/快捷键仍按桌面允许范围工作。
  • portal 返回的截图 URI/数据先完成有效性检查,再转换为现有 QImage/附件流程;临时文件生命周期由适配器负责。

会话类型优先综合 Qt 平台名和 XDG_SESSION_TYPE 判断,并记录最终选择。环境变量与实际 Qt 后端矛盾时,选择可证明可用的后端并输出警告。

实现状态(P1-042026-07-17,证据 evidence/P1-04.mdui/views/system_tools/desktop_session.py 按上文判定顺序实现 session_kind()offscreen→unknownQT_QPA_PLATFORM/WAYLAND_DISPLAY/XDG_SESSION_TYPE 综合);X11 热键 = x11_hotkey.pyctypes→libX11 XGrabKey,同 triggered 信号语义,失败明确日志);Wayland 截图 = portal_capture.pyxdg-desktop-portal Screenshot,系统 gdbus CLI,异步 worker,授权/拒绝/不支持/超时四态明确)。Wayland 全局快捷键依赖 compositor 桌面协议(ext-global-shortcut 等),本版本无免依赖实现 → 按上文“无法提供全局快捷键时给出明确、可操作的错误”处理(日志明确说明 + 保留应用内 Alt+S/按钮),不静默降级。真机验证待 Ubuntu 22.04/24.04 X11/Wayland 会话。

依赖范围

  • requirements.txt 只加入源码确实导入的 Python 包,并使用平台 marker 隔离 Windows/Linux 专用依赖。
  • Ubuntu 所需系统包另写安装说明,不把 apt 包名伪装成 pip 依赖。
  • 不增加 WebKitGTK、打包器、安装器或与现有功能无关的桌面框架。
  • 可选平台能力缺失时要局部报错;聊天、会话和 shell 的基本源码运行仍应可达。

验收矩阵

每行都要留下命令输出、日志或截图证据;人工桌面项不能用 offscreen 结果替代。具体测试分层见 VERIFICATION.md

环境 必验操作 通过标准 证据
Windows / WebView2 启动、流式聊天、弹层、截图、退出 选择 WebView2;弹层无已确认遮挡;退出不影响其他实例 后端日志 + 桌面截图
Windows / 强制 QtWebEngine 同一基本流程 不加载 WebView2;UI 和消息协议行为一致 后端日志 + 定向测试
Windows / 第二实例 首实例占用 WebView2 profile 后启动第二实例 第二实例回落 QtWebEngine;首实例继续工作 双实例日志
Ubuntu 22.04 X11 启动、聊天、Alt+S、区域截图、shell 只使用 QtWebEngine;热键与截图成功;shell 为 bash 日志 + 截图 + shell 测试
Ubuntu 24.04 X11 同上 与 22.04 相同 日志 + 截图 + shell 测试
Ubuntu 22.04/24.04 Wayland portal 授权、拒绝、取消;截图和快捷键 授权路径可用;其余路径明确报错且主程序不退出 portal 日志 + 桌面截图
Linux 进程生命周期 命令创建子进程后取消和超时 父、子、孙进程全部退出;无同名进程误杀 PID/进程组测试记录
Windows 进程生命周期 命令创建子进程后取消和超时 本次命令树全部退出;其他进程不受影响 PID 测试记录
Windows/Linux 提示词 捕获请求构造结果 公共正文一致;shell/路径段与平台匹配;平台段不入历史 契约测试
Windows/Linux 临时配置 使用临时配置和数据库运行 GUI smoke 不访问项目真实配置/数据库;运行结束无生产数据变更 隔离断言
Windows/Linux offscreen 运行自动化 smoke 可重复通过;明确不声称验证系统热键/截图 测试汇总
root/容器 分别在未显式配置和显式配置下启动 默认保持 sandbox;显式 --no-sandbox 时打印警告 启动日志

平台任务完成条件:矩阵中该阶段承诺的每一行都有证据;自动化定向测试和阶段全量测试均通过;Linux 启动链没有 Windows 专用导入;实现没有引入 WebKitGTK、打包工作、通用钩子框架或新的 agent 权限模型。