Files
arinera-minecraft-tool/CLAUDE.md
chenxiangtong 3ff2454c63 feat: 重构
2026-05-28 17:37:57 +08:00

146 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AMT - ARinera Minecraft Tool
Minecraft 实用 TUI 工具。Go + bubbletea前后端分离。
## 文件结构
```
main.go 入口,解析 exe 目录tea.NewProgram(WithAltScreen)
model.go 顶层 model 定义page 枚举Init/Update/View 路由
pages.go 4 个页面的 update/view + resetExecState + describeAction
scan.go 扫描 <exeDir>/*/.minecraft/versions/* 目录
api.go HTTP 客户端 + Action/StepResponse 类型定义
actions.go action 执行引擎download/unzip/delete/copy/move/backup
items.go list.Item 实现versionItem, menuItem, mirrorItem
styles.go lipgloss 样式常量
backend/ Python FastAPI 后端(独立进程,端口 3131
```
全部 Go 文件在项目根目录package main。`go build -o dist/amt.exe .`
## 依赖
- `bubbletea` v1.3.10 / `bubbles` v1.0.0 / `lipgloss` v1.1.0
- 标准库:`net/http`, `archive/zip`, `encoding/json`, `io`, `os`, `path/filepath`
## 架构:页面状态机
```
pageVersionSelect ──Enter──▶ pageMainMenu ──"输入数字码"──▶ pageCodeInput ──Enter(4位)──▶ pageExecuting
▲ │ │ │ │
│ Esc/q=退出 │ Esc=返回 任意键=返回
└──"切换版本"─────────────┘ └──────────────────────────┘◀──────────────────────────┘
```
### model 核心字段
| 字段 | 类型 | 用途 |
|------|------|------|
| `currentPage` | `page` (iota 枚举) | 当前页面 |
| `exeDir` | string | 可执行文件所在目录 |
| `versionDir` | string | 选中的版本完整路径 |
| `versionName` | string | 版本目录名 |
| `versionList` | list.Model | 版本选择列表Init 时预初始化,避免零值 panic |
| `menuList` | list.Model | 主菜单列表(同上) |
| `codeInput` | textinput.Model | 4 位数字码输入框 |
| `actions` | []Action | 当前执行的 action 列表 |
| `actionIdx` | int | 当前执行到第几个 |
| `logLines` | []string | 执行日志(也被 viewVersionSelect 用于显示扫描错误) |
| `execErr` / `execDone` | error / bool | 执行状态 |
| `choosingMirror` | bool | 是否在 mirror 选择子页面 |
| `pendingAction` | *Action | mirror 选择时暂存的 action |
| `backupDir` | string | 当次执行的备份相对路径 `amt/backup/<timestamp>` |
| `progressCh` | chan float64 | 下载进度 channel预留 |
### 消息类型
| 消息 | 来源 | 处理页面 |
|------|------|----------|
| `versionsFoundMsg` | `scanVersions()` | pageVersionSelect |
| `scanErrorMsg` | `scanVersions()` | pageVersionSelect |
| `actionsReceivedMsg` | `fetchActions()` | pageExecuting |
| `apiErrorMsg` | `fetchActions()` | pageExecuting |
| `actionCompleteMsg` | `executeAction()` | pageExecuting |
| `actionErrorMsg` | `executeAction()` | pageExecuting |
| `actionProgressMsg` | `waitForProgress()` | pageExecuting |
| `mirrorChoiceMsg` | `executeAdd()` | pageExecuting |
### 状态清理规则
**关键约束**`logLines``viewVersionSelect` 用于判断是否显示错误,必须在离开相关上下文时清空。
- **进入 pageExecuting (T4)**:调用 `resetExecState(m)` 清空所有执行状态
- **离开 pageExecuting (T6)**:同上
- **进入 pageVersionSelect (T3)**:清空 `logLines` + 清空列表项
- **`versionsFoundMsg` 到达时**:清空 `logLines`(覆盖旧扫描错误)
- **离开 pageVersionSelect (T1)**:清空 `logLines`
- **mirror Esc 取消**:清空 `pendingAction`
`resetExecState` 清空字段:`actions`, `actionIdx`, `logLines`, `execErr`, `execDone`, `choosingMirror`, `pendingAction`, `backupDir`, `progressCh`
## 后端 API
地址:`http://localhost:3131`
### GET /tools?code=XXXX
返回 step 结构:
```json
{
"actions": [
{"type": "add", "path": "相对路径", "unzip": false, "url": "https://...", "mirrors": ["https://..."]},
{"type": "delete", "path": "相对路径"},
{"type": "copy", "path": "源相对路径", "new_path": "目标相对路径"},
{"type": "move", "path": "源相对路径", "new_path": "目标相对路径"}
]
}
```
所有 `path` 相对于 `versionDir`
## Action 执行逻辑 (actions.go)
顺序执行,任一失败立即中断。
| type | 行为 | 备份 |
|------|------|------|
| `add` | 下载 url→pathunzip=true 时解压后删 zip | 目标已存在则备份 |
| `delete` | 删除 path | 删前备份 |
| `copy` | 复制 path→new_path | new_path 已存在则备份 |
| `move` | os.Rename失败则 copy+delete | new_path 已存在则备份 |
### 备份
目录:`<versionDir>/amt/backup/<YYYYMMDD_HHMMSS>/<原相对路径>`
每次执行创建一个时间戳目录,同次执行的所有备份共享。
### 下载失败 Mirror 处理
主 URL 失败 → 发送 `mirrorChoiceMsg` → 设 `choosingMirror=true` → 显示 mirror 列表 → 用户选择后用新 URL 重试。用户 Esc 取消则中断执行。
### 关键函数
```
executeAction(versionDir, action, index, backupDir) → tea.Cmd → actionCompleteMsg | actionErrorMsg | mirrorChoiceMsg
executeAdd(...) add 专用,处理下载/解压/mirror
downloadFile(url, dest) 标准 http.Get + 临时文件 + rename
unzipFile(zip, dir) archive/zip 解压,含 zip slip 防护
backupPath(versionDir, relPath, backupDir) 备份单个文件/目录
copyPath(src, dst) 递归复制文件/目录
copyFile(src, dst) 单文件复制
copyDir(src, dst) filepath.Walk 递归复制
```
## 版本扫描 (scan.go)
`filepath.Glob(exeDir/*/.minecraft/versions/*)` → 过滤目录 → `versionsFoundMsg`
## 构建
```bash
go build -o dist/amt.exe . # 或 make
make backend # 启动后端 (uvicorn, port 3131)
```