Skip to content

feat(maafw): MFW 托管后端链路(导入脱壳、共用运行环境、版本管理、远程更新、迁移),界面暂不接入 - #633

Closed
qiyinxi wants to merge 22 commits into
AUTO-MAS-Project:devfrom
qiyinxi:feat/maafw-managed-20260908
Closed

qiyinxi wants to merge 22 commits into
AUTO-MAS-Project:devfrom
qiyinxi:feat/maafw-managed-20260908

Conversation

@qiyinxi

@qiyinxi qiyinxi commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

接通三层规划的第三层。app/task/MaaFW/tools/{core/automas_maafw_project_store,embedded/managed} 那 9800 行早就落库但从未接线,本 PR 把它接上,并补齐未移植的插件宿主那半边。

本 PR 的口径:后端 API,界面不接

前端一行不接:没有建项入口、没有「转为托管」、没有托管区块,主分支里不存在任何隐藏界面。只留 12 行类型识别(类型表 / 图标 / 列表标签 / 编辑页路由),让通过 API 建出来的托管脚本能正常显示、打开、运行。小范围试用由维护者另行提供界面;完整界面停在 feat/maafw-managed-ui-20260912,不进本 PR。

之所以不做"隐藏开关":开关键在配置模型里,toDict 会把它写进每个用户的 Config.json,等于把开关名印给所有人。

后端提供什么

新脚本类型 MaaFWManaged:项目由 AUTO-MAS 导入并精简——按 interface.json 声明的路径做白名单投影,界面程序、自带 Python、自带 MaaFramework 都不落盘,agent 直接用运行池的解释器。实测 MaaYYs 225.51 MB → 75.51 MB(省 66.51%),M9A 652.6 MB → 71.7 MB(省 89.09%)。

/api/scripts/maafw/managed/*:import / versions / switch / version/delete / inventory / gc / migrate。同一项目多版本并存可切换、删除;更新时下载整包作为新版本导入,旧版本留着可回退;现有 MFW 脚本可原地转为托管(脚本 ID 不变,为此给 MultipleConfig 加了 convert);迁移不动原目录,删不删由用户自己在外面做——投影是白名单式的,原目录是漏文件时唯一的退路。/maafw/update 按脚本形态分流——托管是 MaaFWConfig 的子类,isinstance 拦不住,不分流会拿 Store 的 checkout 去原地改写。

三个写错了不报错、只会出坏结果的点

  • 必须要整包。Store 导入的是一整棵树,差量包导进去是个跑不起来的版本。服务不支持 prefer_full_package 时直接报错,不静默降级。
  • 外壳提示要从 manifest 回填detect_maafw_project_shell_hint 靠根目录的 MFW.exe / maafw/ 判断外壳,而托管载荷正好把这些脱掉了;不回填,M9A 这种同时发 -MXU.zip-MFAA.zip 的项目会选错资产。
  • 运行前更新必须排在准备环境之前。准备那步会解析 Store 的当前版本并建 checkout,顺序反了这一轮仍跑旧版本,日志却说已更新。

取舍

不做两阶段 Managed.PendingUpgrade 升级——那条路要配套的配置迁移计划引擎,在未移植的 plugin.py 里。自选目录形态今天就是直接更新的:新 interface 里没有的任务由 run_plan 记成 skippedTasks,全没了才报错。托管沿用同一口径,而且旧版本留在 Store 里可回退。

#696 的关系

#696c6ca4fb14)按「零实例化」把 MaaFW 第三层托管栈当死代码删了;本 PR 正是这层的实例化方,两者相隔 25 分钟撞车。合入 dev 时按原方案继续:

验证

合 dev 后(2ef3e9880 合并 → 541f3f4b4 恢复 → 2e16eb681 碎片)在本树 .venv 实跑:

  • python -m pytest tests -q -p no:cacheprovider --basetemp <tmp>1123 passed / 4 skipped / 186 subtests--collect-only -q 退出码 0(1127 项)。其中本 PR 自带 4 个测试文件、恢复的 test_maafw_project_store_paths.pyrefactor: 清理死代码与无意义兜底,修复预研发现的性能问题 #696 新增的 test_maafw_project_update_fingerprint / test_maafw_update_download_checkpoint / test_maafw_progress_callback_logging / test_maafw_run_plan_i18n 单独跑 116 passed。
  • ruff check 改动文件全过;ruff format --check 两处「would reformat」(embedded_manager.pycontracts.py)在 dev / 合并基线上就有,不在本 PR 改动行内。
  • 前端 yarn typecheck / yarn lint / yarn build:main 退出码 0;yarn test 515/516,唯一失败是 backendService.test.ts › managed 模式 › …--app-root 就是用户数据根 5s 超时,本机在未改动的 dev 基线上同样失败(既有问题,单跑该文件复现 1 failed / 15 passed)。
  • scripts/changelog.py check --pr-base refs/remotes/upstream/dev --pr-kind normal 通过;git diff refs/remotes/upstream/dev -- CHANGELOG.md res/version.json 为空。
  • OpenAPI 客户端由本树开发后端(36175)重新生成并归一化为 LF:与 dev 已提交的生成物零差异(本 PR 的 MaaFWManaged* 与 dev 的 BAAH 类型都已在库中)。

真机(开发后端 36175,真网络,M9A):新建自选目录脚本(M9A v4.7.1 MXU 发行包解压目录)→ 转托管(m9a@v4.7.1,脱壳省下 83.29%,原目录未动)→ 检查更新(发现 v4.8.0,GitHub 源)→ 执行更新(整包 M9A-win-x86_64-v4.8.0-MXU.zip,外壳资产选择正确,导入并切换到 v4.8.0)→ 回退到 v4.7.1(成功)→ 删除 v4.8.0(被 maafw-upgrade:<scriptId>:v4.8.0 过渡引用挡住:/maafw/managed/gc 走的 collect_garbage 没有带 script_records,reconcile_project_references 不会跑,过渡引用清不掉)。临时下载包在成功路径上已释放。另外把该托管脚本派发到 runner 一次:日志出现「[MaaFW Runner] 复用共享 runtime」「[Python环境] 托管 Python Agent 复用共享 runtime: …(agents=1, shim=…)」,即 #696 删掉又恢复的 route 消费链路真的在跑;同一次运行也暴露出运行前自动更新只切了 Store 版本、没有像 API 路径那样回写 Managed.Version,日志说「已更新到 v4.8.0」但 checkout 仍是 v4.7.1。这两处是本 PR 原有逻辑,未在本次合并中改动,待另行处理。

未验证:按环境约束没跑真实游戏,AutoProxy 真机运行仍待人工确认。

🤖 Generated with Claude Code

qiyinxi and others added 13 commits September 8, 2026 22:30
第三层(MAS 托管)的服务层早已落库,缺的是宿主侧接线。本提交补第一批契约,
不改变自选目录形态的任何行为——两者并存。

- 新增 `MaaFWManagedConfig`,子类化 `MaaFWConfig`:既有的 `isinstance` 分发
  因此继续命中 `MaaFWEmbeddedManager`,无需为托管另造 manager。只补父类没有、
  而托管解析结果需要落盘的 `ImportProjectId` / `RunRootId` / `Status` 三个键。
- 注册进 `ScriptConfig` 列表、`CLASS_BOOK`、`TYPE_BOOK` 与两处 schema Literal。
  `MultipleConfig` 按类名索引,漏注册会在加载时**静默丢弃整条脚本配置**;
  `TYPE_BOOK` 漏了则会在按类名取显示名处 KeyError。
- 新增 `Config.get_script_records()`:托管环境服务要求 `type` 是 `CLASS_BOOK`
  的键而非类名,且 `Managed` / `ManagedRuntime` 下的 JSON 字段按 Mapping 读,
  而配置里存的是字符串,故在此解析。
- 新增 `Config.script_config_transaction()`:按脚本串行化配置写入者。**不复用**
  `ScriptConfig[uid].lock()`——那是运行期禁止界面改配置的闸门,会把事务体内
  自己的 `update_script` 一并拒掉。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
把第三层的服务层接进 `MaaFWEmbeddedManager`:托管脚本在任何用户任务之前先走
Store / Gateway 那条链解析出 checkout 与运行时,产出的可信 route 直接交给
inner task,`runner_task` 在 `managed_execution` 为真时不再自己算。

`check()` 对托管形态改判前置条件:项目目录是**环境准备的产物**而不是输入,
首次运行时 `Info.Path` 还是空的,用原来的「请设置项目路径」会把托管形态卡死;
按路径做的运行环境自检同理,改由准备那一步负责。

途中两处配置层缺陷会让托管形态根本跑不起来,一并修掉:

- `FolderValidator` 把工作目录及其子路径全列为禁区,而托管 checkout 本来就由
  AUTO-MAS 自己产出在 `data/maafw_project_runs/` 下,持久化绑定必然失败。把禁区
  列表提成可覆写的 `_forbidden_paths()`(默认行为不变),新增
  `ManagedFolderValidator` 只放开工作目录,系统目录与盘根仍禁;`MaaFWConfig`
  的 `Info.Path` 校验器改由 `_project_path_validator()` 提供,托管子类覆写它。
- `JSONValidator` 只接受 JSON 字符串,托管环境服务写的是 dict,于是 manifest 与
  runtime binding 被 `correct()` **静默丢成空**,运行时 route 反解必然报「缺少
  运行时 ID」。`correct()` 改为接受结构化输入并序列化;字符串输入行为不变。

实测(M9A v4.6.0 发行包,652.6 MB):导入脱壳后 checkout 71.2 MB,
Python agent 走共享 runtime `maafw-runtime-09379d…`(maafw==5.12.3),
不再建独立 venv;全量测试与基线一致。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`_safe_remove_tree` 用的是裸 `shutil.rmtree`。Windows 上删只读文件必然
`PermissionError`,而 git 仓的 pack 文件(`.git/objects/pack/*.idx`)就是只读的
—— 源目录里带 git 仓时,导入过程中任何一步失败,`finally` 的 staging 清理都会
再抛一个 `Access is denied`,把真正的失败原因整个盖住。

加一个只清只读位再重试的 `onexc` 钩子,非 `PermissionError` 一律照旧抛出。

实测:导入 M9A 源码仓(带 `.git`)从「Access is denied 到 pack-*.idx」变成真实
原因「Python Agent runtime ABI is unknown for indexes 0」——那才是它该被拒的理由。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`tests/task/test_maafw_managed_gate.py`(`137adfed` 落库、AUTO-MAS-Project#509 删除)当年把第三层
的「落库不接线」状态钉死;解 gate 的前提是第二层稳定,而第二层已合入 dev 并经真机
修复,所以这里把它的每一条断言反过来写:接线点必须在位。

覆盖四组,全部是纯逻辑、不碰文件系统也不联网:
- 托管脚本类型在 `CLASS_BOOK` / `TYPE_BOOK` / `ScriptConfig` 列表里都注册了,
  且三个新键只在子类上(漏注册会静默丢弃整条脚本配置);
- `Info.Path` 两种校验器各司其职:父类仍禁工作目录,托管放开、但盘根仍禁;
- `JSONValidator` 接受结构化输入并序列化,字符串输入行为不变;
- `get_script_records` 的 JSON 字段解析对坏值一律退化成空 Mapping。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
托管环境准备完成后,`_run_project_update` 与 `_ensure_project_environment` 会再跑一遍,
而它们走的是自选目录那套口径,结果把托管链路刚绑定好的东西整个覆盖掉。

真机实测:托管准备时 agent 已经是
`[Python环境] Agent python 使用 shared_runtime: …/maafw-runtime-09379da0…`,
被覆盖后变成 `[Python环境] Agent python 使用 external: python`,且换用了另一个
runtime `maafw-runtime-b800e2d9…`——依赖复用直接失效。

托管项目的版本由 Project Store 管,原地更新本就没有意义;环境也已由托管链路准备。
BeforeRun 与 AfterRun 两处都加上托管判据。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
M2 的后端部分。托管形态在此之前只能靠直接调服务层,界面无从接入。

新增端点(都在既有 `/api/scripts/maafw/` 下):
- `managed/import`    导入本地目录或 ZIP 并可选绑定到脚本
- `managed/versions`  列版本(含 current / pinned / references / 体积)
- `managed/switch`    切换当前版本,可同步更新脚本绑定
- `managed/version/delete`  删除版本
- `managed/inventory` Store 占用
- `managed/gc`        回收无人引用的版本,默认 dry-run

两条刻意的取舍:

- **绑定必须带 Store 身份**。只写 projectId/version 而不带 `StoreId` 与 manifest,
  运行时会被「脚本缺少可验证的 Project Store 身份」直接拒掉,所以导入端点在绑定时
  一次写全。
- **闸门与阻断的理由原样透出**。导入被拒(依赖不合规、ABI 未知、路径越界)和删除被
  阻断(current / pinned / references / lease)时,界面需要的正是那句原因,不吞成
  「操作失败」。

脱壳报告直接取 manifest 里现成的 `savedBytes` / `savedPercent` / `excludedReasons` /
`shells.families`,不另算一遍。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
从开发后端(36174)重新生成。生成物是 CRLF,`git add` 已按仓库的行尾规则归一化,
463 个被行尾差异标记的文件里只有 21 个真正有内容变化:15 个新模型、`MaaFwService`
与 `Service` 的六个方法、以及脚本类型与 `Managed` 三个新字段带来的三处增量。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
把 `MaaFWManaged` 加进前端各处按类型索引的表:`ScriptType` 联合、建项类型到后端枚举
的映射、配置类名到前端类型的反查(漏了会被 `resolveScriptType` 回落成 General、渲染成
通用脚本)、图标与短名、标签颜色,以及两处编辑页路径——托管复用 MaaFW 的编辑页,两者
配置结构相同,只多三个 Managed 键。

建项向导里托管选项排在 MaaFW 之前,描述写清它与自选目录的差别:由 AUTO-MAS 导入并
精简项目、去掉界面程序与自带 Python、多个脚本共用一套运行环境。三份词表同步。

`yarn typecheck` 与 `yarn lint` 通过。`yarn test` 419 passed / 1 failed,失败的
`electron/services/backendService.test.ts` 是既存问题(暂存本次改动后同样超时)。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
MaaFW 编辑页新增托管专属区块(只在 `MaaFWManaged` 类型出现,自选目录形态完全不受
影响),配 `useMaaFWManagedApi` 走生成的客户端,不手拼 axios。

三件事对应界面上的三块:

- **导入**:填本地项目目录或 ZIP 发行包,导入后自动绑定到本脚本。失败时用 Modal 展示
  后端给的原因全文——闸门拒绝的理由(依赖不合规、ABI 未知、路径越界)正是用户要看的
  东西,缩成「导入失败」等于什么都没说。
- **脱壳报告**:省了多少、百分比、移除的外壳家族、排除条数,可展开逐条看路径与原因。
  数值全部取自 manifest 里现成的 `savedBytes` / `savedPercent` / `shells` / `excludedReasons`,
  前端不重算。
- **版本管理**:表格列出版本、体积、最近使用,可切换与删除;current 行禁用这两个操作,
  删除被 pinned / references / lease 阻断时同样把原因原样弹出。

导入或切版本后重新拉一次配置——`Info.Path` 与 `Managed` 段都被后端改过了,否则界面还
停在旧 checkout 上。三份词表同步。

`yarn typecheck`、`yarn lint` 通过;`yarn test` 419 passed,唯一失败仍是既存的
`electron/services/backendService.test.ts` 超时。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
按仓库规矩改 CHANGELOG.md 后运行 scripts/changelog.py sync 同步生成物。

sync 顺带抹掉了 res/version.json 里两条既有条目的 by 署名:那两处署名是
机器人 97335f0 用 main 上的旧工作流直接写进生成物的,CHANGELOG.md 这个
唯一手写来源里从来没有,任何一次 sync 都会把它们擦掉。保留它们会让
check-changelog 闸门变红,这里不手改生成物。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
托管形态原本完全不更新:远程编排在未移植的插件宿主里,网关的 project_update
一直传 None。这里补上「下整包 → 导入为新版本 → 切过去」,与自选目录形态共用
同一个更新面板和同一套脚本级凭据。

三处托管特有、写错了不报错只出坏结果的地方:

- Store 导入的是一整棵树,差量包导进去就是个跑不起来的版本,所以恒要整包;
  服务不支持 prefer_full_package 时直接报错,不静默降级。
- 脱壳把根目录的 MFW.exe / maafw/ 之类标志全删了,外壳提示只能从 manifest
  回填,否则 M9A 这种同时发 -MXU.zip 与 -MFAA.zip 的项目会选错资产。
- upgrade_project 固定 inactive 导入,导完必须切版本,否则日志说更新成功、
  跑的还是旧版本。运行前更新也因此必须排在准备环境之前。

顺带修一个既有缺陷:/maafw/update 用 isinstance(MaaFWConfig) 判类型,托管是
它的子类,拦不住;不分流就会拿 Store 产出的 checkout 去做原地更新。

不做两阶段的 Managed.PendingUpgrade 升级——那条路要配套的配置迁移计划引擎。
自选目录形态今天就是直接更新的,新 interface 里没有的任务由 run_plan 记成
skippedTasks;托管沿用同一口径,且旧版本仍留在 Store 里可以切回去。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
迁移是**原地换类型**,不是"新建一个托管脚本再把旧的删掉":脚本 ID 保持不变,
队列成员、计划表、通知绑定和 data/<uid>/ 下的用户数据全都留着。走新建那条路
用户会发现脚本从队列里消失了,而这一步不会有任何报错。

为此给 MultipleConfig 加了 convert:类型不是单独存的字段,而是配置对象自己的
类名,换类型就是在原位换掉这个对象。用户 uuid 不重新生成——data/<script>/<user>
目录按它命名。

删原目录是不可撤销的,所以:只在用户显式勾选时做、一定排在导入与转换都成功
之后、删之前再过一遍 FolderValidator(拦驱动器根、系统目录和 AUTO-MAS 自己的
工作目录)。删除失败不回滚迁移——项目已经在 Store 里了,撤回去更糟,如实报告
让用户自己删。

迁移后清掉 Info.Path:项目已经不在那儿了,留着会把一个可能刚被删掉的目录当成
项目路径显示。真正的 checkout 由准备链路在首次运行时写回。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
真机验证 MaaYYs v3.10.2 -> v3.15.2 时逐个撞出来的:

1. 升级时不再沿用当前版本的 runtimeConstraint。它描述的是「这份载荷需要哪个
   MaaFramework」,是载荷的属性;套到新载荷上会被 Store 的一致性闸门拒成
   「==5.11.1 vs 5.13.0b2」——凡是顺带升了 MaaFramework 的项目都更新不了,
   而这几乎是每一次真实更新。不给时由 Store 从新包自行推导。

2. project_update 服务的 discover_update 补上 prefer_full_package 与
   version_only 两个透传参数。之前只有底层模块函数有,服务方法没暴露,网关按
   签名判断后直接拒掉,托管更新一次都跑不了。检查更新也因此会去换下载地址,
   白扣一次 Mirror 酱当日额度。

3. 版本体积与当前版本读错了键:体积在 summary.size.projectedBytes,项目的当前
   版本叫 currentVersion。读错不报错,界面上一律显示 0 B / 没有当前版本,看起来
   像「托管一点空间都没占」。实测该值是 74,653,605 B。

第 3 条能溜过去,是因为 M2 的两条路由测试用的是我臆造的返回形状而不是 Store
真实的输出;这次把那两个夹具按真实形状改了,并补上按签名校验网关依赖的断言。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@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.

Sorry @qiyinxi, your pull request is larger than the review limit of 150,000 diff characters

qiyinxi and others added 5 commits September 9, 2026 10:09
…afw-managed-20260908

# Conflicts:
#	res/version.json
…afw-managed-20260908

# Conflicts:
#	CHANGELOG.md
#	res/version.json
Function.MaaFWManagedPreview,默认关,故意不在设置界面里露出:谁能用由维护者
逐个告知,改 config/Config.json 打开。拒绝文案里也不写怎么打开。

只锁「进门」——建托管脚本、导入项目、把现有脚本转成托管;不锁「房间」——已经
建好的托管脚本关掉开关后照常运行、看版本、切版本。锁到房间里的话,维护者哪天
关掉开关,试用者的脚本会集体瘫掉,而这一步不会有任何报错。

前端按同一开关藏三个入口:建项向导的托管类型、编辑页的「转为托管」、托管区块
的导入行。设置保存走 exclude_unset,界面不绑这个键就永远不会回写,所以放进
schema 不会被设置页抹掉。

顺带把 dev 合进来(74 个提交),CHANGELOG 两边条目全保留,version.json 从合并
后的 CHANGELOG 重新生成;更新日志条目改口径为「小范围试用,暂不默认开放」。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
改成用户拍板的口径:后端链路与 API 全部保留,前端一行不接——没有建项入口、没有
「转为托管」、没有托管区块。主分支里不存在任何能被翻出来的隐藏界面。

撤掉的开关(80b01672)本来就有漏:那个键在配置模型里,toDict 会把
"MaaFWManagedPreview": false 写进每个用户的 Config.json,等于把开关名印给所有人。

前端只留 12 行类型识别(类型表、图标、列表标签、编辑页路由映射):试用者用
API 建出来的托管脚本在列表里要能正常显示、能打开、能跑,不能让界面炸。

完整的托管界面停在 feat/maafw-managed-ui-20260912,给试用者出包从它构建。
更新日志条目从「新增」挪到「开发流程」——这一版对普通用户没有可见变化。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@qiyinxi qiyinxi changed the title feat(maafw): MFW 托管脚本类型(导入脱壳、共用运行环境、版本管理、远程更新、一键迁移) feat(maafw): MFW 托管后端链路(导入脱壳、共用运行环境、版本管理、远程更新、迁移),界面暂不接入 Sep 12, 2026
用户拍板:删不删由用户在资源管理器里自己做。去掉 deleteSource 入参和两个删除
状态出参,路由里删目录那段整个拿掉,返回话里把原目录路径原样告诉用户,并提示
等托管版本确认能跑之后再删。

理由:投影是白名单式的,万一漏了某个运行时才需要、但 interface.json 没声明的
文件,原目录是唯一的退路;一个软件替用户做不可逆的事,出错时连退路都没了。

测试相应换成「原目录一个字节不动,且回话里说清它在哪」。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
qiyinxi and others added 3 commits September 13, 2026 10:28
…ect#696 死代码清理等)

冲突处理:
- CHANGELOG.md、res/version.json 取 dev 侧(AUTO-MAS-Project#713 起普通 PR 不再改这两处)
- app/models/schema.py 与 ScriptCreateIn.ts 的脚本类型描述串两侧合并,同时保留
  MaaFW托管脚本与 BAAH脚本
- Service.ts 保留本 PR 的托管接口,去掉 dev 已删除的 webhook/order 方法
- AUTO-MAS-Project#696 删除而本 PR 修改的 4 个托管栈文件(project_store/service.py、
  project_update/service.py、embedded/managed/__init__.py、services.py)取本 PR 侧

AUTO-MAS-Project#696 按「零实例化」删掉的其余托管栈文件与活文件中的接线块由下一提交恢复。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
AUTO-MAS-Project#696 把 MaaFW 第三层托管栈当死代码删了;本 PR 正是它的实例化方,合并后
这些模块会静默消失(embedded_manager 直接 import environment_service,
runner_task 不再消费 managed route)。此提交从 PR 的 merge-base bbe4045
原样恢复,同时保留 AUTO-MAS-Project#696 在同一文件里的其他修复。

整文件恢复(与 bbe4045 逐字一致,可用 `git diff bbe4045 -- <paths>` 复核):
- tools/core/automas_maafw_project_store/{__init__.py,py.typed}
- tools/embedded/managed/{environment_service.py,py.typed}
- tools/core/automas_maafw_runner/shared_agent.py
- tools/core/automas_maafw_runner/models.py
- tools/core/automas_maafw_project_update/{__init__.py,state.py,contracts.py}
- tools/core/__init__.py、tools/project_updater.py、tools/embedded/runtime_route.py
- tests/task/test_maafw_project_store_paths.py

只回填托管相关块(新增行全部来自 bbe4045AUTO-MAS-Project#696 的其他修复原样保留):
- runner.py:shared_agent 导入、_prepare_managed_native_runtime 及 sha 助手、
  Python Agent 共享 runtime 路由、SHARED_RUNTIME_KIND 兼容层分支
- runner/service.py:prepare_environment 的 managed_* 参数与共享 runtime 路由
- runner_task.py:maafw_managed_* 字段与消费 route 的分支
- project_update/apply.py:recover_update_operation
- project_update/transport.py:DownloadPaused/DownloadCancelled 与透传
- project_update/updater.py:以 bbe4045 为底,重放 AUTO-MAS-Project#696 的 logger 留痕与
  「指纹只在有候选更新时算一次」两项修复
- embedded/__init__.py:MaaFWManagedExecutionRoute 导出
- embedded_manager.py:Store checkout sidecar 守卫

未恢复:transport 下载循环里逐块 operation.read() 的暂停/取消检查——AUTO-MAS-Project#696 以
tests/task/test_maafw_update_download_checkpoint.py 固化了「每次尝试只读一次
状态」,两者冲突,保留 AUTO-MAS-Project#696 的口径。registry.py、controller_adb、
async_operation 等与托管栈无关的死代码不恢复。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@qiyinxi

qiyinxi commented Sep 13, 2026

Copy link
Copy Markdown
Contributor Author

预计5.6.0上线

@qiyinxi qiyinxi closed this Sep 15, 2026
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