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

5.8 KiB
Raw Blame History

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

状态清理规则

关键约束logLinesviewVersionSelect 用于判断是否显示错误,必须在离开相关上下文时清空。

  • 进入 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 结构:

{
  "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

构建

go build -o dist/amt.exe .    # 或 make
make backend                  # 启动后端 (uvicorn, port 3131)