feat(filelib)!: VersionStore 改为真 git,一项目一仓库

内存 store 换成 gitVersionStore:init 建目录并 git init,VersionId 是
commit hash,某文件的版本取 `git log -1 -- <path>`(D16 文件级版本不因
别的文件提交而失效)。删除也是一个 commit,旧版本仍可读。决策见 ADR-0030。

git 用 execFile 调系统二进制,不引依赖。每次调用钉死 --git-dir/--work-tree
并禁 hooks、隔离全局 gitconfig:项目仓库是老师上传的数据,而 storage root
默认就在本 repo 内,不钉死会让命令落到外层仓库上。

同时:
- 单文件上限改为 HUB_FILELIB_MAX_FILE_BYTES(缺省 10MiB),前端从
  /database/config 读,不再两处硬编码
- commit 身份 name=displayName、email=<userId>@filelib.paradigm-edu.net;
  message 缺省为「【用户名】修改了【路径】」,调用方显式传则优先
- 上传改走弹窗,路径与 commit 信息可手填(原先 prompt 只能填路径)

BREAKING CHANGE: VersionId 由计数器(v1/v2)变为 commit hash;
CommitRequest.author 由字符串变为 { userId, displayName? }。
旧 .version-store.json 不迁移,此前建的项目报 repo_not_found。
This commit is contained in:
2026-07-27 15:49:26 +08:00
parent a306c58db2
commit 82241afb56
16 changed files with 1150 additions and 40 deletions
+5 -1
View File
@@ -23,7 +23,11 @@ describe("InMemoryVersionStore · C1 语义", () => {
it("新建(baseVersion null)→ ok;head/read 命中", async () => {
const store = createInMemoryVersionStore();
await store.init(DIR);
const r = await store.commit(DIR, "a.md", { baseVersion: null, content: "v1 内容", author: "u1" });
const r = await store.commit(DIR, "a.md", {
baseVersion: null,
content: "v1 内容",
author: { userId: "u1" },
});
expect(r).toEqual({ status: "ok", version: "v1" });
expect((await store.read(DIR, "a.md")).toString()).toBe("v1 内容");
});