Skip to content

BetterGI:托管安装中断后提供人工确认恢复(旧方案) - #1900

Closed
youngslin wants to merge 20 commits into
AUTO-MAS-Project:devfrom
youngslin:fix/bettergi-install-recovery-prompt
Closed

youngslin wants to merge 20 commits into
AUTO-MAS-Project:devfrom
youngslin:fix/bettergi-install-recovery-prompt

Conversation

@youngslin

Copy link
Copy Markdown

问题

BetterGI 新正式版发布后官方安装器可能因资源还未就绪而失败;MAS 在安装前写入 bgi-install.json,失败后保留标记是必要保护,但用户后来通过官方安装器修复并关闭更新托管后,MAS 仍在 AutoProxy / ScriptConfig 阻断启动,没有可执行的恢复选择。

Fixes #1899

改动

  • 在 BetterGI 的 AutoProxy、ScriptConfig(设置/查看)与 Update 启动入口统一检测上轮未确认安装,发起一次性 WS 恢复询问。主界面可选择「重试安装」「跳过并继续」「取消本次任务」。
  • 关闭自动更新的情况下,如果用户主动选择重试,仅对本次恢复执行官方更新器;选择跳过时不额外启动自动更新。
  • 跳过需要单独确认风险,并在后端复核原标记未被替换、BetterGI.exe 版本及架构、官方安装器/BetterGI 进程已退出,才移除标记。重试失败继续保留标记;不触发旧版静默回退。
  • 识别从安装目录之外启动的 BetterGI 官方安装器;WebSocket 无界面、超时、任务取消、标记变化都 fail closed。
  • 前端独立常驻订阅及全局弹窗(三语言);更新记录增加当前/目标版本、通道、来源及安装确认日志,不输出 CDK 或鉴权下载地址。
  • 加入跳过、重试、关闭更新、版本损坏、标记更换、独立安装器和 WS 响应相关回归测试。

行为边界

  • 弹窗最多等待 120 秒,未获得明确决定即停止本次任务并保留标记;不自动认可跳过。
  • 跳过后的可执行文件检查无法保证所有依赖均完好;必须由用户确认手动修复或正常运行及风险。
  • 本 PR 仅处理 BetterGI,不改动 BAAH、SRC、奇想盒及 MaaEnd 的事务恢复语义。其他脚本按后续独立 PR 逐项处理。

测试

  • 已补充 tests/task/test_bettergi_program_update.py 回归用例。
  • CI 检查结果以 PR 页面为准;如有失败继续修复。

@github-actions github-actions Bot added 专项: BetterGI 类型: 修复 按更新日志碎片自动设置 labels Nov 10, 2026
@youngslin
youngslin marked this pull request as ready for review November 10, 2026 07:13
Comment on lines +55 to +60
try:
installed = str(await asyncio.to_thread(program_update.read_version, root))
except Exception as error:
# 元数据不可读时仍允许用户选择重试;跳过阶段才严格校验。
logger.warning(f"读取 BetterGI 当前版本失败,恢复提示显示未知:{error}")
installed = "未知"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Retrying an unconfirmed install recovery when BetterGI.exe is missing or corrupt raises unhandled exceptions from read_version and fails repeatedly.
Severity: MEDIUM

Suggested Fix

Add exception handling around read_version and read_pe_architecture within update_before_run, or catch exceptions during the retry branch in _recover_unconfirmed_install and handle corrupted or missing executables gracefully (e.g., treating them as requiring a fresh download rather than crashing).

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: app/task/BetterGI/tools/install_recovery.py#L55-L60

Potential issue: When handling an unconfirmed installation recovery where the executable
is missing or corrupt, `ask_install_recovery` allows the user to choose 'retry' even
when version metadata cannot be read. However, selecting 'retry' invokes
`_run_program_update` and `update_before_run`, which call `read_version` and
`read_pe_architecture` on `BetterGI.exe` without exception handling. In this corrupted
or missing binary state, `win32api.GetFileVersionInfo` raises unhandled exceptions such
as `pywintypes.error` that escape `_recover_unconfirmed_install`. Consequently, the task
terminates abruptly, the installation marker remains uncleared, and subsequent attempts
repeatedly prompt the user with a retry option that cannot succeed.

Also affects:

  • app/task/BetterGI/manager.py:215~221

Did we get this right? 👍 / 👎 to inform future reviews.

Copy link
Copy Markdown
Contributor

总体结论:修改后合并

AUTO-MAS-Project/AUTO-MAS #1900

宝宝,这版把“手工修复后仍被安装记录拦住”的恢复选择接上啦,关闭自动更新也不会直接忽略安装保护。不过重试入口还有一条走不通的路,跳过确认也得先告诉用户正在处理哪份安装。这两处补好再合喵。

BetterGI manager 负责持有安装锁和决定后续任务,恢复模块收集一次选择并检查标记,前端通过常驻 WebSocket 订阅展示全局弹窗。下载与官方安装仍复用原来的更新入口,没有另建安装框架。

[逻辑 · P2] 当前程序损坏时,“重试安装”仍要求先读出它的版本

位置:manager.py:215–219,关联 install_recovery.py:55–60。

静态追踪这个场景:安装中断留下标记,且 BetterGI.exe 的版本资源损坏时,询问阶段会把当前版本显示为“未知”,继续提供“重试安装”。但选择后进入 _run_program_update → update_before_run:294–297,马上再次读取当前程序版本和架构,还没请求安装包就失败了。

这是实际可达的恢复场景:文件仍存在但版本资源损坏时,三个入口都能走到这里;文件完全缺失时,AutoProxy 和 Update 也会先进入恢复流程。结果是任务异常结束、标记保留,用户反复点“重试”仍只能回去手工安装。旧更新器原本要求完整本体,本 PR 新增的“未知版本仍可重试”分支需要单独处理这个前置条件。

建议给显式恢复接入完整安装包修复路径,允许当前本体不可识别,同时保留原有安装锁、进程检查、包校验、安装后版本确认和失败保留标记。普通自动更新的保护不必一起放宽。现有恢复测试把 read_version 固定为成功版本,请补上“版本读取失败 → 用户重试 → 实际进入安装并完成确认”的场景,让这次“重试”真能走到安装器喵。

这项与现有 Sentry 意见重合,dot酱已独立核对入口与失败链,只计同一个问题。

[逻辑 · P2] 全局恢复弹窗没有说明操作的是哪份 BetterGI 安装

位置:恢复提示载荷:82–88、弹窗详情与确认:43–76。

MAS 支持多个 BetterGI 托管和后台定时队列。设 A、B 指向不同安装目录,版本与通道相同:用户正在 A 的设置页,B 的定时任务遇到残留标记,就会弹出这个全局确认。当前弹窗只显示版本、通道和更新开关,没有托管名称或安装位置;隐藏的 taskId 也没有提供可读的对象信息。

用户可能因为 A 已修复而勾选“已修复或确认能正常运行”,实际清除的却是 B 的保护标记。后端检查版本、架构和进程,不能代替用户确认 B 的附属文件已修复;界面也没有自动切到 B 的任务上下文。

请随请求带上当前托管名称及可区分的安装位置,在风险确认前显示。把这次重试、跳过或取消针对谁说清楚,用户的确认才有依据啦;沿现有弹窗补齐信息即可。

dot酱还核对了跳过前后检查、标记变化拒绝、取消时恢复标记、安装器退出等待和原有锁释放链路,未确认其他新增必须修改项。当前提交的 Windows、Ubuntu 全量 pytest、格式检查和 Windows 验证包构建均通过,已读取测试日志;这些是已有 CI 证据,没有覆盖上面的损坏程序恢复及多托管确认场景。本轮为静态源码与调用链审查,未运行项目、测试或真实安装器。

—— dot酱拍拍爪敬上 🐾

Copy link
Copy Markdown
Contributor

总体结论:修改后合并

AUTO-MAS-Project/AUTO-MAS #1900 · 集成状态补充

宝宝,目标分支已合入 #1901,GitHub 现在将本 PR 标为有合并冲突(mergeable=false / dirty)。这次只补充新状态,不把旧问题再算一遍喵。

当前 PR 没有新提交,上一轮两项 P2 仍待处理。解决冲突时,还要把新加入的正式版资源就绪检查 与恢复入口一起保留:资源暂缓不能把未确认安装当成安全旧版放行。

dot酱没有取得解决冲突后的最终代码,也没有运行项目或合并验证;待冲突和上述问题处理后,再核对实际集成结果。

—— dot酱守着合并线敬上 🐾

Copy link
Copy Markdown
Contributor

总体结论:修改后合并

AUTO-MAS-Project/AUTO-MAS #1900 · 修复复审

宝宝,上一轮两处具体问题已经处理:旧程序版本或 PE 信息不可读时,显式重试会带着原安装标记进入完整安装流程;弹窗也显示了托管名称和安装目录。与 #1901 的冲突已解决,正式版资源检查仍在,不能借“暂缓更新”放行未确认安装。这些修复不再重复记账喵。

规范

未确认新增的阻断项。恢复仍复用现有安装锁、下载校验及官方安装器,普通更新没有一起放宽;目标名称和路径只用于当前恢复界面,没有加入遥测。前端沿用 Ant Design Vue 与三语言词条,App.vue 为 256→259 行,新恢复弹窗为 140 行,均符合组件大小规则。

规格

[逻辑 · P2] 主程序文件缺失时,原生配置入口仍到不了恢复询问

位置:新增恢复调用 manager.py:297–298,前置条件见 check():77–82。

安装中断留下 bgi-install.json、原安装目录仍在但 BetterGI.exe 已缺失时,用户点击原生“配置”或“查看”,main_task 会先执行 check()。其中的 is_file() 返回失败,任务在恢复询问前就结束,只提示“请先设置有效的 BetterGI 脚本路径”。前端按钮并不会把这个场景转到重试流程。

这不是说本次新加坏了旧路径检查,而是 PR 承诺的三个恢复入口还少这一段:updater 已能处理显式恢复时的缺失程序,ScriptConfig 却无法进入它。AutoProxy / Update 的恢复可达,不能替代用户当前点击的配置入口。

请在安装目录有效且存在未确认标记时,先走持锁恢复,修复确认后再做启动程序检查;普通无标记的无效路径仍应拒绝。沿现有任务测试补一个“exe 缺失、标记存在 → 配置入口给出恢复选择”的场景即可。当前 missing-executable 用例只证明无显式恢复时拒绝更新,没有覆盖这条入口链,别让入口又躲过回归啦。

验证

dot酱核对了原标记在等待和下载期间被替换时拒绝、同版本带标记仍重装、目标低于记录版本时拒绝、取消保留标记,以及 GitHub 正式版、Mirror、公测版分支与资源检查的组合,未确认其他新增缺陷。

最新提交已修复前一轮缺少 script_info 的测试替身及弹窗格式问题;那条 AttributeError 来自绕过构造函数的测试,不是已确认的生产崩溃。当前格式工作流已通过 Ruff、前端 lint/typecheck/format、56 个测试文件中的 299 项测试及词条检查,Windows 验证包构建也已通过。发布前双平台 pytest 仍在运行,尚不能称为全量 CI 通过。

本轮仅静态源码与既有 CI 日志审查,未运行项目、测试、真实安装器或 Electron 界面;没有声称实际损坏安装、深浅色及窗口操作已经验证。规范轴无新增阻断项,规格轴剩余上述 1 项 P2。

—— dot酱沿着恢复入口复核敬上 🐾

Copy link
Copy Markdown
Contributor

总体结论:修改后合并

AUTO-MAS-Project/AUTO-MAS #1900 · 恢复入口复审

宝宝,缺少 BetterGI.exe 时,ScriptConfig 现在能带着有效安装标记走到恢复询问了;安装锁和恢复后的程序检查也还在,前一轮这项 P2 已修复喵。这次继续核对系统唤醒路径,确认了一个需要补上的弹窗生命周期问题。

规范

[规范 · P2] 主动重连没有清理失效询问,弹窗可能永久卡住

位置:bettergiInstallRecovery.ts L45–68。

这是静态调用链结论:系统恢复时 useAppLifecycle.ts L827 调用 reconnectNow,先置空旧 socket,旧连接的 close/message 回调因此被过滤,不会通知这里订阅的 onDisconnected。

如果询问恰在换连接期间超时或被取消,后端 L122–130 注销处理器后仅发送一次关闭帧,前端可能收不到。重连后旧弹窗仍在,点击任一选择会把 pending 设上,但后端已经不处理这个 requestId。三个按钮无法继续操作,弹窗又禁止关闭,没有后续事件帮用户退出。

请把主动换连接也纳入旧询问的失效清理,或在重连后核对后端仍有效的请求,别只等普通断线通知啦。用“询问已显示 → 主动重连期间丢失关闭帧 → 重连成功”验证旧弹窗不会卡住。这符合 mas-frontend-ui 的 Page States 对重连和超时反馈的要求,无需放宽安装保护。

规格

本轮未确认新的必须修改项。沿真实 main_task 核对了 check → prepare 持安装锁 → 恢复 → confirm_current_install → ScriptConfigTask;无标记、目录或软链接标记仍不能借缺失程序放行,损坏程序也不能直接选择跳过。之前的恢复范围问题这次确实补到了入口,dot酱给这处修复拍拍爪。

验证情况

只做静态审查并读取已有 CI,没有执行项目、安装器或 UI。前一提交的 Windows / Ubuntu pytest 都因新增测试给只读 execution_mode 赋值而失败;最新提交已改为通过 task_info.mode 配置,未改生产逻辑。最新 CI 尚在运行,以完成后的结果为准,不能沿用前一版的绿色状态。

规范轴 1 项 P2,规格轴 0 项确认问题;修好这条重连路径,再确认最新 CI 通过喵。

—— dot酱给失效弹窗找出口敬上 🐾

Copy link
Copy Markdown
Contributor

总体结论:可以合并

AUTO-MAS-Project/AUTO-MAS #1900 · 重连修复复审

宝宝,最后这处失效弹窗也处理好了。新连接建立时会清掉旧询问和 pending,最新两平台 pytest 也已通过,dot酱这轮没有确认的必须修改项喵。

规范

bettergiInstallRecovery.ts L54–59 已增加 onConnected 清理,并在 dispose 成对注销。核对实际连接层后,onopen 会同步执行这些监听,再处理新连接消息;因此主动重连丢失关闭通知后,旧请求不会继续占着弹窗,新请求也仍可操作。前次 P2 撤下。

新增回归调用真实恢复服务,只替换传输边界,覆盖了不触发 disconnected 时清旧询问、拒绝发送失效选择及新询问仍可响应。这次不用为了清理一个弹窗扩大公共连接层的职责啦。

规格

本轮未确认新增问题。此次生产改动只处理询问生命周期,前面已经修好的损坏程序重试、ScriptConfig 入口、安装身份展示,以及持锁和恢复后检查都保留。不会因为重连而自动选择跳过或清除安装标记。

验证情况

读取了当前提交的实际 CI 日志:Windows pytest 1820 通过、2 跳过;Ubuntu 1781 通过、40 跳过。前端 57 个文件、300 项测试通过,包含新增重连用例;格式、类型检查与 Windows 验证包构建通过。之前的只读 execution_mode 测试夹具故障已不再出现。

发布前目标分支刚合入 #1907。已核对其 5 个 Runtime 初始化相关文件,与本次 BetterGI 恢复改动不重叠,未发现新增交互问题;上面的 CI 数字对应本 PR 当前提交的既有验证,不代表刚更新基线后的重新运行。

以上仍是静态审查与已有 CI 核验,未自行运行项目、官方安装器或真实 UI;不把这些单测当成实机安装成功证明。

规范轴 0 项确认问题,规格轴 0 项确认问题。可以合,旧意见这轮都已核对关闭喵。

—— dot酱把恢复分支核清楚敬上 🐾

Copy link
Copy Markdown
Contributor

总体结论:修改后合并

AUTO-MAS-Project/AUTO-MAS #1900 · 配置入口交互补充

宝宝,上一条“可以合并”需要更正:继续沿配置入口核对后,确认恢复询问会被原生配置会话的等待遮罩挡住。之前已修好的重连、损坏程序重试和入口检查没有失效;漏查的是这两个界面同时出现时谁在上面,dot酱补上这条具体问题喵。

[兼容 · P2,阻断] 配置会话先显示遮罩,恢复按钮却在遮罩下面

BetterGIUserEdit:1452调用原生配置会话;useNativeGuiSession:159–171拿到受理返回的 taskId 就立即显示遮罩,接口不等待原生窗口启动。该 GuiSessionMask传送到 body,固定定位、z-index 1000。

如果这份安装存在未确认标记,manager.py:303–308会先等待恢复选择,尚未执行后面的 ScriptConfigTask;新 恢复弹窗:38只有 z-index 900。结果是用户看着“正在配置”的遮罩,却点不到下面的重试、跳过和取消,直到结束会话或恢复等待超时。此前只证明后端能进入询问,还没有证明用户能操作它。

请协调恢复询问与原生会话遮罩的显示时机或层级,让配置入口的恢复选择位于等待遮罩上方,同时保留标题栏操作区。沿真实账号配置入口补一次“受理任务 → 残留安装标记 → 能点恢复按钮”的交互验证即可,不必重做安装器啦。

这是同一代码状态下新增的交互证据,不把旧意见重报一遍。规范侧没有新增问题,规格侧新增上述 1 个必须修复的 P2。当前已有 8 项 CI 仍全部通过,但没有覆盖这条双遮罩路径;dot酱未运行项目或真实 Electron 界面,以上为源码、受理时序及层级规则的静态核对。

—— dot酱把被挡住的按钮找出来敬上 🐾

Copy link
Copy Markdown
Author

由于需求调整为全自动、无弹窗的安装健康检查 + 安装前备份/失败回滚,本 PR 的独立 BetterGI WebSocket 恢复弹窗、手动 retry/skip/stop 协议不再是目标方案,因此按维护者意图关闭,不合并。

后续统一入口见 #1916(公共恢复决策与任务结束汇总),BetterGI 的安装恢复会以单独适配 PR接入公共入口:保留原安装器校验、进程停写保护、缺失/损坏本体识别;安装前保留可回滚旧版,恢复成功并复核后清理备份;纯下载失败且旧版验证完整时仍可继续任务,任务结束后由公共入口统一报告异常。#1900 中可复用的测试边界和实现细节会在适配时参考,但不会把它的前端弹窗合并回来。

注意:#1916 当前还在审查与 CI 阶段,关闭本 PR 不意味着新的恢复功能已上线。

@youngslin youngslin closed this Nov 10, 2026
youngslin added a commit to youngslin/AUTO-MAS that referenced this pull request Nov 10, 2026
youngslin added a commit that referenced this pull request Nov 10, 2026
…ollback snapshots (#1916)

## 背景与取舍

#1900 已关闭且未合并。放弃 BetterGI 单独弹窗 / WS 选择,改为纯后端自动恢复。#1900 中有价值的「识别安装目录之外启动的
BetterGI 官方安装器」进程检查已迁入本 PR;不迁移弹窗与前端组件。

## 公共收束入口与持久备份

- 公共 run_managed_script_install 入口收发检查、安装、回退和恢复结果;专项仅提供 inspect /
acknowledge / install / ensure_idle / after_rollback 适配器。
- script_install_backup
在同磁盘工作区保存原版完整快照、哈希清单与跨任务持久状态;不能覆盖未结算的备份。新安装在确认成功且停写后删除备份。
- 安装器明确失败:确认停写,再回退到经哈希校验的原版;回退并验证成功后可继续任务,但在结束摘要报告该次失败。
-
首次安装超时/状态不明:保留快照并禁止直接覆盖;下轮先做只读健康检查,若完整成功则确认并删除备份,否则重试安装;重试失败/超时,在再次确认完全停写后才允许回滚旧版并继续。
- 恢复时反复下载失败(下载来源与受控错误原因),即使成功回滚旧版继续运行,也会在整轮任务结束时经 ScriptUpdateSession
统一写入后端日志、current.recovery_summary 和 task.notice,专项不再单独弹窗。
- 备份、安装确认、版本及原生事务记录检查出现异常,统一
fail-closed;保留现场,禁止使用半安装版本。安装锁由调用方持有直到事务收束结束。

## 范围和后续

本 PR 提供公共备份/恢复决策能力与 BetterGI
安装器外部进程保护,但**尚未把新的通用事务入口接到每个脚本的真实安装器**。后续需要按脚本的原生
pending、资源布局、数据保护目录、官方安装器停写约束分别接入。不能因为公共测试通过就宣称所有脚本已经自动修复。

历史 UI 尚未消费新 recovery_summary 字段;目前可从任务结束通知和后端日志看到汇总。对外类型生成及历史界面回看需另行完成。

## 测试


新增持久快照、已确认失败回滚、首次超时后下轮重试与清理、下载反复失败最终汇总、安装器仍在写入时拒绝回滚、跨配置恢复、哈希损坏保护、目录交换中断续做和通用报告等回归测试。CI
以最新提交为准;未运行真实游戏或上游官方安装器。
youngslin added a commit that referenced this pull request Nov 10, 2026
…pts (#1905)

## 方向调整:改为 #1916 公共自动恢复

此 PR 原来基于 #1900 的弹窗方案。现已移除奇想盒专有 WebSocket 弹窗、前端常驻订阅和用户选择,改由 #1916
的统一后端入口执行健康性检查、备份、自动重试及可验证回滚。原生 GUI 配置/修复入口仍可打开,但不会因此绕过自动任务的安装保护。

### 具体实现

- 正常更新:只读下载/准备完成后,通过 `run_managed_script_install` 创建旧版快照并运行官方 pip wheel
安装;安装结果由公共层汇总。
- 已有跨任务备份:优先恢复公共事务;下次先检查真实
pip/包入口和版本,确认上次已成功则清理备份,否则重试,只有进程全部停写且原快照通过完整性校验才允许回滚。
- 老版本留下的 `.mas-update-pending`:无可信更新前快照,只能走公共
`auto_recover_script_install` 的健康核验或强制重装,不能虚构可回滚旧版。
- 任务末尾错误汇总交给 #1916;不再使用脚本自带的弹窗服务。
- 保留 `skip_pending_installation` 的依赖完整性检查作为公共 acknowledge 所用的专项安全操作。
- 原前端 modal / websocket / 语言包以及旧弹窗测试已删除,补了公共恢复路径与残留标记回归测试。

### 必须注意的合并顺序

本分支已通过双父提交显式叠加 #1916 的实现,因此合并顺序必须为 **#1916 先进入 dev,本 PR 后合并**。在公共 PR
合并前,这个 PR 的差异会暂时显示公共文件;不能单独将本 PR 作为独立功能合并,也不能因为公共回归测试存在就认定真实 pip
安装端到端通过。

最新 CI 以 PR 最新提交为准。
@youngslin youngslin changed the title fix(bettergi): allow confirmed recovery after interrupted managed install BetterGI:托管安装中断后提供人工确认恢复(旧方案) Nov 10, 2026
youngslin added a commit that referenced this pull request Nov 10, 2026
## 方向:#1916 公共自动恢复,去掉人工弹窗
把 #1911 合法大事务校验与旧版本回执复核收进本 PR;关闭旧弹窗、前端订阅和专用 WS。BAAH 以原生完整包作为修复手段,由
`auto_recover_script_install`、`run_managed_script_install`
和公共下载安全回退决定重试、备份、健康核验、回滚与队列末尾报告。

进程未停写、目录尚存 previous/ready、损坏原生事务、身份回执不可信时禁止错误放行;只允许完成经过
PE、版本与原始文件回执确认的旧事务归档。首次新安装由公共快照保留旧版。没有可靠身份时不猜测架构、不强制下载安装。
本 PR 替代 #1911 与旧 #1900 弹窗,所有最终结论以最新 CI 和审查为准;真实 Windows 官方安装器待 E2E。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

专项: BetterGI 类型: 修复 按更新日志碎片自动设置

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants