Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
2a81d88
build(deps): 新增 uv.lock 与 .python-version 锁定依赖,接入 CI 锁文件校验并补充开发环境文档
qiyinxi Sep 1, 2026
aeec870
fix(supervised): 受监督模式下不自提权、端口固定 36163、关闭请求真实生效
qiyinxi Sep 1, 2026
224b476
feat(core): health 接口补充身份字段并将 pyproject.toml 纳入版本一致性 CI
qiyinxi Sep 1, 2026
6a8326e
refactor(backend): MaaFW 与 HSR 运行期落盘目录迁出 runtime/ 改用 data/
qiyinxi Sep 1, 2026
ae616cd
feat(runtime): 新增 Runtime NDJSON 协议 v1 类型定义
qiyinxi Sep 1, 2026
5027dbf
feat(runtime): 新增 Runtime NDJSON 逐行解析器
qiyinxi Sep 1, 2026
3b2f07d
feat(runtime): 新增 RuntimeClient 与 stdin 控制封装
qiyinxi Sep 1, 2026
8db0958
test(runtime): 用真实 Runtime 输出夹具覆盖解析器与客户端
qiyinxi Sep 1, 2026
36cfbed
test(runtime): 补一条可重试 Runtime 失败的用例
qiyinxi Sep 1, 2026
2d29d80
fix(agent-env): agent 隔离环境的 uv 发现优先读取监督器注入路径
qiyinxi Sep 1, 2026
c81698c
fix(agent-env): 复用隔离 venv 前校验基解释器仍然存在
qiyinxi Sep 1, 2026
562359c
fix(platform): 拉起游戏/模拟器时脱离监督器的 Job Object
qiyinxi Sep 1, 2026
c24dbfb
Merge branch 'fix/health-identity-fields-20260831' into integ/runtime…
qiyinxi Sep 1, 2026
48dd15a
Merge branch 'fix/supervised-mode-semantics-20260831' into integ/runt…
qiyinxi Sep 1, 2026
55e2abb
Merge branch 'feat/uv-lockfile-20260831' into integ/runtime-20260901
qiyinxi Sep 1, 2026
7c0eae1
Merge branch 'refactor/backend-runtime-dir-20260831' into integ/runti…
qiyinxi Sep 1, 2026
edaf9c9
Merge branch 'feat/supervised-job-and-agent-env-20260831' into integ/…
qiyinxi Sep 1, 2026
1376422
feat(resources): 内置资源改为按源码位置解析,受监督模式下不再切换工作目录到源码目录
qiyinxi Sep 1, 2026
8f9c03d
chore(integ): 统一受监督判据为 app.utils.is_supervised 并按版本号重生成 uv.lock
qiyinxi Sep 1, 2026
5836e7e
feat(runtime): 新增后端监督灰度开关与 Runtime 可执行文件定位
qiyinxi Sep 1, 2026
847d516
Merge branch 'feat/source-relative-resources-20260831' into integ/run…
qiyinxi Sep 1, 2026
22c0e1e
feat(backend): 后端启停按灰度开关分流到 Runtime 监督链路
qiyinxi Sep 1, 2026
6cff1cc
feat(backend): Runtime 链路下端点取自 baseUrl 且退出改走监督进程关闭
qiyinxi Sep 1, 2026
83ef777
feat(maafw): 运行池支持复用 Runtime 注入的 uv 缓存/Python 目录与镜像列表并按序重试
qiyinxi Sep 1, 2026
0fef748
test(backend): 覆盖双链路分流、端点派生、关闭与失败展示
qiyinxi Sep 1, 2026
3fdcd89
fix(maafw): 收窄池路径逃逸检查的放行范围,只豁免真正命中注入的那一侧
qiyinxi Sep 1, 2026
5be55db
Merge branch 'feat/maafw-pool-runtime-infra-20260901' into integ/runt…
qiyinxi Sep 1, 2026
7a88abe
Merge branch 'feat/runtime-backend-supervise-20260901' into integ/run…
qiyinxi Sep 1, 2026
c9dbb0f
feat(runtime): 新增 Runtime 初始化链路与 7 段进度映射
qiyinxi Sep 1, 2026
57b145e
feat(init): 初始化流程按灰度开关分流到 Runtime bootstrap
qiyinxi Sep 1, 2026
425eb60
feat(ipc): 单步重试与关键文件检查改走 Runtime 下层命令
qiyinxi Sep 1, 2026
44c466c
test(runtime): 覆盖三态分流、阶段映射、单步重试与镜像映射
qiyinxi Sep 1, 2026
74c0421
Merge branch 'feat/runtime-bootstrap-init-20260901' into integ/runtim…
qiyinxi Sep 1, 2026
2196360
feat(runtime): 失败结果补日志路径,并向界面暴露运行时上下文
qiyinxi Sep 1, 2026
c7227c0
ci(build-app): 下载并校验 AUTO-MAS-Runtime 可执行文件随安装包分发
qiyinxi Sep 1, 2026
9577da4
feat(runtime): 后端更新改为停机、bootstrap 与重新监督三步
qiyinxi Sep 1, 2026
c81c552
feat(ipc): 暴露 Runtime 后端更新的调用、进度与取消通道
qiyinxi Sep 1, 2026
b19f2c2
feat(ui): 标题栏后端更新入口按启动链路分流
qiyinxi Sep 1, 2026
70996d1
test(runtime): 覆盖更新三步顺序、三类结局与版本号校验
qiyinxi Sep 1, 2026
4cc2872
feat(init): 新增按 remediation 决定失败按钮的纯函数
qiyinxi Sep 1, 2026
a061938
feat(init): 初始化界面消费 Runtime 的失败字段与阶段接管
qiyinxi Sep 1, 2026
b6e0208
test(runtime): 补 bootstrap 进行中取消走 stdin cancel 的用例
qiyinxi Sep 1, 2026
a713f66
fix(config): 后端版本信息改从源码目录读取 Git 仓库,受监督时不再误报需要更新
qiyinxi Sep 1, 2026
2ea78e7
Merge branch 'feat/runtime-backend-update-20260901' into integ/runtim…
qiyinxi Sep 1, 2026
bcb7f5b
test(init): 覆盖失败态按钮渲染,并补 changelog
qiyinxi Sep 1, 2026
b0b55ce
style(i18n): 撤回三份词表里误入的既有格式化改动
qiyinxi Sep 1, 2026
98774a1
Merge branch 'feat/runtime-init-ui-20260901' into integ/runtime-20260901
qiyinxi Sep 1, 2026
3cb46af
feat(runtime): 灰度开关升级为环境变量/设置/构建默认值三级来源
qiyinxi Sep 1, 2026
bc6eb94
feat(runtime): 遥测关闭时向 Runtime 透传环境变量,收敛客户端构造
qiyinxi Sep 1, 2026
4d141d7
Merge branch 'feat/runtime-ship-and-switch-20260901' into integ/runti…
qiyinxi Sep 1, 2026
c45ad98
feat(init): Runtime 下依赖段也给换镜像按钮
qiyinxi Sep 1, 2026
690e168
Merge branch 'feat/runtime-init-ui-20260901' into integ/runtime-20260901
qiyinxi Sep 1, 2026
ab00c38
fix(runtime): 镜像映射按 name 或 key 解析,并补 package-index 映射
qiyinxi Sep 1, 2026
d618d98
Merge branch 'feat/runtime-bootstrap-init-20260901' into integ/runtim…
qiyinxi Sep 1, 2026
c8478c0
fix(integ): 更新流程给 RuntimeInitializationService 传镜像查找
qiyinxi Sep 1, 2026
c1a7922
Merge branch 'feat/source-relative-resources-20260831' into integ/run…
qiyinxi Sep 1, 2026
1669ba9
chore(integ): 同步 upstream/dev 并收口 Runtime 版本记录
qiyinxi Sep 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,8 @@
# 因此用户侧直接启动后端始终按生产环境处理。
#
# 想临时按生产环境验证上报链路时,删除或重命名 .env 即可。
#
# 由 AUTO-MAS-Runtime 监督启动时(进程环境变量 AUTO_MAS_SUPERVISED=1)上述
# 开发环境行为不生效:端口固定 36163、关闭请求(/api/core/close)真实生效,
# 优先级高于本文件与 AUTO_MAS_ENV。
AUTO_MAS_ENV=development
64 changes: 64 additions & 0 deletions .github/workflows/build-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ permissions:
contents: write
actions: write

env:
# AUTO-MAS-Project/AUTO-MAS-Runtime 的发布版本,随桌面安装包一起分发。钉死具体版本、不追
# latest:Runtime 有自己的发布节奏,本仓库的改动不应该在没有联调的情况下自动带出一个新
# Runtime。Runtime 不自更新,只随这里构建的安装包整体升级;本仓库如有依赖 Runtime 新行为
# 的改动(T13 系列),必须等 Runtime 一侧先发布对应版本,再手动把这个版本号提上去。
RUNTIME_VERSION: v0.1.0-beta.8

jobs:

build:
Expand All @@ -51,6 +58,52 @@ jobs:
with:
node-version: '20'

- name: 下载并校验 Runtime 可执行文件
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
$runtimeDir = Join-Path "${{ github.workspace }}" 'runtime'
New-Item -ItemType Directory -Force -Path $runtimeDir | Out-Null

$exeName = "auto-mas-runtime-$env:RUNTIME_VERSION.exe"

gh release download $env:RUNTIME_VERSION `
-R AUTO-MAS-Project/AUTO-MAS-Runtime `
-D $runtimeDir `
-p $exeName `
-p 'SHA256SUMS.txt' `
--clobber
if ($LASTEXITCODE -ne 0) {
throw "下载 Runtime $env:RUNTIME_VERSION 失败"
}

Push-Location $runtimeDir
try {
$sumsLine = Select-String -Path 'SHA256SUMS.txt' -Pattern ([regex]::Escape($exeName)) |
Select-Object -First 1
if (-not $sumsLine) {
throw "SHA256SUMS.txt 中找不到 $exeName 对应的记录"
}
$expectedHash = ($sumsLine.Line -split '\s+')[0].ToUpperInvariant()
$actualHash = (Get-FileHash -Path $exeName -Algorithm SHA256).Hash.ToUpperInvariant()

Write-Host "期望哈希: $expectedHash"
Write-Host "实际哈希: $actualHash"

if ($actualHash -ne $expectedHash) {
throw "SHA-256 校验失败:$exeName 与 SHA256SUMS.txt 不匹配,可能下载损坏或被篡改"
}

# 校验通过后改成稳定文件名,Electron 侧固定按 auto-mas-runtime.exe 定位
# (见 frontend/electron/services/runtime/launchConfig.ts)。
Move-Item -Path $exeName -Destination 'auto-mas-runtime.exe' -Force
Remove-Item 'SHA256SUMS.txt'
Write-Host "Runtime $env:RUNTIME_VERSION 校验通过:$runtimeDir\auto-mas-runtime.exe"
} finally {
Pop-Location
}
shell: pwsh

- name: 构建应用程序
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
Expand All @@ -74,6 +127,17 @@ jobs:
Move-Item -Path "dist\win-unpacked\AUTO-MAS.exe" -Destination "..\AUTO-MAS.exe"
shell: pwsh

- name: 放入 Runtime 可执行文件
run: |
# 不经 electron-builder 的 extraResources 声明:本地没有预先下载 runtime\auto-mas-runtime.exe
# 时会让 yarn build 直接报错退出。构建产物出来后按 environment.zip 同样的方式原样拷入
# resources 目录,Lite 与 Full 安装包都直接打包 dist\win-unpacked\* 的全部内容,因此
# 两者会一起带上它。
$target = 'frontend\dist\win-unpacked\resources'
New-Item -ItemType Directory -Force -Path $target | Out-Null
Copy-Item -Path 'runtime\auto-mas-runtime.exe' -Destination (Join-Path $target 'auto-mas-runtime.exe') -Force
shell: pwsh

- name: 上传未签名主程序
id: upload-unsigned-main-program
uses: actions/upload-artifact@v7.0.1
Expand Down
47 changes: 47 additions & 0 deletions .github/workflows/check-uv-lock.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# AUTO-MAS: A Multi-Script, Multi-Config Management and Automation Software
# Copyright © 2025-2026 AUTO-MAS Team

# This file is part of AUTO-MAS.

# AUTO-MAS is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.

# AUTO-MAS is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
# the GNU Affero General Public License for more details.

# You should have received a copy of the GNU Affero General Public License
# along with AUTO-MAS. If not, see <https://www.gnu.org/licenses/>.

# Contact: DLmaster_361@163.com

name: 检查 uv 锁文件

on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
push:
branches: [dev]

permissions:
contents: read

jobs:
check-uv-lock:
name: 检查 uv.lock 与依赖清单一致
runs-on: ubuntu-latest

steps:
- name: 检出代码
uses: actions/checkout@v7.0.1

- name: 安装 uv
uses: astral-sh/setup-uv@v10.0.1
with:
version: "0.12.3"

- name: 检查 uv.lock 是否与清单一致
run: uv lock --check
30 changes: 28 additions & 2 deletions .github/workflows/check-version-json.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,25 @@ jobs:
- name: 检出代码
uses: actions/checkout@v7.0.1

- name: 设置 Python 环境
uses: actions/setup-python@v7.0.0
with:
python-version: '3.12'

- name: 检查 version.json 语法
run: python -m json.tool res/version.json > /dev/null

- name: 检查版本号一致性
run: |
python -m pip install --quiet packaging==25.0
python - <<'PY'
import ast
import json
import tomllib
from pathlib import Path

from packaging.version import Version

with Path("res/version.json").open(encoding="utf-8") as file:
version_json = json.load(file)

Expand Down Expand Up @@ -78,17 +87,34 @@ jobs:
if app_config_version is None:
raise SystemExit("未在 app/core/config.py 的 AppConfig 中找到 VERSION")

with Path("pyproject.toml").open("rb") as file:
pyproject_toml = tomllib.load(file)
pyproject_version = pyproject_toml["project"]["version"]

versions = {
"res/version.json": version_json["version"],
"frontend/package.json": package_json["version"],
"app/core/config.py": app_config_version,
"pyproject.toml": pyproject_version,
}

if len(set(versions.values())) != 1:
# 前三处要求逐字相同;pyproject.toml 走 PEP 440(如 5.5.0b3),
# 去掉前导 v 后按 packaging 规范化比较(5.5.0-beta.3 与 5.5.0b3 规范化后相等)。
literal_versions = {
path: value for path, value in versions.items() if path != "pyproject.toml"
}
is_consistent = len(set(literal_versions.values())) == 1
if is_consistent:
shared_version = next(iter(literal_versions.values()))
is_consistent = Version(shared_version.removeprefix("v")) == Version(
pyproject_version
)

if not is_consistent:
details = "\n".join(
f"- {path}: {version}" for path, version in versions.items()
)
raise SystemExit(f"三处版本号不一致:\n{details}")
raise SystemExit(f"版本号不一致:\n{details}")

print(f"版本号一致: {app_config_version}")
PY
Expand Down
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.12.13
18 changes: 18 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,24 @@ Welcome to contribute to the AUTO-MAS project! Before participating in developme

- [AUTO-MAS Developer Documentation](https://doc.auto-mas.top/developer/).

# 开发环境 / Development Environment

后端依赖由 `pyproject.toml` + `uv.lock` 管理:

1. 安装 [uv](https://docs.astral.sh/uv/getting-started/installation/)。
2. 在仓库根目录执行 `uv sync`,会按 `uv.lock` 在 `.venv` 中创建与锁定版本一致的环境。
3. 执行 `uv run main.py` 启动。

`requirements.txt` 目前与 `pyproject.toml` 并存,修改依赖时请同步更新两者。**修改 `pyproject.toml` 后必须重新执行 `uv lock`,并将更新后的 `uv.lock` 一并提交**,否则 CI 的锁文件检查会失败。`dev` 及各开发分支负责更新 `uv.lock`;发布分支只消费锁文件,不在其上重新解析依赖。

Backend dependencies are managed via `pyproject.toml` + `uv.lock`:

1. Install [uv](https://docs.astral.sh/uv/getting-started/installation/).
2. Run `uv sync` in the repository root; it creates a `.venv` matching the locked versions in `uv.lock`.
3. Start the app with `uv run main.py`.

`requirements.txt` currently coexists with `pyproject.toml` — update both when changing dependencies. **After editing `pyproject.toml`, you must re-run `uv lock` and commit the updated `uv.lock`**, or the CI lockfile check will fail. `dev` and other development branches keep `uv.lock` up to date; release branches only consume the lockfile and never re-resolve it.

# 重要事项 / Important Terms

您通过任意方式提交代码到 **AUTO-MAS-Project** 下属任意仓库,即代表您理解并同意以下条款:
Expand Down
40 changes: 38 additions & 2 deletions app/api/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
from app.services import System
from app.models.schema import *
from app.api.ws_command import ws_command
from app.utils import get_logger
from app.utils import get_logger, is_supervised

router = APIRouter(prefix="/api/core", tags=["核心信息"])
logger = get_logger("DEV")
Expand All @@ -48,12 +48,32 @@ class WebSocketMetaOut(BaseModel):
wsPath: str = Field(default="/api/core/ws", description="主 WebSocket 路径")


# AUTO-MAS-Runtime 健康检查协议版本:固定返回后端自身支持的版本,不回显监督器注入值,
# 协议升级后只有如此监督器才能检出版本不兼容。
HEALTH_PROTOCOL_VERSION = 1


class BackendHealthOut(BaseModel):
"""后端核心服务与后台初始化状态。"""

ready: bool = Field(description="核心 API 是否可用")
backgroundStatus: str = Field(description="后台初始化状态")
backgroundError: str | None = Field(default=None, description="后台初始化失败原因")
protocol: int = Field(description="后端自身支持的健康检查协议版本")
version: str = Field(description="后端版本号")
commit: str = Field(description="后端所在提交哈希,未受监督或监督器未注入时为空")



def _resolve_injected_identity(env_name: str) -> str | None:
"""受监督时读取监督器注入的期望身份值。

未受监督、或对应环境变量缺失/为空字符串时返回 None,交由调用方回退默认值。
"""

if not is_supervised():
return None
return os.getenv(env_name, "") or None


@router.get(
Expand All @@ -63,12 +83,20 @@ class BackendHealthOut(BaseModel):
status_code=200,
)
async def get_health(request: Request) -> BackendHealthOut:
"""返回核心 API 与后台初始化状态。"""
"""返回核心 API 与后台初始化状态,供 AUTO-MAS-Runtime 等外部监督器判定就绪与身份。

version/commit 受监督且监督器注入了期望值时原样回显,否则分别回退到本地版本号
与空字符串;commit 不通过 Git 推断,只能来自监督器注入。
"""

return BackendHealthOut(
ready=True,
backgroundStatus=getattr(request.app.state, "background_status", "starting"),
backgroundError=getattr(request.app.state, "background_error", None),
protocol=HEALTH_PROTOCOL_VERSION,
version=_resolve_injected_identity("AUTO_MAS_EXPECTED_VERSION")
or Config.VERSION,
commit=_resolve_injected_identity("AUTO_MAS_EXPECTED_COMMIT") or "",
)


Expand All @@ -77,8 +105,16 @@ def is_backend_dev_mode() -> bool:

dev 分支的 AUTO_MAS_DEV 标记“由前端拉起”(跳过自行提权),生产环境同样为 1,
不能作为开发模式依据;以 main.py 启动时归一化的 AUTO_MAS_ENV 为准。

受 AUTO-MAS-Runtime 监督时优先级高于 AUTO_MAS_DEV 与 AUTO_MAS_ENV,恒为
False:监督器依赖 /api/core/close 真正退出进程,若判定为开发模式,
_shutdown_backend() 只做轻量清理、不设 should_exit,关闭请求就会永远
不生效,5 秒后被监督器硬杀。
"""

if is_supervised():
return False

raw = str(os.getenv("AUTO_MAS_ENV", "")).strip().lower()
return raw in {"dev", "development"}

Expand Down
25 changes: 20 additions & 5 deletions app/core/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
Webhook,
)
from app.models.schema import PlanComboxConsumer
from app.utils import get_logger
from app.utils import get_logger, is_supervised, resource_path
from app.utils.constants import (
MAA_DEPOT_EXCLUDED_ITEM_IDS,
RESOURCE_STAGE_DATE_TEXT,
Expand All @@ -87,6 +87,7 @@
UTC8,
)
from app.utils.io import write_file
from app.utils.paths import SOURCE_ROOT
from app.utils.platform import IS_WINDOWS

# 孤儿 venv 的宽限期:刚动过的一律不碰,避免与正在准备环境的运行抢。
Expand Down Expand Up @@ -292,7 +293,7 @@ def __init__(self) -> None:
self._inject_truststore()

self.notify_env = Environment(
loader=FileSystemLoader(str(Path.cwd() / "res/html"))
loader=FileSystemLoader(str(resource_path("html")))
)

@staticmethod
Expand Down Expand Up @@ -349,7 +350,9 @@ def _get_repo(self) -> Any:
try:
from git import Repo

self._repo = Repo(Path.cwd())
# .git 随源码走:受 AUTO-MAS-Runtime 监督时源码在 <app-root>/repo/,
# 工作目录(app-root)下没有仓库,不能再按 Path.cwd() 打开
self._repo = Repo(SOURCE_ROOT)
except Exception as e:
logger.warning(f"Git仓库初始化失败: {e}")
self._repo = None
Expand Down Expand Up @@ -717,7 +720,19 @@ async def check_data(self) -> None:
logger.success("数据文件版本更新完成")

async def get_git_version(self) -> tuple[bool, str, str]:
"""获取Git版本信息,如果Git不可用则返回默认值"""
"""获取Git版本信息,如果Git不可用则返回默认值。

受 AUTO-MAS-Runtime 监督时后端不是更新主体:更新由 Runtime 整体替换
repo/ 完成、不在旧仓库上 fetch,比对远端分支判定“需要更新”没有意义,
一律视为最新。managed 模式直接回显 Runtime 从校验过的仓库注入的 HEAD,
不依赖 Runtime 布局里并不存在的 git 命令行;development 模式无注入
身份,仍从源码目录读取 Git 信息用于展示。
"""

supervised = is_supervised()
expected_commit = os.getenv("AUTO_MAS_EXPECTED_COMMIT", "")
if supervised and expected_commit:
return True, expected_commit, "unknown"

def _get_git_info():

Expand Down Expand Up @@ -751,7 +766,7 @@ def _get_git_info():
is_latest, commit_hash, commit_time = await self.loop.run_in_executor(
None, _get_git_info
)
return is_latest, commit_hash, commit_time
return is_latest or supervised, commit_hash, commit_time

async def add_script(
self,
Expand Down
4 changes: 2 additions & 2 deletions app/core/maa_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@

from .config import Config
from app.models.emulator import DeviceInfo
from app.utils import get_logger
from app.utils import get_logger, resource_path

logger = get_logger("MaaFW管理")

Expand All @@ -70,7 +70,7 @@ def __init__(self):
encoding="utf-8",
)
Toolkit.init_option(Path.cwd())
self.resource.post_bundle(Path.cwd() / "res/MaaFW").wait()
self.resource.post_bundle(resource_path("MaaFW")).wait()

@staticmethod
async def do_job(job: Job | JobWithResult) -> Any:
Expand Down
Loading
Loading