feat(BetterGI): 新增更好的原神脚本专项适配 - #410
Conversation
- 用户配置:移除「切换模式」,账户/账号UID/密码同排,切换方式按密码是否填写推断 - 任务配置:「一条龙配置组」改为「默认配置组」MAA 式胶囊开关,「要执行的配置组」删除,新增「自定义配置组」占位 - 新增「用户独立配置 / 脚本直控配置」二选一(IfUseMasConfig),独立配置读写 per-user 一条龙 JSON - 脚本配置:重试次数默认 3 次、代理超时默认 10 分钟;新增「游戏配置」(控制器 / 任务结束后关闭游戏) - 后端:任务结束后按进程名逐一关闭原神(YuanShen / GenshinImpact / 云原神),先优雅后强杀 - ProcessManager 支持 elevated 管理员权限启动;新增 account_switch / one_dragon 工具与资源模板
- apply_groups:按钮 OFF 的内置组在 TaskEnabledList 置 false 并保留组定义(可逆),仅按钮 ON 且配置缺失时才补建 - 自定义组不干预,其启用与否由 BetterGI 内部配置决定 - 保持相对顺序与所有非组设置字段
- 后端:OneDragon 段新增 DailyRewardPartyName/PartyName/AutoBossStrategyName 三个存储字段(config.py + schema.py 双侧同步) - 后端:one_dragon.write_user_one_dragon 支持写入队伍/策略,留空不覆盖 - 后端:新增 GET /api/scripts/bettergi/strategies 接口,动态读取自动战斗策略 (内置「根据队伍自动选择」+ User/AutoFight/*.txt) - 前端:BetterGIUserEdit 配置名称下新增三字段,布局为「配置名称|领取奖励队伍」、 「通用战斗队伍|通用战斗策略」两行;战斗策略为动态下拉并默认「根据队伍自动选择」
- 后端:OneDragon 段新增 IfUseCustomGroups(Bool)与 CustomGroups (JSONValidator list,存 name/enabled)两个存储字段,config.py + schema.py 同步 - 后端:one_dragon.apply_groups 支持自定义组控制——总开关开启时入表按表状态、 未入表默认开、入表启用但缺失自动补建;关闭时自定义组原样保留 - 后端:新增 list_custom_groups / parse_custom_groups 工具与 GET /api/scripts/bettergi/one-dragon/custom-groups 自动加载接口 - 后端:AutoProxy / ScriptConfig 读取并透传自定义组 - 前端:BetterGIUserEdit「配置名称」改名「一条龙名称」,新增自定义配置组区块 (总开关胶囊 + 三列表格:选中/名称/启用胶囊;添加配置组弹窗、删除选中、自动加载)
- 任务配置内置配置组按钮内容改为居左对齐 - 自定义配置组头部增加标题样式与「启用」开关文案 - 账号 UID 字段补充切换建议提示文案 - 配置 npm 镜像源
There was a problem hiding this comment.
Sorry @TCddddd, your pull request is larger than the review limit of 150000 diff characters
审查者指南将 BetterGI 引入为一种新的脚本类型,支持原生 GUI 驱动的一条龙任务管理、账号切换和通知,并通过后端配置/任务管理器接入,同时提供策略/自定义组 API 以及完整的前端编辑支持。 BetterGI 一条龙执行时序图sequenceDiagram
participant Manager as BetterGIManager
participant Proxy as AutoProxyTask
participant Switch as account_switch
participant BGI as BetterGI.exe
participant Monitor as LogMonitor
participant Notify as Notification
Manager->>Proxy: check()
Proxy->>Switch: deploy_switch_script()
Proxy->>Switch: write_switch_group()
Proxy->>BGI: open_process(--startGroups, MAS切换账号)
BGI-->>Monitor: 账号切换日志
Monitor-->>Proxy: 切换结果
Proxy->>Proxy: _write_one_dragon_config()
Proxy->>BGI: open_process(startOneDragon, config)
BGI-->>Monitor: 任务日志
Monitor-->>Proxy: check_log()
Proxy->>Proxy: _snapshot_one_dragon_config()
Proxy->>Notify: push_notification(代理结果)
原生 BetterGI 配置会话时序图sequenceDiagram
actor User
participant UI as BetterGIUserEdit
participant Service as 任务调度服务
participant Task as ScriptConfigTask
participant BGI as BetterGI.exe
participant Config as 用户独立配置
User->>UI: handleBettergiConfig()
UI->>Service: addTaskApiDispatchStartPost(ScriptConfig)
Service->>Task: 启动 ScriptConfigTask
Task->>Config: _write_one_dragon_config()
Task->>BGI: open_process()
BGI-->>User: 原生设置 GUI
User->>UI: handleSaveBettergiConfig()
UI->>Service: stopTaskApiDispatchStopPost()
Service->>Task: final_task()
Task->>Config: _snapshot_one_dragon_config()
BetterGI 配置实体关系图erDiagram
BetterGIConfig ||--o{ BetterGIUserConfig : 包含
BetterGIUserConfig ||--|| OneDragonConfig : 管理
BetterGIUserConfig ||--|| AccountSwitch : 配置
BetterGIUserConfig ||--|| UserNotification : 配置
BetterGIConfig {
string RootPath
string Controller
bool CloseOnFinish
}
BetterGIUserConfig {
string Name
bool IfUseMasConfig
string OneDragonConfigName
}
OneDragonConfig {
string Groups
string CustomGroups
string PartyName
string AutoBossStrategyName
}
AccountSwitch {
string Resource
string Uid
}
UserNotification {
bool Enabled
bool IfSendStatistic
}
文件级变更
可能关联的 issue
提示和命令与 Sourcery 交互
自定义使用体验访问您的控制面板以:
获取帮助Original review guide in EnglishReviewer's GuideIntroduce BetterGI as a new script type with native GUI-driven one-dragon task management, account switching and notification, wiring it through backend config/task manager and exposing strategy/custom-group APIs along with full frontend editing support. Sequence diagram for BetterGI one-dragon executionsequenceDiagram
participant Manager as BetterGIManager
participant Proxy as AutoProxyTask
participant Switch as account_switch
participant BGI as BetterGI.exe
participant Monitor as LogMonitor
participant Notify as Notification
Manager->>Proxy: check()
Proxy->>Switch: deploy_switch_script()
Proxy->>Switch: write_switch_group()
Proxy->>BGI: open_process(--startGroups, MAS切换账号)
BGI-->>Monitor: account-switch logs
Monitor-->>Proxy: switch result
Proxy->>Proxy: _write_one_dragon_config()
Proxy->>BGI: open_process(startOneDragon, config)
BGI-->>Monitor: task logs
Monitor-->>Proxy: check_log()
Proxy->>Proxy: _snapshot_one_dragon_config()
Proxy->>Notify: push_notification(代理结果)
Sequence diagram for native BetterGI configuration sessionsequenceDiagram
actor User
participant UI as BetterGIUserEdit
participant Service as Task dispatch service
participant Task as ScriptConfigTask
participant BGI as BetterGI.exe
participant Config as Per-user config
User->>UI: handleBettergiConfig()
UI->>Service: addTaskApiDispatchStartPost(ScriptConfig)
Service->>Task: start ScriptConfigTask
Task->>Config: _write_one_dragon_config()
Task->>BGI: open_process()
BGI-->>User: native settings GUI
User->>UI: handleSaveBettergiConfig()
UI->>Service: stopTaskApiDispatchStopPost()
Service->>Task: final_task()
Task->>Config: _snapshot_one_dragon_config()
Entity relationship diagram for BetterGI configurationerDiagram
BetterGIConfig ||--o{ BetterGIUserConfig : contains
BetterGIUserConfig ||--|| OneDragonConfig : manages
BetterGIUserConfig ||--|| AccountSwitch : configures
BetterGIUserConfig ||--|| UserNotification : configures
BetterGIConfig {
string RootPath
string Controller
bool CloseOnFinish
}
BetterGIUserConfig {
string Name
bool IfUseMasConfig
string OneDragonConfigName
}
OneDragonConfig {
string Groups
string CustomGroups
string PartyName
string AutoBossStrategyName
}
AccountSwitch {
string Resource
string Uid
}
UserNotification {
bool Enabled
bool IfSendStatistic
}
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
| ("任务执行异常", "BetterGI 任务执行异常"), | ||
| ("[ERR]", "BetterGI 任务执行异常"), | ||
| ) | ||
| _BGI_SUCCESS_LOG = "任务结束" |
There was a problem hiding this comment.
GPT提示:_BGI_SUCCESS_LOG = "任务结束" 范围过宽。当然我不清楚模版怎么写的,模版就这样那也行
| one_dragon.write_user_one_dragon( | ||
| self.script_root_path, | ||
| self.script_info.script_id, | ||
| self.cur_user_item.user_id, | ||
| self.one_dragon_config, | ||
| self.one_dragon_groups, | ||
| daily_reward_party_name=str( | ||
| self.cur_user_config.get("OneDragon", "DailyRewardPartyName") or "" |
There was a problem hiding this comment.
用户独立配置模式会直接覆盖 BetterGI 正在使用的一条龙配置,但当前生命周期没备份原配置,也没有在 final_task / on_crash 恢复。这样后续使用 IfUseMasConfig=false 的用户可能继承上一个独立用户的配置;切换失败或异常退出也会污染原配置。
| template["projects"][0]["jsScriptSettingsObject"] = _build_js_settings( | ||
| account, password, mode, global_account, servers, uid | ||
| ) | ||
|
|
||
| out_path = root_path / _SCRIPT_GROUP_REL_DIR / f"{_GROUP_NAME}.json" | ||
| write_file(out_path, template) | ||
| logger.info(f"已生成切换账号配置组: {out_path} (账号 {mask_account(account)})") | ||
| return out_path |
There was a problem hiding this comment.
明文写账号是BGI要求吗?最好做一下运行结束脱敏
| self.Game_Controller = ConfigItem( | ||
| "Game", | ||
| "Controller", | ||
| "电脑端-前台", | ||
| OptionsValidator(["电脑端-前台", "电脑端-云原神", "电脑端-桌面分身"]), | ||
| ) |
There was a problem hiding this comment.
有点太大了,建议本 PR 至少将自定义配置组和原生 GUI 会话提取为composable,父组件只负责加载用户配置和组合各区域
- AutoProxy: 独立配置模式下覆盖 BetterGI 一条龙配置前先备份现场, final_task/on_crash 结束还原,避免 IfUseMasConfig=false 用户继承上个 独立用户配置、切号失败或异常退出污染原配置 - account_switch: 新增 scrub_switch_group,切号结束后清空明文密码、 账号置回打码形式,防止明文凭据残留磁盘 - config: 标注 Game_Controller 为预留字段(云原神/桌面分身未开发) - AutoProxy: 补充 _BGI_SUCCESS_LOG 判定说明(BetterGI TaskRunner 统一日志)
- 新增 useBettergiCustomGroups / useBettergiGuiSession 两个 composable - BetterGIUserEdit.vue 由 1303 行减至约 1130 行,父组件只负责加载用户配置与组合各区块
# Conflicts: # res/version.json
- account_switch.py 不再内置部署冻结脚本,改为: * _ensure_script_subscription: 把 js/SwitchAccountMultipleMode 合并进订阅清单 * _ensure_auto_update_on_cli: 开启 autoUpdateBeforeCommandLineRun / autoUpdateSubscribedScripts * ensure_switch_subscription: 交由 BetterGI ScriptRepoUpdater 启动时拉取/更新 - write_switch_group: folderName 指向仓库检出目录 SwitchAccountMultipleMode - 删除 res/templates/BetterGI/SwitchAccountMultipleMode_MAS (29 个冻结副本文件)
根因:BetterGI 的「任务结束」在【每个子任务边界】都会输出,并非整条序列收尾信号。 旧判定 _BGI_SUCCESS_LOG='任务结束' 单子串命中即判 Success,导致 4 任务的一条龙在 任务 1 完成时就误判成功、随即 taskkill /F /T 强杀,正好砍在任务 2 的 「前往合成台 → 提瓦特大陆地图模板加载」处——表现为仅走专项(而非散跑 BGI)才闪退、 BGI 无任何崩溃/异常日志(被强制杀死)。 修复:结合 BetterGI 的「一条龙任务执行: X/Y」进度行,仅最后一个任务(X==Y)对应的 「任务结束」才判整条完成;日志无进度行的旧版 BGI 退化为「任务结束」单判兼容。 新增 _one_dragon_sequence_done 及对应单测。
BetterGI ScriptRepoUpdater 内置 RepoChannels 已把 CNB(https://cnb.cool/bettergi/bettergi-scripts-list) 列为默认渠道(ResolveRepoUrl 空渠道即回退 CNB);但用户若在 BGI GUI 选过 GitHub 会盖过默认、 回到境外源。_ensure_auto_update_on_cli 现把 scriptConfig.selectedChannelName 显式钉死为 "CNB",保证切号脚本(以及一条龙启动时)的仓库拉取/更新稳定走 cnb.cool 镜像。
HarcoChen
left a comment
There was a problem hiding this comment.
BetterGI 专项适配审核。整体注册链路(CLASS_BOOK / TYPE_BOOK / SCRIPT_BOOK / USER_BOOK / task_manager 分支 / GlobalConfig)完整,日志格式、CLI 参数、脚本仓库订阅机制均已对照 BetterGI 上游源码核对无误,分支可干净合入 dev。
以下 6 项建议在合并前处理,其中前 4 项会直接影响运行正确性或造成静默数据丢失;另有若干条建议与提示随行内注释给出。
未验证项(如实说明):本机为 macOS 且缺 win32api / loguru,tests/task/test_bettergi_one_dragon_completion.py 未实际执行;结论来自对上游源码与本仓代码的静态核对 + 纯函数复现脚本,不代表测试已跑通。res/version.json 与 Game.Controller 按维护者意见不在本次审核范围内。
| _BGI_GAME_CLOSE_WAIT_SECONDS = 5 | ||
|
|
||
|
|
||
| def _one_dragon_sequence_done(log: str) -> bool: |
There was a problem hiding this comment.
阻塞:一条龙完成判定仍会提前命中,仍会中途强杀 BGI。
本次提交正确诊断了「任务结束 在每个子任务边界都会输出」,但替换后的判定把同一缺陷从任务 1 平移到了任务 N。上游 OneDragonFlowViewModel.OnOneKeyExecute:
int finishOneTaskcount = 1; // 从 1 起
_logger.LogInformation($"一条龙任务执行: {finishOneTaskcount++}/{enabledoneTaskCount}");
await new TaskRunner().RunThreadAsync(...); // 进度行在任务【执行前】打印后置自增且从 1 起、打印在 task.Action() 之前 —— 所以 4/4 出现在任务 4 即将开始时,而此刻 任务结束 已由任务 1~3 写入日志(TaskRunner.RunCurrentAsync 在 finally 里输出)。按真实日志推进复现:
进度行 4/4 (任务4尚未开始) 当前实现: True ← run_book=True → sleep 3s → break → kill
任务4运行中 当前实现: True
main_task 随即 break,final_task 调 kill_managed_process(),正好砍在任务 4 执行中 —— 与修复前同一失效模式。
建议:整条序列的无歧义哨兵是 一条龙和配置组任务结束,仅在整条收尾时输出一次,且受 IsManualStop is false 保护(用户在 BGI 内手动停止时正确地不匹配)。由于 任务结束 是它的子串,把 _BGI_SUCCESS_LOG 直接改为该整串即可彻底移除进度行算术,_one_dragon_sequence_done 与 _BGI_TASK_PROGRESS_RE 可一并删除。
同时需改测试:现有 5 个用例都在进度行后紧跟 任务结束,恰好绕开了失效场景。改用整串哨兵后 test_full_sequence_complete / test_single_task_one_dragon / test_legacy_no_progress_line_fallback 三例会失败(fixture 从未输出真正的收尾行),需重写;并请补一条「N/N 已打印但任务 N 仍在执行」的回归用例 —— 正是这条缺失让本 bug 通过了 CI。
| await self._persist_user_run_result() | ||
|
|
||
| # 用户独立配置:回读 BetterGI 现有配置,捕获运行中/GUI 里改的设置,固化到 per-user 副本 | ||
| self._snapshot_one_dragon_config() |
There was a problem hiding this comment.
阻塞:崩溃与切号失败两条路径会把用户 per-user 一条龙配置覆盖成基线(静默数据丢失)。
TaskExecuteBase._execute_task 的顺序是 main_task → on_crash → final_task(on_crash 在 except 中,final_task 在 finally 中)。
-
崩溃路径:
on_crash先调_restore_one_dragon_config(),把备份写回现场文件并置_reseed_live_config = None;随后final_task执行本行_snapshot_one_dragon_config(),读到的正是刚被还原的覆盖前基线,并写入该用户的 per-user 副本 —— 用户自己的一条龙配置被静默摧毁。此时_restore_one_dragon_config()因幂等置 None 已成空操作。 -
切号失败路径(
main_task:313提前 return):_backup_one_dragon_config()从未执行,但final_task仍无条件快照,于是把「上一个用户 restore 后留下的现场」写进当前用户的副本。
两者根因相同:final_task 无条件快照,未区分本次运行是否正常走完。
参考实现:app/task/general/manager.py:144-180 是本仓既有范式 —— 快照/还原放在 manager 层,final_task 与 on_crash 都还原,并在每个直控用户后重新快照。建议对齐该结构,或至少给快照加上「仅在正常完成且确实接管过」的前置条件。
| return None | ||
| return self.user_config[uuid.UUID(self.cur_user_item.user_id)] | ||
|
|
||
| def _write_one_dragon_config(self) -> None: |
There was a problem hiding this comment.
阻塞:原生 GUI 配置会话没有任何备份/还原,会永久污染 BetterGI 现场配置。
_write_one_dragon_config() 把用户 A 的组开关覆盖进 BetterGI 现场配置,但 final_task 只调 _snapshot_one_dragon_config() 回读到 A 自己的 per-user 副本 —— 现场文件就一直停留在 A 的配置上。此后任何 IfUseMasConfig=false 的用户,或用户自己手动打开 BGI,都会继承 A 的配置。
这正是 288a46a 在 AutoProxy 里修掉的问题,但没有同步到本文件(全文件 backup / restore / reseed 零命中)。建议复用 AutoProxy 的 _backup_one_dragon_config / _restore_one_dragon_config(修完上一条的顺序问题后),或按 general/manager.py 的方式统一上提。
| # BetterGI 使用 Serilog 文件日志,行格式: | ||
| # [{HH:mm:ss.fff}] [{Level:u3}] [{BgiInstance}] {SourceContext}\n{Message} | ||
| # 成功/失败判定取自 TaskRunner 的统一日志片段,BetterGI 不向用户暴露关键词配置。 | ||
| _BGI_BUILTIN_FATAL: tuple[tuple[str, str], ...] = ( |
There was a problem hiding this comment.
阻塞:[ERR] 作为 fatal 且 fatal 优先 —— 正常成功的一条龙也会判异常并整轮重试。
_BGI_BUILTIN_FATAL 含裸 [ERR],check_log:553 的 for/else 让 fatal 优先于成功判定,且匹配的是整轮累计日志。
但 BetterGI 在正常成功的运行中就会输出 LogError(Serilog 渲染为 [ERR])用于可恢复场景,已对照上游确认:
GoToCraftingBenchTask/GoToAdventurersGuildTask:Logger.LogError(...)后重试,仅在耗尽_retryTimes才throwClaimEncounterPointsRewardsTask:LogError("{F}未找到委托按钮...")后return,不中断整条流程Avatar.cs游泳检测:LogError("游泳检测:回到战斗地点异常")后走TpForRecover恢复
配合 RunTimesLimit 默认 3,一次可恢复错误就会触发最多三轮完整重跑。建议移除裸 [ERR](保留 [FTL] 与 任务启动失败 / 任务执行异常 等明确致命片段),或把成功判定提到 fatal 之前 —— 结合上面的整串哨兵,成功命中时即可安全短路。
| * 又经 `saveField` 落库;首次开启总开关且表格为空时,从 BetterGI 现有配置自动加载。 | ||
| */ | ||
| export function useBettergiCustomGroups(options: BettergiCustomGroupOptions) { | ||
| const { scriptId, oneDragon, configName, editable, saveField } = options |
There was a problem hiding this comment.
阻塞:oneDragon 在 setup 期被解引用,loadUser() 后指向失效对象 —— 自定义配置组失效并静默覆盖用户已存配置。
本行把 formData.OneDragon 解构成局部 oneDragon(调用点 BetterGIUserEdit.vue:766 传入 oneDragon: formData.OneDragon),捕获的是 setup 时那一份对象。而 loadUser() 在 BetterGIUserEdit.vue:855 用 Object.assign(formData, { ..., OneDragon: { ...默认, ...userData.OneDragon }, ... }) 整体替换了该嵌套对象。此后模板读的是新代理,composable 读写的仍是旧对象,两者彻底脱钩。
三个可观察后果:
syncFromForm()(:68)解析旧对象的CustomGroups,永远是默认'[]',用户已保存的自定义组永不回显。- 紧接着
BetterGIUserEdit.vue:867判到表格为空便loadCustomGroupsFromBettergi(),用 BGI 现场状态填表;用户下一次任何改动触发persist(),即把这份 BGI 派生表写回后端,永久覆盖原有启用状态。 toggleMaster()(:100)读旧对象的IfUseCustomGroups(恒为默认false),每次点击都算出next = true并重复写 true;模板读新代理,表现为总开关点了没反应 / 无法关闭。
建议:改为传 getter(如 oneDragon: () => formData.OneDragon)或直接传 formData 由 composable 内部按需取值,避免在 setup 期固化嵌套引用。
另:parseList(:64)用 Boolean(x.enabled) 把缺失的 enabled 归为 false,而后端 parse_custom_groups 缺省为 True,两侧默认相反;当前后端总会显式返回该字段,暂不构成现网问题,但建议对齐以免日后往返翻转。
| self.script_log_path: Path | None = None | ||
| self.log_monitor: LogMonitor | None = None | ||
|
|
||
| async def check(self) -> str: |
There was a problem hiding this comment.
建议:直控模式不校验一条龙配置名,配错会静默跑错任务集并报成功。
check() 校验了 RootPath、exe、代理次数与剩余天数,但没校验 Task.OneDragonConfigName 在 BetterGI 中是否真实存在。独立配置模式下 MAS 会自己写出该 JSON 故无妨;但 IfUseMasConfig=false 时 MAS 不写文件,而上游 OneDragonFlowViewModel.OnLoaded 在 startOneDragon <name> 未匹配到配置时只记一条警告 未找到,请检查。 然后沿用当前 SelectedConfig 继续执行,不会中止。
结果是用户名字写错一个字,跑的是另一套任务集,而 MAS 一路判成功。建议在直控模式下检查 {RootPath}/User/OneDragon/{name}.json 是否存在,缺失时按 check() 消息规范返回用户可操作的提示(如「请确认 BetterGI 中已保存该一条龙配置」)。
| self.script_exe_path, | ||
| *self.bettergi_args, | ||
| target_process=self.script_target_process_info, | ||
| elevated=True, |
There was a problem hiding this comment.
建议:elevated=True 收益不明,且在开发环境有副作用。
打包后的应用已在 frontend/package.json:64 声明 requestedExecutionLevel: requireAdministrator,main.py 也会在非 hosted / 非 dev 时自行提权,子进程本就继承管理员权限 —— 生产环境下该参数不带来额外能力(已提权进程再 ShellExecute "runas" 也不会二次弹 UAC)。
而在开发环境(AUTO_MAS_DEV=1,后端不自提权):每次启动 BGI 都会弹一次 UAC;且 ShellExecute 不返回子进程句柄,ProcessManager.process 为 None,kill() 完全依赖 psutil 的 target_process,对高权限进程会拿到 AccessDenied(被 suppress 静默吞掉),BGI 杀不掉。
本仓其余 9 个 open_process 调用点均未用该参数。若 BGI 确实需要管理员权限才能操作游戏窗口,建议在注释里写明依据;否则建议去掉。
| await self._push_dispatch_log("切换账号脚本本地缺失,BGI 启动时将自动从脚本仓库检出") | ||
|
|
||
| await self._push_dispatch_log( | ||
| f"开始切换账号: --startGroups {account_switch._GROUP_NAME}" |
There was a problem hiding this comment.
提示:跨模块访问私有名。
account_switch._GROUP_NAME 在本文件有 4 处引用(:458 / :462 / :474 / :508),而 tools/__init__.py 只导出 push_notification。本仓其他专项没有跨模块取 _ 前缀名的先例。建议改为公开常量,或提供 account_switch.group_name() / 让 write_switch_group 返回组名。
| new_enabled[uid] = True | ||
|
|
||
| # 管理开启时:入表且启用但配置里缺失的自定义组:补建并启用 | ||
| if manage_customs: |
There was a problem hiding this comment.
提示:总开关开启时会静默强开「未入表」的自定义组。
manage_customs=True 时,BGI 里存在但不在 MAS 表中的自定义组会被置 enabled=True(:317 / :331 的 custom_enabled.get(name, True)),覆盖用户在 BGI 侧的关闭意图。已复现:BGI 中 enabled=False 的遗留组、MAS 表为空时,输出变为 True。
docstring 已写明这是有意设计(「未入表默认开」),且前端会自动加载现有组故场景不常见 —— 仅提示语义上「未配置」被解释成「启用」,与内置组「按钮 OFF 即关闭」的方向相反。若确为预期,建议在前端文案里点明。
| table.value = Array.from(existing.values()) | ||
| } | ||
|
|
||
| const loadFromBettergi = async () => { |
There was a problem hiding this comment.
建议:API 失败静默,用户无法知晓自动加载失败。
loadFromBettergi() 仅在 resp.code === 200 时 mergeRows,非 200 分支既不提示也不记日志;:89 的 catch 只 logger.error。而后端 get_bettergi_custom_groups_api 是在 HTTP 200 里返回 code=400/500 + message 的契约,所以 try/catch 根本不会触发,错误信息被整条丢弃 —— 用户只看到空表格。
同一问题见 BetterGIUserEdit.vue:737 loadStrategyOptions():完全不检查 resp.code,直接 resp.data || [],接口报错时静默显示空的战斗策略下拉。按 mas-frontend-ui「API 异常必须给出错误反馈」,建议两处都检查 code 并把后端 message 透出。
ponytail-review:只查过度设计范围仅限「可删/可缩」,不含正确性与安全性问题(那些请走常规 review)。已逐文件读完 6314 行 diff,并核对了 dev 分支现状。 后端
前端
附带一条(非过度设计,顺手提)
其中最大的三块是 notify 去重(-120)、模板瘦身(-110)、 |
f3295c2 to
e981d4b
Compare
- 用户配置:移除「切换模式」,账户/账号UID/密码同排,切换方式按密码是否填写推断 - 任务配置:「一条龙配置组」改为「默认配置组」MAA 式胶囊开关,「要执行的配置组」删除,新增「自定义配置组」占位 - 新增「用户独立配置 / 脚本直控配置」二选一(IfUseMasConfig),独立配置读写 per-user 一条龙 JSON - 脚本配置:重试次数默认 3 次、代理超时默认 10 分钟;新增「游戏配置」(控制器 / 任务结束后关闭游戏) - 后端:任务结束后按进程名逐一关闭原神(YuanShen / GenshinImpact / 云原神),先优雅后强杀 - ProcessManager 支持 elevated 管理员权限启动;新增 account_switch / one_dragon 工具与资源模板
- apply_groups:按钮 OFF 的内置组在 TaskEnabledList 置 false 并保留组定义(可逆),仅按钮 ON 且配置缺失时才补建 - 自定义组不干预,其启用与否由 BetterGI 内部配置决定 - 保持相对顺序与所有非组设置字段
- 后端:OneDragon 段新增 DailyRewardPartyName/PartyName/AutoBossStrategyName 三个存储字段(config.py + schema.py 双侧同步) - 后端:one_dragon.write_user_one_dragon 支持写入队伍/策略,留空不覆盖 - 后端:新增 GET /api/scripts/bettergi/strategies 接口,动态读取自动战斗策略 (内置「根据队伍自动选择」+ User/AutoFight/*.txt) - 前端:BetterGIUserEdit 配置名称下新增三字段,布局为「配置名称|领取奖励队伍」、 「通用战斗队伍|通用战斗策略」两行;战斗策略为动态下拉并默认「根据队伍自动选择」
- 后端:OneDragon 段新增 IfUseCustomGroups(Bool)与 CustomGroups (JSONValidator list,存 name/enabled)两个存储字段,config.py + schema.py 同步 - 后端:one_dragon.apply_groups 支持自定义组控制——总开关开启时入表按表状态、 未入表默认开、入表启用但缺失自动补建;关闭时自定义组原样保留 - 后端:新增 list_custom_groups / parse_custom_groups 工具与 GET /api/scripts/bettergi/one-dragon/custom-groups 自动加载接口 - 后端:AutoProxy / ScriptConfig 读取并透传自定义组 - 前端:BetterGIUserEdit「配置名称」改名「一条龙名称」,新增自定义配置组区块 (总开关胶囊 + 三列表格:选中/名称/启用胶囊;添加配置组弹窗、删除选中、自动加载)
- 任务配置内置配置组按钮内容改为居左对齐 - 自定义配置组头部增加标题样式与「启用」开关文案 - 账号 UID 字段补充切换建议提示文案 - 配置 npm 镜像源
- AutoProxy: 独立配置模式下覆盖 BetterGI 一条龙配置前先备份现场, final_task/on_crash 结束还原,避免 IfUseMasConfig=false 用户继承上个 独立用户配置、切号失败或异常退出污染原配置 - account_switch: 新增 scrub_switch_group,切号结束后清空明文密码、 账号置回打码形式,防止明文凭据残留磁盘 - config: 标注 Game_Controller 为预留字段(云原神/桌面分身未开发) - AutoProxy: 补充 _BGI_SUCCESS_LOG 判定说明(BetterGI TaskRunner 统一日志)
- 新增 useBettergiCustomGroups / useBettergiGuiSession 两个 composable - BetterGIUserEdit.vue 由 1303 行减至约 1130 行,父组件只负责加载用户配置与组合各区块
与通用战斗队伍对称:首领讨伐已走一条龙 AutoBossStrategyName,其余三项由 BGI 在 OneDragonTaskItem 直读全局 config.json 段,故把队伍/策略统一抽象为「叶子路径」: - 新增 apply_global_battle_strategy:补写 autoFightConfig.strategyName(秘境)、 autoLeyLineOutcropConfig.fightConfig.strategyName(地脉花,嵌套)与 autoStygianOnslaughtConfig.strategyName(幽境危战),保留同段其余字段、空值不覆盖; - snapshot/restore 改为覆盖队伍+策略全集叶子,支持嵌套段并在还原时清理空段, 避免单次运行把 per-user 队伍/策略残留到共享全局 config.json。 新增 4 个策略用例(写入三任务/嵌套段/空值不覆盖/还原清理),共 13 项全过。
昨日两条记录均为「启用配置组任务的数量: 2 → 配置组任务执行: 1/2 → 切换账号配置组 → 「任务结束」」然后 MAS 判 Success 强杀。根因:旧逻辑无「一条龙任务执行: X/Y」 进度行时退化为「任务结束」单判,而该行恰是配置组子任务(切换账号)边界的统一片段。 改为以 OneDragonFlowViewModel.RunThreadAsync 的唯一权威收尾行「一条龙和配置组任务结束」 (仅在全部任务 + 配置组任务 + CheckRewardsTask 正常完成路径打印,取消/异常分支提前 return) 作为整条完成的唯一判据。
BGI 的 TaskRunner.Run 为每条子任务(含配置组)单独包 try/catch(Exception), 某步抛异常会打印 [ERR] 但吞掉(不 rethrow),一条龙继续下一条最终仍正常收尾, 直接 BGI『跳过该步继续跑』即此机制。旧 _BGI_BUILTIN_FATAL 把 [ERR] 当进程级 致命,故 MAS 一旦遇到任何任务级异常就把 BetterGI 强杀重启,导致本可跑完的 一条龙永远无法正常完成(通用配置/专项两条路径均受影响,都走同一条 check_log)。 改动: - 致命表只保留真正进程级 [FTL] 与任务锁占用的「任务启动失败」,移除 [ERR]/ 「任务执行异常」(后者仅通知渠道、本就不进文件日志)。 - 已完成判定(命中权威收尾行)优先于杂散 [ERR]:走到收尾行即证明各步可恢复,按成功。 - 新增 _BGI_ERR_STALL_MINUTES=5 卡死兜底:仅当 [ERR] 后连续 5 分钟无任何新日志行 (既不完成也不退出)才判异常,保留快失败但不误杀正常推进。 - 队伍配置错误专属拦截(_party_config_error)与切号 _switch_account 独立 fatal 列表 均不受影响。 测试:真实 check_log 源码 8 场景全过(含『完成但中途有[ERR]→Success』、『仅[ERR] 存活→运行中』、『[FTL]→异常』、『卡死→异常』);team 套件 13 过;completion 套件 新增『杂散[ERR]仍判完成』等 6 断言对真实源码全过。
开启「用户独立配置」(Info.IfUseMasConfig) 后,原本把 per-user 配置直接回写 BGI 同名
User/OneDragon/{配置名}.json,即便有 backup/restore,运行期与崩溃未还原时(主循环并非
try/finally 包裹,靠哨兵保持幂等)BGI 同名实配会被永久改成「用户独立配置」的样子——
即用户反馈的『开了独立配置,bgi 同名的一条龙配置就变成独立配置的样子』。
现改为:per-user 配置物化落到 MAS 独占运行时槽位 User/OneDragon/MAS独立配置.json,
据此 startOneDragon 启动,结束后删除槽位。BGI 同名用户实配全程零接触,不再覆盖。
- one_dragon.py:新增 _MAS_ONE_DRAGON_SLOT_NAME/launch_slot_name/one_dragon_slot_path/
remove_one_dragon_slot(幂等);write_user_one_dragon 物化目标改为槽位(per-user 缓存仍按
用户所选名 key)。
- AutoProxy.py:prepare 中新增 use_mas_launch_slot / launch_config_name,bettergi_args 与启动
日志据此选用槽位名;_backup_one_dragon_config 删去 live 一条龙备份(仅保全局 config.json
队伍/策略叶子快照);_restore_one_dragon_config 重写为还原叶子 + finally 中删除槽位,
幂等(final_task 与 on_crash 相继触发不重复覆盖)。
- 若用户恰好把配置命名为「MAS独立配置」,退化为直连(防自伤)。
- 测试:新增槽位隔离断言(实配字节零接触、槽位删除幂等、槽位名稳定)。
- snapshot_user_one_dragon 增加 read_name 参数:读取源(槽位)与缓存 key(用户所选名)解耦 - AutoProxy/_snapshot 与 ScriptConfig 手动会话快照均以 launch_slot_name 为读取源,独立模式下手工改 GUI 的设置能回写 per-user 缓存 - list_custom_groups 增加 useMasConfig 开关:独立模式显示槽位中的配置组而非同名实配(修复下拉'暂无数据') - 自定义配置组总开关改为 getter 求值,修复 loadUser 替换 formData.OneDragon 引用后的失活 - 新增配置组从输入框改为下拉框,候选取自 BGI 现有配置组
- write_user_one_dragon 缓存缺失/为空(read_file 对不存在返回 {})时回退到 BGI 实配而非
内置模板:否则用户自定义配置组整体丢失、重启后落到一条龙末尾,禁用组也一并消失
- 新增 list_one_dragon_configs(扫 User/OneDragon/*.json,排除 MAS 槽位,默认配置置顶)
与 /bettergi/one-dragon/configs 端点,供一条龙名称下拉
- 补回归测试:缺失种子回退实配、禁用自定义组位置保留、配置名列表过滤槽位
- 一条龙名称改为必填下拉(可选 BGI 现有一龙配置,默认「默认配置」),历史空值归一 - 自定义配置组补充说明:来源(BGI 非内置组)与开关规则(表外默认执行、入表按行开关) - 任务配置卡片:直控模式下警告横幅一键切「用户独立配置」;独立模式下蓝气泡交代 BGI 编辑「MAS独立配置」的配置流程、通用队伍/策略生效范围;胶囊开关说明置于网格上方 - 「配置 BetterGI」按钮在独立模式下挂悬停引导
e981d4b to
220595c
Compare
…TO-MAS into feat/bettergi-adapter # Conflicts: # app/api/scripts.py # app/core/task_manager.py # app/task/BetterGI/AutoProxy.py # app/task/BetterGI/ScriptConfig.py # app/task/BetterGI/tools/account_switch.py # app/task/BetterGI/tools/one_dragon.py # frontend/src/api/services/BettergiService.ts # frontend/src/composables/useBettergiCustomGroups.ts # frontend/src/views/EditView/User/BetterGIUserEdit.vue # frontend/src/views/scripts/components/scriptCreateFlow.ts # res/version.json # tests/task/test_bettergi_one_dragon_completion.py
- 切换账号失败改为中止任务;失败路径脱敏切换配置组,避免明文凭据残留 - 全局 config.json 读-改-写加锁串行化,消除切号与一条龙交错丢失更新 - 内置一条龙配置组单一来源 app.models.config,消除双份硬编码 - 自定义组未入表保持 BetterGI 原启用状态,不再误开已关闭的组 - 前端 saveField 改 promise 队列,连续保存不再丢失;失败结果上抛并记录原因 - 原生设置会话 30 分钟超时前 30 秒预警,不再无预告中断
模块级 __getattr__ 只对属性访问生效,函数体内的裸全局名引用(LOAD_GLOBAL) 仍解析不到,导致通知/上报等初始化期间抛出 'name Config is not defined', 表现为通知发不出去。绑定为模块级 LazyProxy(真实对象引用)后裸名正常解析, 同时转发属性读写保证 Config.xxx = yyy 落到真实对象上。 涉及:app.utils.LazyProxy 新增;notification/matomo/system/update/task_manager 六个模块从 __getattr__ 改为 LazyProxy。
- 一条龙分步报告:从 BetterGI Serilog 日志按执行顺序解析每一步(任务名/起止时间/ 成败/异常次数与原因),成功标 ✓+时间、失败标 ✗+原因+时间,接进统计通知。 邮件(HTML 模板含分步表)与 Server酱(完整版, 32KB 超上限回退简略) 用完整版, 自定义 Webhook 为聊天机器人有真实字数瓶颈, 用回旧 4 字段简略版。 新增独立纯解析模块 one_dragon_report.py(零业务依赖, 可独立于 pytest 加载测试)。 - 推送用户统计通知失败不再静默:既记 ERROR 日志也推到调度台实时日志。 - 冻结 BetterGI 命令行运行前同步更新脚本仓库特性(_UPDATE_REPO_BEFORE_RUN=False, 句保留后台自动更新与误删恢复)。 - 新增 tests/task/test_bettergi_one_dragon_report.py(7 用例)。 涉及:AutoProxy.py / tools/notify.py / tools/one_dragon_report.py(新) / tools/account_switch.py / res/html/general_statistics.html / 新测试。
app/services/notification.py 从 app.utils 导入 ImageUtils,而这个名字在整个 仓库里不存在。app/services/__init__.py 是 eager import(from .notification import Notify),所以 import app.services 直接抛 ImportError——后端起不来, pytest 连 collect 都过不去(32 个收集错误)。 该导入进来后从未被使用,全文件只出现在 import 行,是 #410 合并时的残留。 删除后 tests/ 收集正常:821 passed / 2 failed(两条失败均与本改动无关, 分别是 dev 上已知的 test_activity_fight_preserves_native_options 与 #410 自带的 test_deleted_script_forces_repo_and_resubscribes)。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
用户机器上的报错:
```
MaaFW 运行异常: MaaFW runner worker exited without result: 1: from .library import Library
File "...\maafw-runtime-8113c68.../environment\Lib\site-packages\maa\library.py", line 1, in <module>
import ctypes
File "ctypes\__init__.py", line 157, in <module>
AttributeError: class must define a '_type_' attribute
```
运行池认为环境就绪,直到 worker 起来才炸——而模拟器和游戏已经先被拉起来了。
## 根因
`ctypes/__init__.py` 157 行是 `class py_object(_SimpleCData):`,**158 行就写着
`_type_ = "O"`**。类体里有而 `_ctypes` 说没有,只有一种可能:ctypes 的两半(纯 Python 部分与
`_ctypes.pyd`)来自不同构建。
原来的 `verify_python` 确实会启动解释器校验,但探针只 import
`json/platform/sys/sysconfig`,而 version、soabi、platform
**全部来自解释器二进制**——标准库那一半坏了照样报得一模一样。(探针加 ctypes 的改动已随 dev 上的 `01a20888`
合入。)
## 本 PR 补三道
**1. 装完即验** — `installer._verify_maafw_importable`
原来只有 `importlib.metadata.version('maafw')`,读的是包元数据,装了一半或标准库坏掉时照样报得出版本号。写
manifest 之前真的 `import maa` 一次,坏环境就不会被记成好的。
**2. 跑前自检** — `embedded_manager.describe_unusable_runtime`
`check()` 此前只验模式/脚本 ID/项目路径/用户/模拟器,完全不碰环境。现在解析出该项目会用的 MaaFW
requirement,在池里找到匹配的 runtime 才探一次;**没建过就不拦**,那份环境会在运行时按需准备。
拦在 `check()` 而不是只靠编辑页:队列与定时任务不经过编辑页,绕不过它;而且此时模拟器和游戏都还没启动。
为此把 requirement 解析抽成 `resolve_project_maafw_requirement`,与
`prepare_runner_environment` 内的顺序一致(项目自带原生库的实测版本优先于 `requirements.txt`
的声明)。实测对 MaaYYs 解析出 `maafw==5.13.0b2`,与真机日志一致。
**3. 向导闸门** — `MaaFWScriptEdit.vue`
环境没准备好不让进下一步——首次要下载 MaaFramework,失败时后面每一步都是白填。失败不是死路:提示条里带「重试」。
自检自身出问题(池不可读等)一律放行,不能反过来挡住运行。
## 验证
- 后端 `830 passed`,2 条失败均与本 PR
无关(`test_activity_fight_preserves_native_options`
是既有的,`test_deleted_script_forces_repo_and_resubscribes` 来自 #410)
- 新增 9 项测试;回退实现后以 `AttributeError: ... has no attribute
'_verify_maafw_importable'` 变红
- 前端 `vitest 142 passed`、`vite build` 通过
- 拿 4 个真实池 venv 跑过自检,不误伤
## 未覆盖
向导守卫是 SFC 里的两行 computed,单测要挂载整页,性价比低,**没有前端单测**。真正可执行的闸门是后端那道(有测试)。
## 顺带
`useBettergiGuiSession.ts:88` 的 typecheck error 与 `useScriptApi.ts:1125`
的 `no-dupe-else-if` lint error 都来自 #410,本 PR 未处理。
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Sourcery 总结
在安装、任务预检和设置向导导航期间,快速失败并阻止使用不可用的 MaaFW 环境。
新功能:
- 添加运行前验证,在任务开始前检测现有但不可用的 MaaFW 运行时。
- 在运行时环境准备就绪前,阻止 MaaFW 设置向导继续进行,并支持重试。
错误修复:
- 在安装期间验证 `import maa` 是否成功,从而拒绝损坏的 MaaFW 环境,避免在运行时未就绪时记录该环境。
- 当匹配的 MaaFW 运行时不可用或无法使用时,避免启动模拟器或游戏。
改进:
- 复用项目的 MaaFW 要求解析逻辑,确保准备和验证期间选择一致的运行时。
- 对于与现有匹配运行时无关的验证失败,允许其保持非阻塞状态,以便仍可按需准备环境。
测试:
- 增加对安装期间导入验证和运行时预检门控场景的覆盖。
<details>
<summary>Original summary in English</summary>
## Summary by Sourcery
Fail fast on unusable MaaFW environments during installation, task
pre-flight checks, and setup wizard navigation.
New Features:
- Add pre-run validation that detects unusable existing MaaFW runtimes
before tasks start.
- Prevent the MaaFW setup wizard from advancing until the runtime
environment is ready, with retry support.
Bug Fixes:
- Reject broken MaaFW environments during installation by verifying that
`import maa` succeeds before recording the runtime as ready.
- Avoid starting emulators or games when the matching MaaFW runtime is
unavailable or unusable.
Enhancements:
- Reuse project MaaFW requirement resolution for consistent runtime
selection during preparation and validation.
- Allow validation failures unrelated to a matching existing runtime to
remain non-blocking so environments can still be prepared on demand.
Tests:
- Add coverage for installation-time import validation and runtime
pre-flight gating scenarios.
</details>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
#410 新增的两个 BetterGI 页面与两个 composable 是纯硬编码中文,而同版本 version.json 已登记「各脚本/用户编辑页的界面文案接入词表」。这里补齐。 - 四个文件的界面文案改走 t('edit.*'),edit 命名空间新增 94 条词条, zh-CN / en-US / ja-JP 三份同步 - 参与后端判定的中文保持原样:Game.Controller、Switch.Resource、 OneDragon.Groups 的取值,以及「默认配置」「根据队伍自动选择」; 注释与 logger 诊断日志同既有页面一样保持中文 - oneDragonGroupOptions、自定义配置组表头 columns、表单 rules 改成 computed——常量数组在 setup 期只求值一次,切语言后标签不会重算 - 顺带修 UID 输入框 placeholder 的笔误:请输 UID -> 请输入 UID Refs #498 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
#410 新增的两个 BetterGI 前端页面与两个 composable 没有接词表,界面文案全是硬编码中文;而同版本 `version.json` 已登记「各脚本/用户编辑页的界面文案接入词表」。本 PR 把这块补上。 对照:`HSRUserEdit.vue` 有 2 处 `useI18n` + 38 处 `t()`,`BetterGIUserEdit.vue` / `BetterGIScriptEdit.vue` 此前都是 0。 ## 改了什么 - `BetterGIScriptEdit.vue`、`BetterGIUserEdit.vue`、`useBettergiCustomGroups.ts`、`useBettergiGuiSession.ts` 的界面文案全部改走 `t('edit.*')`。 - `edit` 命名空间新增 94 条 BetterGI 专项词条,zh-CN / en-US / ja-JP 三份同步(三份 key 数一致,1054 条)。 - 尽量复用既有词条,只有 BetterGI 独有的文案才新建 key:`basicInfo`、`scriptName`、`runConfiguration`、`gameConfiguration`、`runsPerDay`、`retryLimit2`、`runTimeoutMinutes`、`daysLeft`、`note`、`password`、`notifyMail`、`notifyServerChan`、`pickDirectory`、`k0MeansNoLimit`、`gotIt`、`deleteSelected`、`saveSettings`、`configuring`、`comp.editUser` / `comp.addUser2` 等约 30 个 key 直接复用。 ## 哪些中文特意没动 参与判断的中文一律保持原样,只翻译显示文案: - `Game.Controller` 取值(`电脑端-前台` 等)—— 后端 `OptionsValidator` 按中文枚举校验。 - `Switch.Resource` 取值(`官服` / `B服` / `亚服` / `欧服` / `美服` / `港澳台服`)—— 同上,且 `account_switch._RESOURCE_MAP` 按中文键查表。 - `OneDragon.Groups` 取值(8 个内置组名)—— 后端 `_BGI_BUILTIN_ONE_DRAGON_GROUPS` 按组名识别。改成 `ONE_DRAGON_GROUPS` 的 `{ value, labelKey }` 结构,取值不变、只有显示名接词表。 - `默认配置`、`根据队伍自动选择` —— 分别是 `resolve_config_name` 的兜底名和 BGI 内置策略名。 - 代码注释与 `logger.*` 诊断日志保持中文,与 `HSRUserEdit.vue` 等既有页面一致。 ## 两个顺带的修正 - `oneDragonGroupOptions` 与自定义配置组表头 `columns` 改成 `computed`。常量数组在 setup 期求值一次,切换语言后不会重算,标签会卡在旧语言;表单校验规则 `rules` 同理。 - UID 输入框 placeholder 的笔误:`请输 UID` → `请输入 UID`。 ## 验证 - `vite build` + `yarn build:main` 通过。 - `yarn test`:22 个文件 142 个用例全过。 - 本 PR 引用的 133 个 key 在 zh-CN / en-US / ja-JP 三份里都能解析到;新增的 94 个 key 全部有引用,无死词条。 - `yarn typecheck` 与 `yarn lint` 各剩 1 条报错,**都在 dev 上已经是红的,与本 PR 无关**(在 `git stash` 后的干净 dev 上复现过),已写进 #498: - `useBettergiGuiSession.ts` 的 `subscribe({ id })` 缺 `WSSubscriptionKey` 必填的 `type`; - `useScriptApi.ts` 里 `BetterGIUserConfig` 分支重复,第二个不可达。 ## version.json 在 `v5.5.0-beta.3` 的「程序优化」下加了一条,沿用既有的 `前端i18n` 前缀。署名没有手写,交给 `append-version-contributor` 在合并后自动补。 其余在 #498 里列的问题(日志跨零点误判超时、`ScriptConfig` 槽位残留、切号仓库重建等)不在本 PR 范围内。 Refs #498 --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
## 概述 BetterGI 专项(#410)合入时没有重新跑 OpenAPI 生成器,`frontend/src/api` 与后端接口定义脱节。 ## 变更 - 重新生成前端 API 客户端:补齐三个 BetterGI 接口、修正一条龙自定义配置组的方法名与参数可选性、补齐 BetterGI 模型缺失的字段与导出。 - 服务类名按生成器的 tag 派生结果统一为 `BetterGiService`(与 `MaaFwService`、`OknteService` 同一规则),仓库里此前的 `BettergiService` 不是生成器产物;已用 `git mv` 完成大小写重命名,避免在大小写敏感环境下解析失败。 - 同步更新两处消费方(`useBettergiCustomGroups.ts`、`BetterGIUserEdit.vue`),后端与业务逻辑未改。 ## 验证 `yarn typecheck`、`yarn lint --max-warnings 1`、`yarn test`(23 文件 / 144 用例)均通过。 ## Sourcery 摘要 重新生成 BetterGI 前端 API 客户端,以恢复与后端接口定义的一致性。 错误修复: - 将生成的 BetterGI 前端客户端与当前后端 API 契约同步,包括新增的 BetterGI 端点和模型字段。 增强功能: - 统一生成的 BetterGI 服务名称并更新其使用者。 - 修正 BetterGI 自定义组和配置模型的签名、可选性及导出内容。 日常维护: - 重新生成前端 API 客户端并更新仓库版本元数据。 <details> <summary>Original summary in English</summary> ## Summary by Sourcery Regenerate the BetterGI frontend API client to restore alignment with the backend interface definitions. Bug Fixes: - Synchronize the generated BetterGI frontend client with the current backend API contract, including the newly available BetterGI endpoints and model fields. Enhancements: - Standardize the generated BetterGI service name and update its consumers. - Correct BetterGI custom-group and configuration model signatures, optionality, and exports. Chores: - Regenerate the frontend API client and update the repository version metadata. </details> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Closes #613 ## 问题 #295(`a671fdd1`,2026-08-28)删除了 `Config.send_websocket_message`,98 处调用当时全部迁到 `Publisher`。但 BetterGI 专项 #410(`a2c78cfe`,09-01)与 ZZZ-OD 专项 #593(`f735b547`,09-08)都在 #295 之前拉出分支、之后合入,合并时没跟随这次迁移,dev 上因此留下 **18 处调用、0 处定义**。 `AppConfig` 没有 `__getattr__`,所以这些路径运行时必抛 `AttributeError`,并把真实的出错原因整个盖掉——Sentry 上看到的就是 `BetterGI任务出现异常: 'AppConfig' object has no attribute 'send_websocket_message'`,而不是「配置检查为什么没过」。 ## 改动 18 处全部按 `app/task/MAA` 的既有写法迁移: ```python # 之前 await Config.send_websocket_message( id=self.task_info.task_id, type="Info", data={"Error": msg} ) # 之后 await Publisher.send( id=self.task_info.task_id, type=protocol.TASK_NOTICE, data=WSTaskNoticeData(level="error", message=msg), ) ``` 18 处原本形态完全一致(`type="Info"` + `data={"Error": ...}`),所以是一一对应的机械迁移,**没有改动任何触发条件、状态赋值或控制流**。`BetterGI/ScriptConfig.py` 与 `ZzzOd/ScriptConfig.py` 迁移后不再用到 `Config`,顺带去掉了该 import。 分布:`BetterGI/manager.py` 4、`BetterGI/AutoProxy.py` 1、`BetterGI/ScriptConfig.py` 1、`ZzzOd/manager.py` 9、`ZzzOd/AutoProxy.py` 2、`ZzzOd/ScriptConfig.py` 1。 ZZZ-OD 模块目前整体没过 `ruff format`,本 PR **没有**顺手格式化,以免把无关重排混进来。 ## 本地验证 ``` .venv/Scripts/python.exe -m pytest tests -q 682 passed, 3 skipped, 1 warning, 151 subtests passed in 7.65s .venv/Scripts/python.exe -m pytest tests --collect-only -q # 685 collected, 退出码 0 .venv/Scripts/python.exe -m ruff check app/task/BetterGI app/task/ZzzOd # All checks passed grep -rn "send_websocket_message" app/ # 0 处残留 ``` 未做真机手测:触发这些分支需要装 BetterGI / ZZZ-OD 并造出「检查不通过」的场景,本地没有环境。迁移是形态一致的机械替换,`Publisher.send` 与旧方法签名相同(`id` / `type` / `data`),风险集中在提示能否正常送达前端,建议合并前由专项作者跑一次能触发提示的路径。 ## 请审阅 @TCddddd BetterGI 专项部分,@AthenaHibou ZZZ-OD 专项部分。确认没问题后**请你们自行合并**,我不代合。 ## Summary by Sourcery 将 BetterGI 和 ZZZ-OD 的错误通知迁移到 Publisher,恢复真实任务错误信息向前端的正常传递。 Bug Fixes: - 修复 BetterGI 和 ZZZ-OD 任务错误提示因使用已移除的 WebSocket 配置接口而无法发送,导致前端显示无关的属性错误。 Enhancements: - 统一将 BetterGI 和 ZZZ-OD 的任务通知迁移到现行 Publisher WebSocket 出口,并使用标准化任务通知格式。 <details> <summary>Original summary in English</summary> ## Summary by Sourcery 将 BetterGI 和 ZZZ-OD 的错误通知迁移到 Publisher,恢复真实任务错误信息向前端的正常传递。 Bug Fixes: - 修复 BetterGI 和 ZZZ-OD 任务错误提示因使用已移除的 WebSocket 配置接口而无法发送,导致前端显示无关的属性错误。 Enhancements: - 统一将 BetterGI 和 ZZZ-OD 的任务通知迁移到现行 Publisher WebSocket 出口,并使用标准化任务通知格式。 </details> <details> <summary>Original summary in English</summary> </details> <details> <summary>Original summary in English</summary> </details> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: AthenaHibou <13084046220@163.com>
概述
新增 BetterGI(更好的原神)脚本专项适配,采用原生 GUI 直控模式:账号由 BetterGI 原生管理,本系统为每个用户独立管理「一条龙」任务配置、自定义配置组、账号切换与通知。
主要变更
User/AutoFight/*.txt版本记录
res/version.json同步登记 BetterGI 专项新增功能。详见
文档站同步新增 BetterGI 配置方法。
Sourcery 摘要
新增端到端的 BetterGI 支持,包括原生 GUI 控制、按用户的 One Dragon 自定义、账号切换、执行监控以及专用管理界面。
新功能:
Bug 修复:
增强:
构建:
文档:
测试:
日常维护:
Original summary in English
Summary by Sourcery
Add end-to-end BetterGI support with native GUI control, per-user One Dragon customization, account switching, execution monitoring, and dedicated management interfaces.
New Features:
Bug Fixes:
Enhancements:
Build:
Documentation:
Tests:
Chores: