Skip to content

Perf(maaend): 清理代码并修改日志导出 - #545

Open
HarcoChen wants to merge 3 commits into
AUTO-MAS-Project:devfrom
HarcoChen:perf/maaend
Open

Perf(maaend): 清理代码并修改日志导出#545
HarcoChen wants to merge 3 commits into
AUTO-MAS-Project:devfrom
HarcoChen:perf/maaend

Conversation

@HarcoChen

@HarcoChen HarcoChen commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

清理了MaaEnd Autoproxy代码逻辑,删掉一些没意义的分支
修改导出日志逻辑,现在允许大文件导出

Sourcery 总结

优化 MaaEnd AutoProxy 执行流程,并将问题报告生成切换为流式归档,以更可靠地导出大型日志。

新功能:

  • 支持问题报告 ZIP 导出处理大型文件,不再受单个文件或整个归档的固定大小限制。

错误修复:

  • 改进 MaaEnd 任务结果跟踪,并更新重试处理逻辑,使任务完成和更新运行能够更可靠地完成。
  • 在应用用户特定的自动化配置时,保留本地 MaaEnd 运行时元数据。

增强功能:

  • 重构 MaaEnd AutoProxy 配置、任务选择、进程清理和奖励选项处理逻辑,以简化执行流程并减少冗余分支。
  • 使用流式 ZIP 写入器生成问题报告,以减少归档生成过程中的内存累积。
  • 统一 AutoProxy 运行时的 MaaEnd 实例选择和配置验证。

杂项:

  • 重命名并重构 MaaEnd 奖励集常量及相关选项映射。
  • 调整延迟加载的工具导出和资源加载器缓存处理。
Original summary in English

Sourcery 总结

优化 MaaEnd 自动代理的执行可靠性,并改进问题报告生成以支持大型日志导出。

新功能:

  • 支持以流式方式生成问题报告 ZIP,允许导出大型日志和诊断文件。

错误修复:

  • 改进 MaaEnd 任务结果跟踪、更新后的自动重试以及用户配置应用时本地运行时元数据的保留。

增强功能:

  • 简化 MaaEnd AutoProxy 的任务配置、实例选择、进程清理和奖励选项处理流程。
  • 统一 MaaEnd 配置校验、资源加载缓存和延迟工具导出逻辑。

日常维护:

  • 重构 MaaEnd 奖励组选项常量及相关映射。
Original summary in English

Summary by Sourcery

优化 MaaEnd 自动代理的执行可靠性,并改进问题报告生成以支持大型日志导出。

New Features:

  • 支持以流式方式生成问题报告 ZIP,允许导出大型日志和诊断文件。

Bug Fixes:

  • 改进 MaaEnd 任务结果跟踪、更新后的自动重试以及用户配置应用时本地运行时元数据的保留。

Enhancements:

  • 简化 MaaEnd AutoProxy 的任务配置、实例选择、进程清理和奖励选项处理流程。
  • 统一 MaaEnd 配置校验、资源加载缓存和延迟工具导出逻辑。

Chores:

  • 重构 MaaEnd 奖励组选项常量及相关映射。
Original summary in English

- 清理了一下MaaEnd的没啥用的死代码
- 移除导出日志包的限制
@sourcery-ai

sourcery-ai Bot commented Sep 3, 2026

Copy link
Copy Markdown

审查者指南

本 PR 重构 MaaEnd AutoProxy 的配置与任务执行流程,集中处理任务结果、更新重试、进程清理及本地运行时元数据保留;同时以自定义逐条写盘的 ZIP writer 替换 AdmZip,取消问题报告的固定大小限制并降低大型日志归档的内存占用。

流式导出问题报告 ZIP 的时序图

sequenceDiagram
    participant Service as IssueReportService
    participant Core as issueReportCore
    participant Writer as StreamingZipWriter
    participant Disk as ZIPFile

    Service->>Core: createCollector(zipPath)
    Core->>Writer: new StreamingZipWriter(zipPath)
    Service->>Core: addDirectory / addDiagnosticFile
    Core->>Writer: addBuffer(archivePath, content)
    Core->>Writer: addFile(archivePath, sourcePath)
    Writer->>Disk: write ZIP entry immediately
    Service->>Writer: finalize()
    Writer->>Disk: write central directory and close
Loading

MaaEnd AutoProxy 任务重试与结果跟踪的时序图

sequenceDiagram
    participant AutoProxyTask
    participant MaaEnd
    participant LogMonitor
    participant ProcessManager

    AutoProxyTask->>AutoProxyTask: set_maaend(device_info)
    AutoProxyTask->>MaaEnd: asyncio.create_subprocess_exec(--autostart, --instance, AUTO-MAS)
    MaaEnd-->>LogMonitor: task start / complete / failure logs
    LogMonitor->>AutoProxyTask: check_log(log)
    AutoProxyTask->>AutoProxyTask: parse_task_result()
    alt MaaEnd 正在更新
        AutoProxyTask->>AutoProxyTask: kill_maaend_process()
        AutoProxyTask->>MaaEnd: restart current user once
    else Success!
        AutoProxyTask->>AutoProxyTask: kill_maaend_process()
    else task failure
        AutoProxyTask->>ProcessManager: kill_managed_process()
    end
Loading

保留 MaaEnd 运行时元数据的流程图

flowchart LR
    Local["本机 MaaEnd 配置"] --> Merge["读取并继承 version、interfaceTaskSnapshot、welcomeShownHash"]
    User["用户自动化配置"] --> Merge
    Merge --> Validate["验证 MaaEnd 实例与任务配置"]
    Validate --> Write["写入运行配置"]
    Write --> Run["使用 AUTO-MAS 启动"]
Loading

文件级变更

变更 详细信息 文件
重构 MaaEnd AutoProxy 的配置、任务执行和进程生命周期管理,减少重复分支并提高重试与结果跟踪可靠性。
  • 统一用户账号、配置路径及 AUTO-MAS 实例处理。
  • 抽取本地运行时元数据继承和理智任务选项配置逻辑。
  • 缓存首轮任务状态并集中解析任务完成/失败日志。
  • 拆分 MaaEnd 进程清理与全部关联进程清理,并调整更新重试和后置脚本流程。
  • 改进更新日志记录清理及任务完成后的历史日志处理。
app/task/MaaEnd/AutoProxy.py
app/task/MaaEnd/manager.py
将 MaaEnd 奖励组选项映射集中化,并同步配置标签解析使用新常量。
  • 以关卡到选项及奖励组值的映射替换硬编码分支。
  • 更新配置标签生成和 AutoProxy 任务选项写入逻辑。
app/utils/constants.py
app/models/config.py
app/task/MaaEnd/AutoProxy.py
改进 MaaEnd 资源与工具模块的缓存和导出机制。
  • 调整资源加载器的内存缓存、磁盘缓存和强制重载优先级。
  • 将工具模块的延迟导出补充为类型检查时可见的声明。
app/task/MaaEnd/resource_loader.py
app/utils/__init__.py
以自定义流式 ZIP 写入器替换 AdmZip,支持大型问题报告并降低归档生成期间的累计内存。
  • 移除单文件和总归档大小限制及截断/跳过状态。
  • 支持将文件逐条写入 ZIP,并在结束时生成中央目录。
  • 统一 MaaEnd、OK-NTE 和 OK-WW 报告服务的创建、收集和 finalize 流程。
frontend/electron/services/streamingZip.ts
frontend/electron/services/issueReportCore.ts
frontend/electron/services/maaEndIssueReportService.ts
frontend/electron/services/okNteIssueReportService.ts
frontend/electron/services/okwwIssueReportService.ts
更新版本资源。
  • 调整应用版本元数据。
res/version.json

可能关联的问题

  • #MAAEND专项:PR 直接修复任务完成状态判断及代理结束流程,与 Issue 中未正确结束代理任务的问题完全一致。

提示与命令

与 Sourcery 交互

  • 触发新的审查: 在拉取请求中评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审查评论。
  • 根据审查评论生成 GitHub issue: 回复审查评论,请 Sourcery 根据该评论创建 issue。你也可以回复审查评论并使用 @sourcery-ai issue,根据该评论创建 issue。
  • 生成拉取请求标题: 在拉取请求标题的任意位置写入 @sourcery-ai,即可随时生成标题。你也可以在拉取请求中评论 @sourcery-ai title,随时重新生成标题。
  • 生成拉取请求摘要: 在拉取请求正文中需要生成摘要的位置写入 @sourcery-ai summary,即可随时在指定位置生成 PR 摘要。你也可以在拉取请求中评论 @sourcery-ai summary,随时重新生成摘要。
  • 生成审查者指南: 在拉取请求中评论 @sourcery-ai guide,即可随时重新生成审查者指南。
  • 解决所有 Sourcery 评论: 在拉取请求中评论 @sourcery-ai resolve,即可解决所有 Sourcery 评论。如果你已经处理完所有评论且不想再看到它们,这个命令会很有用。
  • 忽略所有 Sourcery 审查: 在拉取请求中评论 @sourcery-ai dismiss,即可忽略所有现有的 Sourcery 审查。如果你想重新开始一次新的审查,这个命令尤其有用——别忘了评论 @sourcery-ai review 来触发新的审查!

自定义使用体验

访问你的控制面板以:

  • 启用或禁用审查功能,例如 Sourcery 生成的拉取请求摘要、审查者指南等。
  • 更改审查语言。
  • 添加、删除或编辑自定义审查说明。
  • 调整其他审查设置。

获取帮助

Original review guide in English

Reviewer's Guide

本 PR 重构 MaaEnd AutoProxy 的配置与任务执行流程,集中处理任务结果、更新重试、进程清理及本地运行时元数据保留;同时以自定义逐条写盘的 ZIP writer 替换 AdmZip,取消问题报告的固定大小限制并降低大型日志归档的内存占用。

Sequence diagram for streaming issue-report ZIP export

sequenceDiagram
    participant Service as IssueReportService
    participant Core as issueReportCore
    participant Writer as StreamingZipWriter
    participant Disk as ZIPFile

    Service->>Core: createCollector(zipPath)
    Core->>Writer: new StreamingZipWriter(zipPath)
    Service->>Core: addDirectory / addDiagnosticFile
    Core->>Writer: addBuffer(archivePath, content)
    Core->>Writer: addFile(archivePath, sourcePath)
    Writer->>Disk: write ZIP entry immediately
    Service->>Writer: finalize()
    Writer->>Disk: write central directory and close
Loading

Sequence diagram for MaaEnd AutoProxy task retry and result tracking

sequenceDiagram
    participant AutoProxyTask
    participant MaaEnd
    participant LogMonitor
    participant ProcessManager

    AutoProxyTask->>AutoProxyTask: set_maaend(device_info)
    AutoProxyTask->>MaaEnd: asyncio.create_subprocess_exec(--autostart, --instance, AUTO-MAS)
    MaaEnd-->>LogMonitor: task start / complete / failure logs
    LogMonitor->>AutoProxyTask: check_log(log)
    AutoProxyTask->>AutoProxyTask: parse_task_result()
    alt MaaEnd 正在更新
        AutoProxyTask->>AutoProxyTask: kill_maaend_process()
        AutoProxyTask->>MaaEnd: restart current user once
    else Success!
        AutoProxyTask->>AutoProxyTask: kill_maaend_process()
    else task failure
        AutoProxyTask->>ProcessManager: kill_managed_process()
    end
Loading

Flow diagram for preserving MaaEnd runtime metadata

flowchart LR
    Local["本机 MaaEnd 配置"] --> Merge["读取并继承 version、interfaceTaskSnapshot、welcomeShownHash"]
    User["用户自动化配置"] --> Merge
    Merge --> Validate["验证 MaaEnd 实例与任务配置"]
    Validate --> Write["写入运行配置"]
    Write --> Run["使用 AUTO-MAS 启动"]
Loading

File-Level Changes

Change Details Files
重构 MaaEnd AutoProxy 的配置、任务执行和进程生命周期管理,减少重复分支并提高重试与结果跟踪可靠性。
  • 统一用户账号、配置路径及 AUTO-MAS 实例处理。
  • 抽取本地运行时元数据继承和理智任务选项配置逻辑。
  • 缓存首轮任务状态并集中解析任务完成/失败日志。
  • 拆分 MaaEnd 进程清理与全部关联进程清理,并调整更新重试和后置脚本流程。
  • 改进更新日志记录清理及任务完成后的历史日志处理。
app/task/MaaEnd/AutoProxy.py
app/task/MaaEnd/manager.py
将 MaaEnd 奖励组选项映射集中化,并同步配置标签解析使用新常量。
  • 以关卡到选项及奖励组值的映射替换硬编码分支。
  • 更新配置标签生成和 AutoProxy 任务选项写入逻辑。
app/utils/constants.py
app/models/config.py
app/task/MaaEnd/AutoProxy.py
改进 MaaEnd 资源与工具模块的缓存和导出机制。
  • 调整资源加载器的内存缓存、磁盘缓存和强制重载优先级。
  • 将工具模块的延迟导出补充为类型检查时可见的声明。
app/task/MaaEnd/resource_loader.py
app/utils/__init__.py
以自定义流式 ZIP 写入器替换 AdmZip,支持大型问题报告并降低归档生成期间的累计内存。
  • 移除单文件和总归档大小限制及截断/跳过状态。
  • 支持将文件逐条写入 ZIP,并在结束时生成中央目录。
  • 统一 MaaEnd、OK-NTE 和 OK-WW 报告服务的创建、收集和 finalize 流程。
frontend/electron/services/streamingZip.ts
frontend/electron/services/issueReportCore.ts
frontend/electron/services/maaEndIssueReportService.ts
frontend/electron/services/okNteIssueReportService.ts
frontend/electron/services/okwwIssueReportService.ts
更新版本资源。
  • 调整应用版本元数据。
res/version.json

Possibly linked issues

  • #MAAEND专项: PR直接修复任务完成状态判断及代理结束流程,与Issue中未正确结束代理任务的问题完全一致。

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

你好——我发现了 4 个问题

AI Agent 提示词
请处理本次代码审查中的评论:

## 单独评论

### 评论 1
<location path="app/task/MaaEnd/AutoProxy.py" line_range="149-151" />
<code_context>
-            self.script_config.get("Run", "AccountSwitchMethod") == "MAAEND"
-            and account_id
+        if self.account_id and (
+            len(self.account_id) < 4 or not self.account_id[-4:].isdigit()
         ):
-            if len(account_id) < 4 or not account_id[-4:].isdigit():
-                self.cur_user_item.status = "异常"
-                return (
-                    "MAAEND 内置账号切换需要账号末四位为数字,"
-                    "请检查账号ID或改用 MAS 自建账号切换"
-                )
+            self.cur_user_item.status = "异常"
+            return "账号切换需要账号末四位为数字,请检查账号ID"

-        config_user_id = (
</code_context>
<issue_to_address>
**issue (bug_risk):** 账号末四位校验现在对所有账户切换方式生效,即使 `AccountSwitchMethod``MAS` 也会拒绝非数字结尾的账号 ID;MAS 登录本身不要求账号 ID 末四位为数字。

**Triggers:** 当使用 MAS 自建账号切换且账号 ID 不是四位数字结尾时。

**Suggested fix:** 将校验恢复为仅在 `AccountSwitchMethod == "MAAEND"` 时执行。

```suggestion
        if (
            self.script_config.get("Run", "AccountSwitchMethod") == "MAAEND"
            and self.account_id
            and (
                len(self.account_id) < 4 or not self.account_id[-4:].isdigit()
            )
        ):
```
</issue_to_address>

### 评论 2
<location path="app/task/MaaEnd/AutoProxy.py" line_range="484" />
<code_context>
-            or "AUTO-MAS"
-        )
+        maaend_instance = instances[0]
         if device_info is not None:
             from app.core import MaaFWManager

</code_context>
<issue_to_address>
**issue (bug_risk):** 配置包含多个 MaaEnd 实例时,代码始终修改 `instances[0]`,但启动参数固定使用实例名 `AUTO-MAS`;当 AUTO-MAS 不是第一个实例时,任务配置写入了错误实例,实际启动的实例仍使用未配置的任务。

**Triggers:** 当 MaaEnd 配置中的 AUTO-MAS 实例不是 `instances[0]` 时。

**Suggested fix:** 按实例 ID `automas` 或名称 `AUTO-MAS` 查找目标实例,并在找不到时明确报错。
</issue_to_address>

### 评论 3
<location path="app/task/MaaEnd/AutoProxy.py" line_range="464" />
<code_context>
             )

+        # 版本号、任务快照与欢迎页标记跟随本机 MaaEnd, 不沿用用户配置快照
+        maaend_local_set = read_file(self.maaend_set_path / "mxu-MaaEnd.json")
         shutil.rmtree(self.maaend_set_path, ignore_errors=True)
-        shutil.copytree(maaend_config_path, self.maaend_set_path)
</code_context>
<issue_to_address>
**issue (bug_risk):** `set_maaend` 在清理并复制配置目录前无条件读取本机的 `config/mxu-MaaEnd.json`;该文件不存在时直接抛出文件读取异常,导致 MaaEnd 配置无法初始化,而旧逻辑允许本机配置文件缺失并继续复制用户配置。

**Triggers:** 当 MaaEnd 安装目录尚未生成本机 `config/mxu-MaaEnd.json` 时。

**Suggested fix:** 先检查本机配置文件是否存在;不存在时使用空配置或跳过本机字段继承。

```suggestion
        maaend_local_set = (
            read_file(self.maaend_set_path / "mxu-MaaEnd.json")
            if (self.maaend_set_path / "mxu-MaaEnd.json").exists()
            else {}
        )
```
</issue_to_address>

### 评论 4
<location path="frontend/electron/services/issueReportCore.ts" line_range="218" />
<code_context>
-        'truncated',
-        `原始文件超过 ${MAX_ENTRY_BYTES} 字节`
-      )
+      addEntry(state, archivePath, stat.size, content)
       return
     } catch (error) {
</code_context>
<issue_to_address>
**issue (performance):** 诊断文件导出删除了单文件和压缩包总大小限制,并直接用 `readFileSync` 将每个文本、二进制和脱敏 JSON 文件完整读入内存后加入 AdmZip;包含超大日志或大量大文件的诊断目录会同时占用原文件 Buffer、ZIP 内存和压缩输出内存,最终导致 Electron 主进程内存耗尽或导出崩溃。

**Triggers:** 当诊断目录包含数百 MB 或 GB 级日志/二进制文件时。

**Suggested fix:** 改用流式 ZIP 写入或保留可配置的单文件/总包大小上限,并在超限时记录跳过原因。
</issue_to_address>

Sourcery 评估

需要人工审查。 有 4 个发现需要优先处理;此外,移除单文件和压缩包总大小限制会使诊断导出保留任意大小的日志和文件,可能耗尽内存或磁盘空间,并可能暴露敏感内容。仅回滚只能防止未来的导出,无法撤销已经创建的软件包或已经泄露的数据。此次 PR 还改变了整个自动化流程中的 MaaEnd 任务选择、重试和结果解析,因此除了简单清理之外,还增加了运行时行为不正确的可能性。

阻塞性发现:app/task/MaaEnd/AutoProxy.py:151app/task/MaaEnd/AutoProxy.py:484app/task/MaaEnd/AutoProxy.py:464frontend/electron/services/issueReportCore.ts:218


Sourcery 对开源项目免费——如果你喜欢我们的审查,请考虑分享 ✨
帮助我变得更有用!请在每条评论上点击 👍 或 👎,我会利用反馈来改进审查结果。
Original comment in English

Hey - I've found 4 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="app/task/MaaEnd/AutoProxy.py" line_range="149-151" />
<code_context>
-            self.script_config.get("Run", "AccountSwitchMethod") == "MAAEND"
-            and account_id
+        if self.account_id and (
+            len(self.account_id) < 4 or not self.account_id[-4:].isdigit()
         ):
-            if len(account_id) < 4 or not account_id[-4:].isdigit():
-                self.cur_user_item.status = "异常"
-                return (
-                    "MAAEND 内置账号切换需要账号末四位为数字,"
-                    "请检查账号ID或改用 MAS 自建账号切换"
-                )
+            self.cur_user_item.status = "异常"
+            return "账号切换需要账号末四位为数字,请检查账号ID"

-        config_user_id = (
</code_context>
<issue_to_address>
**issue (bug_risk):** 账号末四位校验现在对所有账户切换方式生效,即使 `AccountSwitchMethod``MAS` 也会拒绝非数字结尾的账号 ID;MAS 登录本身不要求账号 ID 末四位为数字。

**Triggers:** 当使用 MAS 自建账号切换且账号 ID 不是四位数字结尾时。

**Suggested fix:** 将校验恢复为仅在 `AccountSwitchMethod == "MAAEND"` 时执行。

```suggestion
        if (
            self.script_config.get("Run", "AccountSwitchMethod") == "MAAEND"
            and self.account_id
            and (
                len(self.account_id) < 4 or not self.account_id[-4:].isdigit()
            )
        ):
```
</issue_to_address>

### Comment 2
<location path="app/task/MaaEnd/AutoProxy.py" line_range="484" />
<code_context>
-            or "AUTO-MAS"
-        )
+        maaend_instance = instances[0]
         if device_info is not None:
             from app.core import MaaFWManager

</code_context>
<issue_to_address>
**issue (bug_risk):** 配置包含多个 MaaEnd 实例时,代码始终修改 `instances[0]`,但启动参数固定使用实例名 `AUTO-MAS`;当 AUTO-MAS 不是第一个实例时,任务配置写入了错误实例,实际启动的实例仍使用未配置的任务。

**Triggers:** 当 MaaEnd 配置中的 AUTO-MAS 实例不是 `instances[0]` 时。

**Suggested fix:** 按实例 ID `automas` 或名称 `AUTO-MAS` 查找目标实例,并在找不到时明确报错。
</issue_to_address>

### Comment 3
<location path="app/task/MaaEnd/AutoProxy.py" line_range="464" />
<code_context>
             )

+        # 版本号、任务快照与欢迎页标记跟随本机 MaaEnd, 不沿用用户配置快照
+        maaend_local_set = read_file(self.maaend_set_path / "mxu-MaaEnd.json")
         shutil.rmtree(self.maaend_set_path, ignore_errors=True)
-        shutil.copytree(maaend_config_path, self.maaend_set_path)
</code_context>
<issue_to_address>
**issue (bug_risk):** `set_maaend` 在清理并复制配置目录前无条件读取本机的 `config/mxu-MaaEnd.json`;该文件不存在时直接抛出文件读取异常,导致 MaaEnd 配置无法初始化,而旧逻辑允许本机配置文件缺失并继续复制用户配置。

**Triggers:** 当 MaaEnd 安装目录尚未生成本机 `config/mxu-MaaEnd.json` 时。

**Suggested fix:** 先检查本机配置文件是否存在;不存在时使用空配置或跳过本机字段继承。

```suggestion
        maaend_local_set = (
            read_file(self.maaend_set_path / "mxu-MaaEnd.json")
            if (self.maaend_set_path / "mxu-MaaEnd.json").exists()
            else {}
        )
```
</issue_to_address>

### Comment 4
<location path="frontend/electron/services/issueReportCore.ts" line_range="218" />
<code_context>
-        'truncated',
-        `原始文件超过 ${MAX_ENTRY_BYTES} 字节`
-      )
+      addEntry(state, archivePath, stat.size, content)
       return
     } catch (error) {
</code_context>
<issue_to_address>
**issue (performance):** 诊断文件导出删除了单文件和压缩包总大小限制,并直接用 `readFileSync` 将每个文本、二进制和脱敏 JSON 文件完整读入内存后加入 AdmZip;包含超大日志或大量大文件的诊断目录会同时占用原文件 Buffer、ZIP 内存和压缩输出内存,最终导致 Electron 主进程内存耗尽或导出崩溃。

**Triggers:** 当诊断目录包含数百 MB 或 GB 级日志/二进制文件时。

**Suggested fix:** 改用流式 ZIP 写入或保留可配置的单文件/总包大小上限,并在超限时记录跳过原因。
</issue_to_address>

Sourcery assessment

Needs a human reviewer. 4 findings to address first, and removing the per-file and total archive limits makes diagnostic exports retain arbitrary-sized logs and files, which can exhaust memory or disk and may expose sensitive contents; reverting only prevents future exports and cannot undo packages already created or data already disclosed. The PR also changes MaaEnd task selection, retry, and result parsing across the automation flow, increasing the chance of incorrect runtime behavior beyond a simple cleanup.

Blocking findings: app/task/MaaEnd/AutoProxy.py:151, app/task/MaaEnd/AutoProxy.py:484, app/task/MaaEnd/AutoProxy.py:464, frontend/electron/services/issueReportCore.ts:218


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread app/task/MaaEnd/AutoProxy.py
Comment thread app/task/MaaEnd/AutoProxy.py
Comment thread app/task/MaaEnd/AutoProxy.py
Comment thread frontend/electron/services/issueReportCore.ts
@HarcoChen

Copy link
Copy Markdown
Contributor Author

@sourcery-ai review

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

嘿——我发现了 5 个问题

面向 AI Agent 的提示
请处理本次代码审查中的评论:

## 个别评论

### 评论 1
<location path="frontend/electron/services/streamingZip.ts" line_range="57-58" />
<code_context>
+  private entries: ZipEntry[] = []
+
+  constructor(filePath: string) {
+    fs.mkdirSync(fs.realpathSync(filePath + '/..'), { recursive: true })
+    this.fd = fs.openSync(filePath, 'w')
+  }
+
</code_context>
<issue_to_address>
**issue (bug_risk):** `fs.realpathSync(filePath + '/..')` 会尝试通过尚未创建的 ZIP 文件解析路径,因此对于普通的新归档路径,构造过程会抛出 `ENOENT``ENOTDIR`。结果是每次问题报告导出都会在写入任何条目之前失败。

**触发条件:**`zipPath` 尚不存在时,这也是生成新报告时的正常情况。

**建议修复:** 创建路径后直接使用 `path.dirname(filePath)`,而不是解析 `filePath + '/..'`。
</issue_to_address>

### 评论 2
<location path="app/task/MaaEnd/AutoProxy.py" line_range="464" />
<code_context>
                 "未找到 MaaEnd 配置文件, 请先完成「MaaEnd 配置」步骤"
             )

+        # 版本号、任务快照与欢迎页标记跟随本机 MaaEnd, 不沿用用户配置快照
+        maaend_local_set = read_file(self.maaend_set_path / "mxu-MaaEnd.json")
         shutil.rmtree(self.maaend_set_path, ignore_errors=True)
-        shutil.copytree(maaend_config_path, self.maaend_set_path)
+        shutil.copytree(self.maaend_config_path, self.maaend_set_path)
</code_context>
<issue_to_address>
**issue (bug_risk):** `read_file(self.maaend_set_path / "mxu-MaaEnd.json")` 现在是无条件执行的,因此当本地运行时配置缺失时,会在复制用户配置之前抛出异常。之前的代码明确支持本地配置缺失的情况,即不保留任何本地字段。

**触发条件:** 当 MaaEnd 安装尚未生成 `config/mxu-MaaEnd.json`,或本地配置已被删除时。

**建议修复:** 检查本地文件是否存在;如果不存在,则使用空的本地配置。

```suggestion
        maaend_local_set = (
            read_file(self.maaend_set_path / "mxu-MaaEnd.json")
            if (self.maaend_set_path / "mxu-MaaEnd.json").exists()
            else {}
        )
```
</issue_to_address>

### 评论 3
<location path="app/task/MaaEnd/AutoProxy.py" line_range="483" />
<code_context>
-                maaend_instance = instance
-                break
-        if maaend_instance is None:
-            maaend_instance = instances[0]
-        self.maaend_instance_name = (
-            maaend_instance.get("name")
</code_context>
<issue_to_address>
**issue (bug_risk):** 配置始终应用于 `instances[0]`,但进程启动时使用的是硬编码的实例名称 `AUTO-MAS`。当第一个已配置实例不是 `AUTO-MAS` 实例时,被编辑的任务和设备并不是 MaaEnd 实际启动的实例。

**触发条件:** 当 MaaEnd 配置包含多个实例,且 `AUTO-MAS` 不是第一个实例时。

**建议修复:** 在修改实例前先选择 `AUTO-MAS` 实例,或者使用实际选定的实例名称启动进程。
</issue_to_address>

### 评论 4
<location path="app/task/MaaEnd/AutoProxy.py" line_range="150-151" />
<code_context>
-            self.script_config.get("Run", "AccountSwitchMethod") == "MAAEND"
-            and account_id
+        if self.account_id and (
+            len(self.account_id) < 4 or not self.account_id[-4:].isdigit()
         ):
-            if len(account_id) < 4 or not account_id[-4:].isdigit():
-                self.cur_user_item.status = "异常"
</code_context>
<issue_to_address>
**issue (broader_impact):** 账户 ID 格式检查现在会对所有账户切换方式执行,而之前的代码只会对 `MAAEND` 内置切换器执行检查。用户选择 MAS 切换器并使用非数字账户 ID 时,即使 MaaEnd 在内置账户切换过程中不会使用该 ID,仍会被 `check()` 拒绝。

**触发条件:**`AccountSwitchMethod``MAS`,且配置的账户 ID 非空但末尾不是四位数字时。

**建议修复:** 像之前的实现一样,仅在 `AccountSwitchMethod == "MAAEND"` 时进行验证。
</issue_to_address>

### 评论 5
<location path="frontend/electron/services/streamingZip.ts" line_range="84-87" />
<code_context>
+    header.writeUInt16LE(8, 8)
+    header.writeUInt16LE(time, 10)
+    header.writeUInt16LE(date, 12)
+    header.writeUInt32LE(crc, 14)
+    header.writeUInt32LE(compressed.byteLength, 18)
+    header.writeUInt32LE(data.byteLength, 22)
+    header.writeUInt16LE(name.byteLength, 26)
+    header.writeUInt16LE(0, 28)
+
</code_context>
<issue_to_address>
**issue (bug_risk):** 自定义写入器生成的是经典 ZIP 标头,并使用 32 位写入存储大小和偏移量,同时没有 ZIP64 记录。文件、归档或中央目录超过 4 GiB 时,这些字段会溢出;尽管旧的大小限制已被移除,最终仍会生成无法读取或解压不正确的归档。

**触发条件:** 当源文件或生成的归档超过经典 ZIP 的 4 GiB 限制时。

**建议修复:** 实现 ZIP64 标头和 ZIP64 中央目录结束记录,或者保留一个低于经典 ZIP 限制的明确上限。
</issue_to_address>

Sourcery 评估

需要人工审查。 请先处理 5 个发现的问题。此外,问题报告相关改动移除了单文件和整个归档的大小限制,因此大型日志或二进制文件可能会被写入报告并消耗大量磁盘空间或内存;生成的归档在回滚后仍会保留,并且可能已经被分享。MaaEnd 任务和进程管理的重构还引入了若干运行时行为变化,但这些问题通常可以通过回滚并重新运行来恢复。

阻塞性问题:frontend/electron/services/streamingZip.ts:58app/task/MaaEnd/AutoProxy.py:464app/task/MaaEnd/AutoProxy.py:483app/task/MaaEnd/AutoProxy.py:151frontend/electron/services/streamingZip.ts:87


Sourcery 对开源项目免费——如果你喜欢我们的审查结果,请考虑分享它们 ✨
Original comment in English

Hey - I've found 5 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="frontend/electron/services/streamingZip.ts" line_range="57-58" />
<code_context>
+  private entries: ZipEntry[] = []
+
+  constructor(filePath: string) {
+    fs.mkdirSync(fs.realpathSync(filePath + '/..'), { recursive: true })
+    this.fd = fs.openSync(filePath, 'w')
+  }
+
</code_context>
<issue_to_address>
**issue (bug_risk):** `fs.realpathSync(filePath + '/..')` resolves a path through the not-yet-created ZIP file, so construction raises `ENOENT` or `ENOTDIR` for a normal new archive path. Consequently every issue-report export fails before any entries are written.

**Triggers:** When `zipPath` does not already exist, which is the normal case for generating a new report.

**Suggested fix:** Use `path.dirname(filePath)` directly after creating it, rather than resolving `filePath + '/..'`.
</issue_to_address>

### Comment 2
<location path="app/task/MaaEnd/AutoProxy.py" line_range="464" />
<code_context>
                 "未找到 MaaEnd 配置文件, 请先完成「MaaEnd 配置」步骤"
             )

+        # 版本号、任务快照与欢迎页标记跟随本机 MaaEnd, 不沿用用户配置快照
+        maaend_local_set = read_file(self.maaend_set_path / "mxu-MaaEnd.json")
         shutil.rmtree(self.maaend_set_path, ignore_errors=True)
-        shutil.copytree(maaend_config_path, self.maaend_set_path)
+        shutil.copytree(self.maaend_config_path, self.maaend_set_path)
</code_context>
<issue_to_address>
**issue (bug_risk):** `read_file(self.maaend_set_path / "mxu-MaaEnd.json")` is now unconditional, so a missing local runtime configuration raises before the user configuration can be copied. The previous code explicitly supported a missing local configuration by preserving no local fields.

**Triggers:** When the MaaEnd installation has not yet generated `config/mxu-MaaEnd.json` or the local configuration was removed.

**Suggested fix:** Check whether the local file exists and use an empty local configuration when it does not.

```suggestion
        maaend_local_set = (
            read_file(self.maaend_set_path / "mxu-MaaEnd.json")
            if (self.maaend_set_path / "mxu-MaaEnd.json").exists()
            else {}
        )
```
</issue_to_address>

### Comment 3
<location path="app/task/MaaEnd/AutoProxy.py" line_range="483" />
<code_context>
-                maaend_instance = instance
-                break
-        if maaend_instance is None:
-            maaend_instance = instances[0]
-        self.maaend_instance_name = (
-            maaend_instance.get("name")
</code_context>
<issue_to_address>
**issue (bug_risk):** Configuration is always applied to `instances[0]`, but the process is launched with the hard-coded instance name `AUTO-MAS`. When the first configured instance is not the `AUTO-MAS` instance, the edited tasks and device are not the instance that MaaEnd starts.

**Triggers:** When a MaaEnd configuration contains multiple instances and `AUTO-MAS` is not the first instance.

**Suggested fix:** Select the `AUTO-MAS` instance before modifying it, or launch the exact selected instance name.
</issue_to_address>

### Comment 4
<location path="app/task/MaaEnd/AutoProxy.py" line_range="150-151" />
<code_context>
-            self.script_config.get("Run", "AccountSwitchMethod") == "MAAEND"
-            and account_id
+        if self.account_id and (
+            len(self.account_id) < 4 or not self.account_id[-4:].isdigit()
         ):
-            if len(account_id) < 4 or not account_id[-4:].isdigit():
-                self.cur_user_item.status = "异常"
</code_context>
<issue_to_address>
**issue (broader_impact):** The account-ID format check now runs for every account-switch method, whereas the previous code applied it only to the `MAAEND` built-in switcher. A user selecting the MAS switcher with a nonnumeric account ID is rejected by `check()` even though MaaEnd does not consume that ID for built-in account switching.

**Triggers:** When `AccountSwitchMethod` is `MAS` and the configured account ID is nonempty but does not end in four digits.

**Suggested fix:** Keep the validation conditional on `AccountSwitchMethod == "MAAEND"`, as in the previous implementation.
</issue_to_address>

### Comment 5
<location path="frontend/electron/services/streamingZip.ts" line_range="84-87" />
<code_context>
+    header.writeUInt16LE(8, 8)
+    header.writeUInt16LE(time, 10)
+    header.writeUInt16LE(date, 12)
+    header.writeUInt32LE(crc, 14)
+    header.writeUInt32LE(compressed.byteLength, 18)
+    header.writeUInt32LE(data.byteLength, 22)
+    header.writeUInt16LE(name.byteLength, 26)
+    header.writeUInt16LE(0, 28)
+
</code_context>
<issue_to_address>
**issue (bug_risk):** The custom writer emits classic ZIP headers and stores sizes and offsets with 32-bit writes, without ZIP64 records. Files, archives, or central directories exceeding 4 GiB overflow these fields and produce an unreadable or incorrectly extracted archive despite the removal of the old size limits.

**Triggers:** When a source file or the resulting archive crosses the classic ZIP 4 GiB limit.

**Suggested fix:** Implement ZIP64 headers and an ZIP64 end-of-central-directory record, or retain an explicit limit below the classic ZIP limits.
</issue_to_address>

Sourcery assessment

Needs a human reviewer. 5 findings to address first, and the issue-report change removes per-file and total archive size limits, so a large log or binary can be persisted into the report and consume substantial disk space or memory; generated archives also remain after a revert and may already have been shared. The MaaEnd task and process-management refactors add several runtime behavior changes, but their failures are generally recoverable by reverting and rerunning.

Blocking findings: frontend/electron/services/streamingZip.ts:58, app/task/MaaEnd/AutoProxy.py:464, app/task/MaaEnd/AutoProxy.py:483, app/task/MaaEnd/AutoProxy.py:151, frontend/electron/services/streamingZip.ts:87


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment on lines +57 to +58
fs.mkdirSync(fs.realpathSync(filePath + '/..'), { recursive: true })
this.fd = fs.openSync(filePath, 'w')

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (bug_risk): fs.realpathSync(filePath + '/..') 会尝试通过尚未创建的 ZIP 文件解析路径,因此对于普通的新归档路径,构造过程会抛出 ENOENTENOTDIR。结果是每次问题报告导出都会在写入任何条目之前失败。

触发条件:zipPath 尚不存在时,这也是生成新报告时的正常情况。

建议修复: 创建路径后直接使用 path.dirname(filePath),而不是解析 filePath + '/..'

Original comment in English

issue (bug_risk): fs.realpathSync(filePath + '/..') resolves a path through the not-yet-created ZIP file, so construction raises ENOENT or ENOTDIR for a normal new archive path. Consequently every issue-report export fails before any entries are written.

Triggers: When zipPath does not already exist, which is the normal case for generating a new report.

Suggested fix: Use path.dirname(filePath) directly after creating it, rather than resolving filePath + '/..'.

)

# 版本号、任务快照与欢迎页标记跟随本机 MaaEnd, 不沿用用户配置快照
maaend_local_set = read_file(self.maaend_set_path / "mxu-MaaEnd.json")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (bug_risk): read_file(self.maaend_set_path / "mxu-MaaEnd.json") 现在是无条件执行的,因此当本地运行时配置缺失时,会在复制用户配置之前抛出异常。之前的代码明确支持本地配置缺失的情况,即不保留任何本地字段。

触发条件: 当 MaaEnd 安装尚未生成 config/mxu-MaaEnd.json,或本地配置已被删除时。

建议修复: 检查本地文件是否存在;如果不存在,则使用空的本地配置。

Suggested change
maaend_local_set = read_file(self.maaend_set_path / "mxu-MaaEnd.json")
maaend_local_set = (
read_file(self.maaend_set_path / "mxu-MaaEnd.json")
if (self.maaend_set_path / "mxu-MaaEnd.json").exists()
else {}
)
Original comment in English

issue (bug_risk): read_file(self.maaend_set_path / "mxu-MaaEnd.json") is now unconditional, so a missing local runtime configuration raises before the user configuration can be copied. The previous code explicitly supported a missing local configuration by preserving no local fields.

Triggers: When the MaaEnd installation has not yet generated config/mxu-MaaEnd.json or the local configuration was removed.

Suggested fix: Check whether the local file exists and use an empty local configuration when it does not.

Suggested change
maaend_local_set = read_file(self.maaend_set_path / "mxu-MaaEnd.json")
maaend_local_set = (
read_file(self.maaend_set_path / "mxu-MaaEnd.json")
if (self.maaend_set_path / "mxu-MaaEnd.json").exists()
else {}
)

or maaend_instance.get("customName")
or "AUTO-MAS"
)
maaend_instance = instances[0]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (bug_risk): 配置始终应用于 instances[0],但进程启动时使用的是硬编码的实例名称 AUTO-MAS。当第一个已配置实例不是 AUTO-MAS 实例时,被编辑的任务和设备并不是 MaaEnd 实际启动的实例。

触发条件: 当 MaaEnd 配置包含多个实例,且 AUTO-MAS 不是第一个实例时。

建议修复: 在修改实例前先选择 AUTO-MAS 实例,或者使用实际选定的实例名称启动进程。

Original comment in English

issue (bug_risk): Configuration is always applied to instances[0], but the process is launched with the hard-coded instance name AUTO-MAS. When the first configured instance is not the AUTO-MAS instance, the edited tasks and device are not the instance that MaaEnd starts.

Triggers: When a MaaEnd configuration contains multiple instances and AUTO-MAS is not the first instance.

Suggested fix: Select the AUTO-MAS instance before modifying it, or launch the exact selected instance name.

Comment on lines +150 to 151
len(self.account_id) < 4 or not self.account_id[-4:].isdigit()
):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (broader_impact): 账户 ID 格式检查现在会对所有账户切换方式执行,而之前的代码只会对 MAAEND 内置切换器执行检查。用户选择 MAS 切换器并使用非数字账户 ID 时,即使 MaaEnd 在内置账户切换过程中不会使用该 ID,仍会被 check() 拒绝。

触发条件:AccountSwitchMethodMAS,且配置的账户 ID 非空但末尾不是四位数字时。

建议修复: 像之前的实现一样,仅在 AccountSwitchMethod == "MAAEND" 时进行验证。

Original comment in English

issue (broader_impact): The account-ID format check now runs for every account-switch method, whereas the previous code applied it only to the MAAEND built-in switcher. A user selecting the MAS switcher with a nonnumeric account ID is rejected by check() even though MaaEnd does not consume that ID for built-in account switching.

Triggers: When AccountSwitchMethod is MAS and the configured account ID is nonempty but does not end in four digits.

Suggested fix: Keep the validation conditional on AccountSwitchMethod == "MAAEND", as in the previous implementation.

Comment on lines +84 to +87
header.writeUInt32LE(crc, 14)
header.writeUInt32LE(compressed.byteLength, 18)
header.writeUInt32LE(data.byteLength, 22)
header.writeUInt16LE(name.byteLength, 26)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (bug_risk): 自定义写入器生成的是经典 ZIP 标头,并使用 32 位写入存储大小和偏移量,同时没有 ZIP64 记录。文件、归档或中央目录超过 4 GiB 时,这些字段会溢出;尽管旧的大小限制已被移除,最终仍会生成无法读取或解压不正确的归档。

触发条件: 当源文件或生成的归档超过经典 ZIP 的 4 GiB 限制时。

建议修复: 实现 ZIP64 标头和 ZIP64 中央目录结束记录,或者保留一个低于经典 ZIP 限制的明确上限。

Original comment in English

issue (bug_risk): The custom writer emits classic ZIP headers and stores sizes and offsets with 32-bit writes, without ZIP64 records. Files, archives, or central directories exceeding 4 GiB overflow these fields and produce an unreadable or incorrectly extracted archive despite the removal of the old size limits.

Triggers: When a source file or the resulting archive crosses the classic ZIP 4 GiB limit.

Suggested fix: Implement ZIP64 headers and an ZIP64 end-of-central-directory record, or retain an explicit limit below the classic ZIP limits.

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.

1 participant