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/ logs/
pg_log/ pg_log/
# Generated reports # Generated/local-only reports
/docs/reports/fuck-u-code-current.md /docs/reports/generated/
/docs/reports/fuck-u-code-*.md
/docs/reports/*-current.generated.md
/docs/reports/**/SMOKE_REPORT.md
# Backups # Backups
/deployments/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`:当前缺口、优先级和关闭顺序。
包括但不限于: 使用 Claude 时,请先读取 `AGENTS.md`,再按任务需要读取 `CONTRIBUTING.md``docs/guides/development.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 行为要求
你不是代码生成器。
你应该主动思考。
主动发现问题。
主动优化设计。
主动指出潜在风险。
主动提出更优方案。
如果你认为我的设计存在问题,应直接指出并给出充分理由,而不是机械执行。
---
# 最重要要求
不要为了满足当前需求而牺牲整个项目未来架构。
整个项目应以工业级开源项目为目标。
请像维护一个会持续十年以上的大型开源项目一样进行设计和开发,而不是完成一次性的开发任务。
如果你认为我提出的需求、技术路线或设计思路存在不合理之处,请直接指出,不要因为迎合我的要求而保留明显存在缺陷的设计。你的职责是作为首席架构师提供最佳工程方案,而不是机械执行我的所有想法。
此外,如果你不知道一些具体的东西,必须询问我,不准虚空调用
+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` ### `bat-ffi`
状态:**粗粒度 JSON API 可用,稳定边界仍需继续收敛** 状态:**可选无状态兼容层,非主集成边界**
已包含: 已包含:
- `bat_version` - `bat_version`
- `bat_manifest_inspect_json`:解析 Addressables manifest 并返回 JSON summary。 - `bat_manifest_inspect_json`:解析 Addressables manifest 并返回 JSON summary。
- `bat_sync_plan_json`:根据 current/previous snapshot 生成官方同步计划 JSON。 - `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 / API / Web
状态:**Go FFI 包骨架存在,CLI/API/Web 仍未实现** 状态:**CLI/API/Web 仍未实现,仅有可选 CGO 兼容包装**
当前情况: 当前情况:
- `internal/ffi/ffi.go` 已存在。 - `internal/ffi/ffi.go` 已存在。
- Go CLI 默认集成方向是调用 Rust `bat --json` 并转发结构化 report,而不是依赖 FFI。
- `cmd/``pkg/``api/``web/` 仍无可用产品入口。 - `cmd/``pkg/``api/``web/` 仍无可用产品入口。
- `go test ./...` 在没有 Go package 时可能无测试可运行;Makefile 会清晰跳过空 Go 阶段。 - `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 的用户级工作流。 2. 官方同步结果接入 CAS + ResourceRepository 的用户级工作流。
3. AssetBundle UnityFS 基础解析。 3. AssetBundle UnityFS 基础解析。
4. Addressables parser 对更多官方 catalog 结构的覆盖。 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" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" 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]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.103" version = "1.0.103"
@@ -180,15 +130,8 @@ dependencies = [
name = "bat-ffi" name = "bat-ffi"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow",
"bat-adapters", "bat-adapters",
"bat-assetbundle",
"bat-cas-engine",
"bat-core",
"bat-infrastructure", "bat-infrastructure",
"bat-patch",
"cbindgen",
"libc",
"serde", "serde",
"serde_json", "serde_json",
"tokio", "tokio",
@@ -279,25 +222,6 @@ version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" 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]] [[package]]
name = "cc" name = "cc"
version = "1.2.67" version = "1.2.67"
@@ -314,39 +238,6 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" 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]] [[package]]
name = "concurrent-queue" name = "concurrent-queue"
version = "2.5.0" version = "2.5.0"
@@ -680,12 +571,6 @@ dependencies = [
"hashbrown 0.15.5", "hashbrown 0.15.5",
] ]
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.5.0" version = "0.5.0"
@@ -838,12 +723,6 @@ dependencies = [
"hashbrown 0.17.1", "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]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.18" version = "1.0.18"
@@ -1050,12 +929,6 @@ version = "1.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
[[package]]
name = "once_cell_polyfill"
version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
[[package]] [[package]]
name = "parking" name = "parking"
version = "2.2.1" version = "2.2.1"
@@ -1317,15 +1190,6 @@ dependencies = [
"zmij", "zmij",
] ]
[[package]]
name = "serde_spanned"
version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "serde_urlencoded" name = "serde_urlencoded"
version = "0.7.1" version = "0.7.1"
@@ -1498,7 +1362,7 @@ checksum = "19a9c1841124ac5a61741f96e1d9e2ec77424bf323962dd894bdb93f37d5219b"
dependencies = [ dependencies = [
"dotenvy", "dotenvy",
"either", "either",
"heck 0.5.0", "heck",
"hex", "hex",
"once_cell", "once_cell",
"proc-macro2", "proc-macro2",
@@ -1635,12 +1499,6 @@ dependencies = [
"unicode-properties", "unicode-properties",
] ]
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]] [[package]]
name = "subtle" name = "subtle"
version = "2.6.1" version = "2.6.1"
@@ -1766,47 +1624,6 @@ dependencies = [
"tokio", "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]] [[package]]
name = "tracing" name = "tracing"
version = "0.1.44" version = "0.1.44"
@@ -1890,12 +1707,6 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]] [[package]]
name = "vcpkg" name = "vcpkg"
version = "0.2.15" version = "0.2.15"
@@ -2011,15 +1822,6 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "winnow"
version = "0.7.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "writeable" name = "writeable"
version = "0.6.3" version = "0.6.3"
+8 -5
View File
@@ -1,6 +1,6 @@
# BlueArchiveToolkit 文档索引 # BlueArchiveToolkit 文档索引
- **更新时间**2026-07-14 - **更新时间**2026-07-15
- **说明**:本索引用于快速定位当前权威文档和历史资料。 - **说明**:本索引用于快速定位当前权威文档和历史资料。
--- ---
@@ -15,7 +15,9 @@
- `docs/guides/official-full-pull-smoke.md`:真实官方全量拉取 smoke runbook 和可重复命令。 - `docs/guides/official-full-pull-smoke.md`:真实官方全量拉取 smoke runbook 和可重复命令。
- `docs/architecture/official-resource-backend.md`:官方资源后端职责、工作原理和审核说明。 - `docs/architecture/official-resource-backend.md`:官方资源后端职责、工作原理和审核说明。
- `CHANGELOG.md`:版本变更记录。 - `CHANGELOG.md`:版本变更记录。
- `CLAUDE.md`:长期开发约束和项目要求 - `AGENTS.md`:AI agent 和自动化开发助手长期规则
- `CONTRIBUTING.md`:贡献者协作、提交和验证要求。
- `CLAUDE.md`Claude Code 等旧工具的兼容入口。
--- ---
@@ -28,8 +30,6 @@
- `deployments/systemd/`:官方资源同步生产 systemd unit 和环境文件示例。 - `deployments/systemd/`:官方资源同步生产 systemd unit 和环境文件示例。
- `docs/guides/official-resource-test-pull.md`:官方资源拉取与自动更新用户指南。 - `docs/guides/official-resource-test-pull.md`:官方资源拉取与自动更新用户指南。
- `docs/guides/official-full-pull-smoke.md`:真实官方全量拉取 smoke runbook 和可重复命令。 - `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/guides/baseline.md`:稳定工程基线指南。
- `docs/architecture/adr/0001-engine-and-application-boundaries.md`Rust/Go 边界决策。 - `docs/architecture/adr/0001-engine-and-application-boundaries.md`Rust/Go 边界决策。
- `docs/architecture/adr/0002-cas-v1-design-boundary.md`CAS V1 边界决策。 - `docs/architecture/adr/0002-cas-v1-design-boundary.md`CAS V1 边界决策。
@@ -60,6 +60,7 @@
历史报告已按来源和主题归档,供追溯使用,不再代表当前状态。 历史报告已按来源和主题归档,供追溯使用,不再代表当前状态。
- `docs/reports/historical/root/`:原根目录阶段报告。 - `docs/reports/historical/root/`:原根目录阶段报告。
- `docs/reports/historical/current-stage/`:已被 `CURRENT_STATUS.md` 和当前指南取代的阶段交接、推送前核查报告。
- `docs/reports/historical/week2/`Week 2 相关报告。 - `docs/reports/historical/week2/`Week 2 相关报告。
- `docs/reports/historical/week3/`:Week 3 相关报告。注意:这些报告中存在“完成”和“回滚”的冲突描述。 - `docs/reports/historical/week3/`:Week 3 相关报告。注意:这些报告中存在“完成”和“回滚”的冲突描述。
- `docs/reports/historical/build-logs/`:历史构建、测试、Clippy 输出。 - `docs/reports/historical/build-logs/`:历史构建、测试、Clippy 输出。
@@ -81,6 +82,8 @@
7. `docs/guides/baseline.md` 7. `docs/guides/baseline.md`
8. `docs/architecture/README.md` 8. `docs/architecture/README.md`
9. `docs/guides/development.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` 隔离目录并输出本地运行报告。 - 真实官方网络全量拉取 smoke 已固化为 `scripts/official-full-pull-smoke.sh``make official-smoke`,默认写入 `/tmp` 隔离目录并输出本地运行报告。
- `bat` 运行时 progress log 已覆盖总体下载进度、单文件下载进度和校验结果摘要。 - `bat` 运行时 progress log 已覆盖总体下载进度、单文件下载进度和校验结果摘要。
- Addressables 当前真实形态 fixture/golden 覆盖。 - 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、二进制安全处理和性能敏感逻辑。 2. **Rust 核心引擎**:负责 CAS、AssetBundle 解析、Patch、二进制安全处理和性能敏感逻辑。
3. **Go 服务层**:负责 CLI 编排、资源同步、下载器、API Server、任务调度和外部集成。 3. **Go 服务层**:负责 CLI 编排、资源同步、下载器、API Server、任务调度和外部集成。
4. **Web 管理后台**:负责翻译审核、术语管理、全文搜索、历史版本、Diff 和 Dashboard。 4. **Web 管理后台**:负责翻译审核、术语管理、全文搜索、历史版本、Diff 和 Dashboard。
5. **SDK/API**:提供稳定的 Go SDK、进程边界或必要时的 FFI 边界和 REST/OpenAPI 接口,方便其他工具复用。 5. **SDK/API**:提供稳定的 Go SDK、进程边界和 REST/OpenAPI 接口,方便其他工具复用FFI 仅保留为可选兼容层
6. **插件系统**:允许新增解析器、翻译 Provider、存储后端、Patch 算法,而不修改核心代码。 6. **插件系统**:允许新增解析器、翻译 Provider、存储后端、Patch 算法,而不修改核心代码。
--- ---
@@ -33,14 +33,14 @@ BlueArchiveToolkit 不是一次性脚本,也不是演示项目。最终交付
5. `bat-infrastructure` 已改为 CAS 仓储适配层,不再重复实现对象存储。 5. `bat-infrastructure` 已改为 CAS 仓储适配层,不再重复实现对象存储。
6. `bat-infrastructure` 已提供官方资源 pull/update 服务,正式入口是 Rust binary `bat` 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` 运维命令。 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` 已合并。 9. 文档已整理:根目录保留入口文档,历史报告进入 `docs/reports/historical/`,误嵌套的 `docs/docs` 已合并。
### 仍是骨架或占位 ### 仍是骨架或占位
1. AssetBundle 解析器仍是占位 trait,未解析 UnityFS、压缩块、TypeTree 或对象表。 1. AssetBundle 解析器仍是占位 trait,未解析 UnityFS、压缩块、TypeTree 或对象表。
2. Patch 的 Binary/JSON 模块仍返回空结果,不具备真实补丁能力。 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 兼容层。 4. Addressables parser 已覆盖当前真实形态 fixture/golden,但还不是完整 Unity Addressables/SBP catalog 兼容层。
5. 官方同步结果尚未作为用户级流程自动导入 CAS + ResourceRepository。 5. 官方同步结果尚未作为用户级流程自动导入 CAS + ResourceRepository。
6. 真实官方网络全量下载 smoke test 尚未记录。 6. 真实官方网络全量下载 smoke test 尚未记录。
@@ -66,11 +66,11 @@ BlueArchiveToolkit 不是一次性脚本,也不是演示项目。最终交付
2. **Engine**:Rust 实现性能敏感和安全敏感能力,包括 CAS、AssetBundle、Patch、二进制格式校验。 2. **Engine**:Rust 实现性能敏感和安全敏感能力,包括 CAS、AssetBundle、Patch、二进制格式校验。
3. **Infrastructure**:实现数据库、文件系统、缓存、对象存储、HTTP 客户端、任务队列。 3. **Infrastructure**:实现数据库、文件系统、缓存、对象存储、HTTP 客户端、任务队列。
4. **Application**:编排用例,例如同步资源、提取文本、生成补丁、审核翻译。 4. **Application**:编排用例,例如同步资源、提取文本、生成补丁、审核翻译。
5. **Interface**CLI、REST API、Web UI、SDK、FFI 5. **Interface**CLI、REST API、Web UI、SDK,以及可选 FFI 兼容层
### 3.2 技术决策 ### 3.2 技术决策
1. **Rust**:保留为核心引擎语言,用于 CAS、AssetBundle、Patch、完整资源拉取和更新检查核心逻辑,FFI 仅作为可选边界 1. **Rust**:保留为核心引擎语言,用于 CAS、AssetBundle、Patch、完整资源拉取和更新检查核心逻辑`bat --json` 进程边界是当前主集成路径FFI 仅作为可选兼容层
2. **Go**:用于最小稳定 CLI、服务编排、API Server、任务编排、Provider 集成;不强制要求 Rust 核心能力必须写成库供 Go 调用。 2. **Go**:用于最小稳定 CLI、服务编排、API Server、任务编排、Provider 集成;不强制要求 Rust 核心能力必须写成库供 Go 调用。
3. **PostgreSQL**:作为服务端主数据库,承载翻译记忆库、术语库、任务、审核和用户权限。 3. **PostgreSQL**:作为服务端主数据库,承载翻译记忆库、术语库、任务、审核和用户权限。
4. **SQLite**:仅作为本地 CLI 可选元数据后端,必须通过仓储抽象隔离,不能绑定业务逻辑。 4. **SQLite**:仅作为本地 CLI 可选元数据后端,必须通过仓储抽象隔离,不能绑定业务逻辑。
@@ -141,7 +141,7 @@ BlueArchiveToolkit 不是一次性脚本,也不是演示项目。最终交付
**目标**:完成可长期使用的 Content Addressable Storage。 **目标**:完成可长期使用的 Content Addressable Storage。
**当前状态**:已完成 CAS V1。Go CLI 以最小稳定入口优先,Rust 继续承载完整资源拉取与更新检查核心逻辑;FFI 边界保持可选 **当前状态**:已完成 CAS V1。Go CLI 以最小稳定入口优先,Rust 继续承载完整资源拉取与更新检查核心逻辑;`bat-ffi` 仅保留为可选兼容层
交付物: 交付物:
@@ -150,7 +150,7 @@ BlueArchiveToolkit 不是一次性脚本,也不是演示项目。最终交付
3. 实现引用计数、对象元数据、完整性校验、GC、统计信息。 3. 实现引用计数、对象元数据、完整性校验、GC、统计信息。
4. 实现本地元数据后端:优先 SQLite,但必须隔离在 repository adapter 中。 4. 实现本地元数据后端:优先 SQLite,但必须隔离在 repository adapter 中。
5. 编写迁移、恢复、损坏检测和 `doctor cas` 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。 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 后台运维命令返回。 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 输出。 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 已存在,官方同步入口尚未把完整下载结果作为用户级流程自动导入。 7. 下载结果写入 CAS + ResourceRepository**部分完成**。CAS 和 SQLite ResourceRepository 已存在,官方同步入口尚未把完整下载结果作为用户级流程自动导入。
8. Linux 生产同步不依赖已安装官方启动器:**已完成当前 Rust 入口**。`--auto-discover` 只使用官方 HTTP metadata 和临时目录解析 `GameMainConfig` 8. Linux 生产同步不依赖已安装官方启动器:**已完成当前 Rust 入口**。`--auto-discover` 只使用官方 HTTP metadata 和临时目录解析 `GameMainConfig`
9. 真实官方网络全量下载 smoke test:**未完成记录**。需要在隔离目录执行并记录 dry-run、首次下载、二次 up-to-date 和本地损坏 repair。 9. 真实官方网络全量下载 smoke test:**未完成记录**。需要在隔离目录执行并记录 dry-run、首次下载、二次 up-to-date 和本地损坏 repair。
@@ -381,7 +381,7 @@ BlueArchiveToolkit 不是一次性脚本,也不是演示项目。最终交付
## 6. 近期 10 个具体任务 ## 6. 近期 10 个具体任务
1. 落地 Go CLI 的最小生产入口:`bat doctor``bat sync --help``bat official sync --help` 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。 3. 记录一次真实官方网络 smoke:dry-run、首次下载、二次 up-to-date、本地损坏 repair。
4. 将官方同步下载结果接入 CAS + `SqliteResourceRepository` 的用户级流程。 4. 将官方同步下载结果接入 CAS + `SqliteResourceRepository` 的用户级流程。
5. 继续扩展 Addressables parser 的真实 catalog 变体覆盖和错误诊断。 5. 继续扩展 Addressables parser 的真实 catalog 变体覆盖和错误诊断。
@@ -416,7 +416,7 @@ BlueArchiveToolkit 不是一次性脚本,也不是演示项目。最终交付
1. Rust 提供稳定引擎能力,不承担 CLI 编排,但负责完整资源拉取和更新检查的核心逻辑。 1. Rust 提供稳定引擎能力,不承担 CLI 编排,但负责完整资源拉取和更新检查的核心逻辑。
2. Go 负责用户命令、最小稳定 CLI、服务编排、网络和 Provider。 2. Go 负责用户命令、最小稳定 CLI、服务编排、网络和 Provider。
3. 跨边界优先进程或 SDK,FFI 只作为可选的粗粒度、安全、可测试 API。 3. 跨边界优先进程或 SDK,FFI 只作为可选的粗粒度、无状态、安全、可测试兼容 API。
4. Rust 不需要被强制写成 Go 调用库;当前 `bat --watch` / `bat --daemon` 是允许长期运行的 Rust 生产任务。 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` - `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`,明确记录当前已完成版本、正在拉取版本、上一个可用版本和失败版本。 - 官方同步会维护 `<output>/official-version-state.json`,明确记录当前已完成版本、正在拉取版本、上一个可用版本和失败版本。
- 资源导入链路可将 manifest 条目写入 CAS + `ResourceRepository`AssetBundle 会记录 UnityFS 摘要,TextAsset/Table/Media 会按类型分类索引。 - 资源导入链路可将 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 - RustCAS、官方资源同步核心、AssetBundle/Patch 引擎;当前生产同步入口是 `bat` binary
- Go:计划中的最小 CLI、服务编排、API Server、SDK当前仅有 FFI 包骨架 - Go:计划中的最小 CLI、服务编排、API Server、SDK默认通过 `bat --json` 进程边界或未来 SDK 集成 Rust 能力
- `bat-ffi`:可选兼容层,只暴露无状态粗粒度 JSON C ABI,不承载 daemon、下载器、CAS handle 或主控制面。
- PostgreSQL:计划中的服务端主数据库。 - PostgreSQL:计划中的服务端主数据库。
- Redis:计划中的缓存、队列状态、限流和短期锁。 - Redis:计划中的缓存、队列状态、限流和短期锁。
- Vue 3 + TypeScript:计划中的 Web 管理后台。 - Vue 3 + TypeScript:计划中的 Web 管理后台。
@@ -154,8 +155,8 @@ BlueArchiveToolkit/
│ ├── bat-cas-engine/ │ ├── bat-cas-engine/
│ ├── bat-assetbundle/ │ ├── bat-assetbundle/
│ ├── bat-patch/ │ ├── bat-patch/
│ └── bat-ffi/ │ └── bat-ffi/ # 可选无状态 C ABI 兼容层
├── internal/ffi/ # Go 调用 Rust FFI 的早期包装 ├── internal/ffi/ # 可选 CGO 兼容包装,不是 Go CLI 主路径
├── cmd/ # Go CLI 入口,尚未实现 ├── cmd/ # Go CLI 入口,尚未实现
├── pkg/ # Go SDK 包,尚未实现 ├── pkg/ # Go SDK 包,尚未实现
├── api/ # API 定义,尚未实现 ├── 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 解析。 2. 补齐 AssetBundle UnityFS header/block/directory 解析。
3. 扩展 Addressables catalog 解析覆盖,继续用真实形态 fixture/golden 锁定行为。 3. 扩展 Addressables catalog 解析覆盖,继续用真实形态 fixture/golden 锁定行为。
4. 将官方同步结果接入 CAS + ResourceRepository 的用户级工作流。 4. 将官方同步结果接入 CAS + ResourceRepository 的用户级工作流。
-11
View File
@@ -9,20 +9,9 @@ license.workspace = true
crate-type = ["cdylib", "staticlib"] crate-type = ["cdylib", "staticlib"]
[dependencies] [dependencies]
bat-core = { path = "../../core" }
bat-adapters = { path = "../../adapters" } bat-adapters = { path = "../../adapters" }
bat-infrastructure = { path = "../../infrastructure" } 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.workspace = true
serde_json.workspace = true serde_json.workspace = true
tokio.workspace = true tokio.workspace = true
# FFI 绑定
libc = "0.2"
[build-dependencies]
cbindgen = "0.27"
+118 -40
View File
@@ -1,8 +1,9 @@
//! # BAT FFI //! # BAT FFI compatibility layer
//! //!
//! Go 和 Rust 之间的 FFI 绑定层 //! Optional C ABI compatibility layer for coarse-grained JSON helpers.
//! //! Production orchestration should prefer the `bat --json` process boundary or a
//! 导出 C ABI 接口供 Go 通过 CGO 调用 //! 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)] #![warn(clippy::all)]
@@ -17,7 +18,7 @@ use std::collections::HashMap;
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
use std::os::raw::c_char; use std::os::raw::c_char;
/// FFI 版本号 /// FFI compatibility API version.
pub const VERSION: &str = env!("CARGO_PKG_VERSION"); pub const VERSION: &str = env!("CARGO_PKG_VERSION");
/// Sync snapshot JSON 输入。 /// Sync snapshot JSON 输入。
@@ -111,13 +112,13 @@ struct SyncPlanView {
delta: SyncDeltaView, delta: SyncDeltaView,
} }
/// 获取版本号(C ABI /// Returns the compatibility API version as an owned C string.
#[no_mangle] #[no_mangle]
pub extern "C" fn bat_version() -> *const c_char { pub extern "C" fn bat_version() -> *const c_char {
c_string(VERSION).into_raw() c_string(VERSION).into_raw()
} }
/// 释放 C 字符串内存 /// Frees C strings allocated by this crate.
/// ///
/// # Safety /// # 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] #[no_mangle]
pub extern "C" fn bat_manifest_inspect_json(raw_json: *const c_char) -> *mut c_char { pub extern "C" fn bat_manifest_inspect_json(raw_json: *const c_char) -> *mut c_char {
let result = (|| -> Result<ManifestInspectView, String> { 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_result(result)
} }
/// 构建官方同步计划 JSON summary。 /// Builds an official sync plan JSON summary without persisting state.
#[no_mangle] #[no_mangle]
pub extern "C" fn bat_sync_plan_json( pub extern "C" fn bat_sync_plan_json(
current_json: *const c_char, current_json: *const c_char,
@@ -368,16 +369,31 @@ mod tests {
value value
} }
#[test] fn parse_json_response(raw: String) -> serde_json::Value {
fn test_ffi_version() { serde_json::from_str(&raw).unwrap()
let version_ptr = bat_version();
let version = take_string(version_ptr);
assert!(!version.is_empty());
} }
#[test] fn inspect_manifest(raw_json: &str) -> serde_json::Value {
fn test_manifest_inspect_json() { let raw_json = CString::new(raw_json).unwrap();
let catalog_json = r#"{ 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_LocatorId": "AddressablesMainContentCatalog",
"m_InternalIds": [ "m_InternalIds": [
"synthetic/minimal.bundle" "synthetic/minimal.bundle"
@@ -391,34 +407,96 @@ mod tests {
"dependencies": ["shared.bundle"] "dependencies": ["shared.bundle"]
} }
] ]
}"#; }"#
}
let result_ptr = bat_manifest_inspect_json(CString::new(catalog_json).unwrap().as_ptr()); fn sync_snapshot_json(bundle_version: &str) -> String {
let result = take_string(result_ptr); format!(
assert!(result.contains(r#""ok":true"#)); r#"{{
assert!(result.contains(r#""resource_count":1"#)); "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] #[test]
fn test_sync_plan_json() { fn test_sync_plan_json() {
let current = r#"{ let current = sync_snapshot_json("s8tloc7lo3");
"connection_group_name":"Prod-Audit", let result = sync_plan(&current, None);
"app_version":"1.70.0", assert_eq!(result["ok"], true);
"bundle_version":"s8tloc7lo3", assert_eq!(result["data"]["decision"], "DownloadVerifyAndPublish");
"addressables_root":"https://prod-clientpatch.bluearchiveyostar.com/r93_token", assert_eq!(result["data"]["should_download"], true);
"endpoints":[ assert_eq!(result["data"]["should_publish"], true);
{ }
"kind":"TableCatalog",
"platform":null,
"url":"https://prod-clientpatch.bluearchiveyostar.com/r93_token/TableBundles/TableCatalog.bytes"
}
]
}"#;
let result_ptr = #[test]
bat_sync_plan_json(CString::new(current).unwrap().as_ptr(), std::ptr::null()); fn stateless_ffi_json_api_repeats_without_cached_state() {
let result = take_string(result_ptr); let first_manifest = inspect_manifest(catalog_json());
assert!(result.contains(r#""ok":true"#)); let second_manifest = inspect_manifest(catalog_json());
assert!(result.contains(r#""decision":"DownloadVerifyAndPublish""#)); 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. 数据流设计 ### 3. 数据流设计
``` ```
用户请求 → CLI/API → Go 业务层 → Rust 核心/同步层 → CAS 存储 → 数据库 用户请求 → CLI/API → Go 业务层 → bat --json / SDK → Rust 核心/同步层 → CAS 存储 → 数据库
↓ ↓ ↓ ↓
Web UI 缓存层 (Redis) Web UI 缓存层 (Redis)
``` ```
@@ -128,7 +128,8 @@ current symlink → official-sync-snapshot.json + official-download-manifest.jso
**后续 Go 职责** **后续 Go 职责**
- 提供最小稳定 CLI。 - 提供最小稳定 CLI。
- 包装或调用 Rust 同步入口,需要机器输出时使用 `--json` 并转发结构化 report。 - 默认通过 `bat --json` 进程边界包装 Rust 同步入口,并转发结构化 report。
- `bat-ffi` 仅作为可选无状态 C ABI 兼容层,不承载官方同步 daemon、下载器或 CAS handle。
- 编排 API Server、任务队列、Provider 和用户配置。 - 编排 API Server、任务队列、Provider 和用户配置。
--- ---
@@ -320,7 +321,8 @@ CREATE TABLE resource_versions (
``` ```
开发机器 (本地) 开发机器 (本地)
├── CLI (Go) ├── CLI (Go)
├── Rust ├── Rust bat 进程 / 未来 SDK
├── 可选 bat-ffi 兼容层
└── 连接 → 远程数据库服务器 (裸金属) └── 连接 → 远程数据库服务器 (裸金属)
├── PostgreSQL ├── PostgreSQL
└── Redis └── Redis
@@ -35,7 +35,7 @@ BlueArchiveToolkit 的最终目标覆盖资源同步、CAS、AssetBundle 解析
3. **Go 应用层** 3. **Go 应用层**
- 负责 CLI、资源同步、下载器、API Server、任务调度、配置、日志、Provider 编排。 - 负责 CLI、资源同步、下载器、API Server、任务调度、配置、日志、Provider 编排。
- 通过稳定 SDK进程边界,必要时再通过 FFI 调用 Rust 引擎能力 - 通过稳定 SDK进程边界调用 Rust 能力;FFI 只作为可选兼容层
- 不重复实现 AssetBundle 解析、Patch 算法或 CAS 对象存储核心逻辑。 - 不重复实现 AssetBundle 解析、Patch 算法或 CAS 对象存储核心逻辑。
4. **Web 层** 4. **Web 层**
@@ -48,7 +48,7 @@ BlueArchiveToolkit 的最终目标覆盖资源同步、CAS、AssetBundle 解析
1. Rust 引擎 API 必须保持业务无关,不出现 CLI 命令、HTTP 状态码、Web 页面状态。 1. Rust 引擎 API 必须保持业务无关,不出现 CLI 命令、HTTP 状态码、Web 页面状态。
2. Go 应用层不得复制 Rust 引擎中的 Hash、Patch、AssetBundle 核心算法。 2. Go 应用层不得复制 Rust 引擎中的 Hash、Patch、AssetBundle 核心算法。
3. 跨边界优先级应是进程边界或稳定 SDK,其次才是 FFI;若使用 FFI,必须只暴露粗粒度批量和事务语义 3. 跨边界优先级应是进程边界或稳定 SDK,其次才是 FFI;若使用 FFI,必须只暴露粗粒度、无状态、一次调用一次输入输出的兼容 API
4. 所有跨边界错误必须能映射到统一错误码和可读诊断信息。 4. 所有跨边界错误必须能映射到统一错误码和可读诊断信息。
--- ---
@@ -63,7 +63,7 @@ BlueArchiveToolkit 的最终目标覆盖资源同步、CAS、AssetBundle 解析
代价: 代价:
1. 需要维护 FFI 或 SDK 边界。 1. 需要维护进程、SDK 和可选 FFI 兼容边界。
2. 错误类型、数据结构和版本兼容性需要更早设计。 2. 错误类型、数据结构和版本兼容性需要更早设计。
3. 集成测试必须覆盖跨语言调用,而不能只看单 crate 单元测试。 3. 集成测试必须覆盖跨语言调用,而不能只看单 crate 单元测试。
@@ -75,4 +75,5 @@ BlueArchiveToolkit 的最终目标覆盖资源同步、CAS、AssetBundle 解析
1. `crates/bat-cas-engine` 是 CAS 核心实现位置。 1. `crates/bat-cas-engine` 是 CAS 核心实现位置。
2. `infrastructure` 不再复制 CAS 存储算法,只做 `bat-core::repositories::CasRepository` 适配。 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` `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` 输入。 1. 显式执行 `--auto-discover` 或读取已审计 `server-info` 输入。
+3 -2
View File
@@ -288,8 +288,9 @@ BlueArchiveToolkit/
## 📚 相关文档 ## 📚 相关文档
- [完整架构审查报告](./ARCHITECTURE_REVIEW.md)1900+ 行) - [完整架构审查报告](./ARCHITECTURE_REVIEW.md)1900+ 行)
- [当前架构文档](./architecture/README.md) - [当前架构文档](../architecture/README.md)
- [CLAUDE.md](../CLAUDE.md) - 项目开发指南 - [开发指南](../guides/development.md) - 当前开发流程
- [Agent 开发规则](../../AGENTS.md) - AI agent 长期规则
--- ---
+2 -2
View File
@@ -62,10 +62,10 @@ chore: establish development baseline
```bash ```bash
git status --short --branch 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 make fmt
``` ```
开发约束:
1. 先阅读相关文档和代码,再判断实现方式。
2. 跨模块、架构、数据格式或用户工作流变更必须先说明设计取舍。
3. 保持改动聚焦,不做无关重构、批量格式化或元数据 churn。
4. 公共接口、状态文件、manifest、catalog、patch 和下载流程变更必须补充测试或 fixture。
5. 用户可见命令、运行路径、配置、状态文件、日志或缺口状态变化时,同步更新 README、指南、架构文档或 `docs/reports/CURRENT_GAPS.md`
### 3. 提交 ### 3. 提交
```bash ```bash
@@ -86,6 +96,10 @@ git push origin feature/your-feature-name
## 代码规范 ## 代码规范
默认使用简体中文写文档、提交说明、开发日志和面向用户的说明。代码标识符、协议字段、数据库字段、包名和命令参数保持英文命名规范。
禁止使用 demo、临时实现、硬编码路径或只为当前测试通过的伪实现。确实未完成的能力应写入当前缺口文档,而不是用 `TODO``FIXME` 隐藏。
### Go ### Go
- 遵循 [Effective Go](https://golang.org/doc/effective_go) - 遵循 [Effective Go](https://golang.org/doc/effective_go)
- 使用 `gofmt` 格式化 - 使用 `gofmt` 格式化
@@ -104,16 +118,30 @@ git push origin feature/your-feature-name
## 测试 ## 测试
### 当前必跑测试 ### 合并前通用门禁
```bash ```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-adapters -- --nocapture
cargo test -p bat-ffi -- --nocapture cargo test -p bat-ffi -- --nocapture
cargo test -p bat-infrastructure -- --nocapture cargo test -p bat-infrastructure -- --nocapture
cargo test -p bat-infrastructure --bin bat -- --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` 或其他隔离目录,不要写入现有资源目录。 开发环境真实下载默认写入 `./bat-resources`;如果要覆盖,必须使用 `/tmp` 或其他隔离目录,不要写入现有资源目录。
生产或 CI 环境不得依赖安装官方启动器。需要启动器信息时,只能分析启动器资源、官方 manifest 或公开更新数据,并将解析结果固化为可验证流程。
### 基准测试 ### 基准测试
```bash ```bash
@@ -180,9 +210,11 @@ cargo fetch
先确认失败是否来自真实网络或本地资源路径。默认测试应使用 fixture/mock,不应依赖官方线上资源或开发机已有资源目录。 先确认失败是否来自真实网络或本地资源路径。默认测试应使用 fixture/mock,不应依赖官方线上资源或开发机已有资源目录。
### 3. FFI 绑定问题 ### 3. FFI 兼容层问题
重新生成绑定: `bat-ffi` 不是主集成边界,只用于需要 C ABI 的兼容场景。默认 Go CLI 集成优先运行 Rust `bat --json`
重新构建兼容库:
```bash ```bash
cd crates/bat-ffi cd crates/bat-ffi
cargo build cargo build
+3 -1
View File
@@ -172,7 +172,7 @@
现象: 现象:
- `cmd/bat` 目录存在,但无 `main.go` - `cmd/bat` 目录存在,但无 `main.go`
- `internal/ffi/ffi.go` 已存在,但还不是用户可运行 CLI - `internal/ffi/ffi.go` 已存在,但只是可选 CGO 兼容包装,不是用户可运行 CLI,也不是默认 Go/Rust 集成边界
- `go test ./...` 当前没有产品级 Go package 覆盖。 - `go test ./...` 当前没有产品级 Go package 覆盖。
影响: 影响:
@@ -185,6 +185,7 @@
- `bat doctor` 可运行。 - `bat doctor` 可运行。
- `bat --help` 命令结构稳定。 - `bat --help` 命令结构稳定。
- 命令支持默认人类可读输出和 `--json` 机器输出。 - 命令支持默认人类可读输出和 `--json` 机器输出。
- Go CLI 默认通过 Rust `bat --json` 进程边界获取同步 report;除非明确兼容需求,不依赖 FFI。
### G-009API Server 和 OpenAPI 尚未实现 ### G-009API Server 和 OpenAPI 尚未实现
@@ -378,6 +379,7 @@
- 架构 README 已明确当前 Rust 官方同步入口、Go 计划边界和目标架构差异。 - 架构 README 已明确当前 Rust 官方同步入口、Go 计划边界和目标架构差异。
- 官方资源后端说明由 `docs/architecture/official-resource-backend.md` 承载。 - 官方资源后端说明由 `docs/architecture/official-resource-backend.md` 承载。
- `bat-ffi` 已降级为可选无状态兼容层,主集成边界明确为 `bat --json` 进程边界或未来稳定 SDK。
### G-017CI 未落地 ### 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` 覆盖的本地生成报告目录。
+34 -29
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 package ffi
/* /*
@@ -13,45 +18,45 @@ extern char* bat_sync_plan_json(const char* current_json, const char* previous_j
*/ */
import "C" import "C"
import ( import (
"errors" "errors"
"unsafe" "unsafe"
) )
func Version() (string, error) { func Version() (string, error) {
ptr := C.bat_version() ptr := C.bat_version()
if ptr == nil { if ptr == nil {
return "", errors.New("bat_version returned nil") return "", errors.New("bat_version returned nil")
} }
defer C.bat_free_string((*C.char)(unsafe.Pointer(ptr))) defer C.bat_free_string((*C.char)(unsafe.Pointer(ptr)))
return C.GoString(ptr), nil return C.GoString(ptr), nil
} }
func InspectManifest(rawJSON string) (string, error) { func InspectManifest(rawJSON string) (string, error) {
cRaw := C.CString(rawJSON) cRaw := C.CString(rawJSON)
defer C.free(unsafe.Pointer(cRaw)) defer C.free(unsafe.Pointer(cRaw))
ptr := C.bat_manifest_inspect_json(cRaw) ptr := C.bat_manifest_inspect_json(cRaw)
if ptr == nil { if ptr == nil {
return "", errors.New("bat_manifest_inspect_json returned nil") return "", errors.New("bat_manifest_inspect_json returned nil")
} }
defer C.bat_free_string((*C.char)(unsafe.Pointer(ptr))) defer C.bat_free_string((*C.char)(unsafe.Pointer(ptr)))
return C.GoString(ptr), nil return C.GoString(ptr), nil
} }
func BuildSyncPlan(currentJSON, previousJSON string) (string, error) { func BuildSyncPlan(currentJSON, previousJSON string) (string, error) {
cCurrent := C.CString(currentJSON) cCurrent := C.CString(currentJSON)
defer C.free(unsafe.Pointer(cCurrent)) defer C.free(unsafe.Pointer(cCurrent))
var cPrevious *C.char var cPrevious *C.char
if previousJSON != "" { if previousJSON != "" {
cPrevious = C.CString(previousJSON) cPrevious = C.CString(previousJSON)
defer C.free(unsafe.Pointer(cPrevious)) defer C.free(unsafe.Pointer(cPrevious))
} }
ptr := C.bat_sync_plan_json(cCurrent, cPrevious) ptr := C.bat_sync_plan_json(cCurrent, cPrevious)
if ptr == nil { if ptr == nil {
return "", errors.New("bat_sync_plan_json returned nil") return "", errors.New("bat_sync_plan_json returned nil")
} }
defer C.bat_free_string((*C.char)(unsafe.Pointer(ptr))) defer C.bat_free_string((*C.char)(unsafe.Pointer(ptr)))
return C.GoString(ptr), nil return C.GoString(ptr), nil
} }