feat: convert MAA GUI profiles to maa-cli task config file - #559
Conversation
Introduce gui::convert for TaskQueue profiles with StartUp and Fight mappings, plus a default GUI profile fixture for regression tests. Co-authored-by: Cursor <cursoragent@cursor.com>
Wire gui::convert behind convert -g, map Infrast/Recruit/Mall/Award/ Roguelike/Reclamation from GUI TaskQueue, and align StartUp output with daily.json input templates. Co-authored-by: Cursor <cursoragent@cursor.com>
The --gui flag targets MAA GUI profile JSON files; warn users when the input uses another format. Co-authored-by: Cursor <cursoragent@cursor.com>
Prompt users to pick a configuration when converting GUI profiles with multiple entries; use Current as the default in batch mode. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Hey - 我发现了 1 个问题,并给出了一些总体反馈:
- GUI 转换辅助函数在每个子模块中都重新实现了大量几乎相同的测试工具(临时文件读写、JSON 加载/存储);建议将这些工具集中到一个共享的测试辅助模块中,以减少重复并让测试更易维护。
- 在
convert_task中,未知的 GUI$type条目会被静默丢弃;可以考虑记录日志或以其他方式暴露被跳过的任务类型,这样用户就能理解为什么某些 GUI 任务没有出现在生成的配置中。 - 通过
SelectD的交互式select_configuration提示在非交互环境(例如自动化场景)中会阻塞;建议增加一个标志或基于环境变量的覆盖机制,当存在多个配置项时可以以非交互方式选择配置。
给 AI Agent 的提示
请根据以下代码审查评论进行修改:
## 总体评论
- GUI 转换辅助函数在每个子模块中都重新实现了大量几乎相同的测试工具(临时文件读写、JSON 加载/存储);建议将这些工具集中到一个共享的测试辅助模块中,以减少重复并让测试更易维护。
- 在 `convert_task` 中,未知的 GUI `$type` 条目会被静默丢弃;可以考虑记录日志或以其他方式暴露被跳过的任务类型,这样用户就能理解为什么某些 GUI 任务没有出现在生成的配置中。
- 通过 `SelectD` 的交互式 `select_configuration` 提示在非交互环境(例如自动化场景)中会阻塞;建议增加一个标志或基于环境变量的覆盖机制,当存在多个配置项时可以以非交互方式选择配置。
## 具体评论
### 评论 1
<location path="crates/maa-cli/src/config/gui.rs" line_range="71-80" />
<code_context>
+ Ok(object!("tasks" => tasks??))
+}
+
+fn convert_task(task: &MAAValue) -> Result<Option<MAAValue>> {
+ // GUI task discriminator, e.g. "FightTask"
+ let type_tag = task
+ .get("$type")
+ .and_then(|v| v.as_str())
+ .context("GUI task missing $type")?;
+ match type_tag {
+ "StartUpTask" => start_up::convert_start_up_task(task),
+ "FightTask" => fight::convert_fight_task(task),
+ "InfrastTask" => infrast::convert_infrast_task(task),
+ "RecruitTask" => recruit::convert_recruit_task(task),
+ "MallTask" => mall::convert_mall_task(task),
+ "AwardTask" => award::convert_award_task(task),
+ "RoguelikeTask" => roguelike::convert_roguelike_task(task),
+ "ReclamationTask" => reclamation::convert_reclamation_task(task),
+ _ => Ok(None),
+ }
</code_context>
<issue_to_address>
**suggestion (bug_risk):** 静默丢弃未知的 GUI 任务类型可能会隐藏配置问题;建议至少记录一条日志。
在 `convert_task` 中,未匹配到的 `$type` 会返回 `Ok(None)`,因此相关任务会被静默丢弃:
```rust
match type_tag {
// ...
"ReclamationTask" => reclamation::convert_reclamation_task(task),
_ => Ok(None),
}
```
为避免隐藏配置错误或新增加的任务类型,请至少增加一条 `log::warn!`,包含 `$type`(以及可能的标识符如 `Name`)。你可以暂时保留当前宽松的行为,之后再通过一个标志在“警告”与“未知类型视为硬错误”之间切换。
建议实现:
```rust
fn convert_task(task: &MAAValue) -> Result<Option<MAAValue>> {
// GUI task discriminator, e.g. "FightTask"
let type_tag = task
.get("$type")
.and_then(|v| v.as_str())
.context("GUI task missing $type")?;
match type_tag {
"StartUpTask" => start_up::convert_start_up_task(task),
"FightTask" => fight::convert_fight_task(task),
"InfrastTask" => infrast::convert_infrast_task(task),
"RecruitTask" => recruit::convert_recruit_task(task),
"MallTask" => mall::convert_mall_task(task),
"AwardTask" => award::convert_award_task(task),
"RoguelikeTask" => roguelike::convert_roguelike_task(task),
"ReclamationTask" => reclamation::convert_reclamation_task(task),
_ => {
let name = task
.get("Name")
.and_then(|v| v.as_str())
.unwrap_or("<unknown>");
log::warn!(
"Unknown GUI task type `{}` (Name: `{}`); skipping task",
type_tag,
name
);
Ok(None)
}
}
}
```
如果本模块尚未使用 `log` crate,请确保:
1. 在 `Cargo.toml` 中已添加 `log` 依赖(很可能已经存在)。
2. 在可执行程序中初始化了某个日志实现(例如 `env_logger`、`tracing` 的桥接等),以确保 `log::warn!` 实际能输出日志。
由于函数签名与返回行为保持不变(未知类型仍返回 `Ok(None)`),因此不需要对调用方做进一步修改。
</issue_to_address>帮我变得更有用!请对每条评论点击 👍 或 👎,我会根据你的反馈改进后续审查。
Original comment in English
Hey - I've found 1 issue, and left some high level feedback:
- The GUI conversion helpers reimplement a lot of near-identical test utilities (temp file write/read, JSON load/store) in each submodule; consider centralizing these into a shared test helper to reduce repetition and keep the tests easier to maintain.
- Unknown GUI
$typeentries are silently dropped inconvert_task; it might be helpful to log or otherwise surface that a task type was skipped so users understand why some GUI tasks did not appear in the generated config. - The interactive
select_configurationprompt viaSelectDwill block in non-interactive contexts (e.g. automation); consider adding a flag or environment-based override to select a configuration non-interactively when multiple entries exist.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The GUI conversion helpers reimplement a lot of near-identical test utilities (temp file write/read, JSON load/store) in each submodule; consider centralizing these into a shared test helper to reduce repetition and keep the tests easier to maintain.
- Unknown GUI `$type` entries are silently dropped in `convert_task`; it might be helpful to log or otherwise surface that a task type was skipped so users understand why some GUI tasks did not appear in the generated config.
- The interactive `select_configuration` prompt via `SelectD` will block in non-interactive contexts (e.g. automation); consider adding a flag or environment-based override to select a configuration non-interactively when multiple entries exist.
## Individual Comments
### Comment 1
<location path="crates/maa-cli/src/config/gui.rs" line_range="71-80" />
<code_context>
+ Ok(object!("tasks" => tasks??))
+}
+
+fn convert_task(task: &MAAValue) -> Result<Option<MAAValue>> {
+ // GUI task discriminator, e.g. "FightTask"
+ let type_tag = task
+ .get("$type")
+ .and_then(|v| v.as_str())
+ .context("GUI task missing $type")?;
+ match type_tag {
+ "StartUpTask" => start_up::convert_start_up_task(task),
+ "FightTask" => fight::convert_fight_task(task),
+ "InfrastTask" => infrast::convert_infrast_task(task),
+ "RecruitTask" => recruit::convert_recruit_task(task),
+ "MallTask" => mall::convert_mall_task(task),
+ "AwardTask" => award::convert_award_task(task),
+ "RoguelikeTask" => roguelike::convert_roguelike_task(task),
+ "ReclamationTask" => reclamation::convert_reclamation_task(task),
+ _ => Ok(None),
+ }
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Silently dropping unknown GUI task types may hide configuration issues; consider at least logging them.
In `convert_task`, unmatched `$type` values return `Ok(None)`, so those tasks are dropped silently:
```rust
match type_tag {
// ...
"ReclamationTask" => reclamation::convert_reclamation_task(task),
_ => Ok(None),
}
```
To avoid hiding misconfigured or new task types, please add at least a `log::warn!` including the `$type` (and possibly an identifier like `Name`). You can keep the tolerant behavior now and later introduce a flag if you want to switch between warning and hard error for unknown types.
Suggested implementation:
```rust
fn convert_task(task: &MAAValue) -> Result<Option<MAAValue>> {
// GUI task discriminator, e.g. "FightTask"
let type_tag = task
.get("$type")
.and_then(|v| v.as_str())
.context("GUI task missing $type")?;
match type_tag {
"StartUpTask" => start_up::convert_start_up_task(task),
"FightTask" => fight::convert_fight_task(task),
"InfrastTask" => infrast::convert_infrast_task(task),
"RecruitTask" => recruit::convert_recruit_task(task),
"MallTask" => mall::convert_mall_task(task),
"AwardTask" => award::convert_award_task(task),
"RoguelikeTask" => roguelike::convert_roguelike_task(task),
"ReclamationTask" => reclamation::convert_reclamation_task(task),
_ => {
let name = task
.get("Name")
.and_then(|v| v.as_str())
.unwrap_or("<unknown>");
log::warn!(
"Unknown GUI task type `{}` (Name: `{}`); skipping task",
type_tag,
name
);
Ok(None)
}
}
}
```
If the `log` crate is not yet used in this module, ensure that:
1. The `log` dependency is present in `Cargo.toml` (likely already is).
2. A logger implementation (e.g. `env_logger`, `tracing` bridge, etc.) is initialized in your binary so that `log::warn!` actually emits output.
No further changes to callers are required since the function signature and return behavior remain the same (`Ok(None)` for unknown types).
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
- warn when skipping unsupported GUI task $type values - add --gui-config flag and MAA_GUI_CONFIG env for non-interactive multi-profile selection - merge pick_configuration into select_configuration - consolidate per-task tests into gui::tests with gui_task_test! macro
|
本次修改采纳了 @sourcery-ai 的部分优化建议: English versionThis PR incorporates several optimization suggestions from @sourcery-ai: Added a gui_config flag that accepts a string to specify particular configuration files, preventing potential blocking issues. |
|
Tested on my local environment, everything works as expected. 在我的设备上进行了测试,运行正常。 Test Logs / 测试日志Converted config / 转换的配置[[tasks]]
type = "StartUp"
[tasks.params.client_type]
alternatives = [
"Official",
"YoStarEN",
"YoStarJP",
]
description = "a client type"
[tasks.params.client_type.deps]
start_game_enabled = true
[tasks.params.start_game_enabled]
default = true
description = "start the game"
[[tasks]]
type = "Fight"
name = "日常经验本"
strategy = "merge"
[[tasks.variants]]
[tasks.variants.condition]
type = "Weekday"
weekdays = [
"Mon",
"Wed",
"Fri",
]
[tasks.variants.params]
stage = "LS-6"
medicine_expire_days = 2
[[tasks]]
type = "Fight"
name = "日常龙门币"
strategy = "merge"
[[tasks.variants]]
[tasks.variants.condition]
type = "Weekday"
weekdays = [
"Tue",
"Thu",
"Sat",
]
[tasks.variants.params]
stage = "CE-6"
medicine_expire_days = 2
[[tasks]]
type = "Infrast"
name = ""
[tasks.params]
mode = 0
facility = [
"Mfg",
"Trade",
"Control",
"Power",
"Reception",
"Office",
"Dorm",
"Processing",
"Training",
]
drones = "Money"
threshold = 0.3
replenish = true
dorm_notstationed_enabled = true
dorm_trust_enabled = true
reception_message_board = true
reception_clue_exchange = true
reception_send_clue = true
[[tasks]]
type = "Recruit"
name = ""
[tasks.params]
times = 4
extra_tags_mode = 0
refresh = true
expedite = true
select = [
5,
4,
3,
]
confirm = [
5,
4,
3,
]
[tasks.params.recruitment_time]
4 = 540
3 = 540
[[tasks]]
type = "Mall"
name = ""
[tasks.params]
shopping = true
credit_fight = false
formation_index = 0
visit_friends = true
buy_first = [
"加急许可",
"招聘许可",
]
blacklist = [
"碳",
"家具",
]
force_shopping_if_credit_full = true
only_buy_discount = false
reserve_max_credit = false
[[tasks]]
type = "Award"
name = ""
[tasks.params]
award = true
mail = true
recruit = false
orundum = true
mining = true
specialaccess = true |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #559 +/- ##
==========================================
- Coverage 72.36% 68.99% -3.38%
==========================================
Files 72 82 +10
Lines 6804 7869 +1065
Branches 6804 7869 +1065
==========================================
+ Hits 4924 5429 +505
- Misses 1537 2059 +522
- Partials 343 381 +38 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
wangl-cc
left a comment
There was a problem hiding this comment.
感谢贡献,我大概看了一下这个 PR。这个功能的方向是有价值的,不过还有几个需要修正的问题。
-
目前
maa convert的职责是保持数据结构不变,只在 TOML、YAML 和 JSON 之间转换序列化格式;这里实际上是在解析 MAA WPF GUI 的配置结构,将TaskQueue中的任务和字段映射成 maa-cli v1 task config。转换过程中还会选择 GUI configuration、重组字段,并可能跳过不支持的任务,因此更接近一次有损的语义迁移。我倾向于将命令调整为:
maa migrate wpf <input> [output]这样可以清楚地区分:
convert:同一数据结构之间的 TOML/YAML/JSON 格式转换;migrate:从外部配置模型迁移到 maa-cli 配置模型;import:将已有配置安装到 maa-cli 的配置目录。
-
当前迁移是有损的,部分影响执行的参数没有处理,但用户无法知道具体丢失了什么。第一版不一定支持所有字段,但是应该在汇总被跳过的任务和字段。否则生成的文件可以解析,执行行为可能与原 GUI 配置不同。
-
禁用任务会在迁移后变成可执行任务。当前
IsEnable = false只会产生 warning,任务仍然会写入,而且没有保留禁用语义。这可能导致用户迁移后意外执行原本关闭的肉鸽、生息演算等任务。
|
此外,你可以需要 rebase 或者 merge 一下 main,CI 里面有很多在 main 里面修复的问题。 |
Retarget GUI migration to maa migrate wpf and the newer gui.new.json shape from maa v6.16.3. StartUp now maps RuntimeSettings ClientType / StartGame and conditional AccountName; other task types remain as-is for follow-up. zh: 按 maa v6.16.3 重构 WPF 迁移,并完成 StartUp 相关逻辑
Wire UseWeeklySchedule and UseOptionalStage into Fight variants Map medicine, stone, times, drops, series, and expiring medicine into shared params Derive per-stage Always/Weekday/OnSideStory conditions via StageActivityV2 Document the Fight migration rules in zh-CN migrate.md 从 WPF 战斗任务迁移关卡变体与开放条件,并补充中文文档
Add maa migrate wpf for semantic migration from GUI TaskQueue Preserve disabled tasks with Never conditions and report skipped fields Map Fight stage variants, shared params, and open-day conditions Reject unsupported custom Infrast plans instead of silently dropping them Document WPF task mappings in zh-CN migrate.md 将 WPF GUI 任务迁移为 maa-cli 配置,并补充跳过汇总与中文文档
|
抱歉鸽了一段时间。现在接口都和您描述的一样了,然后我才发现gui有一些选择关卡的逻辑,补充了这部分。下面是ai的总结: 对审查意见的回应1. 认同原先放在
迁移流程包括:多配置选择( 2. 有损迁移需要可见汇总 第一版不要求覆盖全部 GUI 字段,但迁移结束会输出摘要,包括:
这样生成的配置即使可解析,用户也能对照摘要检查与原 GUI 行为的差异。 3. 禁用任务不能变成可执行
本 PR 主要能力
|
|
然后我还没测试,可能明天吧。跑粥的实体机炸了... |
Use if-let for single-pattern StartGame matching Prefer slice to_vec for Weekday condition weekdays 修复 WPF 迁移中的 clippy 警告
Skip gui.new.json so upstream GUI field names do not fail spellcheck Keep CI typos/rustfmt checks green for the migrate branch 对 typos 排除 WPF GUI 示例文件使其通过并让 rustfmt 检查通过
|
感谢贡献,但是现在这个版本未来的维护成本太高了, #[derive(Deserialize)]
#[serde(rename_all = "PascalCase")]
struct WpfFightTask {
name: Option<String>,
is_enable: Option<bool>,
// Other known fields ...
#[serde(flatten)]
unknown: BTreeMap<String, serde_json::Value>,
}
enum WpfTask {
StartUp(WpfStartUpTask),
Fight(WpfFightTask),
Infrast(WpfInfrastTask),
Recruit(WpfRecruitTask),
// ...
Unsupported {
type_tag: String,
raw: serde_json::Value,
},
}然后直接使用 serde 来反序列化整个 然后直接对这些是 struct 来实现 trait ToCliconfig {}
impl ToCliConfig for WpfTask {}这样的做法,应该会更清晰一点。 |
zh: 删除default_profile.json example
Move the CLI entry into wpf.rs and parse profiles as serde_json::Value first Drop --format and MAA_GUI_CONFIG; default to adjacent .toml when output is omitted Require .json input and take the selected configuration by ownership 重构 WPF 迁移入口并简化配置选择与输出路径
Build CLI Fight output from FightCliTask/FightParams and From/TryFrom instead of MAAValue insert trees. Serialize Condition/TimeOffset/ClientType so weekly and stage open conditions stay typed. Remove the legacy MAAValue Fight path and temporary parity tests until a unified suite lands. 将 WPF Fight 迁移改为原型结构体序列化,并移除旧路径与临时测试
Migrate remaining Infrast/Recruit/Mall/Award/Roguelike/Reclamation via Wpf*/Cli* structs and From/TryFrom. Reuse Fight/StartUp patterns with Gui.RuntimeSettings for StartUp and shared unknown-field reporting. Drop legacy MAAValue insert paths; keep Unsupported types skipped in the migration summary. 完成 WPF GUI 任务迁移的结构化实现,并覆盖剩余任务类型
Put shared Fight options on task params so variants only select stages. Drop ForceRefresh→expedite mapping and warn on unsupported/dangerous recruit settings. Add zh-CN WPF migrate docs and refresh the example output. 修正 WPF 理智作战/公招迁移并补充中文文档
|
现在所有转换都通过类型了,路径是json->wpf类型->cli类型。然后ToCliconfig 没实现,wpf到cli用TryFrom。感觉专门写一个ToCliconfig 没啥必要?然后之前那个2k行其实是包含测试的,现在这个版本1.6k行不包含,如果这版没问题我再写测试。虽然代码更多了,但有一说一确实靠结构体约束转换行为更容易维护。 文档删除了一些细节,现在主要讲需要特殊处理的部分。 这是ai总结: 针对维护性反馈的重构说明本段改动按该方向重写了 WPF GUI → maa-cli 的迁移路径:不再用大量 范围
设计对齐审核建议的核心是:
当前实现基本按此落地,细节如下。 入口与整体反序列化
按任务分模块
未单独引入名为 相关支撑改动
CLI / 入口行为(顺带简化)
映射与语义修正(相对旧实现)在结构化重写之外,也修正了若干迁移语义,并写入
文档与示例
提交序列(便于按步 review)
建议审核关注点
|
Change the series field in the fight configuration from an optional type to a required i32
|
@wangl-cc 要不你看看这个写法有没有什么问题?没问题我就继续了,虽然好像只有单元测试了。 |
不好意思,我最近比较忙,我尽快今晚或者明天抽空看一下。 |
Read the schedule JSON during `maa migrate wpf` and emit plan_index variants. Add `--custom-schedule` to override Filename when the profile is already custom. Expand `~` in schedule paths; fail if the override is set on a non-custom profile. 从 WPF 迁移自定义基建排班,支持 --custom-schedule 覆盖排班文件。
wangl-cc
left a comment
There was a problem hiding this comment.
感谢根据我的建议进行的重构,改成 Typed Serde 确实好一点。我大概看了一下,提出了几个我注意到的意见。不过具体每个每个 task 我还没有来的及看完,我让 AI 看了一下。他提出来几个意见:
-
WpfFightTask 虽然使用 flatten 收集了未知字段,但迁移时只调用了 report_disabled,没有调用未知字段报告逻辑。当前示例中的 UseCustomAnnihilation = true 和 AnnihilationStage 会被静默丢弃,迁移摘要中没有提示。这应该是 typed 重构过程中遗漏的调用,请补充报告并增加回归测试。
-
可选活动关卡生成的 OnSideStory 条件仍然不够准确。迁移时会从活动数据中收集所有历史活动关卡,但运行时的 OnSideStory 只判断当前是否有任意 SideStory 开放。因此另一个活动开放时,已经关闭的活动关卡也可能满足条件。这里需要保留关卡与具体活动之间的关联,或者暂时不要将这类关卡转换成通用的 OnSideStory。
-
未支持任务使用 #[serde(other)] Unsupported 后,原始 $type 和 Name 会丢失。例如 UserDataUpdateTask 在摘要中只会显示为 Unsupported。建议保留真实任务类型和名称,否则用户无法判断具体丢失了哪个任务。
这里面第二条可能目前也没办法直接匹配,CLI 没有类似的功能,所以可以先不管。
| output: Option<PathBuf>, | ||
| /// Select a named configuration when migrating a multi-profile GUI export | ||
| #[arg(long)] | ||
| config: Option<String>, |
| } | ||
|
|
||
| /// Print a user-facing summary of lossy migration decisions to stderr. | ||
| pub fn print(&self) { |
| let Some(configurations) = input.get_mut("Configurations") else { | ||
| bail!("GUI profile missing Configurations"); |
There was a problem hiding this comment.
这里应该可以直接 get_mut(xx).context(msg). 其他地方的 let Some(xxx) = xxx else { bail } 也应该改一下。
| } | ||
| } | ||
|
|
||
| mod fight { |
There was a problem hiding this comment.
我更倾向于每一个 mod 放在一个单独的文件,而不是全都挤在这个文件里面。加上测试之后可能 4000 行打不住。
| let value = BufReader::new(std::fs::File::open(file).context("Trying to open wpf profile")?); | ||
| let value = serde_json::from_reader(value)?; |
There was a problem hiding this comment.
最外层的 WpfConfig 也可以结构化一下,而不是先反序列化成 json value。此外也可以验证一下 config_version 如果 Wpf 的配置 bump 了可能就不匹配。类似于这样:
#[derive(Debug, Deserialize)]
#[serde(rename_all = "PascalCase")]
struct WpfProfile {
config_version: u32,
#[serde(default)]
current: Option<String>,
configurations: BTreeMap<String, WpfConfiguration>,
#[serde(flatten)]
unknown: Map<String, Value>,
}| "`maa migrate wpf` expected a MAA GUI profile (typically .json); input {file:?} is not a JSON file" | ||
| ); | ||
|
|
||
| let value = BufReader::new(std::fs::File::open(file).context("Trying to open wpf profile")?); |
There was a problem hiding this comment.
没有必要 buffer reader,File 本身就可以 read。
Split `migrate/wpf.rs` into per-task modules under `migrate/wpf/`. Read side-story expire time from StageActivityV2.json at migrate time instead of emitting OnSideStory; fail after hot-update if the activity file cannot be read. Rename migrate `--config` to `--profile-name`. 将 WPF 活动关迁移为 DateTime 截止时间,并拆分 migrate/wpf 模块。
|
ok,这些都做完了,测试也覆盖了,大概率没问题。但最近黑流树海的肉鸽选项在beta版的wpf更新了,等他们把协议文档补充后我会新增上去。到时候再合? 以下是ai总结: Inline comments
AI 补充的三点
|
Add comprehensive tests for Fight, Mall, Reclamation, Recruit, and Roguelike tasks, ensuring correct mapping of parameters and handling of optional fields. Validate behavior for shared parameters, stage plans, and error handling for invalid configurations. Improve overall test coverage for WPF migration functionality.
…eat/get-config-from-gui
Summary
This PR adds GUI profile conversion to
maa-cliby mapping MAA GUITaskQueueentries into maa-cli task config shape, exposed throughmaa convert -g.It lets users take an existing GUI profile node (specifically
gui.new.json, located inMAA_ROOT_DIR\configfor Windows MAA) and produce editable TOML/YAML/JSON task configs without hand-rewriting every field. Since this file stores the full configuration of the GUI program, converting it into a format supported bymaa-clisaves significant manual migration effort.What changed
maa convert -g/--guiflag to theConvertsubtask incrates/maa-cli/src/command.rsto run GUI conversion only when explicitly requestedcrates/maa-cli/src/config/gui.rswhich contains the logic to transform specified GUI profile nodes into maa-cli v1 configs, including 9 unit tests targeting this new logicWhy
MAA GUI stores task settings in its own profile JSON shape, while
maa-cliexpects task configs with typed params, variants, and input templates.Users who start from a GUI profile currently have no supported path to move those settings into
maa-cliconfigs. This closes that gap by providing a deterministic conversion layer instead of manual migration.User impact
This PR introduces the new
-g/--guiflag. Users can now run:If the input file is not a JSON file but the flag is enabled, a notice will be printed:
The --gui flag is for converting MAA GUI profiles, which are typically JSON files; input <input file path> is not JSONIf a task within the GUI profile is disabled (
IsEnableis false), the conversion layer will still process and include it in the final output, but it will emit a warning notification during the process.Furthermore, if the GUI profile contains multiple configurations under
ROOT.Configurations, the command-line interface will prompt the user to interactively select which node they want to convert:The output is a normal
maa-clitask config file that can be edited, versioned, and used with existingmaa-cliworkflows.Validation
cargo test -p maa-cli gui::9 passed, 0 failed
cargo test -p maa-cli convert4 passed, 0 failed
Manual validation
cargo run -- convert -g crates/maa-cli/fixtures/gui/default_profile.json /tmp/t.tomlcargo run -- convert -g crates/maa-cli/fixtures/gui/default_profile.json /tmp/y.yamlNotes
gui.rsis renaming these fields, converting specific fields intocondition, and placing others intoparams. I have roughly checked all fields, and theoretically none should cause MaaCore errors, though I will conduct actual integration testing later today or tomorrow. If you think it is necessary, I can write a document detailing the handling of each key in the GUI profile.config-v2. I am willing to continue working on this feature onceconfig-v2stabilizes, enabling the GUI profile to convert directly into theconfig-v2format.Summary by Sourcery
摘要 (Summary)
本 PR 为
maa-cli增加了 GUI 配置转换功能。该功能通过将 MAA GUI 的TaskQueue项映射到maa-cli的任务配置结构中,并通过maa convert -g命令对外提供。它允许用户直接使用现有的 GUI 配置文件(具体为
gui.new.json,对于 Windows MAA,该文件位于MAA_ROOT_DIR\config)并生成可编辑的 TOML/YAML/JSON 任务配置,无需手动重写每个字段。由于该文件存储了 GUI 程序的全部配置内容,能够将其转换为maa-cli支持的格式可以大幅节省手动配置的时间成本。变更内容 (What changed)
crates/maa-cli/src/command.rs处的Convert子任务中添加一个名为gui的 flag,引入maa convert -g/--gui参数,仅在明确请求时才执行 GUI 转换。crates/maa-cli/src/config/gui.rs,文件包含将所有 GUI profile 指定节点变换为maa-cliv1 config 的逻辑,并且包含 9 个关于新逻辑的测试。变更原因 (Why)
MAA GUI 将任务设置存储在自有的配置文件 JSON 结构中,而
maa-cli则期望任务配置具备类型化的参数、变体和输入模板。目前,从 GUI 配置文件开始使用的用户没有一条受支持的途径将这些设置迁移到
maa-cli配置中。本 PR 通过提供一个确定性的转换层来填补这一空白,从而免去了手动迁移的麻烦。用户影响 (User impact)
本 PR 引入了新的
-g/--gui标志。用户现在可以运行:如果输入文件不是 JSON 文件但开启了该标志,程序将会输出一条提示信息:
The --gui flag is for converting MAA GUI profiles, which are typically JSON files; input <input file path> is not JSON如果 GUI profile 中的某个任务被禁用(
IsEnable为 false),转换层在转换中仍会接受并包含它,但在过程中会输出一条警告提示。此外,如果 GUI profile 中包含多个配置(指
ROOT.Configurations有多个子项),命令行界面将会提示用户交互式地选择需要被转换的节点:输出是一个正常的
maa-cli任务配置文件,可以进行编辑、版本控制,并用于现有的maa-cli工作流中。验证 (Validation)
cargo test -p maa-cli gui::9 通过, 0 失败
cargo test -p maa-cli convert4 通过, 0 失败
手动验证 (Manual validation)
cargo run -- convert -g crates/maa-cli/fixtures/gui/default_profile.json /tmp/t.tomlcargo run -- convert -g crates/maa-cli/fixtures/gui/default_profile.json /tmp/y.yaml注意事项 (Notes)
gui.rs的主要任务就是将 these 字段重命名。并且特定字段转换为condition,其他放到params。我粗略的检查过所有字段,这些理论上都不会引起 MaaCore 报错,但今天稍晚或是明天我才会实际进行测试。如果你们认为有必要,我可以去写一个文档讲述对 GUI profile 每个键的处理细节。config-v2。我愿意在config-v2稳定后为这个功能继续编写代码,让 GUI profile 直接转为config-v2格式的配置文件。Summary by Sourcery
在 maa-cli 中新增支持,通过新的 CLI 标志将 MAA GUI 配置文件转换为 maa-cli 任务配置文件。
新功能:
maa convert命令引入-g/--gui标志,用于触发 GUI 配置转换。TaskQueue条目转换为 maa-cli v1 任务配置结构,包括对多配置文件(multi-configuration profiles)的交互式选择处理。增强:
--gui标志以及在转换被禁用的 GUI 任务时发出警告,以改进用户反馈。测试:
Original summary in English
Summary by Sourcery
Add support in maa-cli to convert MAA GUI profiles into maa-cli task configuration files via a new CLI flag.
New Features:
Enhancements:
Tests: