新增 AGC 模板库与由模板创建项目链路 (#396)
Project CI / AI game creator shell Rust shard 3/4 (push) Successful in 7m12s
Project CI / AI game creator shell Rust shard 2/4 (push) Successful in 7m18s
Project CI / AI game creator shell Rust shard 1/4 (push) Successful in 7m25s
Project CI / AI game creator shell Rust shard 4/4 (push) Successful in 7m22s
Project CI / AI game creator shell Rust smoke (push) Successful in 1m49s
Project CI / AI game creator shell Rust crates (push) Successful in 2m36s
Project CI / Repository checks (push) Failing after 1m11s
Project CI / Frontend tests (push) Failing after 4m37s
Project CI / AI game creator shell web tests (push) Failing after 4m6s
Project CI / Native shell tests (push) Successful in 9m39s
Project CI / Backend tests (push) Successful in 10m12s
Project CI / AI game creator shell Rust shard 3/4 (push) Successful in 7m12s
Project CI / AI game creator shell Rust shard 2/4 (push) Successful in 7m18s
Project CI / AI game creator shell Rust shard 1/4 (push) Successful in 7m25s
Project CI / AI game creator shell Rust shard 4/4 (push) Successful in 7m22s
Project CI / AI game creator shell Rust smoke (push) Successful in 1m49s
Project CI / AI game creator shell Rust crates (push) Successful in 2m36s
Project CI / Repository checks (push) Failing after 1m11s
Project CI / Frontend tests (push) Failing after 4m37s
Project CI / AI game creator shell web tests (push) Failing after 4m6s
Project CI / Native shell tests (push) Successful in 9m39s
Project CI / Backend tests (push) Successful in 10m12s
## 交付范围 - OSS `agc-dev` bucket 的 `templates/` 前缀作为 AGC 游戏模板库(**去掉 `agc/` 这一层**;`agc/` 继续只放客户端安装包与更新清单)。 - 模板正文改为 zip(zip 根 == AGC 项目根,如 `game/index.html`);清单补齐 `tags`、封面字段与包大小/摘要,`templateVersion` 用于判断是否需要重下。 - 客户端:Rust 模板库模块、模板库全屏页、首页模板推荐位、左侧导航入口。 ## 客户端行为 - `fetch_game_template_library`:读取并校验清单(≤4 MiB),缓存到 `<app_data>/templates/index.json`;网络失败回退本机缓存并标注 `source=cache`。 - `download_game_template`:按清单下载 zip(≤512 MiB),校验字节数与 SHA-256 后解压到 `<app_data>/templates/installed/<id>/<version>/`,最后写 `installed.json` 作为安装完成标记。 - `create_automatic_local_game_project_from_template`:先把模板文件铺进新项目目录,再走既有 `init_local_game_project_at` 补 `.agent` 清单与标准目录;失败删除半成品目录。 - 解压只接受普通文件与目录(拒绝绝对路径、`..`、盘符、符号链接),安装目录名由标识符白名单拼出;远端只信「受信任 OSS 主机 + 对象键」,清单里的地址字段不参与请求。 - UI:搜索(空白分隔多关键词「与」)、标签/运行时筛选、仅看已下载、封面卡片与已下载徽标;「使用模板」在版本落后时先重下再建项。 ## 文档与脚本 - 主规范 `docs/technical/【技术方案】AGC模板库与模板建项-2026-09-17.md`;里程碑与实施计划见 `docs/project-memory/plans/`;`decision-log.md` 记录库路径、清单 schema、安装缓存目录与 CSP 约定。 - 发布脚本 `scripts/agc-template-library-publish.mjs`(`--dry-run` 校验 → 上传 → 回读校验)。 - 首页「灵感推荐」替换为模板库推荐位,删除本机灵感图目录与 `InspirationGallery.tsx`;`tauri.conf.json` 的 `img-src` 放行受信任 OSS 主机用于加载封面。 ## 验证 - `cargo test --bin genarrative-ai-game-creator-shell template_library`:9 passed;`--ignored` 真连检查 `fetches_the_live_template_library_index` 通过。 - `npx vitest run src/features/template-library`:9 passed。 - `npm run typecheck`、`cargo fmt --check`、`npm run check:encoding`、`node scripts/check-doc-index.mjs`、`git diff --check` 均通过。 - OSS 侧匿名复核:`templates/index.json`、各 `cover.png` 与 `template.zip` 均返回 200。 ## 未做 / 待确认 - 本轮未做客户端点击级人工验收(下一步单独验证并把结果补进此 PR)。 - 模板封面目前是占位标题卡,正式封面由后续模板包提供。 --------- Co-authored-by: kdletters <61648117+kdletters@users.noreply.github.com> Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/396
This commit was merged in pull request #396.
This commit is contained in:
@@ -39,6 +39,7 @@
|
||||
- [AGC 通用插件宿主与编辑器适配](./technical/【技术方案】AGC通用插件宿主与编辑器适配-2026-09-09.md):通用插件宿主、SDK、权限审计、UI 挂载和 Cocos 编辑器适配边界。
|
||||
- [AGC Cocos Creator 编辑器桥接模块](<./technical/【技术方案】AGC Cocos Creator 编辑器桥接模块-2026-09-09.md>):独立 crate、feature 开关、目标校验与 Windows 注入边界。
|
||||
- [AGC 客户端更新检查与下载](./technical/【技术方案】AGC客户端更新检查与下载-2026-08-31.md):启动版本检测、OSS 清单格式和下载约定。
|
||||
- [AGC 模板库与模板建项](./technical/【技术方案】AGC模板库与模板建项-2026-09-17.md):`templates/` 前缀的模板库契约、下载安装与「用模板建项目」链路。
|
||||
- [DirectProject 本轮附件路径映射](./technical/【技术方案】DirectProject本轮附件路径映射-2026-08-31.md):Direct 首轮只映射附件原名与项目相对路径,不灌正文、不区别 GDD。
|
||||
- [Direct 回合行为审计账本](./technical/【技术方案】Direct回合行为审计账本-2026-08-31.md):Direct GUI 回合把 native 读 / MCP / 写文件落成项目内有界时间线,用于判断有没有打开本轮附件。
|
||||
- [项目开发工作台 PRD](./prd/【AI游戏创作】项目开发工作台PRD-2026-07-20.md):当前工作台页面和验收边界。
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
# AGC 模板库客户端接入实施计划
|
||||
|
||||
Version: 1.0
|
||||
Status: active
|
||||
Date: 2026-09-17
|
||||
Milestone Spec: `docs/project-memory/plans/【里程碑】AGC模板库客户端接入-2026-09-17.md`
|
||||
|
||||
## 步骤
|
||||
|
||||
1. **OSS 库布局与契约**
|
||||
- 在 `agc-dev` 落地 `templates/` 前缀:`index.json`、`v1/<id>/{template.json,template.zip,cover.*}`。
|
||||
- 清单补齐 `tags`、`coverKey/coverWidth/coverHeight/coverSha256`,正文改为 zip(zip 根 == 项目根)。
|
||||
- 模板源落在 `apps/ai-game-creator-shell/template-library/v1/<id>/{meta.json,project/**,cover.*}`;zip 由 `scripts/agc-template-library-publish.mjs` 现场打包(不落仓库)。
|
||||
- 交付:发布脚本(校验 + 打包 + 上传 + 回读校验,支持 `--dry-run` / `--prune`)、`templates/README.md`,以及 5 个模板(3 个空白 + 2 个起步工程)。
|
||||
- 验收:匿名 `GET templates/index.json` 可读,每个 `zipKey` 回读 SHA-256 与清单一致。
|
||||
|
||||
2. **Rust 模板库模块**
|
||||
- 新增 `src-tauri/src/template_library.rs`:清单解析与校验、受信任 base、缓存/安装目录、zip 安全解压、安装记录、由模板建项目。
|
||||
- 注册命令 `fetch_game_template_library`、`download_game_template`、`create_automatic_local_game_project_from_template`。
|
||||
- 交付:模块内 8 项单测(schema/重复模板、键前缀、base 校验、解压逃逸、摘要与大小、安装记录、建项目与失败清理)。
|
||||
- 验收:`cargo test --bin genarrative-ai-game-creator-shell template_library` 全绿。
|
||||
|
||||
3. **前端状态链路**
|
||||
- `src/features/template-library/templateLibraryModel.ts`(类型与搜索/筛选纯函数)与 `useTemplateLibrary.ts`(拉取、下载、建项目、就地更新已下载状态)。
|
||||
- `useHomeProjectCreation` 增加 `enterCreatedTemplateProject`,复用既有进项目通道。
|
||||
- 交付:9 项模型单测。
|
||||
- 验收:`npx vitest run src/features/template-library` 全绿。
|
||||
|
||||
4. **界面接入**
|
||||
- 新增 `src/view/template-library/index.tsx` 全屏页;`LauncherView` 增加 `template-library`;左侧导航加模板库入口。
|
||||
- 首页「灵感推荐」替换为 `TemplateRecommendations`;删除 `InspirationGallery.tsx` 与 `assets/inspiration/`。
|
||||
- `tauri.conf.json` 的 `img-src` 放行受信任 OSS 主机以加载封面。
|
||||
- 验收:模板库页可搜索、筛选、下载、显示已下载并成功建项目;首页推荐位可跳转。
|
||||
|
||||
5. **文档与共享记忆**
|
||||
- 主规范 `docs/technical/【技术方案】AGC模板库与模板建项-2026-09-17.md`,并在 `docs/README.md` 建索引。
|
||||
- 本里程碑与实施计划;`decision-log.md` 记录库路径、清单 schema、缓存目录与 CSP 约定。
|
||||
- 验收:`node scripts/check-doc-index.mjs` 通过。
|
||||
|
||||
## 验证命令
|
||||
|
||||
```bash
|
||||
cargo check --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml
|
||||
cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --bin genarrative-ai-game-creator-shell template_library
|
||||
cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --bin genarrative-ai-game-creator-shell template_library -- --ignored
|
||||
cd apps/ai-game-creator-shell && npx tsc -p tsconfig.json --noEmit
|
||||
npx vitest run apps/ai-game-creator-shell/tests/templateLibraryModel.test.ts apps/ai-game-creator-shell/tests/templateLibraryView.test.tsx
|
||||
node scripts/agc-template-library-publish.mjs --source <dir> --dry-run
|
||||
npm run check:encoding
|
||||
node scripts/check-doc-index.mjs
|
||||
git diff --check
|
||||
```
|
||||
|
||||
## 风险与回退
|
||||
|
||||
- **封面走 WebView 直连**:仅放行受信任 OSS 主机;若日后改用后端签名,清单的 `coverKey` 不变。
|
||||
- **模板包体积**:下载上限 512 MiB、解压文件数 4096、单文件 256 MiB;超限直接拒绝,不落盘。
|
||||
- **清单漂移**:客户端只信「受信任主机 + 对象键」,清单中的地址字段不参与请求。
|
||||
- **回退**:清空 `templates/` 前缀即回到空模板库;客户端保留错误与空态展示,不阻断其它功能。
|
||||
@@ -0,0 +1,40 @@
|
||||
# AGC 模板库客户端接入
|
||||
|
||||
Version: 1.0
|
||||
Status: active
|
||||
Date: 2026-09-17
|
||||
Parent Spec: `docs/technical/【技术方案】AGC模板库与模板建项-2026-09-17.md`
|
||||
|
||||
## 目标
|
||||
|
||||
AGC 客户端能读取公共 OSS 上的游戏模板库,并把「浏览 → 筛选 → 下载 → 用模板建项目」做成一条可用链路,模板更新不再依赖客户端发版。
|
||||
|
||||
## 范围
|
||||
|
||||
- OSS `templates/` 前缀的库布局、清单 schema、封面与 zip 元数据契约。
|
||||
- Rust 侧读取清单、下载安装、由模板创建项目的命令与安全边界。
|
||||
- 模板库全屏页(搜索、标签/运行时筛选、仅看已下载)、首页模板推荐位、左侧导航入口。
|
||||
- 仓库内发布脚本与文档、模板库定向单测与类型检查。
|
||||
|
||||
## 不做
|
||||
|
||||
- 不做模板制作工具、模板审核、模板计费与推荐算法。
|
||||
- 不做模板增量更新(按 `templateVersion` 全量重下)。
|
||||
- 不把模板回填进已创建项目,也不改写用户项目内容。
|
||||
- 不放宽现有项目私有 DACL、下载摘要校验和受信任 OSS 主机边界。
|
||||
|
||||
## 验收标准
|
||||
|
||||
1. `fetch_game_template_library` 能读到清单并合并本机已安装状态;远端不可用时回退本机缓存并标明 `source=cache`。
|
||||
2. `download_game_template` 对字节数与 SHA-256 不一致、越界对象键、非 `templates/` 前缀的包一律拒绝,且不落半成品目录。
|
||||
3. zip 解压拒绝绝对路径、`..`、盘符、符号链接;安装完成后才写 `installed.json` 作为已下载判据。
|
||||
4. `create_automatic_local_game_project_from_template` 建出的项目同时具备模板文件、`.agent` 清单与标准目录;失败时不留项目目录。
|
||||
5. 模板库页可按关键词、标签、运行时与「仅看已下载」筛选;卡片显示封面与已下载徽标;已下载且版本一致时不再显示下载入口(落后显示「更新」);过程提示以浮层 toast 呈现,不占页面内位置;「使用模板」在版本落后时先重下再建项。
|
||||
6. 首页推荐位展示模板库内容并可进入模板库页;左侧导航有模板库入口且为独立全屏页。
|
||||
7. 定向 Rust 单测 9 项(含线上清单 fixture)、前端模型 9 项 + 页面/推荐位 8 项、`tsc` 类型检查、`npm run check:encoding`、`git diff --check` 全部通过;可选真连检查能读线上清单、下载安装线上模板并据此建项目。
|
||||
|
||||
## 依赖
|
||||
|
||||
- 现有自动工作区建项链路(`create_automatic_local_game_project_at` / `init_local_game_project_at`)。
|
||||
- 现有 AGC 更新通道使用的受信任 OSS 主机与 CSP 白名单口径。
|
||||
- 仓库 OSS 凭据(本机 `.env.secrets.local` 的 `ALIYUN_OSS_*`)与 `scripts/agc-template-library-publish.mjs`。
|
||||
@@ -8823,6 +8823,16 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在
|
||||
- 决策:采用后台继续运行语义。Direct 回合由进程内项目身份锁持有,页面离开不取消;重进项目通过活动回合只读快照与 Thread Manager bootstrap/consume 恢复忙碌态和进度。左上角面板复用同一快照列出正在运行的 Direct 项目并支持进入。
|
||||
- 边界:快照不写项目文件、不进入公共 API、不跨应用重启恢复;读取失败保留上一份结果并单独提示,不改写成权限或审批失败。身份锁排他性、付费身份和项目写锁不变。
|
||||
|
||||
## 2026-09-17 AGC 模板库落在 oss://agc-dev/templates/
|
||||
|
||||
- 背景:AGC 需要「真·游戏模板」库,让用户能浏览、筛选、下载模板并直接由模板创建项目,且模板内容更新不依赖客户端发版。
|
||||
- 决策:模板库固定在 bucket `agc-dev`(endpoint `oss-rg-china-mainland.aliyuncs.com`)的 `templates/` 前缀,公共读;**不再嵌套 `agc/` 这一层**(`agc/` 继续只放客户端安装包与 `latest.json` 更新通道)。目录为 `templates/index.json` + `templates/v1/<templateId>/{template.json,template.zip,cover.png}`,zip 根等于 AGC 项目根。
|
||||
- 决策:清单 schema 为 `agc-template-library.v1`,每条模板带 `tags`、`coverKey/coverWidth/coverHeight/coverSha256`、`zipKey/zipSizeBytes/zipSha256` 与 `templateVersion`;客户端只信「受信任 OSS 主机 + 对象键」自行拼 URL,清单里的地址字段不参与请求。
|
||||
- 决策:客户端缓存与安装根为 `<app_data>/templates/`(`index.json` 缓存 + `installed/<id>/<version>/`,安装完成才写 `installed.json`);建项目在 `<app_data>/projects/` 下走既有自动工作区规则,先铺模板文件再补 `.agent` 清单。
|
||||
- 决策:模板库首页推荐位替换原「灵感推荐」本机图片目录(已删除 `InspirationGallery.tsx` 与 `assets/inspiration/`);左侧导航新增模板库入口,打开独立全屏页。`tauri.conf.json` 的 `img-src` 放行受信任 OSS 主机用于封面图。
|
||||
- 关联规范:`docs/technical/【技术方案】AGC模板库与模板建项-2026-09-17.md`;开发期计划见 `docs/project-memory/plans/【里程碑】AGC模板库客户端接入-2026-09-17.md` 与对应实施计划。
|
||||
- 验证:Rust 模板库 8 项定向单测、前端模型 9 项单测、AGC `tsc` 类型检查通过;`templates/index.json` 匿名可读且每个 `zipKey` 回读 SHA-256 与清单一致;发布脚本 `scripts/agc-template-library-publish.mjs` 支持 `--dry-run` 与上传后回读校验。
|
||||
|
||||
## 2026-09-16 CI 宿主 CPU 上限:Jenkins 16 核 / Gitea Actions runner 12 核
|
||||
|
||||
- 背景:`genarrative-station`(32 逻辑核)上 Jenkins Built-In Node 与 Gitea Actions runner 共用同一宿主。Jenkins `jenkins.service` 原先没有任何 CPU 限制(`cpu.max=max`),构建期 Web / Api / Stdb 三分支并行(Vitest 8 线程 + 两次默认 32 job 的 cargo)把整机顶到 80%~95%;`gitea-runner` 容器 `--cpus=24`(75%)在 push 触发的 CI 波峰里实测峰值 24.8~25.3 核,是同一时间窗里更大的单一消耗方。
|
||||
|
||||
@@ -5678,3 +5678,11 @@ Cocos Creator 根目录由 `package.json.creator.version` 与普通 `assets/`
|
||||
- **处理(现行口径)**:不要把重写结果当改动提交。跑过 `cargo test` 或构建后先 `git checkout -- apps/ai-game-creator-shell/src/features/project-workspace/generated`,再删掉多出来的 `DirectCodexUserMessageEnvelope.ts`,然后才做 typecheck / 打包;绑定与前端形状冲突时以**已提交的绑定 + 前端**为基准排查。
|
||||
- **验证**:恢复提交版本后 `npm run ai-game-creator-shell:typecheck` exit 0(`[skill-pack] OK`);保留重写结果时同一条命令 exit 2。release 构建本身还会在 `src/features/ui-editor/types/` 落下 `BindingChange.ts` / `BindingDTO.ts` 两个无人引用的未跟踪文件,属同类生成产物。
|
||||
- **关联**:`apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/`(ts-rs 导出源)、`apps/ai-game-creator-shell/src/features/project-workspace/resourceReferences.ts`、`apps/ai-game-creator-shell/scripts/build-release.mjs`(`beforeBuildCommand`)。
|
||||
|
||||
## 2026-09-17 AGC 壳首页无限 setState:effect 依赖了每次渲染都换身份的普通函数
|
||||
|
||||
- **现象**:dev 客户端停在首页、不点任何东西也会持续刷 `WEBVIEW error webview: Maximum update depth exceeded …`(5 秒涨 ~8.5 KB 日志),对应 WebView2 renderer 工作集涨到 **4.2 GB**、CPU 持续累计(约 0.7–1.5 核);表现上很像"模板库卡片太多/滚动卡",实际与页面内容无关。
|
||||
- **原因**:`WorkspaceLauncher` 里发布"活动项目面板"数据的 effect,依赖数组里带了 `openActiveProject`;它由 `useCallback([openProject, setProjectPath])` 生成,而 `openProject` 来自 `useHomeProjectCreation` 的**普通函数声明**(每次渲染都是新身份)→ `openActiveProject` 每渲染都变 → effect 每渲染重跑 → cleanup/主体调 `setActiveProjectRuns` 改 `WindowChrome` 的 state → 标题栏重渲染 → 又一轮。`WindowChrome` 的 context value 当时还是内联对象,进一步放大了连带重渲染。日志里没有组件栈,是靠在 `console.error` 包装里抓 `new Error().stack`(该日志与 setState 同栈)才定位到 `WorkspaceLauncher.tsx` 的 `commitHookEffectListUnmount → dispatchSetState`。
|
||||
- **处理(现行口径)**:① 依赖里只放数据,回调走 ref(`openActiveProjectRef`)——effect 不再因回调换身份而重跑;② `useDirectActiveTurns` 轮询只在快照内容变化时才 `setActiveTurns`(并给空态做引用稳定),避免每 5 秒换一次数组身份去带动下游 effect;③ `WindowChrome` 的 context value 用 `useMemo` 收口。判断类问题的通行判据:**凡是把"每次渲染新生成的函数/对象"写进 effect 依赖的,一律视为 bug**。
|
||||
- **验证**:修复后同一台机器、同一路径下 35 秒内新增 `Maximum update depth` **0 条**,renderer 工作集 **254 MB**(修复前 4.2–4.4 GB);`apps/ai-game-creator-shell/tests/directActiveTurns.test.tsx` 断言轮询返回值不变时快照引用不变。
|
||||
- **关联**:`apps/ai-game-creator-shell/src/features/app-shell/WorkspaceLauncher.tsx`、`apps/ai-game-creator-shell/src/features/agent-runtime/directActiveTurns.ts`、`apps/ai-game-creator-shell/src/components/WindowChrome.tsx`、`apps/ai-game-creator-shell/src/features/app-shell/useHomeProjectCreation.ts`。
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
# 【技术方案】AGC 模板库与模板建项
|
||||
|
||||
## 交付范围
|
||||
|
||||
AGC 客户端接入公共 OSS 上的**游戏模板库**(真·游戏模板,正文是 zip),并让用户能浏览、搜索、筛选、下载模板,直接由模板创建项目。模板更新不再依赖客户端发版。
|
||||
|
||||
- OSS 侧:bucket `agc-dev`(endpoint `oss-rg-china-mainland.aliyuncs.com`)下的 `templates/` 前缀,公共读。
|
||||
- 客户端侧:Rust `template_library` 模块(读清单、下载、安装、建项目)+ 模板库全屏页 + 首页模板推荐 + 左侧导航入口。
|
||||
- 不在本次范围:模板制作工具、模板审核、模板计费、增量更新、已建项目的模板回填。
|
||||
|
||||
## OSS 契约
|
||||
|
||||
```text
|
||||
templates/
|
||||
index.json # 模板库清单,客户端唯一读取入口
|
||||
v1/<templateId>/
|
||||
template.json # 单模板元数据(含文件级摘要)
|
||||
template.zip # 模板正文,zip 根 == AGC 项目根(如 game/index.html)
|
||||
cover.(png|jpg|webp|svg) # 封面图(卡片展示,客户端 <img> 直接取)
|
||||
```
|
||||
|
||||
`index.json`(schema `agc-template-library.v1`):
|
||||
|
||||
| 字段 | 说明 |
|
||||
| --- | --- |
|
||||
| `schemaVersion` | 固定 `agc-template-library.v1`;破坏性变更换 schema,不原地改语义 |
|
||||
| `library` / `libraryVersion` / `updatedAt` | 库标识、库格式版本、本次更新时间 |
|
||||
| `templates[].id` | 稳定标识,`[a-z0-9][a-z0-9._-]{0,63}`,同时是目录名 |
|
||||
| `templates[].title/summary/tags[]` | 展示与搜索/筛选用文案;`tags` 参与标签筛选与关键词命中 |
|
||||
| `templates[].runtime` | `html` / `unity` / `godot` / `cocos` |
|
||||
| `templates[].engine` / `engineVersion` | 引擎标识与版本(如 `phaser` 4.2.1、`three.js` 0.180.0) |
|
||||
| `templates[].templateVersion` / `updatedAt` | 模板内容版本;客户端按它判断是否需要重新下载 |
|
||||
| `templates[].entry` | 解压后的项目入口相对路径,如 `game/index.html` |
|
||||
| `templates[].zipKey` / `zipSizeBytes` / `zipSha256` | 模板包对象键、字节数、SHA-256(下载后强校验) |
|
||||
| `templates[].coverKey` / `coverWidth` / `coverHeight` / `coverSha256` | 封面对象键与尺寸/摘要 |
|
||||
| `templates[].metadataKey` | 单模板元数据对象键(`template.json`) |
|
||||
|
||||
约束:
|
||||
|
||||
- 所有对象键必须落在 `templates/` 前缀内;客户端只用「受信任 OSS 主机 + 对象键」自行拼 URL,**不直接信任清单里的地址**。
|
||||
- 任何一项校验失败(schema、标识符、sha256、尺寸、键前缀)都让整次清单读取失败,前端拿到的是全有或全无的清单。
|
||||
- 模板源在仓库 `apps/ai-game-creator-shell/template-library/`:`v1/<id>/{meta.json, project/**, cover.(png|jpg|webp|svg)}`,`template.zip` **不落仓库**,由脚本按 `project/` 现场打包(条目排序、固定时间戳,同内容重复打包摘要一致)。
|
||||
- 上传与校验由 [`scripts/agc-template-library-publish.mjs`](../../scripts/agc-template-library-publish.mjs) 完成:`--source apps/ai-game-creator-shell/template-library [--dry-run] [--prune]`,脚本生成 `template.json` 与 `index.json`、上传后回读 zip 摘要;`--prune` 清理该模板前缀下本次没有产出的旧对象(例如换封面扩展名后的残留)。
|
||||
- 当前模板:`blank-web`(空白网页)、`blank-2d-canvas`(空白二维画布)、`blank-3d-scene`(空白三维场景)、`phaser-2d-starter`(Phaser 2D 起步工程)、`threejs-3d-starter`(Three.js 3D 起步工程)。
|
||||
- 客户端可用 `AGC_TEMPLATE_LIBRARY_BASE_URL` 覆盖库地址;只接受 `https://agc-dev.oss-rg-china-mainland.aliyuncs.com`(拒绝其他主机、路径、http)。
|
||||
|
||||
## 客户端实现
|
||||
|
||||
### Rust:`apps/ai-game-creator-shell/src-tauri/src/template_library.rs`
|
||||
|
||||
| 命令 | 行为 |
|
||||
| --- | --- |
|
||||
| `fetch_game_template_library` | 读 `templates/index.json`(≤4 MiB),校验后缓存到 `<app_data>/templates/index.json`;网络失败时回退本机缓存并在 `source` 标 `cache` |
|
||||
| `download_game_template` | 取清单里对应条目,流式下载 zip(≤512 MiB),校验字节数与 SHA-256,解压到 `<app_data>/templates/installed/<id>/<version>/`,最后写 `installed.json` 作为安装完成的唯一标记 |
|
||||
| `create_automatic_local_game_project_from_template` | 需要时先安装模板,然后在 `<app_data>/projects/` 下按既有自动工作区规则建目录:先复制模板文件,再走 `init_local_game_project_at` 补 `.agent` 清单与标准目录 |
|
||||
|
||||
安全与健壮性:
|
||||
|
||||
- 解压只接受普通文件与目录:拒绝绝对路径、`..`、盘符、反斜杠、符号链接,并有文件数(4096)与单文件大小(256 MiB)上限。
|
||||
- 安装目录名由标识符白名单拼出,不拼接远端字符串;重装时只清理该模板自己的安装目录。
|
||||
- 模板文件与安装记录统一走 `write_game_creator_private_file` / `ensure_game_creator_private_directory_tree`,保持项目目录的私有 DACL 口径。
|
||||
- 建项目失败时删除刚创建的项目目录,不留半成品。
|
||||
|
||||
### 前端
|
||||
|
||||
- `src/features/template-library/templateLibraryModel.ts`:清单类型、搜索(空白分隔多关键词「与」)、标签/运行时/已下载筛选、标签选项聚合、体积格式化等纯函数。
|
||||
- `src/features/template-library/useTemplateLibrary.ts`:一次拉清单,暴露筛选状态、下载与「用模板建项目」;下载成功后只就地更新该条目的已下载状态。
|
||||
- `src/view/template-library/index.tsx`:模板库全屏页(返回、刷新、搜索、运行时/标签筛选、仅看已下载、卡片显示封面与已下载徽标、下载/使用模板)。
|
||||
- 卡片动作按安装状态收口:已下载且版本一致时**不再显示下载入口**,只留「使用模板」;版本落后才显示「更新」;缺包显示「下载」。
|
||||
- 过程提示(下载完成、开始建项目)走浮层 toast(复用 `packages/shared` 的 `PlatformRuntimeStatusToast`,`document.body` 浮层 + 2.6 秒自动消失),不再占用页面内位置;页面内只保留可操作的错误与空态。
|
||||
- 首页「灵感推荐」替换为「模板库」推荐位(`src/view/home/TemplateRecommendations.tsx`):只展示封面、标题、运行时与已下载徽标,点击进入模板库页面;首页不再直接触发建项目。
|
||||
- 左侧导航新增模板库入口(`LauncherView = 'template-library'`)。
|
||||
- `src-tauri/tauri.conf.json` 的 `csp` / `devCsp` 在 `img-src` 放行 `https://agc-dev.oss-rg-china-mainland.aliyuncs.com`,用于封面图;`connect-src` 原本已放行同一域名。
|
||||
- 旧的本机灵感图目录 `src/view/home/assets/inspiration/` 与 `InspirationGallery.tsx` 一并删除,不再保留退役实现。
|
||||
|
||||
## 验收与验证
|
||||
|
||||
## 本地压测假数据注入(feature 控制)
|
||||
|
||||
模板库的数据源在 Rust 侧(清单校验、安装状态、下载与建项目都在这里),TS 只消费快照做渲染,所以假数据注入也放在 Rust 侧,走与真实完全一致的链路。
|
||||
|
||||
- 开关:Cargo feature `template-library-fixtures`(**默认关闭**)。关闭时 `apply_template_library_fixtures` 是恒等透传,正式产物里不存在注入分支,并有单测保证这一点。
|
||||
- 条数:环境变量 `AGC_TEMPLATE_LIBRARY_SYNTHETIC_COUNT`(默认 1000;`0` 表示不注入;上限 20000)。
|
||||
- 假数据特征:真实条目保留在最前,其余按真实条目循环复制;`id`/标题唯一,封面地址追加 `?synthetic=N`(强制逐张请求,模拟“每个模板各自封面”);标签追加 `批次-00..19`;安装态按 1/3 混合。
|
||||
- 运行方式:
|
||||
|
||||
```bash
|
||||
# 本机 dev 客户端(保留 Windows 默认 feature)
|
||||
AGC_DEV_CARGO_FEATURES=cocos-editor-execute,template-library-fixtures npm run dev
|
||||
# 直接跑二进制
|
||||
cargo run --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --features template-library-fixtures
|
||||
# 覆盖条数
|
||||
AGC_TEMPLATE_LIBRARY_SYNTHETIC_COUNT=300 AGC_DEV_CARGO_FEATURES=template-library-fixtures npm run dev
|
||||
```
|
||||
|
||||
两种编译模式都要过模板库单测:默认构建跑「恒等透传」用例,`--features template-library-fixtures` 跑「补齐到配置条数」用例。
|
||||
|
||||
### 1000 条实测结论
|
||||
|
||||
### 卡片列表虚拟滚动(react-window)
|
||||
|
||||
- 列表改用 workspace 里已有的 `react-window@1.8.11` 的 `FixedSizeGrid`(`react-arborist` 已在用同一版本,不引入新包;类型来自 devDependency `@types/react-window`)。
|
||||
- 布局契约收在纯函数 `templateLibraryGrid.ts`(单测覆盖):列数 = `floor((容器宽 + gap) / (最小卡宽 + gap))`、列宽 = 容器宽 / 列数、行高 = `卡片宽 × 9/16 + 文字区 150 + gap`;`buildTemplateRows` 按行切分并在行尾补 `null` 占位。
|
||||
- 卡片抽成 `TemplateCard`(`memo`),网格只渲染可视行 + 2 行 overscan;筛选条件(关键词/标签/运行时/仅看已下载)变化时把滚动位置复位到顶部,避免"从筛选切回全量后停在空白处"。
|
||||
- **页面高度契约**:页面根节点的高度按**父级 `.launcher-main` 的实测高度**内联设置,既不用百分比也不用 `100vh`。原因:外壳样式 `.launcher-main > .platform-theme { height: 100% }` 特异性高于 Tailwind 工具类,而这条百分比在 `.launcher-shell { min-height: 100vh }` 链路上是不定高,页面会退化成内容高度(虚拟网格视口高度 0、卡片区整片空白);`100vh` 又比真实舞台高一个标题栏高度(窗口 100vh=800 / 舞台 750),底部会被裁掉。
|
||||
- 筛选区(运行时/标签)改成可独立滚动的区块(`max-h-[24vh]`),标签数量随库量增长时不再把卡片区挤出窗口。
|
||||
- 回归:`templateLibraryGrid.test.ts` 覆盖列数/行高/行数/切行;页面测试用固定视口断言「1000 条只渲染 ≤ 40 张卡片,滚动高度仍按 250 行计算」。
|
||||
|
||||
- 页面能正常渲染 1000 张卡片(头部显示「共 1000 个模板 · 已下载 335 个」),并且滚动容器生效(窗口高度压到 430px 时右侧出现滚动条,页面内容被裁切而不是溢出到窗口外)。
|
||||
- 需要后续收口的两点(本次未改):① 标签筛选条随库量膨胀——1000 条时聚合出 35 个标签、占三行;② 一次性渲染 1000 个卡片节点并触发 1000 次封面请求。建议标签只展示 Top N + 「更多」,卡片列表加分页或虚拟滚动。
|
||||
- 前端回归:1000 条渲染 + 已安装过滤(334)/标签过滤(50)/关键词过滤数量自洽,见 `apps/ai-game-creator-shell/tests/templateLibraryView.test.tsx`。
|
||||
|
||||
```bash
|
||||
# 模板库单测(清单校验、键安全、解压路径逃逸、安装与建项目)
|
||||
cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --bin genarrative-ai-game-creator-shell template_library
|
||||
# 模板库真连检查(可选,需要网络):读线上清单、下载安装线上模板包并据此建项目
|
||||
cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --bin genarrative-ai-game-creator-shell template_library -- --ignored
|
||||
# 前端模型与页面单测(AGC 测试统一在 apps/ai-game-creator-shell/tests/)
|
||||
npx vitest run apps/ai-game-creator-shell/tests/templateLibraryModel.test.ts apps/ai-game-creator-shell/tests/templateLibraryView.test.tsx
|
||||
# 类型检查 / 编码 / 空白
|
||||
cd apps/ai-game-creator-shell && npm run typecheck
|
||||
npm run check:encoding
|
||||
git diff --check
|
||||
# OSS 侧匿名可读
|
||||
curl -s https://agc-dev.oss-rg-china-mainland.aliyuncs.com/templates/index.json
|
||||
```
|
||||
|
||||
手工验收:打开模板库 → 搜索与筛选 → 下载(出现「已下载」徽标)→ 「使用模板」→ 进入项目工作台且项目里已有模板文件。
|
||||
|
||||
运行态核验(客户端真的拉过清单时):本机缓存 `<app_data>/templates/index.json` 与线上 `templates/index.json` 逐字节一致;`<app_data>/templates/installed/<id>/<version>/installed.json` 出现即表示该模板已下载完成。
|
||||
|
||||
## 失败与回退
|
||||
|
||||
- 清单读不到且没有本机缓存:模板库页显示错误与重试,首页推荐位显示「模板库暂时没有可用的模板」。
|
||||
- 版本落后:`installedVersion != templateVersion` 视为需要重新下载,点「使用模板」会先重下再建项目。
|
||||
- 需要回退整条链路时,删除 `templates/` 前缀即可让客户端回到"空模板库";客户端代码路径不受影响。
|
||||
Reference in New Issue
Block a user