refactor(ffi): 降级 FFI 为可选兼容层并整理文档

将 bat-ffi 明确收敛为无状态 C ABI 兼容层,默认集成路径改为 bat --json 进程边界或未来稳定 SDK。

同步 README、当前状态、项目计划、架构文档、开发指南和缺口清单,移除 FFI 作为主集成边界的表述。

新增 AGENTS.md 和 CONTRIBUTING.md,压缩 CLAUDE.md 为兼容入口,并归档阶段性报告、同步 .gitignore 规则。
This commit is contained in:
2026-07-15 21:12:17 +08:00
parent 90307a3243
commit b4b4f25cb3
22 changed files with 420 additions and 772 deletions
+5 -2
View File
@@ -45,8 +45,11 @@ go.work.sum
logs/
pg_log/
# Generated reports
/docs/reports/fuck-u-code-current.md
# Generated/local-only reports
/docs/reports/generated/
/docs/reports/fuck-u-code-*.md
/docs/reports/*-current.generated.md
/docs/reports/**/SMOKE_REPORT.md
# Backups
/deployments/backups/
+72
View File
@@ -0,0 +1,72 @@
# Agent 开发规则
本文件是 BlueArchive Toolkit 中 AI agent、自动化开发助手和长期维护脚本的权威入口。它替代旧 `CLAUDE.md` 中真正长期有效的工程规则。
## 语言和表达
1. 默认使用简体中文交流、写文档、写提交说明、写开发日志和写 API 说明。
2. 代码中的包名、类型名、函数名、变量名、数据库字段、协议字段和命令参数保持英文命名规范。
3. 代码注释只在能降低理解成本时添加;不要写复述代码行为的空泛注释。
4. 如果任务、上游规范或第三方 API 明确要求英文,可以在对应位置使用英文。
## 项目定位
BlueArchive Toolkit 是长期维护的开源工具链,不是 demo、一次性脚本或临时试验项目。
长期目标包括但不限于:
1. 官方资源同步、版本管理、增量同步、断点续传、重试、限速、缓存和校验。
2. Content Addressable StorageCAS)、引用计数、垃圾回收、多版本共享和完整性校验。
3. UnityFS / AssetBundle / Addressables / Manifest 解析框架,并保持解析器与业务逻辑解耦。
4. 文本提取、翻译记忆、术语库、AI Provider 抽象、Patch、CLI、Web、API、SDK 和插件系统。
5. 支持未来扩展到其他区域、语言或 Unity 游戏;不要把架构写死到单一版本。
## 工程边界
1. 默认工作于用户本地环境。不要把生产环境当作开发环境。
2. 真实资源下载、smoke run 和手动验证必须写入隔离目录,例如 `/tmp` 或显式指定的测试目录。
3. 不要默认读取、修改或污染现有客户端目录、生产资源目录或 `/home/wanye/D/BlueArchive` 这类本地资源目录。
4. 不要要求安装官方启动器作为生产运行前提。可以分析启动器资源或官方公开数据,但生产链路必须能在 Linux 环境中独立运行。
5. 涉及官方资源时,优先使用官方 `.hash`、catalog、manifest 和可复现 fixture 做校验依据。
## 架构原则
1. 仓库采用 monorepo;模块必须边界清晰、高内聚、低耦合。
2. 公共接口应稳定、可测试、可维护,并为未来扩展保留合理空间。
3. Rust 侧优先承担二进制解析、AssetBundle、Patch、CAS 和官方资源后端能力;Go 侧优先承担 CLI、运维入口和面向用户的命令编排。边界调整必须先说明理由。
4. Rust/Go 默认集成路径优先进程边界(当前为 `bat --json`)或未来稳定 SDK`bat-ffi` 仅作为可选无状态 C ABI 兼容层,不能扩展成 daemon、下载器、CAS handle 或主控制面。
5. SDK 不得与 CLI 耦合;解析器不得与业务流程耦合;Provider、存储后端、Patch 算法和解析器应保留插件化扩展点。
6. 不引入 God Object、God Class、超长函数、超长文件、硬编码、魔法数字、重复代码、临时实现或只为当前测试通过的伪实现。
7. 不使用 `TODO``FIXME` 掩盖未完成设计。确实无法完成时,应在当前缺口文档中说明边界、风险和后续工作。
## 开发流程
1. 动手前先读相关文档和代码,确认当前真实状态。
2. 对跨模块、架构、数据格式或用户工作流有影响的改动,先给出设计判断或简短计划。
3. 实现后必须同步验证。验证范围要覆盖改动实际影响面,而不是只跑最窄的命令。
4. 涉及用户可见行为、运行方式、架构边界或缺口状态时,必须同步更新文档。
5. 保持改动范围和任务目标一致;不要顺手做无关重构或格式化 churn。
6. 如果需求、技术路线或设计存在明显风险,应直接指出并给出可执行替代方案。
7. 不确定的事实必须查证或询问;不要凭空调用不存在的接口、命令、路径或线上资源。
## 质量要求
1. 所有错误必须显式处理,并给出可诊断信息。
2. 日志应结构化或至少足够定位阶段、路径、版本、URL、重试、校验和失败原因。
3. 下载、写文件、状态切换和发布操作必须考虑原子性、断点续传、并发锁、失败恢复和清理策略。
4. 本地状态文件和索引必须有版本字段或兼容策略。
5. 新增 fixture、golden 或回归样本时,应说明它覆盖的真实风险。
6. 默认验证命令见 `docs/guides/development.md`;稳定工程基线见 `docs/guides/baseline.md`
## 文档职责
长期规则的权威位置如下:
1. `AGENTS.md`:agent 行为、工程边界、架构原则和质量要求。
2. `CONTRIBUTING.md`:贡献者工作流、提交规范、验证和 PR 要求。
3. `docs/guides/development.md`:环境准备、开发命令、测试、调试和真实资源验证方式。
4. `PROJECT_PLAN.md`:产品目标、阶段路线图和长期能力规划。
5. `CURRENT_STATUS.md`:当前实现状态。
6. `docs/reports/CURRENT_GAPS.md`:当前缺口、优先级和关闭顺序。
`CLAUDE.md` 只保留兼容入口,不应继续新增长期规则。
+10 -448
View File
@@ -1,452 +1,14 @@
# BlueArchive Toolkit 项目开发任务(Claude Opus 4.6
# Claude 兼容入口
你现在不是普通 AI,而是本项目唯一的长期架构师(Chief Architect)、首席开发工程师(Lead Developer)、代码审查者(Code Reviewer)、技术负责人(Tech Lead)以及长期维护者(Maintainer
本文件仅作为 Claude Code 等旧工具默认读取 `CLAUDE.md` 时的兼容入口,不再承载项目长期规则
请始终牢记
当前权威文档
**整个开发过程中,必须始终使用简体中文回复。**
- `AGENTS.md`:AI agent 和自动化开发助手必须遵守的长期规则。
- `CONTRIBUTING.md`:贡献者协作、提交、验证和文档要求。
- `docs/guides/development.md`:本地开发环境、工作流、测试和调试指南。
- `PROJECT_PLAN.md`:项目长期目标和路线图。
- `CURRENT_STATUS.md`:当前工作区真实状态。
- `docs/reports/CURRENT_GAPS.md`:当前缺口、优先级和关闭顺序。
包括但不限于:
* 所有解释
* 所有设计
* 所有分析
* 所有文档
* 所有 README
* 所有注释
* 所有 API 文档
* 所有提交说明
* 所有开发日志
均默认使用简体中文。
代码中的类名、接口名、方法名、变量名、包名等仍然保持英文命名规范。
---
# 项目背景
我要开发一个名为 **BlueArchive Toolkit** 的大型开源项目。
该项目目标不是 Demo,也不是脚本,而是一个能够长期维护、持续扩展、达到工业级质量的完整平台。
本项目默认工作于用户本地环境。
整个系统围绕 Blue Archive(日服)资源展开,但请不要假设项目仅服务于某一个游戏版本,整个架构必须具有良好的可扩展能力,以便未来支持其他区域、其他语言甚至其他 Unity 游戏。
整个项目必须按照 Production Ready 标准开发。
严禁以 Demo、最小实现(Minimum Viable Product)、临时方案、占位实现等思路完成任何模块。
---
# 项目目标
项目需要逐步实现并形成完整生态。
包括但不限于:
## 资源同步
能够同步资源。
支持:
* Manifest
* 版本管理
* 增量同步
* Hash 校验
* 多线程下载
* 断点续传
* 自动重试
* 限速
* 下载缓存
* 本地对象存储
---
## 存储系统
采用 Content Addressable StorageCAS)。
必须支持:
* Hash 去重
* 引用计数
* 垃圾回收
* 多版本共享
* 完整性校验
不得使用简单目录堆放文件。
---
## Unity AssetBundle
设计完整解析框架。
要求支持插件化。
未来能够支持:
* TextAsset
* Localization
* MonoBehaviour
* ScriptableObject
* Texture
* Sprite
* Audio
* Video
* 其他 Unity 资源
解析器必须独立。
不得与业务逻辑耦合。
---
## 文本提取
自动提取:
* 剧情
* UI
* 系统文本
* 配置文本
统一导出标准格式。
不得直接修改原始资源。
---
## Translation Memory
建立翻译记忆库。
支持:
* 自动匹配
* 模糊匹配
* Provider 来源
* 审核状态
* 历史记录
* 多语言
---
## Glossary
建立术语库。
术语优先级必须高于 AI。
所有 AI 翻译必须优先遵循术语。
支持:
* 多语言
* 别名
* 分类
* 冲突检测
* 审核
---
## AI 翻译
设计 Provider 抽象层。
未来支持:
* DeepL
* OpenAI
* Anthropic
* Google
* Azure
* 自定义 Provider
所有 Provider 必须统一接口。
不得耦合具体实现。
---
## Patch
设计完整 Patch 系统。
支持:
* 增量 Patch
* Binary Patch
* JSON Patch
* Rollback
* Integrity Check
---
## CLI
设计完整命令体系。
例如:
sync
extract
translate
patch
verify
doctor
serve
cache
manifest
bundle
所有命令必须统一风格。
---
## Web
设计完整后台。
包括:
* 登录
* 权限
* 翻译审核
* 术语管理
* 全文搜索
* 历史版本
* Diff
* Dashboard
---
## SDK
整个项目必须提供 SDK。
方便其他项目调用。
不得把 SDK 与 CLI 耦合。
---
## API
所有接口:
RESTful。
OpenAPI。
版本管理。
统一错误码。
统一响应结构。
支持未来扩展。
---
## Database
自行设计完整数据库。
要求:
高性能。
规范化。
支持 Migration。
支持未来扩展。
---
## Plugin System
整个项目必须支持插件。
以后新增:
新的解析器
新的翻译 Provider
新的存储后端
新的 Patch 算法
不得修改核心代码。
---
# 技术栈
请根据不同模块自行选择最适合的技术。
我倾向于:
* GoCLI、Downloader、API
* Rust(二进制解析、AssetBundle、Patch
* Vue3 + TypeScriptWeb
* PostgreSQL
* Redis
* Docker
* GitHub Actions
但如果你认为有更合理的方案,请给出完整论证后再调整。
---
# 架构要求
采用 Monorepo。
严格模块化。
高内聚。
低耦合。
支持长期维护。
支持未来十年以上持续开发。
所有模块必须具有明确边界。
禁止出现:
* God Object
* God Class
* 超长函数
* 超长文件
* Magic Number
* Hard Code
* 重复代码
* 临时实现
* Demo 思维
* TODO
* FIXME
---
# 开发要求
不要一次性生成整个项目。
必须按照真正的软件工程流程。
每开始一个模块:
先分析。
再设计。
给出架构。
等待确认(如果我没有要求直接实现)。
然后编码。
然后测试。
然后 Benchmark。
然后 Documentation。
最后 Review。
再继续下一模块。
---
# 代码质量
所有代码必须达到 Production Ready。
所有公共接口必须稳定。
所有配置不得硬编码。
所有错误必须处理。
所有日志必须结构化。
所有模块必须可测试。
所有模块必须可维护。
所有模块必须具有扩展能力。
---
# 文档
每完成一个模块:
自动同步更新:
README
Architecture
Sequence Diagram
Flow Diagram
API Documentation
Developer Guide
User Guide
Deployment Guide
Change Log
---
# AI 行为要求
你不是代码生成器。
你应该主动思考。
主动发现问题。
主动优化设计。
主动指出潜在风险。
主动提出更优方案。
如果你认为我的设计存在问题,应直接指出并给出充分理由,而不是机械执行。
---
# 最重要要求
不要为了满足当前需求而牺牲整个项目未来架构。
整个项目应以工业级开源项目为目标。
请像维护一个会持续十年以上的大型开源项目一样进行设计和开发,而不是完成一次性的开发任务。
如果你认为我提出的需求、技术路线或设计思路存在不合理之处,请直接指出,不要因为迎合我的要求而保留明显存在缺陷的设计。你的职责是作为首席架构师提供最佳工程方案,而不是机械执行我的所有想法。
此外,如果你不知道一些具体的东西,必须询问我,不准虚空调用
使用 Claude 时,请先读取 `AGENTS.md`,再按任务需要读取 `CONTRIBUTING.md``docs/guides/development.md`。如果本文件与上述权威文档冲突,以上述权威文档为准。
+68
View File
@@ -0,0 +1,68 @@
# 贡献指南
感谢参与 BlueArchive Toolkit。这个项目按长期维护的开源工具链标准推进,不接受只为临时通过、不可维护或污染本地资源目录的改动。
## 开始前
1. 阅读 `README.md``CURRENT_STATUS.md``docs/reports/CURRENT_GAPS.md`,确认当前实现状态和优先级。
2. 涉及官方资源同步、Rust 后端、Go CLI 或架构边界时,额外阅读 `docs/guides/development.md``docs/guides/official-resource-test-pull.md` 和相关 ADR。
3. AI agent 或自动化助手还必须遵守 `AGENTS.md`
## 工作流
1. 基于当前开发分支创建功能分支。
2. 先分析现有文档和代码,再决定实现方式。
3. 保持改动聚焦,避免无关重构、批量格式化或元数据 churn。
4. 实现后运行覆盖改动范围的测试、格式化和 lint。
5. 如果用户可见行为、运行命令、架构边界、缺口状态或数据格式发生变化,同步更新文档。
## 提交规范
提交信息使用 Conventional Commits
- `feat:` 新功能
- `fix:` 修复 bug
- `docs:` 文档更新
- `test:` 测试或 fixture 更新
- `refactor:` 不改变行为的重构
- `chore:` 构建、依赖或辅助工具调整
提交说明默认使用简体中文。代码标识符和协议字段仍使用英文。
## 验证要求
基础验证命令见 `docs/guides/development.md`。常用最低门禁:
```bash
cargo fmt --check
cargo test --workspace
cargo clippy --workspace -- -D warnings
```
如果改动只影响部分 crate,可以先跑更窄的测试,但合并前必须确保影响面被覆盖。官方资源同步、下载、daemon、status、verify 或 repair 相关改动还应运行:
```bash
cargo test -p bat-infrastructure --bin bat -- --nocapture
cargo test -p bat-infrastructure -- --nocapture
```
真实官方网络 smoke run 必须写入隔离目录,禁止写入现有游戏客户端或生产资源目录。
## 资源和数据安全
1. 不要把生产环境当作开发环境。
2. 不要默认读取或修改 `/home/wanye/D/BlueArchive` 等已有资源目录。
3. 不要提交真实账号、token、cookie、私有路径、下载产物、数据库或本地 CAS 数据。
4. 新增 fixture 应尽量最小化,只保留验证解析、校验或错误处理所需的数据。
## PR 要求
PR 描述应包含:
1. 改动摘要。
2. 影响范围。
3. 已运行的验证命令。
4. 未覆盖风险或后续缺口。
5. 相关 issue、ADR 或文档链接。
如果改动关闭缺口或 issue,请在 PR 或提交中明确引用。
+13 -6
View File
@@ -173,28 +173,35 @@ Rust 侧官方日服资源链路已经从实验验证推进到正式入口:
### `bat-ffi`
状态:**粗粒度 JSON API 可用,稳定边界仍需继续收敛**
状态:**可选无状态兼容层,非主集成边界**
已包含:
- `bat_version`
- `bat_manifest_inspect_json`:解析 Addressables manifest 并返回 JSON summary。
- `bat_sync_plan_json`:根据 current/previous snapshot 生成官方同步计划 JSON。
- `internal/ffi/ffi.go` 提供 Go 包装骨架。
- `internal/ffi/ffi.go` 提供可选 CGO 兼容包装骨架。
定位约束:
- `bat-ffi` 只暴露粗粒度、无状态、一次调用一次 JSON 输入输出的 C ABI helper。
- 它不持有 downloader、daemon、CAS handle、资源目录锁或长生命周期状态。
- Go CLI 和生产运维默认应调用 `bat --json` 进程边界;未来稳定 SDK 也优先于 FFI。
- FFI 仅用于需要嵌入 C ABI 的兼容场景,不能作为官方同步控制面或主集成边界。
待完成:
- Go CLI 调用链路。
- 错误码与结构化响应约定。
- 发布用头文件、构建脚本和跨平台产物。
- 如确有兼容需求,再补发布用头文件、构建脚本和跨平台产物。
### Go / API / Web
状态:**Go FFI 包骨架存在,CLI/API/Web 仍未实现**
状态:**CLI/API/Web 仍未实现,仅有可选 CGO 兼容包装**
当前情况:
- `internal/ffi/ffi.go` 已存在。
- Go CLI 默认集成方向是调用 Rust `bat --json` 并转发结构化 report,而不是依赖 FFI。
- `cmd/``pkg/``api/``web/` 仍无可用产品入口。
- `go test ./...` 在没有 Go package 时可能无测试可运行;Makefile 会清晰跳过空 Go 阶段。
@@ -256,7 +263,7 @@ cargo run -p bat-infrastructure --bin bat -- \
下一阶段必须优先完成:
1. Go CLI 最小可用入口:`bat doctor``bat sync --help`、Rust 官方同步命令包装
1. Go CLI 最小可用入口:`bat doctor``bat sync --help`通过 `bat --json` 包装 Rust 官方同步命令。
2. 官方同步结果接入 CAS + ResourceRepository 的用户级工作流。
3. AssetBundle UnityFS 基础解析。
4. Addressables parser 对更多官方 catalog 结构的覆盖。
Generated
+1 -199
View File
@@ -8,56 +8,6 @@ version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
[[package]]
name = "anstream"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
[[package]]
name = "anstyle-parse"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
dependencies = [
"anstyle",
"once_cell_polyfill",
"windows-sys 0.61.2",
]
[[package]]
name = "anyhow"
version = "1.0.103"
@@ -180,15 +130,8 @@ dependencies = [
name = "bat-ffi"
version = "0.1.0"
dependencies = [
"anyhow",
"bat-adapters",
"bat-assetbundle",
"bat-cas-engine",
"bat-core",
"bat-infrastructure",
"bat-patch",
"cbindgen",
"libc",
"serde",
"serde_json",
"tokio",
@@ -279,25 +222,6 @@ version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04"
[[package]]
name = "cbindgen"
version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fce8dd7fcfcbf3a0a87d8f515194b49d6135acab73e18bd380d1d93bb1a15eb"
dependencies = [
"clap",
"heck 0.4.1",
"indexmap",
"log",
"proc-macro2",
"quote",
"serde",
"serde_json",
"syn",
"tempfile",
"toml",
]
[[package]]
name = "cc"
version = "1.2.67"
@@ -314,39 +238,6 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "clap"
version = "4.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
version = "4.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_lex"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
[[package]]
name = "colorchoice"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
[[package]]
name = "concurrent-queue"
version = "2.5.0"
@@ -680,12 +571,6 @@ dependencies = [
"hashbrown 0.15.5",
]
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "heck"
version = "0.5.0"
@@ -838,12 +723,6 @@ dependencies = [
"hashbrown 0.17.1",
]
[[package]]
name = "is_terminal_polyfill"
version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
[[package]]
name = "itoa"
version = "1.0.18"
@@ -1050,12 +929,6 @@ version = "1.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
[[package]]
name = "once_cell_polyfill"
version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
[[package]]
name = "parking"
version = "2.2.1"
@@ -1317,15 +1190,6 @@ dependencies = [
"zmij",
]
[[package]]
name = "serde_spanned"
version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
dependencies = [
"serde",
]
[[package]]
name = "serde_urlencoded"
version = "0.7.1"
@@ -1498,7 +1362,7 @@ checksum = "19a9c1841124ac5a61741f96e1d9e2ec77424bf323962dd894bdb93f37d5219b"
dependencies = [
"dotenvy",
"either",
"heck 0.5.0",
"heck",
"hex",
"once_cell",
"proc-macro2",
@@ -1635,12 +1499,6 @@ dependencies = [
"unicode-properties",
]
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "subtle"
version = "2.6.1"
@@ -1766,47 +1624,6 @@ dependencies = [
"tokio",
]
[[package]]
name = "toml"
version = "0.8.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
"toml_edit",
]
[[package]]
name = "toml_datetime"
version = "0.6.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
version = "0.22.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
dependencies = [
"indexmap",
"serde",
"serde_spanned",
"toml_datetime",
"toml_write",
"winnow",
]
[[package]]
name = "toml_write"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
[[package]]
name = "tracing"
version = "0.1.44"
@@ -1890,12 +1707,6 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "vcpkg"
version = "0.2.15"
@@ -2011,15 +1822,6 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "winnow"
version = "0.7.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945"
dependencies = [
"memchr",
]
[[package]]
name = "writeable"
version = "0.6.3"
+8 -5
View File
@@ -1,6 +1,6 @@
# BlueArchiveToolkit 文档索引
- **更新时间**2026-07-14
- **更新时间**2026-07-15
- **说明**:本索引用于快速定位当前权威文档和历史资料。
---
@@ -15,7 +15,9 @@
- `docs/guides/official-full-pull-smoke.md`:真实官方全量拉取 smoke runbook 和可重复命令。
- `docs/architecture/official-resource-backend.md`:官方资源后端职责、工作原理和审核说明。
- `CHANGELOG.md`:版本变更记录。
- `CLAUDE.md`:长期开发约束和项目要求
- `AGENTS.md`:AI agent 和自动化开发助手长期规则
- `CONTRIBUTING.md`:贡献者协作、提交和验证要求。
- `CLAUDE.md`Claude Code 等旧工具的兼容入口。
---
@@ -28,8 +30,6 @@
- `deployments/systemd/`:官方资源同步生产 systemd unit 和环境文件示例。
- `docs/guides/official-resource-test-pull.md`:官方资源拉取与自动更新用户指南。
- `docs/guides/official-full-pull-smoke.md`:真实官方全量拉取 smoke runbook 和可重复命令。
- `docs/reports/current-stage-prepush.md`:当前阶段说明与推送前核查记录。
- `docs/reports/current-status-handoff.md`:给下一次对话使用的当前进度交接说明。
- `docs/guides/baseline.md`:稳定工程基线指南。
- `docs/architecture/adr/0001-engine-and-application-boundaries.md`Rust/Go 边界决策。
- `docs/architecture/adr/0002-cas-v1-design-boundary.md`CAS V1 边界决策。
@@ -60,6 +60,7 @@
历史报告已按来源和主题归档,供追溯使用,不再代表当前状态。
- `docs/reports/historical/root/`:原根目录阶段报告。
- `docs/reports/historical/current-stage/`:已被 `CURRENT_STATUS.md` 和当前指南取代的阶段交接、推送前核查报告。
- `docs/reports/historical/week2/`Week 2 相关报告。
- `docs/reports/historical/week3/`:Week 3 相关报告。注意:这些报告中存在“完成”和“回滚”的冲突描述。
- `docs/reports/historical/build-logs/`:历史构建、测试、Clippy 输出。
@@ -81,6 +82,8 @@
7. `docs/guides/baseline.md`
8. `docs/architecture/README.md`
9. `docs/guides/development.md`
10. `CONTRIBUTING.md`
11. `AGENTS.md`
---
@@ -98,7 +101,7 @@
- 真实官方网络全量拉取 smoke 已固化为 `scripts/official-full-pull-smoke.sh``make official-smoke`,默认写入 `/tmp` 隔离目录并输出本地运行报告。
- `bat` 运行时 progress log 已覆盖总体下载进度、单文件下载进度和校验结果摘要。
- Addressables 当前真实形态 fixture/golden 覆盖。
- SQLite Resource Repository 和粗粒度 FFI JSON 接口。
- SQLite Resource Repository 和可选无状态 `bat-ffi` JSON 兼容接口。
优先待办:
+10 -10
View File
@@ -15,7 +15,7 @@ BlueArchiveToolkit 不是一次性脚本,也不是演示项目。最终交付
2. **Rust 核心引擎**:负责 CAS、AssetBundle 解析、Patch、二进制安全处理和性能敏感逻辑。
3. **Go 服务层**:负责 CLI 编排、资源同步、下载器、API Server、任务调度和外部集成。
4. **Web 管理后台**:负责翻译审核、术语管理、全文搜索、历史版本、Diff 和 Dashboard。
5. **SDK/API**:提供稳定的 Go SDK、进程边界或必要时的 FFI 边界和 REST/OpenAPI 接口,方便其他工具复用。
5. **SDK/API**:提供稳定的 Go SDK、进程边界和 REST/OpenAPI 接口,方便其他工具复用FFI 仅保留为可选兼容层
6. **插件系统**:允许新增解析器、翻译 Provider、存储后端、Patch 算法,而不修改核心代码。
---
@@ -33,14 +33,14 @@ BlueArchiveToolkit 不是一次性脚本,也不是演示项目。最终交付
5. `bat-infrastructure` 已改为 CAS 仓储适配层,不再重复实现对象存储。
6. `bat-infrastructure` 已提供官方资源 pull/update 服务,正式入口是 Rust binary `bat`
7. `bat` 支持 `--auto-discover``--watch``--daemon`、默认 1 小时间隔、本地 manifest audit/repair、官方 seed `.hash` 校验、snapshot/cache,以及基于 Unix socket JSON-RPC 的 `status/stop/restart/reload/refresh/logs/verify/repair/doctor/clean-stable` 运维命令。
8. `bat-ffi` 已提供 Manifest inspect 和官方 sync plan 的粗粒度 JSON API
8. `bat-ffi` 已提供 Manifest inspect 和官方 sync plan 的可选无状态粗粒度 JSON C ABI helper
9. 文档已整理:根目录保留入口文档,历史报告进入 `docs/reports/historical/`,误嵌套的 `docs/docs` 已合并。
### 仍是骨架或占位
1. AssetBundle 解析器仍是占位 trait,未解析 UnityFS、压缩块、TypeTree 或对象表。
2. Patch 的 Binary/JSON 模块仍返回空结果,不具备真实补丁能力。
3. Go CLI/API/SDK 仍没有产品级入口;只有 `internal/ffi`早期包装
3. Go CLI/API/SDK 仍没有产品级入口;只有 `internal/ffi`可选兼容包装骨架
4. Addressables parser 已覆盖当前真实形态 fixture/golden,但还不是完整 Unity Addressables/SBP catalog 兼容层。
5. 官方同步结果尚未作为用户级流程自动导入 CAS + ResourceRepository。
6. 真实官方网络全量下载 smoke test 尚未记录。
@@ -66,11 +66,11 @@ BlueArchiveToolkit 不是一次性脚本,也不是演示项目。最终交付
2. **Engine**:Rust 实现性能敏感和安全敏感能力,包括 CAS、AssetBundle、Patch、二进制格式校验。
3. **Infrastructure**:实现数据库、文件系统、缓存、对象存储、HTTP 客户端、任务队列。
4. **Application**:编排用例,例如同步资源、提取文本、生成补丁、审核翻译。
5. **Interface**CLI、REST API、Web UI、SDK、FFI
5. **Interface**CLI、REST API、Web UI、SDK,以及可选 FFI 兼容层
### 3.2 技术决策
1. **Rust**:保留为核心引擎语言,用于 CAS、AssetBundle、Patch、完整资源拉取和更新检查核心逻辑,FFI 仅作为可选边界
1. **Rust**:保留为核心引擎语言,用于 CAS、AssetBundle、Patch、完整资源拉取和更新检查核心逻辑`bat --json` 进程边界是当前主集成路径FFI 仅作为可选兼容层
2. **Go**:用于最小稳定 CLI、服务编排、API Server、任务编排、Provider 集成;不强制要求 Rust 核心能力必须写成库供 Go 调用。
3. **PostgreSQL**:作为服务端主数据库,承载翻译记忆库、术语库、任务、审核和用户权限。
4. **SQLite**:仅作为本地 CLI 可选元数据后端,必须通过仓储抽象隔离,不能绑定业务逻辑。
@@ -141,7 +141,7 @@ BlueArchiveToolkit 不是一次性脚本,也不是演示项目。最终交付
**目标**:完成可长期使用的 Content Addressable Storage。
**当前状态**:已完成 CAS V1。Go CLI 以最小稳定入口优先,Rust 继续承载完整资源拉取与更新检查核心逻辑;FFI 边界保持可选
**当前状态**:已完成 CAS V1。Go CLI 以最小稳定入口优先,Rust 继续承载完整资源拉取与更新检查核心逻辑;`bat-ffi` 仅保留为可选兼容层
交付物:
@@ -150,7 +150,7 @@ BlueArchiveToolkit 不是一次性脚本,也不是演示项目。最终交付
3. 实现引用计数、对象元数据、完整性校验、GC、统计信息。
4. 实现本地元数据后端:优先 SQLite,但必须隔离在 repository adapter 中。
5. 编写迁移、恢复、损坏检测和 `doctor cas`
6. 提供稳定的 Go 调用边界,优先进程或 SDK,必要时再补 FFI
6. 提供稳定的 Go 调用边界,优先进程或 SDK;FFI 只保留为可选兼容层,不作为默认集成方案
验收标准:
@@ -175,7 +175,7 @@ BlueArchiveToolkit 不是一次性脚本,也不是演示项目。最终交付
3. Rust 官方下载器:**已完成当前生产入口需要的核心能力**。包含官方 URL 校验、`.part` 续传、重试、本地 manifest size+BLAKE3 校验、官方 seed `.hash` 校验和 repair。
4. Rust 自动更新入口:**已完成当前生产入口**。`bat` 支持 snapshot、marker diff、bootstrap cache、one-shot、`--watch``--daemon`、默认 1 小时间隔、北京时间固定强制刷新,以及 Unix socket JSON-RPC 后台运维命令返回。
5. Go CLI:**未完成**。需要实现 `bat doctor``bat sync --help`、Rust 官方同步命令包装和 JSON/human 输出。
6. 用户级 `sync``manifest inspect``cache status`**未完成**。Rust FFI 已提供 Manifest inspect 和 sync plan JSON 边界,但 Go CLI 尚未串联
6. 用户级 `sync``manifest inspect``cache status`**未完成**。Rust `bat --json` 是 Go CLI 默认进程边界;`bat-ffi` 只提供可选兼容用的 Manifest inspect 和 sync plan JSON helper
7. 下载结果写入 CAS + ResourceRepository**部分完成**。CAS 和 SQLite ResourceRepository 已存在,官方同步入口尚未把完整下载结果作为用户级流程自动导入。
8. Linux 生产同步不依赖已安装官方启动器:**已完成当前 Rust 入口**。`--auto-discover` 只使用官方 HTTP metadata 和临时目录解析 `GameMainConfig`
9. 真实官方网络全量下载 smoke test:**未完成记录**。需要在隔离目录执行并记录 dry-run、首次下载、二次 up-to-date 和本地损坏 repair。
@@ -381,7 +381,7 @@ BlueArchiveToolkit 不是一次性脚本,也不是演示项目。最终交付
## 6. 近期 10 个具体任务
1. 落地 Go CLI 的最小生产入口:`bat doctor``bat sync --help``bat official sync --help`
2. 让 Go CLI 调用 Rust `bat --json` 官方同步入口或 FFI/进程边界,并稳定转发结构化 report。
2. 让 Go CLI 默认调用 Rust `bat --json` 官方同步入口,并稳定转发结构化 report;除非有明确兼容需求,不走 FFI
3. 记录一次真实官方网络 smoke:dry-run、首次下载、二次 up-to-date、本地损坏 repair。
4. 将官方同步下载结果接入 CAS + `SqliteResourceRepository` 的用户级流程。
5. 继续扩展 Addressables parser 的真实 catalog 变体覆盖和错误诊断。
@@ -416,7 +416,7 @@ BlueArchiveToolkit 不是一次性脚本,也不是演示项目。最终交付
1. Rust 提供稳定引擎能力,不承担 CLI 编排,但负责完整资源拉取和更新检查的核心逻辑。
2. Go 负责用户命令、最小稳定 CLI、服务编排、网络和 Provider。
3. 跨边界优先进程或 SDK,FFI 只作为可选的粗粒度、安全、可测试 API。
3. 跨边界优先进程或 SDK,FFI 只作为可选的粗粒度、无状态、安全、可测试兼容 API。
4. Rust 不需要被强制写成 Go 调用库;当前 `bat --watch` / `bat --daemon` 是允许长期运行的 Rust 生产任务。
### 官方资源真实下载风险
+7 -6
View File
@@ -16,7 +16,7 @@
- `bat`:官方资源自动发现、全量拉取、原子发布到 `current -> versions/<id>`、本地 manifest audit/repair、`.part` 断点续传、403/404/5xx 分类重试、下载 quarantine 诊断、ZIP 结构校验、官方 seed `.hash` 校验、snapshot/cache、`--watch` 常驻更新、`--daemon` 后台运行,以及 Unix socket JSON-RPC 后台控制命令 `status/stop/restart/reload/refresh/logs/verify/repair/doctor/clean-stable`
- 官方同步会维护 `<output>/official-version-state.json`,明确记录当前已完成版本、正在拉取版本、上一个可用版本和失败版本。
- 资源导入链路可将 manifest 条目写入 CAS + `ResourceRepository`AssetBundle 会记录 UnityFS 摘要,TextAsset/Table/Media 会按类型分类索引。
- `bat-ffi` 粗粒度 JSON 接口:Manifest inspect 和官方 sync plan。
- `bat-ffi` 可选无状态 C ABI 兼容层:仅保留 Manifest inspect 和官方 sync plan 的粗粒度 JSON helper,不作为 Go CLI 或生产同步的主集成边界
- 文档路线图、当前状态、缺口清单、官方资源运行指南。
仍未完成:
@@ -134,8 +134,9 @@ make official-smoke
## 技术栈
- RustCAS、官方资源同步核心、AssetBundle/Patch 引擎、FFI
- Go:计划中的最小 CLI、服务编排、API Server、SDK当前仅有 FFI 包骨架
- RustCAS、官方资源同步核心、AssetBundle/Patch 引擎;当前生产同步入口是 `bat` binary
- Go:计划中的最小 CLI、服务编排、API Server、SDK默认通过 `bat --json` 进程边界或未来 SDK 集成 Rust 能力
- `bat-ffi`:可选兼容层,只暴露无状态粗粒度 JSON C ABI,不承载 daemon、下载器、CAS handle 或主控制面。
- PostgreSQL:计划中的服务端主数据库。
- Redis:计划中的缓存、队列状态、限流和短期锁。
- Vue 3 + TypeScript:计划中的 Web 管理后台。
@@ -154,8 +155,8 @@ BlueArchiveToolkit/
│ ├── bat-cas-engine/
│ ├── bat-assetbundle/
│ ├── bat-patch/
│ └── bat-ffi/
├── internal/ffi/ # Go 调用 Rust FFI 的早期包装
│ └── bat-ffi/ # 可选无状态 C ABI 兼容层
├── internal/ffi/ # 可选 CGO 兼容包装,不是 Go CLI 主路径
├── cmd/ # Go CLI 入口,尚未实现
├── pkg/ # Go SDK 包,尚未实现
├── api/ # API 定义,尚未实现
@@ -173,7 +174,7 @@ BlueArchiveToolkit/
近期优先级:
1. 落地 Go CLI 最小可用入口:`bat doctor``bat sync --help`、Rust 同步命令包装
1. 落地 Go CLI 最小可用入口:`bat doctor``bat sync --help`通过 `bat --json` 包装 Rust 同步命令。
2. 补齐 AssetBundle UnityFS header/block/directory 解析。
3. 扩展 Addressables catalog 解析覆盖,继续用真实形态 fixture/golden 锁定行为。
4. 将官方同步结果接入 CAS + ResourceRepository 的用户级工作流。
-11
View File
@@ -9,20 +9,9 @@ license.workspace = true
crate-type = ["cdylib", "staticlib"]
[dependencies]
bat-core = { path = "../../core" }
bat-adapters = { path = "../../adapters" }
bat-infrastructure = { path = "../../infrastructure" }
bat-cas-engine = { path = "../bat-cas-engine" }
bat-assetbundle = { path = "../bat-assetbundle" }
bat-patch = { path = "../bat-patch" }
anyhow.workspace = true
serde.workspace = true
serde_json.workspace = true
tokio.workspace = true
# FFI 绑定
libc = "0.2"
[build-dependencies]
cbindgen = "0.27"
+117 -39
View File
@@ -1,8 +1,9 @@
//! # BAT FFI
//! # BAT FFI compatibility layer
//!
//! Go 和 Rust 之间的 FFI 绑定层
//!
//! 导出 C ABI 接口供 Go 通过 CGO 调用
//! Optional C ABI compatibility layer for coarse-grained JSON helpers.
//! Production orchestration should prefer the `bat --json` process boundary or a
//! future stable SDK. This crate intentionally stays stateless: it must not own
//! downloader state, daemon lifecycle, CAS handles, or long-lived resources.
#![warn(clippy::all)]
@@ -17,7 +18,7 @@ use std::collections::HashMap;
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
/// FFI 版本号
/// FFI compatibility API version.
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
/// Sync snapshot JSON 输入。
@@ -111,13 +112,13 @@ struct SyncPlanView {
delta: SyncDeltaView,
}
/// 获取版本号(C ABI
/// Returns the compatibility API version as an owned C string.
#[no_mangle]
pub extern "C" fn bat_version() -> *const c_char {
c_string(VERSION).into_raw()
}
/// 释放 C 字符串内存
/// Frees C strings allocated by this crate.
///
/// # Safety
/// 调用者必须确保:
@@ -130,7 +131,7 @@ pub unsafe extern "C" fn bat_free_string(s: *mut c_char) {
}
}
/// 解析 Addressables Manifest,并返回 JSON summary
/// Parses an Addressables manifest and returns a stateless JSON summary.
#[no_mangle]
pub extern "C" fn bat_manifest_inspect_json(raw_json: *const c_char) -> *mut c_char {
let result = (|| -> Result<ManifestInspectView, String> {
@@ -170,7 +171,7 @@ pub extern "C" fn bat_manifest_inspect_json(raw_json: *const c_char) -> *mut c_c
json_result(result)
}
/// 构建官方同步计划 JSON summary。
/// Builds an official sync plan JSON summary without persisting state.
#[no_mangle]
pub extern "C" fn bat_sync_plan_json(
current_json: *const c_char,
@@ -368,16 +369,31 @@ mod tests {
value
}
#[test]
fn test_ffi_version() {
let version_ptr = bat_version();
let version = take_string(version_ptr);
assert!(!version.is_empty());
fn parse_json_response(raw: String) -> serde_json::Value {
serde_json::from_str(&raw).unwrap()
}
#[test]
fn test_manifest_inspect_json() {
let catalog_json = r#"{
fn inspect_manifest(raw_json: &str) -> serde_json::Value {
let raw_json = CString::new(raw_json).unwrap();
parse_json_response(take_string(bat_manifest_inspect_json(raw_json.as_ptr())))
}
fn sync_plan(current_json: &str, previous_json: Option<&str>) -> serde_json::Value {
let current_json = CString::new(current_json).unwrap();
let previous_json = previous_json.map(|value| CString::new(value).unwrap());
let previous_ptr = previous_json
.as_ref()
.map(|value| value.as_ptr())
.unwrap_or(std::ptr::null());
parse_json_response(take_string(bat_sync_plan_json(
current_json.as_ptr(),
previous_ptr,
)))
}
fn catalog_json() -> &'static str {
r#"{
"m_LocatorId": "AddressablesMainContentCatalog",
"m_InternalIds": [
"synthetic/minimal.bundle"
@@ -391,34 +407,96 @@ mod tests {
"dependencies": ["shared.bundle"]
}
]
}"#;
}"#
}
let result_ptr = bat_manifest_inspect_json(CString::new(catalog_json).unwrap().as_ptr());
let result = take_string(result_ptr);
assert!(result.contains(r#""ok":true"#));
assert!(result.contains(r#""resource_count":1"#));
fn sync_snapshot_json(bundle_version: &str) -> String {
format!(
r#"{{
"connection_group_name":"Prod-Audit",
"app_version":"1.70.0",
"bundle_version":"{bundle_version}",
"addressables_root":"https://prod-clientpatch.bluearchiveyostar.com/r93_token",
"endpoints":[
{{
"kind":"TableCatalog",
"platform":null,
"url":"https://prod-clientpatch.bluearchiveyostar.com/r93_token/TableBundles/TableCatalog.bytes"
}}
]
}}"#
)
}
#[test]
fn test_ffi_version() {
let version_ptr = bat_version();
let version = take_string(version_ptr);
assert!(!version.is_empty());
}
#[test]
fn test_manifest_inspect_json() {
let result = inspect_manifest(catalog_json());
assert_eq!(result["ok"], true);
assert_eq!(result["data"]["resource_count"], 1);
assert_eq!(
result["data"]["resources"][0]["path"],
"synthetic/minimal.bundle"
);
}
#[test]
fn test_sync_plan_json() {
let current = r#"{
"connection_group_name":"Prod-Audit",
"app_version":"1.70.0",
"bundle_version":"s8tloc7lo3",
"addressables_root":"https://prod-clientpatch.bluearchiveyostar.com/r93_token",
"endpoints":[
{
"kind":"TableCatalog",
"platform":null,
"url":"https://prod-clientpatch.bluearchiveyostar.com/r93_token/TableBundles/TableCatalog.bytes"
let current = sync_snapshot_json("s8tloc7lo3");
let result = sync_plan(&current, None);
assert_eq!(result["ok"], true);
assert_eq!(result["data"]["decision"], "DownloadVerifyAndPublish");
assert_eq!(result["data"]["should_download"], true);
assert_eq!(result["data"]["should_publish"], true);
}
]
}"#;
let result_ptr =
bat_sync_plan_json(CString::new(current).unwrap().as_ptr(), std::ptr::null());
let result = take_string(result_ptr);
assert!(result.contains(r#""ok":true"#));
assert!(result.contains(r#""decision":"DownloadVerifyAndPublish""#));
#[test]
fn stateless_ffi_json_api_repeats_without_cached_state() {
let first_manifest = inspect_manifest(catalog_json());
let second_manifest = inspect_manifest(catalog_json());
assert_eq!(first_manifest, second_manifest);
let current = sync_snapshot_json("s8tloc7lo3");
let initial_plan = sync_plan(&current, None);
let up_to_date_plan = sync_plan(&current, Some(&current));
let initial_plan_again = sync_plan(&current, None);
assert_eq!(initial_plan["data"]["decision"], "DownloadVerifyAndPublish");
assert_eq!(up_to_date_plan["data"]["decision"], "UpToDate");
assert_eq!(
initial_plan_again["data"]["decision"],
initial_plan["data"]["decision"]
);
assert_eq!(
initial_plan_again["data"]["should_download"],
initial_plan["data"]["should_download"]
);
}
#[test]
fn ffi_json_api_returns_structured_errors() {
let manifest_error =
parse_json_response(take_string(bat_manifest_inspect_json(std::ptr::null())));
assert_eq!(manifest_error["ok"], false);
assert!(manifest_error["error"]
.as_str()
.unwrap()
.contains("null pointer"));
let sync_error = parse_json_response(take_string(bat_sync_plan_json(
std::ptr::null(),
std::ptr::null(),
)));
assert_eq!(sync_error["ok"], false);
assert!(sync_error["error"]
.as_str()
.unwrap()
.contains("null pointer"));
}
}
+5 -3
View File
@@ -42,7 +42,7 @@ BlueArchive Toolkit 采用 **Monorepo + 多语言混合** 架构,旨在构建
### 3. 数据流设计
```
用户请求 → CLI/API → Go 业务层 → Rust 核心/同步层 → CAS 存储 → 数据库
用户请求 → CLI/API → Go 业务层 → bat --json / SDK → Rust 核心/同步层 → CAS 存储 → 数据库
↓ ↓
Web UI 缓存层 (Redis)
```
@@ -128,7 +128,8 @@ current symlink → official-sync-snapshot.json + official-download-manifest.jso
**后续 Go 职责**
- 提供最小稳定 CLI。
- 包装或调用 Rust 同步入口,需要机器输出时使用 `--json` 并转发结构化 report。
- 默认通过 `bat --json` 进程边界包装 Rust 同步入口,并转发结构化 report。
- `bat-ffi` 仅作为可选无状态 C ABI 兼容层,不承载官方同步 daemon、下载器或 CAS handle。
- 编排 API Server、任务队列、Provider 和用户配置。
---
@@ -320,7 +321,8 @@ CREATE TABLE resource_versions (
```
开发机器 (本地)
├── CLI (Go)
├── Rust
├── Rust bat 进程 / 未来 SDK
├── 可选 bat-ffi 兼容层
└── 连接 → 远程数据库服务器 (裸金属)
├── PostgreSQL
└── Redis
@@ -35,7 +35,7 @@ BlueArchiveToolkit 的最终目标覆盖资源同步、CAS、AssetBundle 解析
3. **Go 应用层**
- 负责 CLI、资源同步、下载器、API Server、任务调度、配置、日志、Provider 编排。
- 通过稳定 SDK进程边界,必要时再通过 FFI 调用 Rust 引擎能力
- 通过稳定 SDK进程边界调用 Rust 能力;FFI 只作为可选兼容层
- 不重复实现 AssetBundle 解析、Patch 算法或 CAS 对象存储核心逻辑。
4. **Web 层**
@@ -48,7 +48,7 @@ BlueArchiveToolkit 的最终目标覆盖资源同步、CAS、AssetBundle 解析
1. Rust 引擎 API 必须保持业务无关,不出现 CLI 命令、HTTP 状态码、Web 页面状态。
2. Go 应用层不得复制 Rust 引擎中的 Hash、Patch、AssetBundle 核心算法。
3. 跨边界优先级应是进程边界或稳定 SDK,其次才是 FFI;若使用 FFI,必须只暴露粗粒度批量和事务语义
3. 跨边界优先级应是进程边界或稳定 SDK,其次才是 FFI;若使用 FFI,必须只暴露粗粒度、无状态、一次调用一次输入输出的兼容 API
4. 所有跨边界错误必须能映射到统一错误码和可读诊断信息。
---
@@ -63,7 +63,7 @@ BlueArchiveToolkit 的最终目标覆盖资源同步、CAS、AssetBundle 解析
代价:
1. 需要维护 FFI 或 SDK 边界。
1. 需要维护进程、SDK 和可选 FFI 兼容边界。
2. 错误类型、数据结构和版本兼容性需要更早设计。
3. 集成测试必须覆盖跨语言调用,而不能只看单 crate 单元测试。
@@ -75,4 +75,5 @@ BlueArchiveToolkit 的最终目标覆盖资源同步、CAS、AssetBundle 解析
1. `crates/bat-cas-engine` 是 CAS 核心实现位置。
2. `infrastructure` 不再复制 CAS 存储算法,只做 `bat-core::repositories::CasRepository` 适配。
3. Go CLI 后续通过稳定边界调用 CAS,不直接操作 CAS 内部目录结构。
3. Go CLI 后续默认通过 `bat --json` 进程边界或稳定 SDK 调用 Rust 能力,不直接操作 CAS 内部目录结构。
4. `bat-ffi` 只能保持为可选无状态兼容层,不能承担 daemon lifecycle、下载器状态、资源锁或 CAS handle。
@@ -183,6 +183,12 @@
`OfficialUpdateService` 是当前 Rust 侧的自动更新核心,正式命令入口是 `bat`
集成边界:
1. 当前生产和 Go CLI 默认集成路径是运行 `bat --json` 并消费结构化 report。
2. systemd、容器或上层 Go 进程只负责守护 `bat --watch` / `bat --daemon`,不直接接管下载器内部状态。
3. `bat-ffi` 只允许作为可选无状态 C ABI 兼容层,用于 Manifest inspect 和 sync plan 这类一次性 JSON helper;它不是官方同步 daemon、下载器、资源锁、CAS handle 或主控制面的承载位置。
流程是:
1. 显式执行 `--auto-discover` 或读取已审计 `server-info` 输入。
+3 -2
View File
@@ -288,8 +288,9 @@ BlueArchiveToolkit/
## 📚 相关文档
- [完整架构审查报告](./ARCHITECTURE_REVIEW.md)1900+ 行)
- [当前架构文档](./architecture/README.md)
- [CLAUDE.md](../CLAUDE.md) - 项目开发指南
- [当前架构文档](../architecture/README.md)
- [开发指南](../guides/development.md) - 当前开发流程
- [Agent 开发规则](../../AGENTS.md) - AI agent 长期规则
---
+2 -2
View File
@@ -62,10 +62,10 @@ chore: establish development baseline
```bash
git status --short --branch
git check-ignore -v Cargo.lock CLAUDE.md
git check-ignore -v Cargo.lock CLAUDE.md AGENTS.md CONTRIBUTING.md
```
`Cargo.lock``CLAUDE.md` 必须纳入版本控制。
`Cargo.lock``CLAUDE.md``AGENTS.md``CONTRIBUTING.md` 必须纳入版本控制。
---
+36 -4
View File
@@ -1,5 +1,7 @@
# 开发指南
本指南是本地开发流程的权威入口。贡献协作规则见 `../../CONTRIBUTING.md`AI agent 长期规则见 `../../AGENTS.md`
## 环境准备
### 安装依赖
@@ -59,6 +61,14 @@ make test
make fmt
```
开发约束:
1. 先阅读相关文档和代码,再判断实现方式。
2. 跨模块、架构、数据格式或用户工作流变更必须先说明设计取舍。
3. 保持改动聚焦,不做无关重构、批量格式化或元数据 churn。
4. 公共接口、状态文件、manifest、catalog、patch 和下载流程变更必须补充测试或 fixture。
5. 用户可见命令、运行路径、配置、状态文件、日志或缺口状态变化时,同步更新 README、指南、架构文档或 `docs/reports/CURRENT_GAPS.md`
### 3. 提交
```bash
@@ -86,6 +96,10 @@ git push origin feature/your-feature-name
## 代码规范
默认使用简体中文写文档、提交说明、开发日志和面向用户的说明。代码标识符、协议字段、数据库字段、包名和命令参数保持英文命名规范。
禁止使用 demo、临时实现、硬编码路径或只为当前测试通过的伪实现。确实未完成的能力应写入当前缺口文档,而不是用 `TODO``FIXME` 隐藏。
### Go
- 遵循 [Effective Go](https://golang.org/doc/effective_go)
- 使用 `gofmt` 格式化
@@ -104,16 +118,30 @@ git push origin feature/your-feature-name
## 测试
### 当前必跑测试
### 合并前通用门禁
```bash
cargo fmt --check
cargo test --workspace
cargo clippy --workspace --all-targets -- -D warnings
```
Go CLI 尚未实现时,`go test ./...` 可能没有产品级 package 可运行;Makefile 会在空 Go 阶段清晰跳过。
### 常用聚焦命令
```bash
cargo test -p bat-core -- --nocapture
cargo test -p bat-adapters -- --nocapture
cargo test -p bat-ffi -- --nocapture
cargo test -p bat-infrastructure -- --nocapture
cargo test -p bat-infrastructure --bin bat -- --nocapture
cargo clippy -p bat-core -p bat-adapters -p bat-infrastructure --all-targets -- -D warnings
```
Go CLI 尚未实现时,`go test ./...` 可能没有产品级 package 可运行;Makefile 会在空 Go 阶段清晰跳过
官方资源同步、下载、daemon、status、verify 或 repair 相关改动必须至少覆盖 `bat-infrastructure``bat` 二进制测试
`bat-ffi` 只是可选无状态 C ABI 兼容层。修改 FFI 导出、JSON schema、错误返回或 `internal/ffi` CGO 包装时必须运行 `cargo test -p bat-ffi -- --nocapture`Go CLI 和生产同步默认应通过 `bat --json` 进程边界集成。
### 集成测试
@@ -141,6 +169,8 @@ cargo run -p bat-infrastructure --bin bat -- \
开发环境真实下载默认写入 `./bat-resources`;如果要覆盖,必须使用 `/tmp` 或其他隔离目录,不要写入现有资源目录。
生产或 CI 环境不得依赖安装官方启动器。需要启动器信息时,只能分析启动器资源、官方 manifest 或公开更新数据,并将解析结果固化为可验证流程。
### 基准测试
```bash
@@ -180,9 +210,11 @@ cargo fetch
先确认失败是否来自真实网络或本地资源路径。默认测试应使用 fixture/mock,不应依赖官方线上资源或开发机已有资源目录。
### 3. FFI 绑定问题
### 3. FFI 兼容层问题
重新生成绑定:
`bat-ffi` 不是主集成边界,只用于需要 C ABI 的兼容场景。默认 Go CLI 集成优先运行 Rust `bat --json`
重新构建兼容库:
```bash
cd crates/bat-ffi
cargo build
+3 -1
View File
@@ -172,7 +172,7 @@
现象:
- `cmd/bat` 目录存在,但无 `main.go`
- `internal/ffi/ffi.go` 已存在,但还不是用户可运行 CLI
- `internal/ffi/ffi.go` 已存在,但只是可选 CGO 兼容包装,不是用户可运行 CLI,也不是默认 Go/Rust 集成边界
- `go test ./...` 当前没有产品级 Go package 覆盖。
影响:
@@ -185,6 +185,7 @@
- `bat doctor` 可运行。
- `bat --help` 命令结构稳定。
- 命令支持默认人类可读输出和 `--json` 机器输出。
- Go CLI 默认通过 Rust `bat --json` 进程边界获取同步 report;除非明确兼容需求,不依赖 FFI。
### G-009API Server 和 OpenAPI 尚未实现
@@ -378,6 +379,7 @@
- 架构 README 已明确当前 Rust 官方同步入口、Go 计划边界和目标架构差异。
- 官方资源后端说明由 `docs/architecture/official-resource-backend.md` 承载。
- `bat-ffi` 已降级为可选无状态兼容层,主集成边界明确为 `bat --json` 进程边界或未来稳定 SDK。
### G-017CI 未落地
+14
View File
@@ -0,0 +1,14 @@
# 历史报告归档说明
本目录只保存追溯资料,不代表当前项目状态。当前状态以根目录 `CURRENT_STATUS.md``PROJECT_PLAN.md``DOCS_INDEX.md``docs/reports/CURRENT_GAPS.md` 为准。
归档分类:
- `current-stage/`:曾用于阶段交接或推送前核查的临时 current report,已由当前状态文档和指南取代。
- `root/`:早期位于仓库根目录的阶段报告。
- `week2/``week3/`:早期周报、阶段报告和质量报告。
- `quality/`:早期质量状态报告。
- `build-logs/`:历史构建、测试和 Clippy 输出。
- `nested-docs/`:从误嵌套 `docs/docs` 移出的历史报告。
新增运行产物、smoke 输出、质量扫描输出和本地分析报告不要放入本目录;这些文件应写入 `/tmp`、显式的隔离输出目录,或被 `.gitignore` 覆盖的本地生成报告目录。
+5
View File
@@ -1,3 +1,8 @@
// Package ffi is an optional CGO compatibility wrapper around bat-ffi.
//
// It is not the primary Go integration path. Product CLI orchestration should
// prefer the Rust bat process boundary with --json output, or a future stable
// SDK. Keep this package stateless and limited to coarse JSON helper calls.
package ffi
/*