Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set reproducible build epoch
run: echo "SOURCE_DATE_EPOCH=$(git show -s --format=%ct HEAD)" >> "$GITHUB_ENV"
- uses: astral-sh/setup-uv@v6
with:
python-version: "3.12"
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ jobs:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Set reproducible build epoch
run: echo "SOURCE_DATE_EPOCH=$(git show -s --format=%ct HEAD)" >> "$GITHUB_ENV"
- uses: astral-sh/setup-uv@v6
with:
python-version: "3.12"
Expand Down
134 changes: 134 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# Changelog

## 0.1.5 — 托管更新事务内核(默认仍关闭)

- 新增 HSR 插件自有的事务更新内核:固定 release/asset 身份、大小与
SHA-256 校验,安全 ZIP 解压、同卷 staging、跨进程锁、journal、崩溃
恢复及保留上一版本的手动回滚。
- 新增 SRA/M7A Managed 布局声明。SRA 安装目录整体由发布包管理且不触碰
`%APPDATA%\SRA`;M7A 仅迁移 `config.yaml`、用户 YAML、日志和截图,
`sponsor.jpg` 与其检查器始终作为同一 release 成对更新。
- 增加 17 项 deterministic 事务/安全测试;真实下载、真实进程占用和真实
Windows 安装仍未手测,因此 `managed_enabled` 继续 fail-closed。
- `automas-script-hsr` 升级到 `0.1.4`;
`automas-hsr-adapter-sra` 升级到 `0.1.4`;
`automas-hsr-adapter-m7a` 与一键安装元包升级到 `0.1.5`。
- SRA/M7A 能力描述版本更新为已固定 release 的 `2.18.3` / `2026.6.8`。

## 0.1.4 — 外部安装版本与更新策略契约

### 新增

- HSR 核心新增稳定的安装快照与更新策略 DTO;适配器版本和用户安装的脚本版本
不再混为同一字段。
- SRA 适配器通过 `SRA-cli.exe` 的 PE fixed-file metadata 只读探测已安装版本,
不增加 pywin32 依赖。
- M7A 适配器从上游真实路径 `assets/config/version.txt` 只读探测版本。
- 能力快照向已认证前端暴露各引擎的 update policy 与 installation snapshot。
- 固定 SRA v2.18.3 与 M7A v2026.6.8 的 GitHub release ID、asset ID、文件大小
和 GitHub 计算的 SHA-256 digest,供后续更新器严格比对。

### 安全边界

- 默认模式为 External;Custom-fork 仅只读探测。
- Managed 与网络 release check 仍 fail closed。固定清单随 AUTO-MAS 插件版本发布,
可检测上游可变 release 的资产漂移;事务安装、配置迁移和回滚接通前不得因为已有
digest 就宣称 Managed 可用。

### 发行

- `automas-script-hsr` 升级到 `0.1.3`。
- `automas-hsr-adapter-sra` 升级到 `0.1.3`,要求核心 `>=0.1.3`。
- `automas-hsr-adapter-m7a` 升级到 `0.1.4`,要求核心 `>=0.1.3`。
- 一键安装元包 `automas-hsr` 升级到 `0.1.4` 并锁定上述最低兼容版本。

## 0.1.3 — 培养目标执行闭环修复

### 修复

- M7A 在启用培养目标且未配置手动主关卡时,仍开启 `power_enable` 进入原生
Power 流程,并用 `侵蚀隧洞=无` 覆盖旧的手动副本选择,避免静默跳过或误刷
上一轮残留关卡。
- 移除“清体力未开启,跳过历战余响和清体力”这一伪成功标记;该输出不再能让
Daily 被错误判定为成功。
- SRA 培养目标模式明确由 SRA 原生逻辑接管历战余响是否进入执行计划。MAS
不再因缺少手动 EOW 关卡记录跳过,而是始终监测真实日志,仅在确认完成后回写。
- SRA 输出“未找到任何培养目标任务”“未识别到可执行任务”,或全部目标 OCR
均为空时,即使进程退出码为 0 也按失败处理;部分 OCR 为空但至少一个目标识别
成功时不误判。
- `M7AOrnamentWeeklyCount` 的 0..7 限制改为 Pydantic `Annotated` 运行时
约束;`PluginField(min/max)` 仅保留为宿主 UI 元数据,测试替身与真实宿主一致。

### 发行

- `automas-script-hsr` 升级到 `0.1.2`。
- `automas-hsr-adapter-sra` 升级到 `0.1.2`,要求核心 `>=0.1.2`。
- `automas-hsr-adapter-m7a` 升级到 `0.1.3`,要求核心 `>=0.1.2`。
- 一键安装元包 `automas-hsr` 升级到 `0.1.3` 并锁定上述最低兼容版本。

## 0.1.2 — M7A 非 Daily 超时传递修复

### 修复

- `ReceiveRewards`、`DivergentUniverse` 与 `CurrencyWars` 创建原生运行计划时,
将脚本级 `timeout_seconds` 显式传入共用的 patch 运行闭包,避免计划创建阶段
因未知关键字参数抛出 `TypeError`。
- 新增三个非 Daily 模块的运行计划回归测试,验证计划可执行并将超时值原样传递
给 M7A runner。

### 发行

- `automas-hsr-adapter-m7a` 升级到 `0.1.2`。
- 一键安装元包 `automas-hsr` 升级到 `0.1.2`,并要求
`automas-hsr-adapter-m7a>=0.1.2,<0.2.0`。
- `automas-script-hsr` 与 `automas-hsr-adapter-sra` 保持 `0.1.1`。

## 0.1.1 — 培养目标双引擎支持

### 新增

- 公共配置 `HSRConfig.CultivationTarget`,包含四个引擎无关字段:
- `Enabled: bool = False`
- `M7ARecognitionScheme: Literal["instance","drop"] = "instance"`
- `M7AOrnamentWeeklyCount: int = 1`(0..7)
- `M7AUseUserStageWhenOnlyRelics: bool = False`
- SRA 适配器:Daily 模块开启培养目标时写入
`trailblazePower.useBuildTarget=true`、`tasklist=[]`,由 SRA 原生识别流程
决定副本;关闭时显式重置 `useBuildTarget=false`,保持手动副本行为。
目标模式下 `tasklist` 为空不再被判为「无可执行副本」而跳过 Daily。
- M7A 适配器:Daily 模块开启培养目标时 MAS 完全接管四个 M7A 原生键
(`build_target_enable` / `build_target_scheme` /
`build_target_ornament_weekly_count` /
`build_target_use_user_instance_when_only_erosion_and_ornament`);
关闭时显式写入 `build_target_enable=false`。
非法 scheme、越界次数、顶层非对象、写盘失败均 fail closed。
- 公共编排层 `_resolve_daily_runnable_parts`:培养目标启用时即使
`main_configured` 为 false 也不跳过 Daily。
- 测试:新增 `test_cultivation_target_contract.py`(21 例)、
`test_sra_cultivation_target.py`(23 例)、
`test_m7a_cultivation_target.py`(45 例)。

### 变更

- 四个 distribution 版本从 `0.1.0` 升至 `0.1.1`。
- 内部依赖下限从 `>=0.1.0,<0.2.0` 升至 `>=0.1.1,<0.2.0`。
- `M7A_DAILY_PATCH_WHITELIST` 新增三个键:`build_target_scheme`、
`build_target_ornament_weekly_count`、
`build_target_use_user_instance_when_only_erosion_and_ornament`。
- `build_m7a_daily_patch` 新增 `cultivation_target` 参数。

### 兼容性

- 默认关闭,旧配置无需迁移。
- 关闭时 SRA/M7A 适配器严格保持 0.1.0 的手动副本/EOW 行为。
- 开关切换时显式重置上一轮脏状态,不跨轮残留。
- 失败、超时、取消不产生伪完成状态或半写配置。

### 参考版本

- StarRailAssistant v2.16.1
- March7thAssistant v2026.4.27

## 0.1.0 — 首次发布

四个 distribution 的初始版本。
83 changes: 83 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,89 @@ AUTO-MAS 的崩坏:星穹铁道插件工作区,也是 HSR 插件及其引擎
每个目录独立构建为一个 Python distribution。`automas-hsr` 不包含运行时代码或
插件 entry point;适配器依赖 `automas-script-hsr`,适配器之间互不依赖。

## External inspection and managed transaction foundation (0.1.5+)

- 能力快照中的适配器 `version` 表示该适配器验证过的上游基线,不代表用户当前
安装的脚本版本。
- SRA 安装版本从 `SRA-cli.exe` 的 PE fixed-file metadata 读取;M7A 从
`assets/config/version.txt` 读取。探测过程不启动脚本、游戏或 Agent。
- 默认模式是 External,只读展示路径、可用性和本地版本;源码 fork 可使用
Custom-fork 语义,MAS 不修改其目录。
- AUTO-MAS 插件版本固定了经 GitHub Release API 观察到的 release ID、asset ID、
文件大小与 SHA-256 digest;上游 release 可变更,因此运行时必须与固定清单逐项
一致,不能盲目信任 `latest` 或下载后自算哈希。
- HSR 核心包已提供固定资产校验、安全解压、同卷 staging、跨进程锁、journal、
崩溃恢复和手动回滚的事务内核;SRA/M7A 适配器也声明了各自的安装布局与配置
保留边界。
- Managed 下载与覆盖安装仍未对用户开放:宿主鉴权下载/进度接口及真实 Windows
SRA/M7A 安装测试接通前继续 fail closed。事务内核通过 deterministic 测试不等于
真实安装链已经验收。

## Cultivation Target (0.1.1+)

培养目标模式让 HSR 双引擎使用各自原生培养目标识别流程,由公共配置
`CultivationTarget.Enabled` 统一开关。默认关闭,旧配置与现有手动副本行为完全不变。

### 公共配置(`HSRConfig.CultivationTarget`)

| 字段 | 类型 | 默认 | 说明 |
| --- | --- | --- | --- |
| `Enabled` | `bool` | `False` | 由当前 `TaskMapping.Daily` 选中的引擎使用其原生培养目标能力 |
| `M7ARecognitionScheme` | `Literal["instance","drop"]` | `"instance"` | M7A 识别方案:instance=按副本名称,drop=按副本素材 |
| `M7AOrnamentWeeklyCount` | `int` | `1` | M7A 饰品提取周次数,范围 0..7 |
| `M7AUseUserStageWhenOnlyRelics` | `bool` | `False` | 仅识别到侵蚀隧洞和饰品提取时是否改用用户手动副本 |

`Enabled` 只表达引擎无关的意图;`M7A*` 前缀字段只由 M7A 适配器解释,SRA 适配器
忽略它们。公共层不传递任何引擎原生键。

### SRA 适配(`automas-hsr-adapter-sra`)

- 参考版本:StarRailAssistant v2.18.3
- 开启时写入 `trailblazePower.useBuildTarget=true`、`tasklist=[]`,由 SRA 原生
识别流程决定副本;MAS 不向 tasklist 注入手动副本(含 EOW)。
- SRA 原生培养目标可能自行把 EOW 加入计划,且没有“仅排除 EOW”的配置开关;
因此目标模式下 EOW 的执行时机由 SRA 接管,MAS 只根据真实日志回写完成状态。
- 关闭时显式写入 `useBuildTarget=false`,严格保持现有手动副本/EOW tasklist 行为。
- 目标模式下 `tasklist` 为空不会被判为「无可执行副本」而跳过 Daily。
- 无培养目标、无可执行任务、全部 OCR 为空均按失败处理,不接受退出码 0 的
空运行作为成功。

### M7A 适配(`automas-hsr-adapter-m7a`)

- 参考版本:March7thAssistant v2026.6.8
- 开启时 MAS 完全接管四个 M7A 原生键:
`build_target_enable`、`build_target_scheme`、
`build_target_ornament_weekly_count`、
`build_target_use_user_instance_when_only_erosion_and_ornament`。
- 有手动 `Stage.ScriptStage` 时保留其回退语义;没有手动主关卡时写入
`侵蚀隧洞=无` 的安全占位并开启 Power 流程,避免沿用旧关卡。
- 关闭时显式写入 `build_target_enable=false`,其余手动副本行为不变。
- 非法 scheme、越界次数、顶层非对象、写盘失败均 fail closed,不产生半文件。

### 行为差异

| 维度 | SRA | M7A |
| --- | --- | --- |
| 开关字段 | `trailblazePower.useBuildTarget` | `build_target_enable` |
| 识别方案 | 原生流程,无 MAS 侧参数 | `build_target_scheme`(instance/drop) |
| 饰品次数 | 由 SRA 自行决定 | `build_target_ornament_weekly_count` |
| 回退副本 | 不注入(tasklist 为空) | 保留 `Stage.ScriptStage` |
| 完成判定 | 依赖 SRA 日志/退出码 | 依赖 M7A 日志/退出码 |

### 可观测性与已知限制

- 开关切换时 SRA/M7A 适配器均显式重置上一轮脏状态(useBuildTarget /
build_target_enable),不会跨轮残留。
- 培养目标模式下 MAS 不伪造完成状态:EOW/周常仍依赖
`detect_echo_of_war_completion` / `detect_weekly_completion` 从原生日志
中提取证据;SRA 目标模式只是扩大 EOW 日志监测范围,不会无证据写完成。
- SRA 目标模式下若 SRA 本身未返回可判断的完成日志,MAS 不会标记 EOW 完成,
下次运行会继续尝试。
- `M7AOrnamentWeeklyCount` 的 0..7 边界在公共 schema 中通过 Pydantic
`Annotated` 约束执行,`PluginField(min=0,max=7)` 同时向 UI 暴露边界;
M7A 适配器在 `build_m7a_daily_patch` 中再次做整数与范围校验,非法值抛
`ValueError` 并 fail closed。

## Development

```powershell
Expand Down
8 changes: 4 additions & 4 deletions packages/automas_hsr/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@ build-backend = "setuptools.build_meta"

[project]
name = "automas-hsr"
version = "0.1.0"
version = "0.1.6"
description = "AUTO-MAS HSR plugin bundle for one-click core, SRA, and M7A installation"
readme = { file = "README.md", content-type = "text/markdown" }
requires-python = ">=3.12"
authors = [{ name = "AUTO-MAS Team" }]
license = "AGPL-3.0-or-later"
license-files = ["LICENSE"]
dependencies = [
"automas-script-hsr>=0.1.0,<0.2.0",
"automas-hsr-adapter-sra>=0.1.0,<0.2.0",
"automas-hsr-adapter-m7a>=0.1.0,<0.2.0",
"automas-script-hsr>=0.1.5,<0.2.0",
"automas-hsr-adapter-sra>=0.1.5,<0.2.0",
"automas-hsr-adapter-m7a>=0.1.6,<0.2.0",
]

[project.urls]
Expand Down
4 changes: 2 additions & 2 deletions packages/automas_hsr_adapter_m7a/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ build-backend = "setuptools.build_meta"

[project]
name = "automas-hsr-adapter-m7a"
version = "0.1.0"
version = "0.1.6"
description = "March7thAssistant adapter for AUTO-MAS HSR"
readme = { file = "README.md", content-type = "text/markdown" }
requires-python = ">=3.12"
authors = [{ name = "AUTO-MAS Team" }]
license = "AGPL-3.0-or-later"
license-files = ["LICENSE"]
dependencies = [
"automas-script-hsr>=0.1.0,<0.2.0",
"automas-script-hsr>=0.1.5,<0.2.0",
"PyYAML>=6",
]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
M7A_DESCRIPTOR = HSRAdapterDescriptor(
engine="M7A",
display_name="March7thAssistant",
version="2026.4.27",
version="2026.6.8",
tasks=M7A_TASKS,
supported_modes=("AutoProxy",),
capabilities=frozenset({"stage_catalog"}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@ def _echo_of_war_weekday_to_iso(weekday: object) -> int:
"echo_of_war_enable",
"echo_of_war_timestamp",
"build_target_enable",
"build_target_scheme",
"build_target_ornament_weekly_count",
"build_target_use_user_instance_when_only_erosion_and_ornament",
"instance_type",
"instance_names",
"instance_names_challenge_count",
Expand All @@ -146,9 +149,20 @@ def build_m7a_daily_patch(
daily_eow_enabled: bool,
main_stage: tuple[str, str] | None = None,
eow_name: str | None = None,
cultivation_target: dict | None = None,
) -> dict:
"""构造 M7A routine 的运行配置 patch。"""
"""构造 M7A routine 的运行配置 patch。

``cultivation_target`` 为公共配置 ``HSRCultivationTargetConfig`` 序列化
后的字典(或 None)。当 ``Enabled`` 为 true 时,MAS 接管四个 M7A 原生
``build_target_*`` 键;为 false 或缺省时显式写入
``build_target_enable=False`` 以避免上一轮脏状态。
"""

eow_enabled = bool(daily_eow_enabled)
cultivation_enabled = bool(
cultivation_target is not None and cultivation_target.get("Enabled")
)

# 配置不完整时直接报错,避免刷错副本。
if eow_enabled and eow_name is None:
Expand Down Expand Up @@ -199,12 +213,12 @@ def build_m7a_daily_patch(
new_instance_names[main_type] = main_name
new_instance_counts[main_type] = count_max
patch["power_enable"] = True
elif not eow_enabled:
patch["power_enable"] = False
else:
elif cultivation_enabled or eow_enabled:
patch["power_enable"] = True
patch["instance_type"] = M7A_NO_OP_INSTANCE_TYPE
new_instance_names[M7A_NO_OP_INSTANCE_TYPE] = M7A_NO_OP_INSTANCE_NAME
else:
patch["power_enable"] = False

if eow_enabled:
assert eow_name is not None, "前置校验保证启用历战余响时 eow_name 不为 None"
Expand All @@ -219,6 +233,35 @@ def build_m7a_daily_patch(
if new_instance_counts:
patch["instance_names_challenge_count"] = new_instance_counts

# 培养目标接管:MAS 完全控制四个 build_target_* 键,显式写入以避免上一轮脏状态。
if cultivation_enabled:
assert cultivation_target is not None
raw_scheme = cultivation_target.get("M7ARecognitionScheme")
if raw_scheme is None or raw_scheme == "":
scheme = "instance"
elif raw_scheme in ("instance", "drop"):
scheme = raw_scheme
else:
raise ValueError(f"build_target_scheme 非法: {raw_scheme!r}")
ornament_count = cultivation_target.get("M7AOrnamentWeeklyCount")
if (
not isinstance(ornament_count, int)
or isinstance(ornament_count, bool)
or ornament_count < 0
or ornament_count > 7
):
raise ValueError(
f"build_target_ornament_weekly_count 越界: {ornament_count!r}"
)
patch["build_target_enable"] = True
patch["build_target_scheme"] = scheme
patch["build_target_ornament_weekly_count"] = ornament_count
patch["build_target_use_user_instance_when_only_erosion_and_ornament"] = bool(
cultivation_target.get("M7AUseUserStageWhenOnlyRelics")
)
else:
patch["build_target_enable"] = False

return patch


Expand Down
Loading
Loading