Skip to content

Claude/debug acecode crash xn wgr - #11

Merged
shaohaozhi286 merged 7 commits into
masterfrom
claude/debug-acecode-crash-XNWgr
May 11, 2026
Merged

Claude/debug acecode crash xn wgr#11
shaohaozhi286 merged 7 commits into
masterfrom
claude/debug-acecode-crash-XNWgr

Conversation

@shaohaozhi286

Copy link
Copy Markdown
Collaborator

No description provided.

claude added 6 commits May 11, 2026 11:58
…ssing

很多企业 / 信创环境的机器只装了 Microsoft Edge 浏览器,而没有单独安装
"Microsoft Edge WebView2 Runtime"。现状下 acecode-desktop 走 WebView2Loader
默认 Runtime 发现路径直接抛 webview::exception,被 wWinMain 一路裸抛触发
Windows "未经处理的异常" 调试器对话框 — 普通用户既看不懂也无从下手。

WebView2Loader 公开了 WEBVIEW2_BROWSER_EXECUTABLE_FOLDER 环境变量(等价于
CreateCoreWebView2EnvironmentWithOptions 的 browserExecutableFolder 参数),
而 Edge 100+ 浏览器目录里都自带同版本的 msedgewebview2.exe,可以直接复用
避免分发 ~180MB 的 Fixed Version Runtime。

新增 src/desktop/webview2_runtime_probe.{hpp,cpp},暴露纯函数
find_edge_browser_folder_in(roots) + Win32 系统调用版
find_edge_browser_folder()。Impl ctor 被改成三段式:默认 Loader → Edge
浏览器目录 fallback → 终态 MessageBox + ExitProcess(1)。wWinMain 同时包顶层
try/catch 兜底任何其他启动期异常,避免再有"无声秒退"。

测试覆盖纯函数版本(版本号字典序陷阱、缺 exe 跳过、跨 root global latest 等)。
Step 1 of the desktop -> daemon migration. 让 webview JS bridge 不再独占
workspace rename / remove —— 浏览器降级模式以及未来"webview 不可用时 ShellExec
默认浏览器跑 daemon URL"的路径下,前端也能通过纯 HTTP 完成 workspace CRUD。

- OPTIONS /api/workspaces/<hash>:CORS preflight
- PATCH  /api/workspaces/<hash>  body {"name": "<新名>"} → 200 workspace JSON
  · workspace_registry 未挂载 → 503
  · 缺 name / 空 name / 非法 JSON → 400
  · 未知 hash → 404
- DELETE /api/workspaces/<hash> → 204 No Content (registry.hide,desktop_visible
  写 false,不删 hash 目录 / session / 用户文件)

实现复用 WorkspaceRegistry::set_name / hide,语义跟原 desktop aceDesktop_*
bridge 完全一致。下一步 (P2) 加 native 操作下沉端点。
Step 2 of the desktop -> daemon migration.

把 webview JS bridge 里两个"必须 native"动作下沉到 daemon:
  - aceDesktop_openInExplorer  → POST /api/system/open-in-explorer
  - aceDesktop_addWorkspace 的 folder picker → POST /api/system/pick-folder

daemon 跟前端 (webview 或浏览器) 跑在同一台机器、同一 session、同一用户
权限,完全可以代执行 ShellExecuteW / IFileOpenDialog。这样浏览器降级模式
(WebView2 不可用时直接 ShellExec 系统默认浏览器跑 daemon URL) 下,前端
所有 UI 路径都不依赖 webview-specific JS bridge,行为跟 webview 模式一致。

POST /api/system/open-in-explorer body {"path": "<abs>"}
  · 复用 desktop::open_directory_in_file_manager,白名单 = workspace
    registry 里所有 cwd → 浏览器中恶意页面不能让 daemon 打开 System32
  · 错误码 400 / 403 / 404 / 500,跟 launcher 错误字符串映射
  · launcher 是 ShellExecuteW (Win) / open (mac) / xdg-open (Linux)

POST /api/system/pick-folder
  · 复用 desktop::pick_folder(nullptr),Windows 走 IFileOpenDialog
    (自管 CoInitializeEx),POSIX MVP 阶段返 nullopt
  · 同步阻塞;Crow thread pool 阻塞一个 handler 线程不影响其它请求
  · 选定 → 200 {ok,path};取消 / 平台不支持 → 200 {ok:false,canceled:true}

测试:open-in-explorer 三条入参校验(白名单 / 缺 path / 不存在) + POSIX
环境下 pick-folder stub 行为。真"打开 Explorer / 弹文件夹选择"的端到端
路径在 headless CI 跑不动,留作手动 e2e。
…emon HTTP (P3)

Step 3 of the desktop -> daemon migration. P1/P2 把业务接口落到 daemon HTTP,
P3 让前端真正调它们,WebView2 不可用的浏览器降级模式下也能完整跑 workspace
管理与"在资源管理器中打开"功能。

lib/api.js 新增 4 个客户端方法,对应 P1/P2 的新 daemon route:
  - renameWorkspace(hash, name)  → PATCH  /api/workspaces/:hash
  - removeWorkspace(hash)        → DELETE /api/workspaces/:hash
  - openInExplorer(path)         → POST   /api/system/open-in-explorer
  - pickFolder()                 → POST   /api/system/pick-folder

components/Sidebar.jsx 三个 handler 改 HTTP-first:
  - onRename:走 api.renameWorkspace,bridge 退化为 fire-and-forget 副作用
  - removeWorkspace:走 api.removeWorkspace;前端按"删完取首项当 active"
    替代原 bridge 返的 active_workspace_hash hint
  - onAddWorkspace:抽 pickWorkspaceCwd() — webview 模式优先调 bridge(原行
    为不变);浏览器降级模式走 api.pickFolder() 让 daemon 弹 native 文件夹
    对话框,再调 api.registerWorkspace 入册。File System Access API 的
    handle 拿不到绝对路径,不接它,以免 daemon 端 register 时缺 cwd
  - 列表的 "remove" 按钮可见性不再依赖 bridge,永远显示(daemon HTTP 已覆盖)

components/DesktopContextMenu.jsx:
  - openTargetInExplorer 改走 api.openInExplorer,不再 require
    window.aceDesktop_openInExplorer
  - isDesktopShell() 把 loopback host 也认作 capable —— 浏览器从 daemon
    URL 访问时,右键菜单依然可用(复制/粘贴/在资源管理器中打开等都通)

webview 模式下旧 bridge 仍可触达但已不承担业务通路;P4 的浏览器降级流程
打通后再考虑 P5 清理 desktop 进程里的冗余 bridge 实现。
…able (P4)

Step 4 of the desktop -> daemon migration. WebView2 在企业 / 信创机器(Edge
>=126 不允许借浏览器二进制 + 没装独立 Evergreen Runtime)上必然失败 — 现在
不再走"弹错误 MessageBox 后退出"的死胡同,改成询问用户是否在系统默认浏览器
中继续。P1-P3 已经把业务逻辑全下沉到 daemon HTTP,前端在浏览器里跑功能完整。

src/desktop/web_host.cpp:
  · WebHost::Impl::Impl 第一段 (默认 Loader + offscreen→nullptr) 失败 + 第
    二段 (Edge browser folder fallback) 也失败时,不再 show 自己的 MessageBox
    + ExitProcess(1) — 改成 rethrow,由 wWinMain 上层接管。
  · 删 anonymous-namespace 的 show_webview2_failure_message_box helper。

src/desktop/main.cpp::wWinMain:
  · 在 WebHost host(...) 构造点开 try 块,catch (...) 内进入"浏览器降级"流程
    (用 catch(...) 兜底因为 webview::exception 是否派生自 std::exception 取决
    于 webview/webview 版本,内部用 throw; + catch (std::exception&) 抽 what())
  · 询问用户 (MessageBoxW MB_YESNO + 中文文案 + 排查信息):
      - No  → pool.stop_all() + return 1
      - Yes → ShellExecuteW(url) 调起系统默认浏览器,desktop 进程保持运行
              (daemon 被 Job Object KILL_ON_JOB_CLOSE 绑生死,desktop 不在
              daemon 跟着死) → 空 Windows message loop 等系统/任务管理器
              结束,Windows session logoff 时 WM_QUIT 自然退出 loop。
  · ShellExecuteW 失败时弹文案让用户手动拷贝 URL,desktop 仍挂着。
  · URL 在 onboarding daemon 未起来时仍是 about:blank,降级也跑不通,弹错
    退出避免误以为浏览器是空白页。
  · POSIX 路径 webview 异常 rethrow 给顶层 catch,POSIX 不构造浏览器降级
    (那里走 WKWebView / WebKitGTK,跟 WebView2 路径不重叠)。

后续(P5 / future)托盘"退出"菜单让用户不必开任务管理器结束 desktop;以及
清理 desktop 进程里的冗余 workspace bridge(已被 HTTP 全覆盖)。
P4 在 WebView2 失败时弹了一个 YesNo 询问"是否用浏览器继续",然后 ShellExecuteW
默认浏览器。两个体验问题:
  (a) 多一步打扰用户;现在 P1-P3 已把业务全下沉到 daemon HTTP,降级路径本就
      跟原 webview UI 等价,没必要让用户选
  (b) 默认浏览器开普通 tab,带地址栏 / 标签栏 / 书签栏,不像独立 native app

P5 改成静默直进 + 优先 Chromium 系浏览器的 `--app=<url>` 模式启动,Chromium 的
app 模式渲染无地址栏单窗口、独立 taskbar 图标,体感最接近原生 webview。同时
给降级流程加最小托盘(图标 + "重新打开窗口" + "退出"菜单),让用户不必任务
管理器结束 desktop 进程(daemon 由 Job Object KILL_ON_JOB_CLOSE 绑生死)。

新文件 src/desktop/chromium_app_launcher.{hpp,cpp}:
  - find_chromium_app_browser_in(roots): 纯函数,按 (Edge > Chrome) 优先级
    跨 root 扫 <root>/<vendor>/<product>/Application/<exe>。Edge 优先因为
    同事场景里 Edge 几乎必装,且 UI 跟 native app 体感最接近。
  - find_chromium_app_browser(): SHGetKnownFolderPath PF + PFx86 调上面纯函数
  - launch_chromium_app_mode(exe, url): CreateProcessW 起 `<exe> --app="<url>"`,
    detached(不进 desktop Job Object,但浏览器是用户进程,desktop 退出
    Job 关 daemon kill 后浏览器 page 加载失败也是预期)。
  二线 Chromium(360 / QQ / Brave / Vivaldi)有的不兼容 --app= 或参数改名,
  贸然走会出现"浏览器开了但啥也没显示"的诡异体验,本期不试,留给
  ShellExecuteW 兜底默认浏览器。

main.cpp 浏览器降级流程改写:
  - 去掉 MessageBoxW MB_YESNO 询问,catch (...) 内直接进降级
  - daemon URL 未就绪(onboarding 占位)仍弹错退出 — 否则会开空白窗口
  - open_app_window lambda:Chromium 系优先 --app=,失败 fallback
    ShellExecuteW;两条都失败时弹文案让用户手动拷贝 URL,desktop 仍挂着
  - init_tray_icon 在 catch 内独立注册一份(正常路径的 line 525 没机会
    执行 — 异常发生在 host ctor 上面),on_show 重开 app 窗口,
    on_quit -> PostQuitMessage(0) 退 message loop
  - 退出走 shutdown_tray_icon + pool.stop_all

tests/desktop/chromium_app_launcher_test.cpp 覆盖纯函数:
  - 空 roots / 无浏览器 root → nullopt
  - Edge / Chrome 各自命中
  - 同 root 双装 → Edge 优先
  - 跨 root → Edge 仍优先于 Chrome
  - 空字符串 root 跳过
  - 路径是目录而非文件 → 不算命中
@shaohaozhi286

Copy link
Copy Markdown
Collaborator Author

@copilot resolve the merge conflicts in this pull request

Co-authored-by: shaohaozhi286 <267735072+shaohaozhi286@users.noreply.github.com>

Copilot AI commented May 11, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Confirmed resolved in b07ad2d. I fetched the latest origin/master, verified this branch is already up to date with it, and confirmed there are no unresolved merge conflicts. No UI changes were made, so no screenshot is applicable.

@shaohaozhi286
shaohaozhi286 merged commit 4d4d621 into master May 11, 2026
1 check failed
Copilot stopped work on behalf of shaohaozhi286 due to an error May 11, 2026 16:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants