Repository navigation
Conversation
| try: | ||
| installed = str(await asyncio.to_thread(program_update.read_version, root)) | ||
| except Exception as error: | ||
| # 元数据不可读时仍允许用户选择重试;跳过阶段才严格校验。 | ||
| logger.warning(f"读取 BetterGI 当前版本失败,恢复提示显示未知:{error}") | ||
| installed = "未知" |
There was a problem hiding this comment.
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.
总体结论:修改后合并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酱拍拍爪敬上 🐾 |
总体结论:修改后合并AUTO-MAS-Project/AUTO-MAS #1900 · 集成状态补充 宝宝,目标分支已合入 #1901,GitHub 现在将本 PR 标为有合并冲突(mergeable=false / dirty)。这次只补充新状态,不把旧问题再算一遍喵。 当前 PR 没有新提交,上一轮两项 P2 仍待处理。解决冲突时,还要把新加入的正式版资源就绪检查 与恢复入口一起保留:资源暂缓不能把未确认安装当成安全旧版放行。 dot酱没有取得解决冲突后的最终代码,也没有运行项目或合并验证;待冲突和上述问题处理后,再核对实际集成结果。 —— dot酱守着合并线敬上 🐾 |
总体结论:修改后合并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酱沿着恢复入口复核敬上 🐾 |
总体结论:修改后合并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酱给失效弹窗找出口敬上 🐾 |
总体结论:可以合并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酱把恢复分支核清楚敬上 🐾 |
总体结论:修改后合并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酱把被挡住的按钮找出来敬上 🐾 |
|
由于需求调整为全自动、无弹窗的安装健康检查 + 安装前备份/失败回滚,本 PR 的独立 BetterGI WebSocket 恢复弹窗、手动 retry/skip/stop 协议不再是目标方案,因此按维护者意图关闭,不合并。 后续统一入口见 #1916(公共恢复决策与任务结束汇总),BetterGI 的安装恢复会以单独适配 PR接入公共入口:保留原安装器校验、进程停写保护、缺失/损坏本体识别;安装前保留可回滚旧版,恢复成功并复核后清理备份;纯下载失败且旧版验证完整时仍可继续任务,任务结束后由公共入口统一报告异常。#1900 中可复用的测试边界和实现细节会在适配时参考,但不会把它的前端弹窗合并回来。 注意:#1916 当前还在审查与 CI 阶段,关闭本 PR 不意味着新的恢复功能已上线。 |
…ocess guard without UI prompts
…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 以最新提交为准;未运行真实游戏或上游官方安装器。
…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 最新提交为准。
## 方向:#1916 公共自动恢复,去掉人工弹窗 把 #1911 合法大事务校验与旧版本回执复核收进本 PR;关闭旧弹窗、前端订阅和专用 WS。BAAH 以原生完整包作为修复手段,由 `auto_recover_script_install`、`run_managed_script_install` 和公共下载安全回退决定重试、备份、健康核验、回滚与队列末尾报告。 进程未停写、目录尚存 previous/ready、损坏原生事务、身份回执不可信时禁止错误放行;只允许完成经过 PE、版本与原始文件回执确认的旧事务归档。首次新安装由公共快照保留旧版。没有可靠身份时不猜测架构、不强制下载安装。 本 PR 替代 #1911 与旧 #1900 弹窗,所有最终结论以最新 CI 和审查为准;真实 Windows 官方安装器待 E2E。
问题
BetterGI 新正式版发布后官方安装器可能因资源还未就绪而失败;MAS 在安装前写入
bgi-install.json,失败后保留标记是必要保护,但用户后来通过官方安装器修复并关闭更新托管后,MAS 仍在 AutoProxy / ScriptConfig 阻断启动,没有可执行的恢复选择。Fixes #1899
改动
行为边界
测试
tests/task/test_bettergi_program_update.py回归用例。