Skip to content
5 changes: 5 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ uv run --env-file .env ruff check --fix src/你修改的文件.py

- 默认不要主动执行 `git commit`、`git push`、`git reset`、删分支等版本控制操作,除非用户明确要求。
- 测试改动在独立仓 `zzz-od-test` 提交:主仓 `git add zzz-od-test/...` 会被 `.gitignore` **静默跳过**(不报错但未加入)→ 须 `git -C zzz-od-test add test/ && git -C zzz-od-test commit` 单独提交,否则 PR 丢测试。
- **两仓协同**(涉及测试仓改动时,主仓 + 测试仓配对;详见 [development_workflow.md](docs/develop/development_workflow.md) §4):
- **同分支**:测试仓建同名分支(`feat/xxx` ↔ `feat/xxx`),测试改动落测试仓,不进主仓。
- **配对提交**:主仓 commit + `git -C zzz-od-test commit` 同步推进,别只提交一仓。
- **同开关联 PR**:开主仓 PR 时同开测试仓 PR,PR 描述互相挂链接(**跨仓链接用 `OneDragon-Anything/<repo>#<N>` 或完整 URL,禁裸 `#N`** —— 裸 `#N` 会被 GitHub 识别成本仓而非目标仓);别让测试仓分支挂着改动却没开 PR(主仓合了才补测试仓 = 漏)。
- **合并顺序:测试仓先 → 主仓后**(主仓 main 的 test-check clone 测试仓 main,测试仓先合才稳)。
- 如果用户明确要求切换分支,先 `stash` 当前改动,再切换。
- Review 关注逻辑错误、运行时崩溃、死循环、资源泄漏;不要为风格问题大改现有代码。
- 提交 PR 后,review comment 需要逐条回复或修正。
Expand Down
4 changes: 3 additions & 1 deletion docs/develop/development_workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

> 一个功能从立项到交付的端到端链路。AGENTS.md 有 always-on 骨架;本页给详细判据、实例与配套更新规则。
>
> 当前只覆盖**游戏自动化功能**(已验证场景:OpenAndEnterGame)。bug 修复 / 性能 / UI / 模型等其他类型见文末「其他类型」,后续补。
> 当前主干只覆盖**游戏自动化功能**(已验证场景:OpenAndEnterGame);但 **§4 提 PR 的两仓协同适用所有涉及测试仓改动的开发**(backend / 重构 / UI / 模型等只要动了测试仓代码都走这套,不限游戏自动化)。bug 修复 / 性能 / UI / 模型等其他类型见文末「其他类型」,后续补。

## 主干

Expand Down Expand Up @@ -37,6 +37,8 @@

### 4. 提 PR

> **本步两仓协同适用所有涉及测试仓改动的开发,不限游戏自动化功能**。下文以游戏自动化为例,但「同分支 / 配对提交 / 关联 PR / 合并顺序」对 backend / 重构 / UI / 模型等任何动测试仓的改动同样强制(非游戏流程改动也常漏开测试仓 PR,见 AGENTS.md「提交流程与协作边界」)。

跨仓 PR 顺序:**先建测试仓 PR,再建主仓 PR**:

1. 测试仓改动先提交、推送、开 PR(`git -C zzz-od-test`),拿到测试仓 PR 链接。
Expand Down
29 changes: 29 additions & 0 deletions docs/develop/zzz/application/predefined_team_checker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# 预备编队角色识别(PredefinedTeamChecker)

## 概述

`PredefinedTeamChecker` 是一个**校准工具**(**开发工具应用 / devtools app** —— 不参与玩法流程,只用于校准并回写配置,非自动化玩法),识别游戏内预备编队的**实际角色**并写回 `team_config`。用途:玩家在游戏里改了预备编队后,跑此 app 核对 / 同步配置(切队前校准),避免 `team_config` 与游戏实际不一致导致后续选队错位。

⚠️ 它进入的是预备编队的**编辑 / 管理画面**(菜单-更多功能 → 预备编队),只能查看 / 编辑,**不能选队出战** —— 与战斗前的「选择(准备出战)」子态不同(后者有 `SELECT` / `预备出战`)。详见 [预备编队](../../../game/screens/预备编队.md)。

## 流程

1. **前往菜单**(GotoMenu)→ **菜单-更多功能** → 点「按钮-预备编队」→ 进入预备编队管理画面(编辑子态)。
2. **识别编队角色**(`update_team_members`):
- OCR 全图队名 → 用 `difflib` 模糊匹配 `team_config` 的队伍名(找对应配置队)。
- 在匹配队名左侧 -10 起、宽 800 高 250 的区域(`avatar_rect = Rect(x-10, y, x+800, y+250)`),`match_team_agent_template` 模板匹配代理人头像 → 按横坐标排序 + 重叠过滤(issue #1487,同位置多识别取高置信)。
- `team_config.update_team_members(队名, [代理人])` 写回配置(按队名匹配,非 idx)。
Comment thread
coderabbitai[bot] marked this conversation as resolved.
3. **翻页**:中屏 drag 上滑(`-500px`),最多翻 4 次,每页重复识别。
4. **返回**:`BackToNormalWorld` 回大世界。

## 关键点

- **画面**:编辑 / 管理子态(无 `SELECT` / `预备出战`);主体布局同选择子态(2×3 卡片 + 1P/2P/3P + 核心技 X/3)。详见 [预备编队画面](../../../game/screens/预备编队.md)。
- **识别依据**:OCR 队名(模糊匹配 config)+ **代理人头像模板**(不是 1P/2P/3P 文字标记)。
- **写回**:`update_team_members`(按队名匹配),保留该队已有的自动战斗配置。

## 相关

- 画面:[预备编队](../../../game/screens/预备编队.md)(通用画面,选择 / 编辑两子态)。
- 代码:`src/zzz_od/application/game_config_checker/predefined_team_checker/`。
- 同类:`game_config_checker` 下其他 checker(均为校准工具,非玩法)。
6 changes: 6 additions & 0 deletions docs/develop/zzz/backend/entry.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ GUI 的「开发工具 -> MCP 服务」页面提供本机 server 管理:

这个 GUI 页面管理的是一个本机 server 子进程,不是把 MCP server 嵌进 GUI 主进程。当前不做 GUI 主进程与 server 子进程之间的跨进程运行互斥。

## 开机自启

`.\tools\mcp\create_mcp_server_startup_shortcut.ps1` —— 在 Startup 文件夹建主 server 快捷方式,登录后自动起主 server(23001),在登录态(Session 1)直接起、不经 daemon。卸载即删该 `.lnk`。与[远程 SSH daemon 自启](remote-ssh.md#开机自启)互相独立、可共存:daemon 仍能按进程命令行发现并管理这样启动的主 server(`status` / `stop` / `restart`)。

自启调用的 `tools\mcp\start_mcp_server.ps1` 把日志重定向到同一个 `.debug/zzz_od_mcp/main_server.log`(与 GUI / daemon `start` 一致)。

## `.env`

`uv run --env-file .env ...` 会要求项目根目录存在 `.env`。如果本地没有 `.env`,命令会在启动前报错。GUI 启动会先判断 `.env` 是否存在;命令行手动启动时,开发环境可以按项目需要创建 `.env`,或在不需要环境变量的场景下省略 `--env-file .env`。
Expand Down
2 changes: 2 additions & 0 deletions docs/develop/zzz/backend/remote-ssh.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ daemon 就是那个**常驻 Session 1、握有管理员权限**的管理者—

`.\tools\mcp\daemon\create_startup_shortcut.ps1` —— 在 Startup 文件夹建快捷方式,登录后自动起 daemon。卸载即删该 `.lnk`。

主 server 的本机自启(登录后直接起、不经 daemon)见 [entry.md 开机自启](entry.md#开机自启);两者互相独立、可共存——daemon 仍能按进程命令行发现并管理这样启动的主 server(`status` / `stop` / `restart`)。

## 排查

- 端口:daemon **23000**、主 server **23001**;用 `get_zzz_od_mcp_server_status` 看 server 状态,或 `netstat -ano | findstr :2300`。
Expand Down
2 changes: 2 additions & 0 deletions docs/game/screens/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,6 @@

> 跳过的 app 待 MCP 补足 `transport`/`move`/`drag`/键盘注入能力后,或用框架 `run_standalone_app` 跑通后沿途截图补。

| 预备编队 | [预备编队.md](预备编队.md) | **通用画面**(多玩法共用预备编队列表);两子态:选择(准备出战,有 SELECT/预备出战)/ 编辑管理(PredefinedTeamChecker,只能编辑);当前命中实战模拟室,无独立 screen_info |

(后续自由补充)
62 changes: 62 additions & 0 deletions docs/game/screens/预备编队.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
screen_name: 预备编队
appears_in: [实战模拟室, 式舆防卫战, 恶名狩猎]
last_updated: 2026-08-01
source_image: screens/预备编队/默认.webp
---

# 预备编队

预备编队列表(队伍卡片网格),**通用画面**,多个玩法共用:战斗前选队出战(实战模拟室 / 式舆防卫战 / 恶名狩猎等)、或从菜单进入管理编辑(`PredefinedTeamChecker` 识别角色)。

## 两个子态(关键区别)

| 子态 | 入口 | 能否选队出战 | 底部按钮 |
|---|---|---|---|
| **选择(准备出战)** | 各玩法出战态点「预备编队」按钮 | ✅ 能 | `+SELECT` / `TEAM 01-02`(选中态)+ **预备出战** |
| **编辑 / 管理** | 菜单-更多功能 → 预备编队(`PredefinedTeamChecker` 走这条) | ❌ 只能编辑 / 查看(不能选出战) | 无 `SELECT` / `预备出战` |

两子态**主体 UI 相同**(2×3 卡片网格 + 1P/2P/3P + 核心技 X/Y + 等级),区别在底部:选择子态有 `SELECT`/`预备出战`,编辑子态没有。

## 布局(主体,两子态共用)

2 列 × 3 行 = 6 张队伍卡片(每页),可上下拖动翻页(每页翻 4 队、与上页重叠 2)。

每张卡片:
- **队名**(卡片顶部)
- **3 个代理人头像** + **1P / 2P / 3P 位置标记**(代理人位;空位也保留标记)
- **核心技激活 `X/Y`**(右上):分母 = 队伍人数 —— `3/3`=3 人满员、`2/3`=3 人 2 激活、`0/1`=1 人、`0/0`=空队
- **等级**(头像旁,如 `60`)
- 选择子态还有:`+SELECT`(未选中)/ `TEAM 01-02`(已选中)

底部:**预备出战**(右下,仅选择子态)。

## 识别特征

- 当前命中 `实战模拟室` screen(因「预备出战」area 在 `combat_simulation.yml`)—— 预备编队列表本身**无独立 screen**(待独立化)。
- 卡片元素识别靠 `ChoosePredefinedTeam` 硬编码坐标(`CARD_TITLE_X_LIST=[150,970]` × `CARD_TITLE_Y_LIST=[115,398,680]` 网格 + 1P/2P/3P OCR + 核心技 X/Y + SELECT/TEAM),不走 screen_info area。

## 选队(选择子态)

点**队名右侧空白**(`TEAM_NAME_CLICK_OFFSET = +300px`)切换选中 —— 点队名本身是改名弹窗,只有 +300px 才是选中。选中后显示 `TEAM 01/02`;全部目标选中后点「预备出战」回配队选择页。

## 识别快照

### 1. 选择(准备出战)(source_image: screens/预备编队/默认.webp)

6 张满员队(日常刷本 / 简薇耀 / 冰莱凯苍 / 冰雅狼苍 / 火莱凯露 / 仪玄),均 `+SELECT`(未预选)。核心技 `3/3`(满员)。代理人位 1P/2P/3P 齐全 + 等级 60。右下「预备出战」。

- **匹配画面**:`实战模拟室` `is_precise=false`(靠「预备出战」area 命中)
- **全量 OCR**:队名(日常刷本 等)+ `1P/2P/3P/BANGBOO` + `3/3`(核心技)+ `60`(等级)+ `+ SELECT` + `预备出战`

### 2. 编辑 / 管理(source_image: screens/预备编队/编辑.webp)

`PredefinedTeamChecker` 从菜单-更多功能进入。队伍列表主体同选择子态(2×3 卡片 + 1P/2P/3P + 核心技 X/Y + 等级),但**无 `+SELECT` / `预备出战` / `TEAM` 选中态**(只能编辑查看,不能选出战)。`PredefinedTeamChecker` 在此 OCR 队名 + 模板匹配代理人头像 → 更新 `team_config`。

- **全量 OCR**:队名(日常刷本 等)+ `1P/2P/3P/BANGBOO` + `3/3` / `2/3`(核心技)+ `60`(等级)+ `AGENT` —— **无 `+SELECT` / `预备出战`**(与选择子态的关键区别)。

## 备注

- **screen_info 现状**:预备编队列表**无独立 screen**(命中实战模拟室);卡片元素识别:选队子态靠 `ChoosePredefinedTeam` 硬编码网格坐标(`CARD_TITLE_*`),管理子态靠 `PredefinedTeamChecker` 按队名算 `avatar_rect`(x-10 到 x+800);均未建 screen_info area。后续可考虑独立化 screen「预备编队」。
- **多玩法进入**:实战模拟室(出战态→预备编队)/ 式舆防卫战(选队)/ 恶名狩猎?/ 菜单-更多功能(管理编辑,`PredefinedTeamChecker`)。
- **核心技 `X/Y` 的 OCR 坑**:游戏里斜线 `/` 易被 OCR 识成 `1`(连写,如 `313`=3/3、`315`=3/5),代码侧已兼容(`_get_team_count_text` 按 `\d1\d` 还原)。
1 change: 1 addition & 0 deletions skills/zzz-od-dev-pr-finishing/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ resolve 前确保 CodeRabbit 对这条「说完话了」,不抢它的判断、

### 6. 关联 PR(跨仓)协同
本项目跨仓:主仓 PR 常带配套**测试仓 PR**(同分支名,主仓描述带测试仓 PR 链接)。
- **关联 PR 不只看 open PR(由真实事故提炼)**:测试仓改动可能挂在同分支但**没开 PR**(改动没经 review)→ `gh pr list --head <分支>` 查 open PR 为空**不等于**"无配套"。收尾主仓前用 git 验证测试仓同分支有无未合改动:`git -C zzz-od-test fetch https && git -C zzz-od-test log https/main..<同名分支>`(有输出 = 测试仓有未合改动,必须先开 PR 合掉再合主仓,否则主仓 main 的 test-check 跑测试仓 main 缺这些测试 = CI 通过但测试缺失;无输出 = 确实无配套)。
Comment thread
coderabbitai[bot] marked this conversation as resolved.
- **一起收尾**:关联 PR 都按本 skill 走(CI/review/unresolved 全清),不只当前 PR。
- **合并顺序:测试仓先 → 主仓后**。主仓合到 main 后,main 的 `test-check` clone 测试仓 **main**;测试仓先合确保测试改动进测试仓 main,主仓 main CI 才稳(主仓先合 → 主仓 main CI clone 测试仓 main 无新改动 → 测试缺失/失败)。
- **都 done 才合**:关联 PR 全 green + review pass + 无 unresolved 后,按顺序合(测试仓 → 主仓)。
Expand Down
1 change: 1 addition & 0 deletions skills/zzz-od-dev-pr-finishing/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
8. **push 后不自动触发 = 被 auto-pause(非偶发)**:CodeRabbit 有 `reviews.auto_review.auto_pause_after_reviewed_commits` 机制 —— PR 活跃开发 / 频繁 commit 时**自动暂停** review,之后**每次 push 都不自动触发**(不是偶尔)。检测:PR 有 `Reviews paused` comment(grep body 含 `Reviews paused` / `review paused`)。暂停下两命令语义不同:`@coderabbitai review` = **单次**触发(保持暂停,下次 push 仍不自动);`@coderabbitai resume` = **恢复**自动(之后 push 自动触发,ack `Reviews resumed.`)。ack 里那句「此命令仅在自动 review 暂停时适用」就是在提示当前处于暂停态。预防:调 `.coderabbit.yaml` 的 `auto_pause_after_reviewed_commits` 阈值 / 关闭。实战:PR 2419 从 7-01 起被 auto-pause,故每轮 push 都要手动补 —— 曾误判为「偶尔不触发」,实际是**始终暂停**。
9. **增量 review 无建议时 API 无痕**:增量 review 没新建议时,CodeRabbit 不建 check run、不留 review 记录,只回复一条 issue comment(`✅ Action performed` / `Review finished`)。故「review 完成」的可靠判据是这条 ack comment 的 body,不是 check run / reviews(实战:PR 2419 增量 review 完成但 API reviews 停在上一天、该 commit 无 CodeRabbit check run)。**手动 @ 后 ack 的演变**:ack comment 先回 `Review triggered`(review 进行中),真正完成后 CodeRabbit **编辑同一条** comment 为 `Review finished`(不另发新 comment)。`triggered` 是中间态 —— 判完成必须看到 `finished`,别把 `triggered` 当结果(实战:PR 2419 bf2ebfea 手动 @ 后 06:38Z 回 triggered,review 完成后同条被编辑成 finished)。
10. **时区**:GitHub API 时间是 UTC(`Z` 后缀),显示给用户前转本地(维护者 UTC+8);避免时间串造成困惑。
11. **关联 PR 用 git 验证,不只查 open PR**:`gh pr list --head <分支>` 查 open PR 为空 ≠ 无配套 —— 测试仓改动可能挂在同分支但没开 PR(有改动但没开 PR)。收尾主仓前必须 `git -C zzz-od-test fetch https && git -C zzz-od-test log https/main..<同名分支>` 验证无未合改动。**为什么不用 open PR 判**:PR #2608 收尾时查测试仓同分支 open PR 为空就判"无配套"、直接合了主仓,事后才发现测试仓分支有 11 个未合 commit(有改动、没开 PR)→ 补救才开测试仓 #35。根因:open PR 是「是否已开 PR」的判据,不是「是否有配套改动」的判据;后者要看 git 分支。该方法进 SKILL.md §6;配套的预防约束(开发阶段就同开关联 PR)进 AGENTS.md「提交流程与协作边界」+ development_workflow.md §4(泛化到非游戏流程改动)。
Comment thread
coderabbitai[bot] marked this conversation as resolved.

## 落点

Expand Down
58 changes: 58 additions & 0 deletions tools/mcp/create_mcp_server_startup_shortcut.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Create ZZZ OD MCP Server Startup Shortcut
#
# Creates a shortcut in the Windows Startup folder so the main MCP server (port 23001)
# starts automatically after login, without being spawned by daemon.
# Independent of the daemon startup shortcut (tools/mcp/daemon/create_startup_shortcut.ps1);
# both can coexist: daemon manages server lifecycle, this shortcut keeps the server ready
# right after login.

$ErrorActionPreference = "Stop"

# This script lives in tools/mcp/, go up 2 levels to project root
$ProjectRoot = Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent
$StartScript = Join-Path $ProjectRoot "tools\mcp\start_mcp_server.ps1"

# Startup folder
$StartupFolder = "$env:APPDATA\Microsoft\Windows\Start Menu\Programs\Startup"
$ShortcutPath = Join-Path $StartupFolder "ZZZ OD MCP Server.lnk"

Write-Host "============================================================" -ForegroundColor Cyan
Write-Host "ZZZ OD MCP Server - Startup Shortcut Creator" -ForegroundColor Cyan
Write-Host "============================================================" -ForegroundColor Cyan
Write-Host ""
Write-Host "Project Root: $ProjectRoot"
Write-Host "Start Script: $StartScript"
Write-Host "Shortcut Path: $ShortcutPath"
Write-Host "============================================================" -ForegroundColor Cyan
Write-Host ""

# Check if start_mcp_server.ps1 exists
if (-not (Test-Path $StartScript)) {
Write-Host "[ERROR] start_mcp_server.ps1 not found: $StartScript" -ForegroundColor Red
exit 1
}

# Create WScript.Shell object
$WshShell = New-Object -ComObject WScript.Shell

# Create shortcut
$Shortcut = $WshShell.CreateShortcut($ShortcutPath)
$Shortcut.TargetPath = "powershell.exe"
$Shortcut.Arguments = "-ExecutionPolicy Bypass -WindowStyle Hidden -File `"$StartScript`""
$Shortcut.WorkingDirectory = $ProjectRoot
$Shortcut.Description = "ZZZ OD MCP Server - backend main server (game operation)"
$Shortcut.Save()

# Release COM object
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($WshShell) | Out-Null

Write-Host "[SUCCESS] Shortcut created!" -ForegroundColor Green
Write-Host ""
Write-Host "Shortcut location: $ShortcutPath" -ForegroundColor Cyan
Write-Host ""
Write-Host "ZZZ OD MCP Server will now automatically start when you log in." -ForegroundColor Green
Write-Host ""
Write-Host "To remove:" -ForegroundColor Yellow
Write-Host " Delete the shortcut file: $ShortcutPath"
Write-Host ""
Write-Host "============================================================" -ForegroundColor Cyan
Loading