Merge branch 'master' into feat/gptimage2to2.5
Project CI / AI game creator shell Rust crates (pull_request) Successful in 1m20s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m59s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 10m32s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 8m27s
Project CI / Backend tests (pull_request) Successful in 5m36s
Project CI / Native shell tests (pull_request) Successful in 8m0s
Project CI / Frontend tests (pull_request) Failing after 4m13s
Project CI / AI game creator shell web tests (pull_request) Failing after 3m55s
Project CI / Repository checks (pull_request) Successful in 4m7s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 1m20s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m59s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 10m32s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 8m27s
Project CI / Backend tests (pull_request) Successful in 5m36s
Project CI / Native shell tests (pull_request) Successful in 8m0s
Project CI / Frontend tests (pull_request) Failing after 4m13s
Project CI / AI game creator shell web tests (pull_request) Failing after 3m55s
Project CI / Repository checks (pull_request) Successful in 4m7s
This commit is contained in:
@@ -1,59 +0,0 @@
|
||||
# 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,49 @@
|
||||
# 【实施计划】AGC 渠道安装身份隔离
|
||||
|
||||
| 字段 | 值 |
|
||||
| --- | --- |
|
||||
| Milestone | `docs/project-memory/plans/【里程碑】AGC渠道安装身份隔离-2026-09-21.md` |
|
||||
| Status | ready |
|
||||
| Owner | 当前 Agent |
|
||||
|
||||
## 修改边界
|
||||
|
||||
- 允许修改:
|
||||
- `apps/ai-game-creator-shell/scripts/channel-identity.mjs`(新增,渠道身份单点定义)
|
||||
- `apps/ai-game-creator-shell/scripts/build-release.mjs`、`build-macos-ci.mjs`、`check-config.mjs`、`agent-swarm-test-chat.mjs`
|
||||
- `apps/ai-game-creator-shell/src-tauri/src/main.rs`、`src-tauri/src/windows.rs`、`src-tauri/src/config.rs`
|
||||
- 对应测试:`build-release.test.mjs`、`prepare-macos-codex.test.mjs`
|
||||
- 文档:AGC 更新主规范、共享记忆与本计划对
|
||||
- 明确不修改:OSS 分区布局、官网下载接口与页面、Jenkins Job 参数、渠道版本发行逻辑、Apple 签名/公证、移动壳。
|
||||
|
||||
## 实现顺序
|
||||
|
||||
1. 抽出 `channel-identity.mjs`:渠道校验、渠道显示名、`resolveChannelInstallIdentity()`;`build-release.mjs` 复用并再导出渠道校验。
|
||||
2. 渠道 `--config` 同时注入 `productName` 与 `identifier`;macOS 发布入口按发布渠道解析产品名(`.app`、updater 归档、DMG 卷名与文件名)。
|
||||
3. Rust:主窗口/工作区/启动器窗口标题取构建期产品名;AGC 自有 AppData 目录的 ACL managed 识别覆盖 `<基线>` 与 `<基线>.<渠道>`。
|
||||
4. 门禁与测试:`check-config.mjs` 断言基线等于默认渠道身份、非默认渠道身份隔离;`build-release.test.mjs` 增补身份与首装包用例;`prepare-macos-codex.test.mjs` 改断言为消费渠道身份。
|
||||
5. 文档:更新 AGC 更新主规范与共享记忆,登记决策与踩坑。
|
||||
|
||||
## 验证命令
|
||||
|
||||
1. `node --check apps/ai-game-creator-shell/scripts/channel-identity.mjs apps/ai-game-creator-shell/scripts/build-release.mjs apps/ai-game-creator-shell/scripts/build-macos-ci.mjs apps/ai-game-creator-shell/scripts/check-config.mjs`
|
||||
2. `node --test apps/ai-game-creator-shell/scripts/build-release.test.mjs apps/ai-game-creator-shell/scripts/release-oss.test.mjs apps/ai-game-creator-shell/scripts/prepare-macos-codex.test.mjs apps/ai-game-creator-shell/scripts/cargo-features.test.mjs`
|
||||
3. `node apps/ai-game-creator-shell/scripts/check-config.mjs`
|
||||
4. `cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --bin genarrative-ai-game-creator-shell -- config::tests:: --test-threads=1`
|
||||
5. `npm run check:encoding`、`npm run check:doc-index`、`git diff --check`
|
||||
|
||||
## 验证结果
|
||||
|
||||
- `node --test build-release.test.mjs release-oss.test.mjs prepare-macos-codex.test.mjs cargo-features.test.mjs`:64/64 通过(新增渠道身份、身份注入与渠道 DMG 首装选择三条用例)。
|
||||
- `node apps/ai-game-creator-shell/scripts/check-config.mjs`、`npm --prefix apps/ai-game-creator-shell run typecheck`:通过。
|
||||
- `cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --bin genarrative-ai-game-creator-shell -- config::private_path_elevation_policy_tests`:12/12 通过。
|
||||
- `AGC_UPDATE_CHANNEL=release npm --prefix apps/ai-game-creator-shell run build -- --no-bundle --debug`:Tauri 接受派生的 `productName` / `identifier` 并完成构建;产物字符串实测 `陶泥儿 Release` × 1、`agc/release-win/latest.json` × 1、`world.genarrative.ai-game-creator.release` × 1、`agc/dev-win/latest.json` × 0。
|
||||
- `cargo fmt --check`(AGC 壳)、`npm run check:encoding`、`npm run check:doc-index`、`git diff --check`:通过。
|
||||
- 未执行:真实渠道打包(需要签名私钥与发号/上传授权)、双渠道真机安装与并存、macOS 节点实跑。
|
||||
|
||||
## 风险与回滚点
|
||||
|
||||
- 风险:默认渠道身份若被改动,既有安装目录、卸载项与升级链会断。回滚点:基线 `tauri.conf.json` 与默认渠道映射不变,门禁用例钉住。
|
||||
- 风险:非默认渠道首次以新身份安装,老 `dev` 用户不会自动迁移本地数据。回滚点:渠道身份只影响非默认渠道构建,撤销该渠道的构建产物即可,仓库侧无数据迁移。
|
||||
- 风险:窗口标题改为构建期产品名后,标题不再等于配置里的字面量。回滚点:去掉 `main.rs` 的标题覆盖调用,行为回到配置标题。
|
||||
- 风险:ACL managed 识别放宽到前缀族。回滚点:`is_game_creator_packaged_app_data_leaf` 收紧回单一直线值,但非默认渠道的提权修复会重新失败关闭。
|
||||
@@ -0,0 +1,40 @@
|
||||
# 后台模板上传实施计划
|
||||
|
||||
| 字段 | 值 |
|
||||
| --- | --- |
|
||||
| Version | 1.0 |
|
||||
| Status | in-progress |
|
||||
| Date | 2026-09-21 |
|
||||
| Milestone Spec | `docs/project-memory/plans/【里程碑】后台模板上传-2026-09-21.md` |
|
||||
|
||||
## 修改边界与顺序
|
||||
|
||||
1. **领域规则(`module-assets/template_library.rs`)**:新增「导入准备」函数——按 ID 合并清单条目(新增默认上架、已存在就地更新并保留 `enabled` 与未知字段),校验 ID / 版本 / entry / runtime / 显示字段上限,产出待提交的清单与 `template.json` 字节;不接触存储。
|
||||
2. **存储(复用 `platform-oss/template_library.rs`)**:只使用既有 `begin_publish` / `read_index` / `put_immutable` / `commit_index` / `finish`;如缺少「读单个对象作元数据基线」的能力,再补最小只读方法,不改锁与提交语义。
|
||||
3. **契约(`shared-contracts/admin.rs` + `apps/admin-web/src/api/adminApiTypes.ts`)**:新增导入请求(manifest)与导入结果 DTO;错误体沿用现有 `AppError` + 逐项原因结构。
|
||||
4. **接口(`api-server/admin_templates.rs` + `modules/admin.rs`)**:新增 multipart handler,按「解析 manifest → 校验每个 ZIP / 封面 → 取锁 → CAS → 写内容寻址对象并回读 → 提交清单 → 释放锁」顺序实现;路由套 `require_admin_auth` 与 256 MiB body 上限,并同步路由契约测试与页签权限矩阵测试。
|
||||
5. **后台页面(`AdminAgcTemplatesPage.tsx` + `adminApiClient.ts`)**:新增「上传模板」入口与弹窗(多选 ZIP、逐行元数据、批量提交、逐行错误、写入确认),沿用既有 `useAdminWriteConfirm` 与刷新语义。
|
||||
6. **文档**:主规范新增「后台模板上传」章节;决策记录补一条;主规范中「本轮只允许…不上传 ZIP」改为指向新章节。
|
||||
|
||||
## 验证命令
|
||||
|
||||
```bash
|
||||
cargo test --locked -p module-assets --manifest-path server-rs/Cargo.toml -- template_library
|
||||
cargo test --locked -p api-server --manifest-path server-rs/Cargo.toml -- agc_template
|
||||
cargo fmt --all --manifest-path server-rs/Cargo.toml -- --check
|
||||
npm run admin-web:typecheck
|
||||
npx vitest run apps/admin-web/src/pages/AdminAgcTemplatesPage.test.tsx apps/admin-web/src/api/adminApiClient.test.ts
|
||||
npm run check:encoding
|
||||
npm run check:doc-index
|
||||
git diff --check
|
||||
```
|
||||
|
||||
接口 smoke:`npm run dev:api-server`(本地 8082)+ `npm run dev:admin-web`,先用未授权/无页签权限请求确认失败关闭,再以隔离存储替身或用户显式确认的 dev bucket 做一次真实导入。
|
||||
|
||||
## 时间盒与风险
|
||||
|
||||
- **风险:真实发布不可逆**。导入会写公共 bucket 且不提供删除,因此默认只在本地用替身验证;对 dev bucket 的写验证必须由用户显式确认,测试用模板需可在事后下架。
|
||||
- **风险:ZIP 原字节发布与 CLI 确定性打包不一致**。同一模板可能被两条路径写成不同字节;由「同 ID 同版本字节必须一致」的门禁兜住,导入失败时提示改用 CLI 或递增版本。
|
||||
- **风险:大文件内存**。ZIP(≤64 MiB)与封面在内存中校验,单批上限 20;需要更大模板时走 CLI。
|
||||
- **风险:批量部分写入**。所有对象在清单提交前写入且不删除;中途失败时清单不变、已写对象成为未被引用的历史对象,由后续同键复用。
|
||||
- **回退**:下线路由与页面入口即可停止使用;已发布内容按既有 CLI / 后台下架流程处理,历史对象保留。
|
||||
@@ -1,7 +1,7 @@
|
||||
# AGC 模板库客户端接入
|
||||
|
||||
Version: 1.0
|
||||
Status: active
|
||||
Status: accepted(2026-09-21 复核:7 条验收项均有定向、前端与线上真连证据)
|
||||
Date: 2026-09-17
|
||||
Parent Spec: `docs/technical/【技术方案】AGC模板库与模板建项-2026-09-17.md`
|
||||
|
||||
@@ -38,3 +38,17 @@ AGC 客户端能读取公共 OSS 上的游戏模板库,并把「浏览 → 筛
|
||||
- 现有自动工作区建项链路(`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`。
|
||||
|
||||
## 验收证据(2026-09-21)
|
||||
|
||||
| 验收项 | 证据 |
|
||||
| --- | --- |
|
||||
| 1 读清单 + 合并已安装状态 + 远端不可用回退缓存并标 `source=cache` | `template_library::tests::template_index_*` 5 项(网络优先并标 `network`、远端失败回退缓存并标 `cache`、无缓存暴露远端错误、远端正文非法不用缓存掩盖、缓存损坏失败关闭);`fetches_the_live_template_library_index` 真连通过 |
|
||||
| 2 下载拒绝字节数 / SHA-256 / 越界键 / 非 `templates/` 前缀,且不落半成品 | `rejects_archive_when_size_or_digest_do_not_match_the_index`(含新增断言:拒绝后无安装目录、无已下载判据)、`rejects_object_keys_outside_the_templates_prefix`、`rejects_template_base_url_outside_trusted_oss`;`downloads_and_installs_a_live_template` 真连通过 |
|
||||
| 3 解压拒绝绝对路径 / `..` / 盘符 / 符号链接;安装完成才写 `installed.json` | `rejects_archive_entries_that_escape_the_destination`(含新增断言:失败后不产生安装记录)、`installs_template_archive_and_reports_it_as_installed`、`parses_content_addressed_objects_without_changing_the_template_contract` |
|
||||
| 4 建项具备模板文件 + `.agent` + 标准目录,失败不留项目目录 | `creates_project_from_installed_template_without_leaking_install_marker`、`installs_official_cocos_templates_and_creates_native_projects`、新增 `failed_project_creation_removes_the_partial_project_directory`、`refuses_to_create_project_when_template_is_not_installed`;`downloads_and_creates_live_cocos_templates` 真连通过 |
|
||||
| 5 页面筛选 / 卡片 / 已下载徽标 / 更新入口 / 浮层提示 / 版本落后先重下 | `templateLibraryView.test.tsx` 12 项、`templateLibraryModel.test.ts` 9 项、`templateLibraryGrid.test.ts` 6 项、`useTemplateLibrary.test.tsx` 11 项 |
|
||||
| 6 首页推荐位与左侧导航入口 | `appSurface.test.ts` 首页模板用例 2 项:灰度外隐藏入口与推荐位、点击推荐位进入模板库且不建项目 |
|
||||
| 7 定向用例 + 类型 / 编码 / 文档检查 + 可选真连 | Rust 24 项 + 线上 3 项、前端 38 项 + `appSurface` 2 项、AGC `typecheck`、`check:encoding`、`check:doc-index`、`git diff --check` 全部通过;匿名 `GET templates/index.json` 返回 200(`schemaVersion=agc-template-library.v1`、9 个模板) |
|
||||
|
||||
仍未验证:Creator 内场景运行;真机 iOS / Android 观感。持久结论已并入主规范 [`【技术方案】AGC模板库与模板建项-2026-09-17.md`](../../technical/【技术方案】AGC模板库与模板建项-2026-09-17.md),本里程碑的实施计划已按工作流删除。
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
# 里程碑:AGC 渠道安装身份隔离
|
||||
|
||||
| 字段 | 值 |
|
||||
| --- | --- |
|
||||
| Version | 1.0 |
|
||||
| Status | 代码与源码级验收已落地,等待真机双渠道安装验收 |
|
||||
| Date | 2026-09-21 |
|
||||
| Parent Spec | `docs/technical/【技术方案】AGC客户端更新检查与下载-2026-08-31.md` |
|
||||
|
||||
## 目标
|
||||
|
||||
不同渠道的 AGC 包体在同一台设备上并存:安装、运行、客户端数据与更新互不覆盖、互不顶掉。
|
||||
|
||||
## 范围
|
||||
|
||||
- 构建期按渠道产出安装身份(`productName` / `identifier`),默认渠道 `dev` 身份保持不变。
|
||||
- 渠道产物命名、首装包选择、macOS 发布入口与配置门禁都消费同一份渠道身份。
|
||||
- 同机并存的可见区分(窗口标题)与 AGC 自有 AppData 目录的提权 ACL 识别范围。
|
||||
|
||||
## 不在范围内
|
||||
|
||||
- 不迁移、不共享既有本地项目、工程快照、模板、登录态与诊断数据。
|
||||
- 不新增渠道,不改 OSS 分区布局、官网下载页与后端接口。
|
||||
- 不做 Apple 代码签名/公证,不恢复 Intel 架构。
|
||||
|
||||
## 依赖与前置条件
|
||||
|
||||
- 渠道与更新端点合同已落地(`<channel>-win` / `<channel>-mac` 分区与 Tauri updater 端点)。
|
||||
- 构建入口统一在 Tauri 构建前注入渠道 `--config`。
|
||||
|
||||
## 验收标准
|
||||
|
||||
- [x] 默认渠道的 `productName` / `identifier` 与基线配置逐字一致,既有安装与升级链不断(`check-config.mjs` + 渠道身份用例)。
|
||||
- [x] `release` 与自定义渠道派生独立 `productName` 与 `identifier`,与 `dev` 可在同一台设备并存(源码级;真机安装见下方未完成项)。
|
||||
- [x] 渠道产物(NSIS `.exe`、`.app.tar.gz`、DMG)与首装包选择跟随渠道身份且唯一匹配(发布脚本用例)。
|
||||
- [x] 非默认渠道的客户端数据目录、WebView2 目录与窗口标题跟随渠道身份(构建产物字符串实测 + 运行期标题取产品名)。
|
||||
- [x] AGC 自有 AppData 目录的 ACL managed 范围覆盖全部渠道身份,且不扩大到相似前缀目录(Rust 定向 12/12)。
|
||||
- [ ] 真机:同一台设备同时安装 `dev` 与 `release`,二者可并存、可各自原地更新。
|
||||
|
||||
## 证据要求
|
||||
|
||||
- 自动化:`build-release.test.mjs`、`release-oss.test.mjs`、`prepare-macos-codex.test.mjs`、`check-config.mjs` 与 Rust `config::tests::` 定向测试。
|
||||
- 运行时:单渠道 `--no-bundle` 构建烟测;真机双渠道安装、并存与各自更新。
|
||||
- 边界:非法渠道失败关闭;默认渠道身份不变;相似前缀目录不进入 managed 赋权范围。
|
||||
@@ -0,0 +1,73 @@
|
||||
# 后台模板上传
|
||||
|
||||
| 字段 | 值 |
|
||||
| --- | --- |
|
||||
| Version | 1.0 |
|
||||
| Status | implemented-awaiting-runtime-acceptance(接口、页面与定向用例已交付;真实 dev bucket 写入 smoke 未执行) |
|
||||
| Date | 2026-09-21 |
|
||||
| Parent Spec | `docs/technical/【技术方案】AGC模板库与模板建项-2026-09-17.md` |
|
||||
|
||||
## 目标与范围
|
||||
|
||||
管理员在后台直接上传模板并发布到公共模板库,不必走本地 CLI;一批可以带多个模板(批量上传),一批只做一次发布锁和一次清单提交。
|
||||
|
||||
- 新增 `POST /admin/api/agc-templates/import`(`multipart/form-data`):`manifest` 文本字段 + `zip_<index>` / `cover_<index>` 文件字段,字段下标与 manifest 条目顺序一一对应。
|
||||
- manifest:`{ expectedRevision, templates: [{ id, title, summary, tags, runtime, engine, engineVersion, entry, templateVersion }] }`;`expectedRevision` 是当前清单字节 SHA-256,用于锁内 CAS。
|
||||
- 限制:单批最多 20 个模板;单个 ZIP ≤ 64 MiB;单张封面 ≤ 5 MiB;请求体 ≤ 200 MiB;`id` / `templateVersion` / `entry` 走既有标识符与相对路径白名单;`runtime` 仅接受 `html / unity / godot / cocos`。存储层为 `application/zip` 单独放宽单对象上限到 64 MiB(图片与元数据仍是 5 MiB)。
|
||||
- 语义:一批**全有或全无**——任一模板校验失败都在写入前整批拒绝并逐项给出原因;通过后在同一把发布锁内写入全部内容寻址对象、逐个回读校验,最后提交一次清单。
|
||||
- 新 ID 默认上架;已存在 ID 的导入就地更新该条目(保留 `enabled` 状态、所属分组与未知扩展字段,包含下架条目);同一 ID 同一 `templateVersion` 但 ZIP 字节不同时拒绝,提示递增 `templateVersion`。
|
||||
- ZIP 由服务端校验后按原字节发布(不重新打包、不解压落盘):合法 zip、无符号链接、无绝对路径 / `..` / 盘符条目、必须包含声明的 `entry`、至少一个文件,条目数与解压后体积受上限保护;正文含 `.agent` / `.git` / `.svn` / `node_modules` 段(任意层级)或根目录 `dist` / `build` / `library` / `temp` / `local` / `.idea` / `.vscode` 的包直接拒绝,与 CLI 打包同一份段名单。
|
||||
- 封面**每个模板必填**(与 CLI 源布局 `v1/<id>/cover.*` 一致),仅接受真实 PNG / JPEG / WebP,上限与编辑路径相同(5 MiB、单边 4096、1600 万像素);上传按字节嗅探格式,不信任 multipart 声明的 content-type。SVG 仍只可能来自 CLI 历史发布,编辑与上传都不产生新的 SVG 封面。
|
||||
- 后台「模板管理」页新增上传入口:可多选 ZIP、逐行编辑元数据(含可选封面)、批量提交、逐行显示校验错误;沿用现有写入确认、防重复提交与刷新语义。
|
||||
|
||||
## 不做
|
||||
|
||||
- 不做模板删除、版本回滚、下架条目清理、历史对象回收。
|
||||
- 不改 ZIP 内容、不做服务端重新打包(CLI 仍是确定性打包与 `--only` 定向发布的入口)。
|
||||
- 不做审核流、不做从 URL 拉取、不做 CLI 源布局目录(`v1/<id>/{meta.json,project/**,cover.*}`)的自动打包上传。
|
||||
- 不新增 SpacetimeDB 表或 schema。
|
||||
|
||||
## 合同与依赖
|
||||
|
||||
- 存储与锁:复用 `platform-oss` 的 `TemplateLibraryStore` / `TemplatePublishSession`(`begin_publish` / `read_index` / `put_immutable` / `commit_index` / `finish`)与既有版本控制前置检查;不新增第二套发布协议。
|
||||
- 领域规则:`module-assets/template_library.rs` 承担清单合并与字段校验(保留未知字段、下架状态、两组间 ID 唯一),沿用既有标识符 / 相对路径 / 摘要规则。
|
||||
- DTO:`shared-contracts/admin.rs` 新增导入结果类型;前端类型在 `apps/admin-web/src/api/adminApiTypes.ts`。
|
||||
- 鉴权:沿用后台认证与 `agc-templates` 页签权限;路由挂载在 `modules/admin.rs`。
|
||||
|
||||
## 验收标准
|
||||
|
||||
1. 权限与路由:未授权读取/写入均失败关闭;无 `agc-templates` 页签权限不可导入;路由契约测试覆盖新路径与方法。
|
||||
2. 校验失败关闭:manifest 非法、ID/版本/entry 越界、runtime 不在白名单、ZIP 非法或含越界/符号链接条目、缺少 entry、封面超限或非真实图片,全部在**任何写入之前**整批拒绝,响应逐项给出模板 ID 与原因。
|
||||
3. 批量原子性:一批 3 个模板(含 1 个新 ID、1 个新版本、1 个下架 ID)在锁内一次提交;中途任一环节失败时清单与历史对象不变,返回可诊断错误。
|
||||
4. 版本一致性:同 ID 同版本、ZIP 字节不同必须拒绝并要求递增版本;同 ID 同版本、字节完全一致视为幂等复用,不报错。
|
||||
5. CAS 与锁:`expectedRevision` 过期返回 409;锁被占用返回 409;清单写入结果不明时保留锁并返回 503,不自动重试。
|
||||
6. 保留语义:既有条目的展示字段按上传内容更新,`enabled` 分组、其它条目、未知扩展字段与历史对象不变;下架条目仍留在 `inactiveTemplates`。
|
||||
7. 内容寻址与回读:ZIP / 封面 / template.json 以自身字节摘要寻址,写入后逐项回读校验,清单最后提交且返回最新快照。
|
||||
8. 界面:桌面与窄屏都能完成多选 ZIP、逐行元数据编辑、批量提交与错误展示;保存中防重复提交,409 引导刷新后重试。
|
||||
9. 检查:`cargo test`(module-assets / platform-oss / api-server 定向)、`npm run admin-web:typecheck`、后台页面 vitest、`npm run check:encoding`、`npm run check:doc-index`、`cargo fmt --check`、`git diff --check` 全部通过。
|
||||
|
||||
## 依赖
|
||||
|
||||
- 已交付的后台模板管理链路(`GET/PUT /admin/api/agc-templates`、页面、锁与内容寻址发布协议)。
|
||||
- 模板库 OSS 写凭据(`GENARRATIVE_AGC_TEMPLATE_LIBRARY_OSS_ACCESS_KEY_ID/SECRET` 或成套 `ALIYUN_OSS_*`);无凭据时导入返回 503 且页面明确不可用。
|
||||
- 真实 dev bucket 的写入验证需要用户显式确认(见实施计划「验证」)。
|
||||
|
||||
## 实现与证据(2026-09-21)
|
||||
|
||||
| 验收项 | 证据 |
|
||||
| --- | --- |
|
||||
| 1 权限与路由 | 路由契约测试覆盖 `POST /admin/api/agc-templates/import`;页签权限矩阵用例覆盖 GET / PUT / POST 三条路径(`admin::tests::agc_template_routes_require_the_template_tab_permission`) |
|
||||
| 2 校验失败关闭(写入前整批拒绝) | `template_import_archive_validation_fails_closed`(缺 entry / 越界路径 / 符号链接)、`template_import_plan_rejects_unknown_and_unreferenced_fields`(未引用字段、缺 ZIP 字段、字段前缀、未知 manifest 字段、非法 zip)、`template_import_archive_rejects_identity_and_build_directories`(13 条身份 / 版本库 / 依赖 / 构建目录逐条拒绝 + 正文内 `game/dist/**`、`game/.gitignore` 放行) |
|
||||
| 3 批量原子性 | `module-assets` 的 `template_import_appends_new_entries_with_metadata`(3 条口径:新 ID 入 `templates`、下架条目留在 `inactiveTemplates`、未知字段保留);发布编排在锁内写完全部对象后才提交一次清单 |
|
||||
| 4 版本一致性 | `template_import_rejects_same_version_with_different_bytes`(同句文案)、`template_import_reuses_identical_bytes_for_the_same_version`(`reused`) |
|
||||
| 5 CAS 与锁 | `import_templates` 复用 `check_revision`(409)与 `TemplatePublishSession`(`commit_index` 不确定即留锁 → 503);存储层既有用例覆盖锁与不确定写入 |
|
||||
| 6 保留语义 | 领域用例断言 `enabled` 分组、`extension` 未知字段与 `metadataKey` 保持不变 |
|
||||
| 7 内容寻址与回读 | `template_import_plan_uses_content_addressed_keys_and_sniffed_cover`;`put_immutable` 逐个回读校验 |
|
||||
| 8 界面 | 页面用例:多选 ZIP 生成行、封面匹配齐才可提交、确认后提交 manifest 与文件、成功后刷新列表、409 刷新引导、400 展示真实原因(共 40 项 vitest 通过) |
|
||||
| 9 检查 | `cargo test`(module-assets 11、platform-oss 12、api-server 定向 4)、`npm run admin-web:typecheck`、`check:encoding`、`check:doc-index`(193 份)、`cargo fmt --check`、`git diff --check` 全部通过 |
|
||||
|
||||
仍未执行:真实 `agc-dev` bucket 的批量写入 smoke(需要用户显式确认;建议用两个 `smoke-import-<时间戳>` 模板验证一批多模板 + 一次清单提交,验证后下架保留历史对象)。
|
||||
|
||||
## 追加:模板正文目录门禁(2026-09-21)
|
||||
|
||||
验收标准 2 的补充落地——把「不要放进 ZIP」从文档约定升级为机器门禁,CLI 与后台上传同一份段名单(任意层级 `.agent` / `.git` / `.svn` / `node_modules`,根目录 `dist` / `build` / `library` / `temp` / `local` / `.idea` / `.vscode`)。证据:Rust `admin_templates` 8 项通过(含新增 `template_import_archive_rejects_identity_and_build_directories`);Node 发布回归 28 项通过(含新增 CLI 门禁用例);仓库 9 个模板源无一条命中,本地重打包 ZIP 摘要与线上清单 `zipSha256` 逐条一致。规则说明见 `docs/【模板规范】AGC模板包组织指南-2026-09-21.md`。
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
- [ ] 正式项目窗口可被同步调度识别;周期与关闭触发保持有界,失败有项目级诊断。
|
||||
- [ ] 未单独配置快照目标时仍使用 agc-dev,只复用资源存储凭据;显式快照目标保持有效,不迁移现存对象。
|
||||
- [ ] 后台列表显示项目名/ID、用户 ID、同步时间、文件数、体积和完整性,支持刷新与分页。
|
||||
- [ ] 后台列表按部署渠道查询,显示项目名/ID、用户(昵称 + 陶泥号)、同步时间、文件数、体积和完整性,支持刷新与游标分页(每页 20/50/100 + 上一页/下一页)。
|
||||
- [ ] ZIP 按清单还原相对路径;不含对象存储摘要目录;空文件可上传与导出。
|
||||
- [ ] 清单名称/完整性变化在无内容差异时也提交,partial 可恢复 ready,历史缺字段不冒充 ready。
|
||||
- [ ] 缺失、损坏、越界路径和非完整清单失败关闭;历史未声明完整性的清单明确标记,允许导出已有文件但不称为完整工程。
|
||||
|
||||
@@ -1,5 +1,70 @@
|
||||
# 决策记录
|
||||
|
||||
## 2026-09-21 渠道进安装身份:不同渠道的 AGC 包体在同一台设备并存
|
||||
|
||||
- 背景:渠道此前只决定更新端点(`plugins.updater.endpoints`)与渲染层平台 origin,`productName` / `identifier` 与渠道无关,于是所有渠道共用 `%LOCALAPPDATA%\陶泥儿` 安装目录、同一个卸载项(`HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall\陶泥儿`,另有 `HKCU\Software\genarrative\陶泥儿`)以及同一份 `%APPDATA%\world.genarrative.ai-game-creator` 数据目录。本机 0.1.48 安装实测:主程序二进制里只有 1 处 `agc/dev-win/latest.json`、0 处 release 端点,说明渠道在产物里只体现为端点。后果是后装的渠道静默顶掉先装的渠道,并接管更新端点、平台服务器与本地登录态/项目数据。
|
||||
- 决策:渠道同时决定**安装身份**。默认渠道 `dev` 保持基线 `productName = 陶泥儿`、`identifier = world.genarrative.ai-game-creator`(既有安装目录、卸载项与升级链不断);其它渠道派生 `陶泥儿 <渠道显示名>`(`release` → `陶泥儿 Release`)与 `world.genarrative.ai-game-creator.<渠道>`。身份与更新端点必须在同一个构建期 `--config` 里注入,禁止分别回读默认值。窗口标题、macOS 产物名(`.app` / updater 归档 / DMG 卷名)、首装包选择与 Windows 提权 ACL 的 managed 识别范围同批跟随该身份。
|
||||
- 边界:不做本地数据迁移或共享——切渠道等于换一个客户端;`release` 与自定义渠道首次以新身份安装,不接管、不迁移既有 `dev` 安装与本地项目,由用户自行决定是否卸载其一。
|
||||
- 影响范围:新增 `apps/ai-game-creator-shell/scripts/channel-identity.mjs`;`build-release.mjs`、`build-macos-ci.mjs`、`check-config.mjs`、`agent-swarm-test-chat.mjs`、`src-tauri/src/{main.rs,windows.rs,config.rs}` 与对应测试;主规范 `docs/technical/【技术方案】AGC客户端更新检查与下载-2026-08-31.md`。
|
||||
- 验证方式:`node --test apps/ai-game-creator-shell/scripts/build-release.test.mjs release-oss.test.mjs prepare-macos-codex.test.mjs cargo-features.test.mjs`(64/64,新增渠道身份与渠道 DMG 首装选择用例)、`node apps/ai-game-creator-shell/scripts/check-config.mjs`(基线等于默认渠道身份、非默认渠道身份隔离)、`cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --bin genarrative-ai-game-creator-shell -- config::private_path_elevation_policy_tests`(12/12,含基线/`<基线>.release`/`<基线>.beta-2` 与相似前缀反向断言)、`AGC_UPDATE_CHANNEL=release npm --prefix apps/ai-game-creator-shell run build -- --no-bundle --debug`(产物字符串实测 `陶泥儿 Release` × 1、`agc/release-win/latest.json` × 1、`world.genarrative.ai-game-creator.release` × 1、`agc/dev-win/latest.json` × 0)。真机双渠道安装、并存与各自更新尚未执行,按未验证项记录。
|
||||
|
||||
## 2026-09-21 项目快照按部署渠道分区,后台按渠道查看并按素材查询口径展示用户
|
||||
|
||||
- 背景:AGC 项目快照此前统一写在 `agc/project-snapshots/v1/{user}/{project}/`,而开发与正式两套部署共用同一个 bucket(都默认 `agc-dev`)。结果是渠道混在一层前缀里:正式后台会列出开发渠道上传的项目,列表上也看不出项目属于哪个渠道;同时“项目工程”列表只有裸用户 ID,且用“加载更多”逐段追加,翻页与定位都困难。
|
||||
- 决策(存储):对象键升级为 `agc/project-snapshots/v2/{channel}/{user}/{project}/`。渠道是**部署渠道**,由服务端 `GENARRATIVE_AGC_PROJECT_SNAPSHOT_CHANNEL` 决定(缺省沿用 `GENARRATIVE_CLIENT_DOWNLOAD_CHANNEL`,当前缺省 `dev`),客户端不上报渠道、也不需要发新版;渠道名必须是小写字母开头的 `[a-z0-9-]{1,32}`,非法值在上传与后台查询处失败关闭(`503`/`400`),不悄悄回落。正式部署必须在 api-server 环境里显式写 `GENARRATIVE_AGC_PROJECT_SNAPSHOT_CHANNEL=release`。
|
||||
- 决策(后台):新增 `GET /admin/api/project-snapshots/channels` 返回本部署渠道与远端已存在渠道的并集;列表与下载接口都接受 `channel`(缺省本部署渠道),游标里带上渠道并在解码时校验一致,跨渠道复用游标一律 400。页面顶部提供“渠道”选择框,切换渠道回到第 1 页。
|
||||
- 决策(列表形态):“用户 ID”列改为与“素材查询”同口径的“用户”列——昵称 + 陶泥号 + 用户详情入口,昵称/陶泥号由 api-server 用 `resolve_work_author_by_user_id` 解析(账号不可读时回退占位作者),原始 `userId` 不再直接铺在列里;“加载更多”改为游标分页(每页 20/50/100 + 上一页/下一页 + 当前页),前端按页记录游标链,换令牌或换每页条数从第 1 页重来;翻页失败保留当前页。
|
||||
- 原因:渠道属于“这套部署服务哪个客户端渠道”,客户端正式包按构建渠道连接不同平台服务(release → 正式站,dev → 开发站),所以服务端是唯一可靠的渠道来源;把渠道放进对象键第一层,既不需要迁移历史对象就能让两套部署互不可见,也让后台的渠道维度天然对齐存储布局。
|
||||
- 影响范围:`server-rs/crates/platform-oss/src/{lib.rs,project_snapshots.rs,template_library.rs,examples/agc_project_snapshot_live_smoke.rs}`、`server-rs/crates/api-server/src/{config.rs,project_snapshots.rs,admin_project_snapshots.rs,modules/admin.rs}`、`server-rs/crates/shared-contracts/src/admin.rs`、`apps/admin-web/src/{api/adminApiClient.ts,api/adminApiTypes.ts,pages/AdminProjectSnapshotsPage.tsx,pages/AdminProjectSnapshotsPage.test.tsx,styles/admin.css}`、`deploy/env/api-server.env.example` 与本仓运维/技术文档。
|
||||
- 未迁移的历史对象:`agc/project-snapshots/v1/` 下现存对象(只读核对过的两份历史清单)保留在 OSS,但不再写入、不再进入后台列表;需要取回时按旧前缀在 OSS 侧直接读取,确实要在后台看到时再单独开一个只读兼容视图。
|
||||
- 验证方式:`cargo test -p platform-oss snapshot` 7 passed(渠道校验、键布局、v2 根渠道枚举、v1 历史键仍必须私有);`cargo test -p api-server project_snapshot` 18 passed/1 ignored(渠道失败关闭、游标跨渠道拒绝、用户昵称/陶泥号解析、归档与配额回归);`cargo test -p api-server protected_route_matrix`、`route_contract` 通过(新路由纳入后台鉴权矩阵);`npm run admin-web:typecheck` 与 `npx vitest run apps/admin-web/src` 202 passed。
|
||||
|
||||
## 2026-09-21 Godot 模板入库与按模板建项的 Godot 分流
|
||||
|
||||
- 背景:模板库此前只有网页(html)、Cocos 与 Unity 占位,`runtime` 白名单早就接受 `godot`,但既没有 Godot 模板,也没有按模板建项的 Godot 分流——Godot 模板即使上传,建项也会落到 Web 分支,写出 `game/index.html` 占位入口并让 `godotProjectRoot` 为空。
|
||||
- 决策(模板内容):新增四个仓库内手写的 Godot 4.7 模板 `godot-empty-2d`、`godot-empty-3d`、`godot-hello-world`、`godot-platformer-2d`,`entry` 统一为 `project.godot`。模板只用内置 `ui_*` 输入动作、GL Compatibility 渲染,并用 `Polygon2D` / `BoxMesh` 搭可视骨架,不引入外部贴图或音频二进制;不打包 `.godot/` 缓存与导出产物。
|
||||
- 决策(建项分流):`create_project_from_installed_template_at` 在复制模板后按工程文件分流——Cocos 更新自身身份后走 Cocos 导入,Godot 先改写 `project.godot` 里 `[application]` 段的 `config/name`(只改这一行,其余字节逐字保留)再走既有 Godot 导入,写入 `godotProjectRoot: "."`,其余继续走 `init_local_game_project_at`。分流靠工程文件识别,不新增只读 `entry` 或 `runtime` 字段的契约。
|
||||
- 原因:Godot 工程身份是 `project.godot` 所在目录,与 Cocos 的 `package.json` 身份同一类问题;复用既有导入流程能同时拿到相对根记录、`.agent` 初始化与「不生成 Web 占位入口」这三条既有保证,并且与 Cocos 分支保持对称。
|
||||
- 影响范围:`apps/ai-game-creator-shell/template-library/v1/godot-*`(新增模板源)、`apps/ai-game-creator-shell/src-tauri/src/template_library.rs`、`.../src/project/manifest.rs`(`apply_godot_project_display_name`)、`.../src/project/manifest/import_tests.rs`、`docs/【模板规范】AGC模板包组织指南-2026-09-21.md`、`docs/technical/【技术方案】AGC模板库与模板建项-2026-09-17.md`。
|
||||
- 验证方式:本机 Godot `4.7.2.stable` 对四个模板逐一做「主场景实例化 + 3 帧 + GDScript `--check-only`」,平台跳跃模板另做真实物理试玩(落地 y=627.99、1 秒右移 320px、跳上平台 y=515.93、三枚金币全收集);Rust 定向回归 `import_tests::rewrites_only_the_godot_display_name_line`、`import_tests::keeps_a_godot_project_without_a_display_name_line_untouched`、`template_library::tests::godot_template_creates_native_project_with_relative_root_and_display_name` 与既有 Cocos/Web 建项回归;发布走 `--only godot-*` 定向合并。
|
||||
|
||||
## 2026-09-21 Godot 工作区发现放宽与内置插件行去掉手动启动
|
||||
|
||||
- 背景:2026-08-10 “发现与歧义决策”把「一层多命中」和「`project.godot` 必须是普通文件」两条定为失败关闭。这两种布局都会让整个工作区被判成「没有 Godot 工程」,而 `PluginHost::list` 只按发现结果过滤,结果是 Godot 内置插件在设置→扩展 里直接消失,用户看不到任何可诊断入口。
|
||||
- 决策(发现):根目录命中仍然优先;根未命中时一层直接子目录多命中改为按目录名排序取第一个,`godotProjectRoot` 记录该相对目录名,结果确定且可复现。`project.godot` 允许是符号链接 / Windows reparse point / 硬链接,判据改为「链接目标解析后是文件」,目录与悬空链接仍不算命中。工作区根本身是链接、候选子目录是链接、二层及更深不递归这三条边界不变。
|
||||
- 决策(界面):设置→扩展 的内置插件行去掉手动「启动 / 停止」按钮。启动本来就由项目切换时的 `startAvailableAgcEditorPlugins` 自动完成,手动按钮只是第二个可绕过入口;停止改走该行的启用/禁用开关,`set_agc_plugin_enabled(false)` 会停止插件并断开编辑器连接。导入扩展行的启动按钮保留,因为导入扩展没有自动启动路径。
|
||||
- 原因:Godot 插件列表是按项目过滤的,发现失败等于功能静默消失;把不确定性收敛成一个确定的排序选择,比让用户面对空列表更好。链接放宽只作用于只读的工程标记文件,受管描述文件、运行缓存与项目目录的链接拒绝规则不动。
|
||||
- 影响范围:`apps/ai-game-creator-shell/src-tauri/src/project/manifest.rs`、`.../src/commands.rs`(错误文案)、`.../src/project/manifest/import_tests.rs`、`.../src/tests/project.rs`、`apps/ai-game-creator-shell/src/features/runtime-config/RuntimeConfigDialog.tsx`、`docs/prd/【AI游戏创作】项目开发工作台PRD-2026-07-20.md` §3.8、`docs/technical/【技术方案】AGC Godot编辑器插件接入-2026-09-20.md`、`docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md`。
|
||||
- 验证方式:`cargo test --locked -p genarrative-ai-game-creator-shell --bin genarrative-ai-game-creator-shell -- project::manifest::import_tests::` 与 `-- tests::project::`;前端 `agc:typecheck` 与 `runtime-settings` / `pluginHost` 套件。
|
||||
|
||||
## 2026-09-21 模板正文目录门禁:CLI 打包与后台上传同一份段名单
|
||||
|
||||
- 背景:模板包组织指南把 `.agent/`、`.git/`、`node_modules/`、根目录 `dist/` 等列为「不要放进 ZIP」,但两条发布路径此前只校验路径安全与 `entry` 是否存在,放进去的东西会跟着建到用户项目里(模板自带 `.agent/` 会让新项目继承一个陌生身份)。这条约定只靠作者自觉。
|
||||
- 决策:升级成机器门禁,CLI(`readProjectFiles`)与后台上传(`validate_import_archive`)用同一份段名单与同一句文案——任意层级拒绝 `.agent` / `.git` / `.svn` / `node_modules`,根目录拒绝 `dist` / `build` / `library` / `temp` / `local` / `.idea` / `.vscode`。同名目录段只在根目录受限:正文内 `game/dist/**` 是模板自身内容;`.gitignore` 不等于 `.git`,Cocos 模板的 `.creator` / `.gitignore` 不受影响。
|
||||
- 原因:两类目录性质不同。`.agent/`、`.git/`、`.svn/`、`node_modules/` 放哪一层都是错的,进包即污染用户项目;而 `dist` / `library` / `temp` 这类只说明「作者把编辑器缓存或构建产物当成了模板内容」,出现在根目录才是信号,全面禁止会误伤工程内的正常同名目录。
|
||||
- 影响范围:`scripts/agc-template-library-publish.mjs` 及其测试、`server-rs/crates/api-server/src/admin_templates.rs`、`docs/technical/【技术方案】AGC模板库与模板建项-2026-09-17.md`、`docs/【模板规范】AGC模板包组织指南-2026-09-21.md`、`docs/project-memory/plans/【里程碑】后台模板上传-2026-09-21.md`。
|
||||
- 验证方式:`node --test scripts/agc-template-library-publish.test.mjs`(28 项,新增 1 项:13 条拒绝用例 + `game/dist/**` 与 `game/.gitignore` 放行断言);`cargo test --locked -p api-server admin_templates`(8 项,新增 `template_import_archive_rejects_identity_and_build_directories`);仓库现有 9 个模板源无一条命中,本地重打包的 ZIP 摘要与线上清单 `zipSha256` 逐条一致;`cargo fmt --check`、`check:encoding`、`check:doc-index`、`git diff --check` 通过。
|
||||
|
||||
## 2026-09-21 后台模板上传:成品 ZIP + 每模板封面,批量全有或全无
|
||||
|
||||
- 背景:模板发布此前只有本地 CLI(源目录 + 确定性打包 + `--only`),后台上传需要一条不依赖本地仓库的通道,并支持一次提交多个模板。
|
||||
- 决策(输入形态):后台上传**成品 ZIP**(库内字节原样发布,不重新打包),每个模板必须同时给一张 PNG/JPEG/WebP 封面(与 CLI 源布局 `v1/<id>/cover.*` 一致),`id/title/templateVersion/runtime/entry` 由页面逐行确认;简介、标签与引擎上传后用编辑接口补齐。服务端按字节嗅探封面格式,不信任 multipart 声明的 content-type。
|
||||
- 决策(批量语义):一批 = 一把发布锁 + 一次清单提交,**全有或全无**;任一模板的 manifest/归档/封面不合法都在写入前整批拒绝并逐项给出原因。单批上限 20 个模板、单包 64 MiB、单封面 5 MiB、请求体 200 MiB。
|
||||
- 决策(校验与安全):归档只校验不落盘——合法 zip、无符号链接、无绝对路径 / `..` / 盘符条目、必须包含声明的 `entry`、条目数 ≤ 4096 且解压后 ≤ 512 MiB。
|
||||
- 决策(版本与保留):新 ID 默认上架;已存在 ID 就地更新并保留 `enabled` 分组、其它条目与未知扩展字段;同一 ID 同一 `templateVersion` 的 ZIP 字节不同时拒绝并要求递增版本,字节一致时按内容复用(`reusedObjects`)。
|
||||
- 决策(存储契约):`platform-oss` 的 `put_immutable` 为 `application/zip` 单独放宽到 64 MiB(此前只有 json/图片的 5 MiB),图片与元数据上限不变。
|
||||
- 影响范围:`server-rs/crates/{shared-contracts/api-server/module-assets/platform-oss}`、`apps/admin-web/src/{api,pages,styles}`、模板库技术方案与 `docs/project-memory/plans/【里程碑】后台模板上传-2026-09-21.md`。
|
||||
- 验证方式:`cargo test`(module-assets 11、platform-oss 12、api-server 定向 4)、`npm run admin-web:typecheck`、后台页面与模型 40 项 vitest、`check:encoding`、`check:doc-index`、`git diff --check`;真实 dev bucket 写入验证需用户显式确认。
|
||||
|
||||
## 2026-09-21 模板库线上产物对齐仓库源:递增版本重发 + 说明文档纳入发布
|
||||
|
||||
- 背景:`agc-dev` 上的 `templates/` 产物停在 2026-09-17 发布的那一版,仓库源在那之后改过(`5e4ff54a9` 删掉模板内嵌 `package-lock.json`、`game.js` / `main.js` 等内容调整),9 个模板里 7 个的 ZIP 与线上不一致;dry-run 被「同一 `templateVersion` 的 ZIP 不得变」门禁拒绝,发布器因此无法把仓库状态发上去。
|
||||
- 决策:按门禁要求为内容已变的 7 个模板递增 `templateVersion` 到 `0.1.1`(`blank-2d-canvas`、`blank-web` 内容未变,保持 `0.1.0`),并完成一次真实发布;对象使用内容寻址键 `v1/<id>/sha256/<摘要>/…`,`index.json` 与说明文档在发布锁内最后提交,历史对象不删除。
|
||||
- 决策(说明文档):`templates/README.md` 不再是手工副本——它由发布脚本从仓库源 `apps/ai-game-creator-shell/template-library/README.md`(≤64 KiB)覆盖写入并回读校验,写在清单之前;改契约只改仓库源。
|
||||
- 决策(CLI 行为):发布器遇到门禁拒绝时用 `process.exitCode = 1` 正常退出,不再 `process.exit(1)` 让 Node 在 fetch 句柄未关闭时抛 libuv 断言(此前现场只剩 `Assertion failed`,看不到拒绝原因)。
|
||||
- 影响范围:`apps/ai-game-creator-shell/template-library/v1/*/meta.json`、`apps/ai-game-creator-shell/template-library/README.md`、`scripts/agc-template-library-publish.mjs` 与其测试、本文件与模板库技术方案。
|
||||
- 验证方式:`node --test scripts/agc-template-library-publish.test.mjs`(27 项,含新增「说明文档随发布覆盖写且写在清单之前」「源目录没有 README 时不写线上文档」);真实发布 28 个对象回读通过;匿名读取线上清单(9 个模板、7 个 `0.1.1`、全部内容寻址键)与 `templates/README.md`(与仓库源逐字节一致);AGC 壳 3 项线上用例(读清单、下载安装、下载并原生建项 Cocos)重跑通过。
|
||||
|
||||
## 2026-09-21 macOS 发布改为只出 arm64 单架构(Intel 暂不支持)
|
||||
|
||||
- 背景:Mac 发布管线按 `universal-apple-darwin` 构建,但随包 Node 便携运行时只有**单架构官方发行版**(`stage-node-runtime.mjs` 从 `process.execPath` 取材),于是 macOS Job #7~#13 连续失败在「Node 运行时不支持发布目标:universal-apple-darwin」。期间出现过一版「按宿主架构放行」的过渡实现,它能骗过通用包自检(`check-macos-bundle.mjs` 按 `process.arch` 校验),但 Intel 上那份 arm64 侧车不可执行,并且已发布的 dev-mac 0.1.86 就带着这个缺陷。
|
||||
@@ -8211,7 +8276,7 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在
|
||||
## 2026-08-10 AGC 打开现有 Godot 项目
|
||||
|
||||
- 项目双根决策(2026-08-14 更新):项目组只保留通用“打开项目 / 新建项目”,不再提供独立 Godot 入口。用户选择目录始终是工作区根,也是 `.agent`、Session、Runner、沙箱、通用文件工具和外围资料的唯一授权根;实际 Godot 根由根目录或一层直接子目录中的普通文件 `project.godot` 唯一确定,并以工作区相对 `godotProjectRoot` 记录,根目录使用 `.`。不得把 Runtime 根切换成 Godot 子目录,也不得复制工程或建立第二套工作区。
|
||||
- 发现与歧义决策:根目录命中优先;根未命中时只检查一层直接子目录,唯一命中才通过,多个命中在任何 `.agent` 写入前失败关闭。候选目录与工程文件拒绝符号链接和 Windows reparse point,二层及更深不递归。未来只有 Godot 专属命令显式使用经过校验的相对 Godot cwd。
|
||||
- 发现与歧义决策:根目录命中优先;根未命中时只检查一层直接子目录,唯一命中才通过,多个命中在任何 `.agent` 写入前失败关闭。候选目录与工程文件拒绝符号链接和 Windows reparse point,二层及更深不递归。未来只有 Godot 专属命令显式使用经过校验的相对 Godot cwd。(2026-09-21 部分取代:多命中改为按目录名排序取第一个,`project.godot` 允许链接并按目标判定;候选子目录与更深层的边界不变,见本文件「2026-09-21 Godot 工作区发现放宽与内置插件行去掉手动启动」。)
|
||||
- 元数据决策:首次导入只在工作区根创建并保留 `.agent/manifest.json`、`.agent/agent.db`、`.agent/logs/` 与 `.agent/runtime/`;不得创建默认 Web 原型的 `game/`、`assets/`、`memory/`、`exports/`。已有有效 `.agent` 项目继续复用身份;缺失或错误的可推导 `godotProjectRoot` 只在 Godot 打开边界按唯一文件布局校准,歧义时不改写。
|
||||
- Windows 锁文件决策:提升权限进程新建 `.agent/.manifest.json.lock` 时,Windows 可能把 owner 设为 `Administrators`。仅在固定锁路径已取得不共享独占句柄并确认是普通、非 reparse、单链接文件后,才初始化为当前 `TokenUser`;随后再次复核句柄并执行原有 owner/DACL 校验,不放宽既有异常对象的安全规则。
|
||||
- 运行决策:Godot 项目提交给 Project Supervisor 时使用 `standard` Run Profile,避免触发 Web 专用 `game/index.html`、HTTP preview 与自主 Web 完成门。Godot 编辑器启动和内嵌运行预览不在本切片范围。
|
||||
@@ -8988,7 +9053,7 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在
|
||||
- 决策(矩阵):`ui-interaction` = 生成图片 / 生成规范(图标规范、自定义规范)/ 生成图标素材 / 生成 UI 设计图 / 上传;`character` = 生成图片 / 生成规范(角色规范、自定义规范)/ 生成角色形象 / 上传;`scene` = 生成图片 / 生成规范(自定义规范)/ 上传;`audio` = 生成背景音乐 / 生成音效 / 上传。文档、待归类、项目版本、「所有资源」展开态与资源总览**不渲染**工具栏(`resolveResourceCanvasBottomTools` 返回空数组,渲染判据 `resourceBookState.view === 'child'` 且 category 命中四个栏目)。工具项与顺序是纯数据表,事实源落在 `resourceCanvasBottomToolbarModel.ts`。
|
||||
- 决策(落点与几何):工具栏是 `.game-resource-book-manager` 的**直接子节点**(与画本场景、右下 Dock、通知条并列,不进带 `scale()` 的场景层),锚在**左下角**(`left/bottom: 14px; z-index: 40`)——右下角是既有缩放 / 撤销 Dock,左下角是画布上唯一两者都不占的稳定空位;外壳消费共享 `packages/image-canvas-react` 的 `CanvasToolbar / CanvasToolbarGroup / CanvasChromeButton`(AGC 侧第一次真正消费这组共享 chrome)。一处必要覆盖:共享 `.genarrative-image-canvas__toolbar` 是横向滚动容器,会裁掉它自己弹出的二级菜单,消费端改成 `overflow: visible` + `flex-wrap: wrap`。
|
||||
- 决策(接线与收敛):图片类入口 `generate_local_project_asset`(kind 映射:图片 `image` / 角色形象 `character` / 图标规范 `icon-spec` / 角色规范与自定义规范 `spec` / 图标素材 `art-spritesheet` / UI 设计图 `ui-prototype`);音频入口复用既有 `derive_local_project_resource` 无源生成链路(**不另写一份音频生成**);上传复用 `upload_local_asset`。两者成功后的刷新形状统一为「**配对读 `(revision, manifest)`** → `onManifestChange` → `pendingResourceFocusRef` 定位新卡」,不重算依赖图、不另写布局。**音频入口收敛**:既有「生成素材」浮层入口改为只保留视频(`ResourceCanvasGenerationPanelView` 新增 `kinds` prop,单类型入口不再渲染类型选择器,面板标题与提交文案跟类型走),视频能力不删只是不进工具栏。
|
||||
- 决策(参数口径,避免假控件):比例 / 尺寸选项与默认值复用网页端纯模型 `ImageCanvasGenerationModel.ts`,但按本地 IPC 白名单收窄(本地通道明确拒绝 `4:3`,照搬就是一个点了必失败的选项);提示词上限复用 `resourceEditPromptMaxLength`(32000,与 Rust `LOCAL_PROJECT_ASSET_MAX_PROMPT_CHARS` 同口径);**面板不渲染模型选择器**(本地 IPC 没有 `model` 入参)。规范入口是固定档:只读展示规格,不给点了不生效的比例控件。
|
||||
- 决策(参数口径,避免假控件):比例 / 尺寸选项与默认值复用网页端纯模型 `ImageCanvasGenerationModel.ts`,但按本地 IPC 白名单收窄(本地通道明确拒绝 `4:3`,照搬就是一个点了必失败的选项);图标素材描述去除首尾空白后最多 `200` 个 Unicode 字符,作为唯一 `iconDescriptions` 元素原样提交,不包装、截断或拆条;其余图片提示词上限为 `32000`,前端与 Rust 原生校验保持一致;**面板不渲染模型选择器**(本地 IPC 没有 `model` 入参)。规范入口是固定档:只读展示规格,不给点了不生效的比例控件。
|
||||
- 决策(前置规范图,本轮的关键设计):`ui-prototype` 与 `art-spritesheet` 在 Rust 侧要求项目里已有登记并绑定当前账号的 `assets/art-spec.png`(`local_path` 精确匹配 + `kind == icon-spec` + 图片媒体类型 + 画布来源)。前端判据 `projectHasIconSpecReference` 与它逐字对齐;缺前置时入口**保持可点击**并给可执行原因(`aria-disabled` 而非原生 `disabled`,文案含 `assets/art-spec.png` 与「生成规范 → 图标规范」),且零生成请求。**同时**把「图标规范」入口在缺前置时按 `assets/art-spec.png` 落盘(`outputPath`),否则那两条入口会被前置条件永久锁死、工具栏自身无法满足自己的前置;已有权威规范图时不再传 `outputPath`(Rust `replace_existing` 固定 `false`,指向已存在文件会被硬拒),改为生成一张新的普通图标规范资产。这条是**前端策略**,不扩接口。
|
||||
- 已知能力缺口(用户口径是「缺参数就停下汇报,不自行扩接口」,记账备查):本地 IPC 没有 ① `model` ② `specType` ③ `replaceExisting` 入参。后果:面板不给模型选择;**角色规范与自定义规范共用 `spec` 通道**(靠 `assetName` / 提示词区分),因此「角色规范」不是真正的角色设定板通道;权威规范图存在时无法重写它。另:网页端 composer 子视图(含 `ImageCanvasSpecGenerationPanelView` 直连 `/api/editor/llm/icon-specs/*`)**没有复用**,因为 AGC 无该 BFF 通道且本地 IPC 不接受模型 / 参考图入参,照搬会渲染改不了请求的控件——本轮只把**纯模型**接进来。
|
||||
- 影响范围:`apps/ai-game-creator-shell/src/features/resource-canvas/{resourceCanvasBottomToolbarModel.ts,ResourceCanvasBottomToolbarView.tsx,ResourceCanvasAssetGenerationPanelView.tsx,ResourceCanvasGenerationPanelView.tsx,resourceCanvasChrome.css}`、`apps/ai-game-creator-shell/src/view/project-development/index.tsx`、测试 `apps/ai-game-creator-shell/tests/{resourceCanvasBottomToolbar.test.tsx(新增),resourceCanvasGenerationEntry.test.tsx,projectResourceLiveIntegration.test.tsx,appSurface/project-development.suite.ts}`、PRD §3.10 / §7.9 / §8、`docs/technical/【AGC】栏目画布底部工具栏入口矩阵-2026-09-13.md`(新增)、验收用例 S11 / S11a。**未动**:Rust、external v1 / OpenAPI、`packages/`(只消费共享 chrome)、SpacetimeDB。
|
||||
|
||||
@@ -1,5 +1,29 @@
|
||||
# 踩坑与排障记录
|
||||
|
||||
## 客户端图标素材描述不能先包装再截断
|
||||
|
||||
- 现象:资源画布填写了具体图标需求,平台实际收到的 `iconDescriptions` 却只包含泛化的小游戏美术指令,生成结果不遵循输入。
|
||||
- 原因:客户端先给用户描述套“Web 小游戏首版原型、核心美术素材”和默认 brief 模板,再把包装后的文本压入单项 `200` 字符;固定前缀已占满额度,用户描述在发给 API Server 之前就被丢弃。服务端校验只能看到被截短的文本,无法恢复原需求。
|
||||
- 处理:客户端画布图标生成只 trim 描述并以单项 `iconDescriptions` 原样提交,保留内部换行;面板与原生入口按 `200` 个 Unicode 码点校验并拒绝空白或超限输入,不静默截断、不机械拆条。服务端共用的提示词流程负责规范图、背景与排布要求;其它图片生成的 `32000` 字符上限保持不变。
|
||||
- 验证:检查实际请求体与 trim 后的原文一致,并覆盖 `200/201` 码点、补充平面字符、换行和空白输入;不能只断言“请求长度未超限”。完整合同见 [画板图标素材生成入口设计](../../【编辑器】画板图标素材生成入口设计-2026-06-15.md)。
|
||||
|
||||
## 2026-09-21 不同渠道的包体在同一台设备安装会互相顶掉
|
||||
|
||||
- **现象**:在一台已经装了某个渠道 AGC 客户端的设备上安装另一个渠道的安装包,装完后旧客户端直接消失(安装目录被覆盖、卸载项被接管),更新端点、平台服务器与本地登录态一起换成新渠道的;两个渠道的客户端无法共存。
|
||||
- **原因**:渠道此前只烘焙了 `plugins.updater.endpoints` 与 `VITE_AGC_PLATFORM_CHANNEL`(`apps/ai-game-creator-shell/scripts/build-release.mjs` 的 `createChannelConfig`),`productName` / `identifier` 用的是渠道无关的基线值。Tauri 的 Windows 安装目录与卸载项由 `productName` 决定,WebView2 数据目录与客户端数据目录由 `identifier` 决定,于是所有渠道落到 `%LOCALAPPDATA%\陶泥儿`、`HKCU\...\Uninstall\陶泥儿` 与 `%APPDATA%\world.genarrative.ai-game-creator`。
|
||||
- **处理(现行口径)**:渠道进入安装身份,默认渠道保持基线身份不变,其它渠道派生 `<产品名> <渠道显示名>` 与 `<基线>.<渠道>`;身份与端点在同一次构建期 `--config` 注入。见决策记录 2026-09-21 条目。
|
||||
- **核对方式**:装完任渠道的包后看 `HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall\<产品名>` 的 `InstallLocation`、`%APPDATA%\<identifier>` 与主程序窗口标题是否按渠道分开;同名安装目录或同名数据目录说明身份没有生效。
|
||||
- **易错点**:只改安装包文件名或快捷方式名而不改 `identifier`,两个渠道仍会抢同一份 Agent Runner / 项目锁与登录态;反过来把渠道后缀加在默认渠道上,既有安装的升级链会断(客户端认不出旧安装)。相似前缀目录(如 `world.genarrative.ai-game-creator-backup`)不得进入提权 ACL 的 managed 范围。
|
||||
- **关联**:`apps/ai-game-creator-shell/scripts/channel-identity.mjs`、`build-release.mjs`、`build-macos-ci.mjs`、`src-tauri/src/config.rs`。
|
||||
|
||||
## 发布器守卫拒绝时不要把 process.exit 用在 fetch 句柄未关闭处
|
||||
|
||||
- 现象:`agc-template-library-publish.mjs --dry-run` 撞上「同一 `templateVersion` 的 ZIP 不得变」门禁时,终端只剩一句 `Assertion failed: !(handle->flags & UV_HANDLE_CLOSING), file src\win\async.c`,看不到任何拒绝原因,看起来像脚本崩溃而不是被拒绝。
|
||||
- 原因:`main().catch(...)` 里直接 `process.exit(1)`;此时 dry-run 刚用 fetch 读过公共清单,句柄仍在关闭流程中,Node/libuv 在 Windows 上先抛断言,把真实错误信息挤掉。
|
||||
- 处理:`catch` 里只设 `process.exitCode = 1`,让事件循环自然退出;同批把说明文档纳入受管发布(见决策记录 2026-09-21 条目)。
|
||||
- 验证:把模板源复制到临时目录、把某个模板的 `templateVersion` 改回与线上同版本并改动一个字节,`--dry-run` 应打印 `同版本 ZIP 内容或尺寸变化,请递增 templateVersion` 且退出码为 1,不再出现 `Assertion failed`。
|
||||
- 关联:`scripts/agc-template-library-publish.mjs`。
|
||||
|
||||
## macOS 只出 arm64 单架构,universal 必须失败关闭
|
||||
|
||||
`stage-node-runtime.mjs` 只把**构建宿主的 Node**打成便携运行时(官方发行版是单架构,没有 universal 发行版),而 2026-09-21 之前 `build-macos-ci.mjs` 构建的是 `universal-apple-darwin`:macOS Job #7~#13 因此在 `stageNodeRuntime` 直接抛「Node 运行时不支持发布目标:universal-apple-darwin」。期间出现过一版「按宿主架构放行」的过渡实现(`targetRuntime` 对 universal 返回宿主架构),它能骗过通用包自检(`check-macos-bundle.mjs` 按 `process.arch` 校验),但**Intel Mac 上这份 arm64 侧车不可执行**,等于把坏包发出去。当前决策:macOS 固定只构建 `aarch64-apple-darwin`,清单只登记 `darwin-aarch64`,`targetRuntime('universal-apple-darwin')` 保持失败关闭。恢复 Intel 的正确路径是先在 staging 支持按架构各带一份**同版本**运行时(另下载另一架构官方发行版)并让通用包自检按架构分别校验,再切回 universal 目标、把 `darwin-x86_64` 键登记回去;不得用「只带宿主架构」充数,也不得把 arm64 产物登记成 x86_64 键。
|
||||
@@ -4135,6 +4159,14 @@ Cocos Creator 根目录由 `package.json.creator.version` 与普通 `assets/`
|
||||
- 验证:活会话下 finalization 和 `runner.shutdown_if_idle` 必须失败关闭;分别验证 graceful handler 尾部输出、宽限超时后的 force、忽略 SIGHUP 的 npm 孙进程和 Windows Job 路径,只有 child 已终态、同组残留已处理且 PTY 尾部排空才出现唯一 terminal record。另用允许程序证明代理和固定 cwd 不是文件系统 / 网络沙箱,不得把该现象误写成测试失败或安全能力。
|
||||
- 关联:`docs/technical/【技术方案】AI游戏创作Agent Runtime V1.1-2026-07-12.md`、`apps/ai-game-creator-shell/src-tauri/src/runner.rs`、`apps/ai-game-creator-shell/src-tauri/src/agent.rs`。
|
||||
|
||||
## 一次性命令不能把孤儿僵尸误判为仍在执行的进程组
|
||||
|
||||
- 现象:Linux CI 的命令已退出,但 `command.exec` 返回 `needs-reconciliation`,后续修复计划或输出读取请求一直等不到;普通 WSL 下相同命令可通过。
|
||||
- 原因:容器 PID 1 未回收孤儿 `bwrap` 僵尸,`kill(-pgid, 0)` 仍返回成功;主进程已被 wait 回收,后续 leader 启动身份核对必然失败,掩盖了真实退出结果与原本应触发的日志审计错误。
|
||||
- 处理:确认 target 终态且回收主进程后扫描 `/proc/<pid>/stat`,空组或仅含 `Z / X` 成员无需发送信号;有存活成员仍保留 leader 身份门禁,读取失败保守进入 reconciliation,不放宽未知进程组的信号权限。
|
||||
- 验证:隔离 subreaper 夹具覆盖 leader 已回收时的存活后代拒绝、孤儿僵尸接受和空组接受;原有诊断命令、审计失败、命令修复与长输出/历史读取测试在不回收孤儿的 PID namespace 下验证。
|
||||
- 关联:`apps/ai-game-creator-shell/src-tauri/src/command_exec.rs`、`apps/ai-game-creator-shell/src-tauri/src/tests/command_runtime.rs`。
|
||||
|
||||
## 命令环境变量、代理和进程组不能冒充 OS 沙箱
|
||||
|
||||
- 现象:命令看似使用隔离 HOME / TMP、离线包管理器和不可达代理,仍能直接读取宿主用户文件、用原始 socket 联网,或由 `project.verify` 的平行 npm spawn 绕开 `command.exec` 限制。
|
||||
@@ -5417,6 +5449,14 @@ Cocos Creator 根目录由 `package.json.creator.version` 与普通 `assets/`
|
||||
- 处理:Windows 专用 Tauri 配置设置 `bundle.useLocalToolsDir: true`,把工具缓存到 `src-tauri/target/.tauri/NSIS`;Jenkins 预检验证实际用户、项目工具目录可写,并在构建失败时打印实际缓存路径和绝对路径执行结果。
|
||||
- 验证:不要把 PATH 中 `makensis` 可发现当作 Tauri bundler 工具可执行的充分证据;需要在 Windows Agent 上检查 `target/.tauri/NSIS/makensis.exe`、ACL、EDR/Defender 和直接 `-VERSION` 结果。
|
||||
|
||||
## Tauri NSIS 工具链必须在打包前预置并重试(2026-09-21)
|
||||
|
||||
- 现象:AGC Windows 发布构建已完成 Rust release,Tauri 依次打印 `Downloading .../nsis-3.11.zip`、`Info extracting NSIS`、`Downloading .../nsis_tauri_utils.dll` 之后,直接以 ``failed to bundle project `io: unexpected end of file` `` 失败(退出码 1),安装包不会产出。
|
||||
- 原因:tauri-bundler 的 `download_and_verify` 现场从 GitHub 取 NSIS 工具链,只有一次机会、没有重试;响应体被截断即报 `io: unexpected end of file`,看起来像打包错误其实是网络问题。Checkout 阶段的 `git clean -fdx` 每次都会清掉 `target/.tauri`,所以每个构建都要重新下载,在受限网络下必然反复失败。
|
||||
- 处理:新增 `apps/ai-game-creator-shell/scripts/nsis-toolset.mjs` 与 `ensure-nsis-toolset.mjs`,在 `buildRelease`(Windows 目标且需要打包时)与 Jenkins `Tauri NSIS toolchain` 阶段按固定 SHA1 预置 `target/.tauri/NSIS`:原始归档带 4 次重试,缓存在工作区外的 `%ProgramData%\genarrative\tauri-nsis-cache`(可用 `AGC_TAURI_NSIS_CACHE_DIR` 覆盖),镜像开关沿用 bundler 的 `TAURI_BUNDLER_TOOLS_GITHUB_MIRROR_TEMPLATE` / `TAURI_BUNDLER_TOOLS_GITHUB_MIRROR`。该阶段同时执行 `makensis.exe -VERSION`,把 2026-09-02 记录的缓存目录不可执行问题也提前到编译之前暴露。Checkout 阶段改为 `git clean -fdx -e apps/ai-game-creator-shell/src-tauri/target/.tauri`:Tauri 的工具缓存位于工作区内,裸 `git clean -fdx` 会连它一起删,排除后同一节点的稳态构建不再需要联网,只有冷缓存(新节点、工作区重建)才下载。
|
||||
- 验证:`node --test apps/ai-game-creator-shell/scripts/nsis-toolset.test.mjs`(已就绪零下载复用、缓存离线还原、失败重试、哈希不符与归档越界失败关闭)与 `node --test apps/ai-game-creator-shell/scripts/build-release.test.mjs`;真实节点上该阶段必须早于 Rust 编译失败关闭。
|
||||
- 注意:不要改回 `bundle.useLocalToolsDir: false` 去用 `%LOCALAPPDATA%`,也不要依赖 PATH 里预装的 `makensis`;升级 `@tauri-apps/cli` 时同步核对归档 URL、SHA1 与必需文件清单。
|
||||
|
||||
## AGC 登录态续期必须同步本地运行时
|
||||
|
||||
- 模型目录 HTTP 请求与 DirectProject 的 Rust/app-server 使用同一账号,但凭据分别保存在 WebView 与 Rust / Runner;续期应复用 `requestPlatformSessionRefresh` 完成用户核验及本地会话安装,不能只写 localStorage。
|
||||
@@ -5851,3 +5891,10 @@ Cocos Creator 根目录由 `package.json.creator.version` 与普通 `assets/`
|
||||
- **处理(现行口径)**:① 依赖里只放数据,回调走 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`。
|
||||
|
||||
## 2026-09-21 DirectProject 结构化消息不能逐个拒绝空白文本片段
|
||||
|
||||
- **现象**:多行正文、末尾空段落或合法引用前后的分隔空格会让有内容的消息报错;编辑器为了保持结构产生的空白文本片段被误判为“聊天内容为空”。
|
||||
- **原因**:校验器对每个 `input_text` 单独执行 `trim().is_empty()` 并立即拒绝,混淆了结构化片段合法性和整条消息是否有实际内容。
|
||||
- **处理(现行口径)**:`input_text` 允许空字符串、空格和换行,校验过程保持全部片段的原文、分段与顺序,不做合并或删除;遍历完整条消息后,只在既没有非空白文字、也没有合法 `agc_resource_reference` / `agc_runtime_region_reference` 时返回“聊天内容不能为空”。两类引用仍逐个执行原有校验,消息带正文也不能绕过非法引用。
|
||||
- **关联**:`apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/validation.rs`、`docs/【功能说明】AGC聊天素材引用-2026-09-08.md`。
|
||||
|
||||
@@ -58,7 +58,7 @@ SpacetimeDB crate、SDK、CLI / standalone 与生成 bindings 按 `2.8.3` 对齐
|
||||
- DirectProject 对话先在完整历史中按回合/原始 item 身份关联,再分页渲染;每个回合只有一个呈现入口。有流按 item `seq` 交替文本和工具,无流采用历史正文;禁止位置猜配或同时展示累计回复与 item 正文。流写入单调归并,收尾等待落盘任务,不按磁盘“最后一段”猜最终回复位置。详见 AGC 实施计划的“DirectProject 回合展示唯一归属”。
|
||||
- 回合生命周期只由活动 client 回合快照和 Direct 事件恢复;Provider 的历史终态通知不能创建活动 client 回合。消息发送时间保存在历史信封,原始 item 不混入宿主字段;完成后的中间文本和工具默认收进“执行过程”,最终回复及失败提示保持可见。
|
||||
|
||||
- AGC 安装产品名统一为“陶泥儿”,由 Tauri `productName` 控制安装项、快捷方式与 EXE 产品描述;Windows 内置 Codex 安装到顶层 `coding-agent/win-x64/`,打包资源映射与运行时查找路径必须一致。内部可执行文件名与应用 identifier 保持稳定。
|
||||
- AGC 安装产品名基线为“陶泥儿”,由 Tauri `productName` 控制安装项、快捷方式与 EXE 产品描述;默认渠道 `dev` 保持基线产品名与 identifier `world.genarrative.ai-game-creator` 不变,其它渠道派生 `陶泥儿 <渠道显示名>` 与 `<基线>.<渠道>`,让不同渠道的包体在同一台设备上并存而不互相顶掉(详见《AGC客户端更新检查与下载》的渠道与安装身份合同)。Windows 内置 Codex 安装到顶层 `coding-agent/win-x64/`,打包资源映射与运行时查找路径必须一致。内部可执行文件名保持稳定。
|
||||
|
||||
- 新 Web 游戏为 `game/` 下的 npm + Vite + Phaser 4.2.1 工程,使用包导入且允许其它依赖;npm 预览与导出只读取 dist,运行素材需纳入构建。单 HTML → Phaser 迁移固定走 DirectProject:文件落盘后先用受控 `project.bootstrap` 在 `game` 执行无参数 `npm install`,再用支持相对 cwd 的 `project.verify` 构建并确认 `game/dist/index.html`,已有单 HTML/Godot 不通过 JSON Generator 伪装成 npm 工程。
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
- AGC 批量追加素材标签由原生在一次项目写锁与 revision CAS 下合并各项原标签,先校验全批再写 manifest;前端不能循环单素材分类命令,不回传展示层推导的分类或旧标签全集,以免部分写入或覆盖未编辑字段。
|
||||
|
||||
- AGC 正式包的平台服务跟随构建渠道:`release` 连接 `https://www.genarrative.world`,`dev` 连接 `https://dev.genarrative.world`;本地 debug 态保留 release/dev/custom 服务器选择,会话凭据始终按 origin 隔离。发布渠道为 `dev/release/自定义名称`,Windows/Mac 是系统,OSS 的 `<channel>-win/mac` 仅是延续既有地址的分区。官网通过服务端 `GENARRATIVE_CLIENT_DOWNLOAD_CHANNEL`(默认 dev)选择渠道,公开同源 `/api/client-downloads` 汇总其各系统首装包与真实版本;未发布隐藏,单系统失败不影响其它下载,不跨渠道补齐。发布先上传 EXE/DMG 再写对应分区清单,不维护会互相覆盖的共享 OSS 索引。主站 Vite 代理复用实际 `runtimeServerTarget`。完整约定见 AGC 客户端更新检查与下载专题。
|
||||
- AGC 正式包的平台服务跟随构建渠道:`release` 连接 `https://www.genarrative.world`,`dev` 连接 `https://dev.genarrative.world`;本地 debug 态保留 release/dev/custom 服务器选择,会话凭据始终按 origin 隔离。发布渠道为 `dev/release/自定义名称`,Windows/Mac 是系统,OSS 的 `<channel>-win/mac` 仅是延续既有地址的分区。官网通过服务端 `GENARRATIVE_CLIENT_DOWNLOAD_CHANNEL`(默认 dev)选择渠道,公开同源 `/api/client-downloads` 汇总其各系统首装包与真实版本;未发布隐藏,单系统失败不影响其它下载,不跨渠道补齐。发布先上传 EXE/DMG 再写对应分区清单,不维护会互相覆盖的共享 OSS 索引。主站 Vite 代理复用实际 `runtimeServerTarget`。渠道同时决定安装身份:默认渠道 `dev` 必须保持基线 `productName` / `identifier` 不变,其它渠道派生独立身份,使不同渠道的包体可在同一台设备并存且本地数据不共享;身份与更新端点必须在同一次构建期注入里确定,禁止分别回读默认值。完整约定见 AGC 客户端更新检查与下载专题。
|
||||
- AGC 模板库灰度复用 `agc:template-library`:未配置关闭,已配置时遵循现有灰度启停、用户 ID/标签和比例规则;服务端返回权威结论,客户端入口和原生清单/下载/建项均执行门禁,主体切换丢弃旧异步结果。公开 OSS 不是保密边界,已创建项目不受影响。
|
||||
|
||||
- 画布卡片类型与信息角标共用 `CanvasCardCornerActions`;菜单收纳共用 `OverflowActions`,宿主决定展示数量和资源命令。AGC 选中菜单前 5 项直显,Web 默认不折叠;浮层 portal 继续接入现有画布关闭与滚轮归属判据。
|
||||
|
||||
Reference in New Issue
Block a user