CLI-Anything Slay the Spire 2:通过进程内 Bridge Mod 让真实 Steam 游戏 Agent 原生化的完整指南
【免费下载链接】CLI-Anything"CLI-Anything: Making ALL Software Agent-Native" -- CLI-Hub: https://clianything.cc/项目地址: https://gitcode.com/GitHub_Trending/cl/CLI-Anything
CLI-Anything-Slay-the-Spire-2是 CLI-Anything 生态中面向Slay the Spire 2(杀戮尖塔 2)的 CLI 驱动(harness):它通过在真实 Steam 游戏进程内部署一个.NET 9桥接模组STS2_Bridge,将游戏状态通过本地 HTTP API 暴露给命令行,从而实现对真实运行中游戏的有状态控制。本文将从工作原理、安装链路、命令体系、源码级实现到排障方法,完整讲解如何把这款 Roguelike 卡牌游戏变成"Agent 原生"的可编程环境。
读完本文你将掌握:桥接模组的构建与安装、cli-anything-sts2的全部常用命令、15 种归一化决策状态与角色映射、底层 HTTP API 的请求/响应格式,以及如何从源码验证每一步的实际行为。
工作原理:不是模拟器,也不是屏幕自动化
与 CLI-Anything 中大多数"包装独立桌面应用"的 harness 不同,本项目控制的是真实运行中的游戏本体。它既不使用无头模拟器,也不依赖屏幕图像识别与键鼠注入,而是采用"进程内桥接 + 本地 HTTP API"的架构:
- 游戏内桥接模组
STS2_Bridge作为 mod 运行在游戏进程内部,直接读取游戏的内部状态与动作 API; - 模组在
http://localhost:15526/api/v1/singleplayer暴露本地 HTTP 服务; - CLI 通过该 API 读取归一化状态,并回传动作指令。
这一架构的完整调用关系见 agent-harness/STS2.md 中的架构图,以及桥接模组的说明文档 agent-harness/bridge/plugin/README.md。
从源码看,HTTP 监听由模组侧在游戏进程中创建:BridgeMod.cs中初始化了HttpListener并同时绑定http://localhost:15526/与http://127.0.0.1:15526/两个前缀(见 BridgeMod.cs)。由于模组运行在游戏进程内部,它天然拥有对游戏内部状态和动作 API 的直接访问权,因此 CLI 到 HTTP 调用之间的"翻译损耗"极低——这正是本项目命名为"low translation gap"的原因。
与其他 harness 的本质区别:本 harness 无法脱离桥接模组工作,模组必须被构建并安装进游戏。构建与安装脚本目前会自动探测默认的 macOS Steam 游戏路径,若游戏安装在其他位置,需要显式传参或用环境变量覆盖。
环境要求与依赖清单
| 依赖 | 版本/说明 | 用途 |
|---|---|---|
| Steam 版Slay the Spire 2 | 已安装即可 | 承载桥接模组的真实游戏本体 |
| Python | >= 3.10 | 运行 CLI(setup.py 中python_requires=">=3.10",见 setup.py) |
.NET 9 SDK | 仅构建桥接模组时需要 | 编译STS2_Bridge模组 |
| click | >= 8.0.0 | CLI 唯一运行期依赖(见 setup.py) |
需要特别强调的是:桥接模组构建脚本会自动探测游戏数据目录;若自动探测失败,需要设置STS2_GAME_DATA_DIR环境变量或直接传入目录路径。
安装与联通:从零到state返回 JSON
第 1 步:安装 CLI
从仓库根目录进入 harness 目录并执行可编辑安装:
cd slay_the_spire_ii/agent-harness pip install -e .该命令会注册cli-anything-sts2控制台命令。入口点定义在 setup.py,指向 slay_the_spire_ii_cli.py 中的main函数。
第 2 步:构建桥接模组
cd slay_the_spire_ii/agent-harness/bridge/plugin ./build.sh脚本会尝试自动探测游戏数据目录,并把构建产物刷新到本地安装包目录:
slay_the_spire_ii/agent-harness/bridge/install/bridge_plugin/该目录最终包含两个关键文件:STS2_Bridge.dll与STS2_Bridge.json(manifest),可参考当前仓库中已生成的 bridge_plugin/。
若自动探测失败,显式传入游戏数据目录:
STS2_GAME_DATA_DIR="/path/to/data_sts2_macos_arm64" ./build.sh注意:目标数据目录至少需要包含以下文件,构建脚本才能链接成功:
sts2.dllGodotSharp.dll0Harmony.dll
第 3 步:安装模组到游戏
cd slay_the_spire_ii/agent-harness/bridge/install ./install_bridge.sh默认安装目标为:
~/Library/Application Support/Steam/steamapps/common/Slay the Spire 2/SlayTheSpire2.app/Contents/MacOS/mods/STS2_Bridge/从 install_bridge.sh 的源码可以看到,脚本会创建mods/STS2_Bridge/目录并把STS2_Bridge.dll与STS2_Bridge.json复制进去。若游戏不在默认位置,将游戏根目录作为参数传入:
./install_bridge.sh "/path/to/Slay the Spire 2"第 4 步:在游戏中启用模组
启动游戏,确认STS2_Bridge已被加载并启用。启用后模组监听:
http://localhost:15526/模组启动时会在游戏控制台打印类似[STS2 Bridge] v1.0.0 server started on http://localhost:15526/的日志(见 BridgeMod.cs),可用于确认服务已就绪。
第 5 步:验证连通
cli-anything-sts2 --help cli-anything-sts2 state如果cli-anything-sts2 state返回 JSON,说明 CLI 与桥接模组已经正确连通。
命令体系详解:菜单、战斗、地图与奖励全流程
cli-anything-sts2的命令全部由 click 定义在 slay_the_spire_ii_cli.py 中,每条命令都映射到 action_adapter.py 里对应的动作 payload 工厂函数。
从主菜单开始一局游戏
cli-anything-sts2 state cli-anything-sts2 continue-game cli-anything-sts2 start-game --character IRONCLAD --ascension 0 cli-anything-sts2 abandon-game cli-anything-sts2 return-to-main-menustart-game的两个参数在 CLI 源码中均有默认值(见 slay_the_spire_ii_cli.py):--character默认为IRONCLAD,--ascension默认为0。--character当前可识别的角色为:
| 角色 | 说明 |
|---|---|
IRONCLAD | 铁甲战士 |
SILENT | 静默猎手 |
DEFECT | 故障机器人 |
NECROBINDER | 死灵缚者 |
REGENT | 摄政者 |
一局游戏中的手动控制
cli-anything-sts2 state cli-anything-sts2 choose-map 0 cli-anything-sts2 play-card 0 --target jaw_worm_0 cli-anything-sts2 end-turn cli-anything-sts2 claim-reward 0 cli-anything-sts2 pick-card-reward 0 cli-anything-sts2 rest 0 cli-anything-sts2 event 0 cli-anything-sts2最后一条不带子命令的cli-anything-sts2会进入交互式 REPL 模式。从源码看(slay_the_spire_ii_cli.py),REPL 会打印 banner,支持help、quit/exit,并把输入的每一行用shlex切分后以相同参数递归调用 CLI 主入口。
常用命令分组速查
| 分组 | 命令 |
|---|---|
| 状态查看 | state、raw-state |
| 菜单动作 | continue-game、start-game、abandon-game、return-to-main-menu |
| 战斗 | play-card、use-potion、end-turn |
| 地图与房间 | choose-map、event、advance-dialogue、rest、proceed |
| 奖励与覆盖层 | claim-reward、pick-card-reward、skip-card-reward、select-card、confirm-selection、select-relic |
play-card的--target参数用于指定目标实体的entity_id(如jaw_worm_0),仅在卡牌需要指定任意敌人目标时必须提供;use-potion的--target语义相同。两个命令的 payload 构造见 action_adapter.py。
完整命令面可通过cli-anything-sts2 --help查看。
配置项与源码对应关系
CLI 配置
| 参数 | 默认值 | 说明 |
|---|---|---|
--base-url | http://localhost:15526 | 本地桥接 API 基础地址 |
--timeout | 10.0 | HTTP 请求超时(秒) |
示例:
cli-anything-sts2 --base-url http://127.0.0.1:15526 --timeout 20 state这两个参数在 slay_the_spire_ii_cli.py 中被注入CliRuntime,再传给 HTTP 客户端Sts2RawClient。后者的singleplayer_url属性会拼出{base_url}/api/v1/singleplayer完整端点(见 sts2_backend.py)。
桥接模组构建配置
| 环境变量 | 用途 |
|---|---|
STS2_GAME_DATA_DIR | 当 build.sh 无法自动探测游戏数据目录时手动指定 |
底层 HTTP API 参考:状态读取与动作回传
桥接模组暴露两个端点(详见 raw_api.md):
http://localhost:15526/api/v1/singleplayer— 单机模式http://localhost:15526/api/v1/multiplayer— 多人(合作)模式
两个端点互斥:在多人对局中调用单机端点(反之亦然)会返回 HTTP 409。这些端点面向本地使用设计,没有认证或安全措施,不应暴露到公网。
GET /api/v1/singleplayer
查询参数:
| 参数 | 取值 | 默认值 | 说明 |
|---|---|---|---|
format | json、markdown | json | 响应格式 |
返回的state_type字段标识当前所在界面:monster/elite/boss(战斗中)、hand_select(战斗内选牌)、combat_rewards(战后奖励)、card_reward(选卡奖励)、map(地图)、rest_site(休息点)、shop(商店)、event(事件/Ancient)、card_select(牌组选卡)、relic_select(遗物选择)、treasure(宝箱房)、overlay(兜底覆盖层,防止卡死)、menu(无对局进行中)。
CLI 侧的state命令会通过 state_adapter.py 的normalize_state把上述原始状态进一步归一化为 15 种"决策状态":
menu·combat_play·hand_select·map_select·game_over·combat_rewards·card_reward·event_choice·rest_site·shop·card_select·relic_select·treasure·overlay·unknown
每种决策状态会附带统一格式的type、decision、context(含act、floor、ascension)与run字段,并针对各自界面抽取关键决策数据——例如战斗状态会包含energy、hand、enemies、三堆牌库计数等,方便 Agent 直接依据归一化 JSON 做决策,而不必解析原始结构。raw-state命令则直接透传桥接模组的原始 JSON,用于排查或调试。
POST /api/v1/singleplayer
请求体为 JSON,action字段标识动作名。以下为核心动作及参数语义:
| 动作 | 关键参数 | 说明 |
|---|---|---|
play_card | card_index(手牌 0 基索引)、target | 出牌;target对AnyEnemy卡牌必填,自目标/群体卡可省略 |
use_potion | slot(药水槽索引)、target | 使用药水;target对AnyEnemy药水必填 |
end_turn | 无 | 结束回合 |
combat_select_card | card_index | 战斗内"选择要消耗/丢弃的卡"时选中卡牌 |
combat_confirm_selection | 无 | 确认战斗内卡牌选择(需确认按钮可用) |
claim_reward | index | 领取战后奖励;金币/药水/遗物即时领取,卡牌奖励会进入card_reward界面 |
select_card_reward | card_index | 从卡牌奖励中加入牌组 |
skip_card_reward | 无 | 跳过卡牌奖励 |
proceed | 无 | 从奖励界面、休息点、商店(自动关闭货架)、宝箱房前进到地图;事件界面请用choose_event_option |
choose_rest_option | index | 休息点选项(休息回血、锻造升级卡牌、遗物附加选项) |
shop_purchase | index | 购买商店物品(需有货且买得起,自动打开货架) |
choose_event_option | index | 普通事件与 Ancient 事件(对话后)选项 |
advance_dialogue | 无 | 点击 Ancient 事件对话,需反复调用直到in_dialogue为false |
choose_map_node | index | 依据地图状态的next_options索引选择节点 |
select_card | index | 选卡界面(变形/升级/移除等);格子界面为切换选中,选卡类界面即时选择 |
confirm_selection | 无 | 确认当前选卡(升级/变形预览或主确认按钮);选卡类界面无需调用 |
cancel_selection | 无 | 预览时返回格子;选卡类界面点击跳过(若可用);否则关闭选卡界面 |
select_relic | index | Boss 遗物选择(即时选择) |
skip_relic_selection | 无 | 跳过遗物选择 |
claim_treasure_relic | index | 领取宝箱房已揭示的遗物(宝箱在查询状态时自动开启) |
continue_game/abandon_game/return_to_main_menu | 无 | 菜单层对局管理 |
start_new_game | character、ascension | 从主菜单开启新对局 |
所有错误响应统一返回:
{ "status": "error", "error": "Description of what went wrong" }CLI 侧的 HTTP 客户端在收到非 JSON 响应或连接失败时,会抛出带可读信息的ApiError(见 sts2_backend.py),例如"无法连接游戏桥接 API,游戏是否在运行且已启用桥接模组?"。
从源码看 CLI 的执行链路
一条命令的完整执行链路可以概括为:
- 用户输入
cli-anything-sts2 play-card 0 --target jaw_worm_0; - click 解析参数后调用
play_card命令处理器(slay_the_spire_ii_cli.py); _run_post从actions.play_card(card_index, target=...)取得 payload(action_adapter.py),弹出action键后调用client.post_action(action, **payload);Sts2RawClient.post_action将action与其余字段合并为请求体,POST 到单机端点(sts2_backend.py);- 响应以缩进 JSON 打印到标准输出。
state命令则先通过get_state(format="json")拉取原始状态,再交给normalize_state归一化后输出。另外,action命令提供了"透传通道":cli-anything-sts2 action <name> --kv key=value会把任意动作名和键值对原样 POST 给桥接模组,--kv的值会自动做类型推断(整数、布尔、字符串),便于在 CLI 尚未覆盖新动作时应急使用(见 slay_the_spire_ii_cli.py 与 action_adapter.py 的from_name注册表)。
Troubleshooting:常见问题与处理
cli-anything-sts2 state无法连接
这通常意味着以下条件之一尚未满足:
- 游戏没有在运行;
STS2_Bridge未安装或未启用;localhost:15526上的本地 API 尚未就绪。
可以先在游戏内确认模组日志已打印server started,再重试命令;若端口被占用或地址有异,可通过--base-url指向http://127.0.0.1:15526显式指定。
build.sh找不到游戏目录
确认游戏已安装,然后显式传入数据目录:
STS2_GAME_DATA_DIR="/path/to/data_sts2_macos_arm64" ./slay_the_spire_ii/agent-harness/bridge/plugin/build.sh安装脚本报"插件文件缺失"
install_bridge.sh 会校验安装包内是否存在STS2_Bridge.dll与STS2_Bridge.json。若缺失,说明尚未执行构建步骤,先运行../plugin/build.sh生成安装包再重试。
相关文档与进一步阅读
- agent-harness/STS2.md:项目专属架构分析与 SOP,含完整的桥接架构图、核心领域模块表与决策状态清单。
- agent-harness/bridge/plugin/README.md:桥接模组的构建与安装说明。
- agent-harness/bridge/plugin/docs/raw_api.md:原始 HTTP API 全量参考,含单机/多人两种模式、全部动作与状态字段细节。
- agent-harness/cli_anything/slay_the_spire_ii/slay_the_spire_ii_cli.py:CLI 全部命令定义与 REPL 实现。
- agent-harness/cli_anything/slay_the_spire_ii/skills/SKILL.md:面向 Agent 的安装与使用技能描述。
- agent-harness/setup.py:包元数据、依赖与
cli-anything-sts2入口点定义。
【免费下载链接】CLI-Anything"CLI-Anything: Making ALL Software Agent-Native" -- CLI-Hub: https://clianything.cc/项目地址: https://gitcode.com/GitHub_Trending/cl/CLI-Anything
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考