Merge branch 'master' into feat/play-count-with-cache
Project CI / AI game creator shell Rust crates (pull_request) Successful in 3m7s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 4m20s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 5m28s
Project CI / Backend tests (pull_request) Successful in 7m46s
Project CI / Frontend tests (pull_request) Successful in 3m55s
Project CI / AI game creator shell web tests (pull_request) Successful in 3m18s
Project CI / Native shell tests (pull_request) Successful in 8m37s
Project CI / Repository checks (pull_request) Failing after 6m40s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 3m7s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 4m20s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 5m28s
Project CI / Backend tests (pull_request) Successful in 7m46s
Project CI / Frontend tests (pull_request) Successful in 3m55s
Project CI / AI game creator shell web tests (pull_request) Successful in 3m18s
Project CI / Native shell tests (pull_request) Successful in 8m37s
Project CI / Repository checks (pull_request) Failing after 6m40s
This commit is contained in:
@@ -27,6 +27,14 @@
|
||||
- 影响范围:`apps/ai-game-creator-shell/src/features/project-workspace/activeChatComposer.ts`(新增)、`src/App.tsx`、`src/view/project-development/chat/DirectProjectChatView.tsx`、`.../chat/components/DirectProjectComposer/DirectProjectComposer.tsx`、`.../planning/PlanningChatView.tsx`、`tests/activeChatComposer.test.ts`(新增,钉注册表合同)、`tests/resourceCanvasChatReferenceDrop.test.tsx`、`tests/appSurface/{project-development,design-agent}.suite.ts`、`docs/【功能说明】AGC聊天素材引用-2026-09-08.md`、`pitfalls.md`、本文件。
|
||||
- 验证(合并 master 后的最终一轮):`npx vitest run apps/ai-game-creator-shell/tests`(197 passed / 1 skipped 文件,1918 passed / 17 skipped 用例)、`npx vitest run tests/activeChatComposer.test.ts tests/resourceCanvasChatReferenceDrop.test.tsx`(2 files / 12 passed,含注册表合同:空批次、无输入区、句柄报落空、注销身份校验、重复注册告警、乱序注销)、`npx vitest run tests/appSurface.test.ts -t 引用`(4 passed)、`npm run agc:typecheck`(含 `check:tests:types`,exit 0)、`npm run check:encoding`、`git diff --check`、eslint `--max-warnings 0`(改动文件)。反向证伪:去掉注册调用后端到端用例变红;去掉空批次短路 / 重复注册告警后对应新用例各红一处。
|
||||
|
||||
## 2026-10-04 AGC 渠道更新进程与快捷方式隔离
|
||||
|
||||
- 背景:Tauri 2.11 的 Windows NSIS 模板通过 `MAINBINARYNAME` 查找并结束进程。dev 与 release 过去共用 `genarrative-ai-game-creator-shell.exe`,更新任一渠道都会结束另一渠道;release 从「陶泥儿 Release」改为「陶泥儿」后,`/UPDATE` 又不会自动重建旧快捷方式。
|
||||
- 决策:dev 保留历史主程序文件名以维持升级链;release 使用 `genarrative-ai-game-creator-shell-release.exe`,其它非默认渠道使用带渠道后缀的主程序名。构建期把 `mainBinaryName` 与渠道端点、productName、identifier 同批注入,NSIS 因文件名隔离而只匹配自身渠道进程。
|
||||
- 迁移:release Windows 包通过独立安装钩子读取旧 `陶泥儿 Release` 卸载项的安装目录,在原目录安装新包,迁移旧桌面/开始菜单快捷方式并清理旧主程序与孤儿卸载项;dev 继续使用原有旧展示名迁移钩子。
|
||||
- 影响范围:AGC 渠道身份脚本、发布构建配置、Tauri 基线配置、Windows NSIS 钩子与渠道发布测试;不改变 OSS 分区、更新端点或客户端数据目录合同。
|
||||
- 验证方式:渠道发布脚本定向测试、`check-config.mjs`、真实 NSIS 编译与双渠道安装/更新 smoke;真机安装仍需发布环境执行。
|
||||
|
||||
## 2026-10-03 AGC 栏目画布上传素材按入口栏目登记(Issue 359)
|
||||
|
||||
- 背景:AGC 客户端在资源栏目子画布(「UI 交互 / 角色与对象 / 场景与环境 / 音频」)左下角工具栏点「上传」后,提示条给出「已上传 1 个素材」,但当前栏目计数不变(仍「0 项」)、素材出现在「待归类」,用户看到的是"上传成功了但它从这一页消失了"。原因是上传登记的 manifest `kind` 只由**内容证据**推导(`assets.rs::uploaded_asset_kind`:图片 / 视频 / 代码 → `unclassified`,音频 → `audio`,文档 / 字体 → `document`),kind 派生分类与栏目词汇(`ui-interaction` / `character` / `scene` / `audio`)不是同一套,而 `upload_local_asset` 原先不接受入口栏目。
|
||||
|
||||
@@ -10,6 +10,15 @@
|
||||
- **判据/取证**:`npm run test -- apps/ai-game-creator-shell/tests` 里的 `resourceCanvasChatReferenceDrop.test.tsx`、`appSurface/project-development.suite.ts`(工具条「引用」)、`appSurface/design-agent.suite.ts`(策划链路)都断言**真实输入盒草稿**里出现 `[data-resource-reference-id="<assetId>"]`,不再是「事件被派发」;临时去掉注册调用后这三条会红,证明用例钉的是真链路。详见 [`【功能说明】AGC聊天素材引用-2026-09-08`](../../【功能说明】AGC聊天素材引用-2026-09-08.md) 文首一节。
|
||||
- **边界**:只要还保留「window 事件 + 模块外 ref 约定」这种形态,新增聊天面就必须一起进注册表;更彻底的形态是画布与聊天的共同宿主(`ProjectDevelopmentView`)用 context 下发插入能力,注册表语义与它一致,将来换实现不必动画布。
|
||||
|
||||
## 2026-10-04 AGC 渠道更新按固定主程序名互相查杀
|
||||
|
||||
- **现象**:开发版和 release 同时运行时,更新其中一个渠道会把另一个进程一起结束;release 从旧产品名升级后,旧 `陶泥儿 Release.lnk` 仍指向旧安装目录,更新后的 release 没有可用快捷方式。
|
||||
- **原因**:Tauri 2.11 的 NSIS `CheckIfAppIsRunning` / `KillProcess` 只按 `MAINBINARYNAME` 匹配。所有渠道都使用 `genarrative-ai-game-creator-shell.exe`,所以插件无法按安装目录区分进程;更新模式还会跳过快捷方式创建,产品名变化后旧图标不会自动迁移。
|
||||
- **处理**:`channel-identity.mjs` 新增 `resolveChannelMainBinaryName`:dev 保留旧文件名,release 与其它渠道使用后缀文件名;`createChannelConfig` 同批注入 Tauri `mainBinaryName`。release Windows 包使用独立 `release-installer-hooks.nsh`,从旧 `陶泥儿 Release` 卸载项恢复安装目录,迁移旧快捷方式并删除旧主程序/卸载项;dev 的历史改名钩子保持不变。
|
||||
- **不要踩的坑**:只改 `productName` 或 `identifier` 不能阻止 NSIS 互相查杀;只改安装包文件名也不能让 updater 选中正确的进程,必须把 `mainBinaryName` 写入构建期 Tauri 配置,并保证 dev 的历史文件名不变。NSIS 钩子仍只能在 `!macro` 内引用模板常量/插件,且文件必须 UTF-8 with BOM。
|
||||
- **判据/验证**:`node --test apps/ai-game-creator-shell/scripts/build-release.test.mjs` 覆盖渠道主程序名、release 钩子与宏位置;`node apps/ai-game-creator-shell/scripts/check-config.mjs` 校验基线;真实 Windows NSIS 编译与 dev/release 同机更新 smoke 仍需发布环境执行。
|
||||
- **关联**:`apps/ai-game-creator-shell/scripts/channel-identity.mjs`、`apps/ai-game-creator-shell/scripts/build-release.mjs`、`apps/ai-game-creator-shell/src-tauri/windows/{installer-hooks.nsh,release-installer-hooks.nsh}`、`docs/technical/【技术方案】AGC客户端更新检查与下载-2026-08-31.md`。
|
||||
|
||||
## 2026-10-03 AGC 栏目画布上传素材落「待归类」:kind 派生分类不等于入口栏目
|
||||
|
||||
- **现象**(Issue 359):在 AGC 资源栏目子画布(如「UI 交互」「角色与对象」)左下角工具栏点「上传」选图片 / 视频 / 代码类文件,提示条给出「已上传 1 个素材」,但当前栏目计数纹丝不动(仍「0 项」),素材出现在「待归类」。用户看到的是"上传成功了,可它就消失在这个页面里"。
|
||||
@@ -6323,6 +6332,7 @@ Cocos Creator 根目录由 `package.json.creator.version` 与普通 `assets/`
|
||||
- **验证**:`cargo test --locked -p api-server --bin api-server app::tests::http_tracing`(默认并发与 `--test-threads=1` 各连跑 20 次)、`cargo test -p platform-llm observability_tests`;更接近 CI 并发的是整段 `app::tests::`(91 用例同进程)与 `--skip bgfilter_worker --skip wallet_refund_outbox` 的全量 bin(1133 用例)连跑。
|
||||
- **关联**:`server-rs/crates/api-server/src/app.rs`、`server-rs/crates/platform-llm/src/observability_tests.rs`。
|
||||
|
||||
|
||||
## 2026-10-04 AGC 通知计数与 graceful terminate 的断言偶发都来自"跨线程 / 跨用例串台"
|
||||
|
||||
- **现象**:`agent::thread_manager::tests::active_turn_changes_publish_one_notification_per_real_change` 偶发 `left: 8 / right: 7`(进度内容变化必须通知一次);`process_session::tests::process_session_graceful_terminate_keeps_wrapper_alive_for_target_cleanup` 偶发 `left: "exited" / right: "terminated"`;两者都在 `AI game creator shell Rust lane 2/2` 分片里红。
|
||||
|
||||
@@ -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 安装产品名由渠道身份决定:`dev` 显示“陶泥儿开发版”,`release` 复用正式产品名“陶泥儿”,自定义渠道显示“陶泥儿 <渠道显示名>”;Tauri `productName` 控制安装项、快捷方式与 EXE 产品描述,identifier 继续按 `<基线>.<渠道>` 派生,保证渠道数据与运行身份隔离(详见《AGC客户端更新检查与下载》的渠道与安装身份合同)。Windows 内置 Codex 安装到顶层 `coding-agent/win-x64/`,打包资源映射与运行时查找路径必须一致。内部可执行文件名保持稳定。
|
||||
- AGC 安装产品名由渠道身份决定:`dev` 显示“陶泥儿开发版”,`release` 复用正式产品名“陶泥儿”,自定义渠道显示“陶泥儿 <渠道显示名>”;Tauri `productName` 控制安装项、快捷方式与 EXE 产品描述,identifier 继续按 `<基线>.<渠道>` 派生,主程序文件名也按渠道隔离(dev 保留历史名,release 使用 `-release` 后缀),保证渠道数据、运行身份与更新进程隔离(详见《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 工程。
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
### 渠道与安装身份合同
|
||||
|
||||
- 渠道同时决定**更新端点**与**安装身份**,两者都由构建期写入产物。默认渠道 `dev` 保持基线身份 `productName = 陶泥儿开发版`、`identifier = world.genarrative.ai-game-creator`;`release` 渠道使用正式产品名 `陶泥儿` 并派生 `identifier = world.genarrative.ai-game-creator.release`;其它自定义渠道派生 `productName = 陶泥儿 <渠道显示名>`(如 `beta-2` → `陶泥儿 Beta-2`)与 `identifier = world.genarrative.ai-game-creator.<渠道>`。渠道显示名按连字符分段首字母大写,不改动渠道本身。
|
||||
- Windows 主程序文件名也是渠道安装身份的一部分:`dev` 保留 `genarrative-ai-game-creator-shell.exe` 以延续既有升级链,`release` 使用 `genarrative-ai-game-creator-shell-release.exe`,其它渠道使用 `genarrative-ai-game-creator-shell-<channel>.exe`。NSIS 更新/卸载按该文件名查找进程,保证更新一个渠道不会结束另一个渠道。
|
||||
- 默认渠道身份**不可变更**:既有安装目录、卸载项、快捷方式与已发布客户端的升级链都建立在基线身份上。渠道身份由 `apps/ai-game-creator-shell/scripts/channel-identity.mjs` 单点定义,构建入口、macOS 发布入口与配置门禁共同消费;基线 `tauri.conf.json` 必须逐字等于默认渠道身份。
|
||||
- 安装身份决定的持久与可见事实:Windows 安装目录 `%LOCALAPPDATA%\<产品名>`、卸载项与 `HKCU\Software\genarrative\<产品名>`、WebView2 数据目录 `%LOCALAPPDATA%\<identifier>`、客户端数据目录 `%APPDATA%\<identifier>`;macOS `.app` 名、bundle id、DMG 卷名与菜单栏应用名。
|
||||
- 同机并存:不同渠道的包体可以在同一台设备上同时安装并同时运行,互不覆盖、互不顶掉;同一渠道的新版本仍是原地升级,因为更新端点与安装身份同属一个渠道。
|
||||
@@ -124,19 +125,20 @@
|
||||
|
||||
- 渠道安装身份映射(`<channel>` 为 `dev`、`release` 或自定义名称;`<Channel>` 为渠道显示名):
|
||||
|
||||
| 渠道 | productName | identifier | Windows 安装目录 | 客户端数据目录 |
|
||||
| -------------------- | ------------------ | ---------------------------------------------- | ----------------------------------- | ----------------------------------------------- |
|
||||
| `dev`(默认) | `陶泥儿` | `world.genarrative.ai-game-creator` | `%LOCALAPPDATA%\陶泥儿` | `%APPDATA%\world.genarrative.ai-game-creator` |
|
||||
| `release` / 自定义 | `陶泥儿 <Channel>` | `world.genarrative.ai-game-creator.<channel>` | `%LOCALAPPDATA%\陶泥儿 <Channel>` | `%APPDATA%\world.genarrative.ai-game-creator.<channel>` |
|
||||
| 渠道 | productName | 主程序文件名 | identifier | Windows 安装目录 | 客户端数据目录 |
|
||||
| -------------------- | ------------------ | ------------------------------------------------- | ---------------------------------------------- | ----------------------------------- | ----------------------------------------------- |
|
||||
| `dev`(默认) | `陶泥儿开发版` | `genarrative-ai-game-creator-shell.exe` | `world.genarrative.ai-game-creator` | `%LOCALAPPDATA%\陶泥儿开发版` | `%APPDATA%\world.genarrative.ai-game-creator` |
|
||||
| `release` | `陶泥儿` | `genarrative-ai-game-creator-shell-release.exe` | `world.genarrative.ai-game-creator.release` | `%LOCALAPPDATA%\陶泥儿` | `%APPDATA%\world.genarrative.ai-game-creator.release` |
|
||||
| 自定义渠道 | `陶泥儿 <Channel>` | `genarrative-ai-game-creator-shell-<channel>.exe` | `world.genarrative.ai-game-creator.<channel>` | `%LOCALAPPDATA%\陶泥儿 <Channel>` | `%APPDATA%\world.genarrative.ai-game-creator.<channel>` |
|
||||
|
||||
- 安装身份迁移:`dev` 客户端保持原身份,升级链路连续;`release` 与自定义渠道首次以新身份安装,**不接管也不迁移**任何既有 `dev` 安装、本地项目或登录态,设备上因此可以同时存在两个渠道的客户端,由用户自行决定是否卸载其一。
|
||||
- 安装身份迁移:`dev` 客户端保持原 identifier 与主程序文件名,升级链路连续;dev Windows 包继续清理历史展示名 `陶泥儿` / `Genarrative AI Game Creator` 的旧快捷方式。release 从旧展示名 `陶泥儿 Release` 迁移安装目录与快捷方式到当前 `陶泥儿` 身份;release 与自定义渠道不接管也不迁移其它渠道的数据或登录态。
|
||||
|
||||
## 构建与发布
|
||||
|
||||
- 发布入口:`npm run ai-game-creator-shell:release:upload`(构建 + 按渠道上传);仅构建不发布的 smoke 使用 `--no-bundle` 分支,不读远端版本、不改版本、不生成清单。
|
||||
- 发布入口只解析一次目标,优先级为 CLI `--target value` / `--target=value` / `-t value`、`AGC_BUILD_TARGET`、Windows 默认值;重复/空目标与不支持目标失败关闭。版本高水位、构建 feature/渠道端点、bundle 路径、产物后缀、清单平台键及摘要必须消费同一个发布上下文,不能分别回读默认目标。
|
||||
- 渠道由 `AGC_UPDATE_CHANNEL` 显式指定,默认 dev;Windows 与 macOS 目标均支持 dev、release 和自定义渠道,目标校验独立进行。
|
||||
- 渠道 `--config` 在 Tauri 构建前最后合并,同时注入 `productName`、`identifier`、updater 端点与窗口标题:安装身份与更新端点必须来自同一个渠道,不能各自回读默认值。macOS 发布入口构建 `*.app`、updater 归档与 DMG 前先按发布渠道解析产品名,产物名一律派生而不写死。
|
||||
- 渠道 `--config` 在 Tauri 构建前最后合并,同时注入 `productName`、`identifier`、`mainBinaryName`、updater 端点与窗口标题:安装身份与更新端点必须来自同一个渠道,不能各自回读默认值。macOS 发布入口构建 `*.app`、updater 归档与 DMG 前先按发布渠道解析产品名,产物名一律派生而不写死。
|
||||
- 渠道配置走 Tauri 的 JSON Merge Patch 语义:对象递归合并,**数组整体替换**。因此 `app.windows` 必须按基线 `tauri.conf.json` 的完整 client 窗口对象下发、只覆盖 `title`(脚本从基线读取后展开);任何"只写 `{ title }`"的写法都会让 `label` / `decorations` / 尺寸回落成 Tauri 默认值(`label=main`、`decorations=true`、800x600),表现为打包产物重新出现系统标题栏,并按 label 连带失效承载平台 HTTP 权限等 capability。守卫用例:`build-release.test.mjs` 的渠道配置合并用例与 `check-config.mjs` 的 `decorations` 门禁。
|
||||
- 定时调度分别判断服务端与客户端 scope:dev 小时调度在提交含 AGC 相关路径时发布对应渠道,纯文档或流水线自身的提交仍只跑 Full Build;release 每日调度在服务端相关路径变化时发布正式 Full Build,在 AGC 相关路径变化时发布 release 客户端,并在同一调度内等待、汇总各 lane 结果,失败 lane 下一轮补发。判定失败或勾选强制触发时按"需要发布"处理。
|
||||
- 更新摘要不再自动生成:发布脚本不读取提交记录生成 `notes`;只有 `AGC_UPDATE_RELEASE_NOTES` 非空时,才把显式手动文案写入渠道清单和旧协议清单的 `releaseNotes`。未设置时清单不携带更新说明,归档文件 `release-notes.txt` 记录“本次没有可用的更新摘要”。
|
||||
@@ -184,10 +186,11 @@
|
||||
|
||||
| 条款 | 验收方式 | 结果 |
|
||||
| --- | --- | --- |
|
||||
| 渠道身份派生与默认渠道不变 | `node --test apps/ai-game-creator-shell/scripts/build-release.test.mjs` | 通过;`dev` 逐字等于基线 `陶泥儿开发版` / `world.genarrative.ai-game-creator`,`release` 使用 `陶泥儿` 并保持独立 identifier,`beta-2` 派生带后缀的产品名与独立 identifier,非法渠道失败关闭 |
|
||||
| 渠道身份派生与默认渠道不变 | `node --test apps/ai-game-creator-shell/scripts/build-release.test.mjs` | 通过;`dev` 逐字等于基线 `陶泥儿开发版` / `world.genarrative.ai-game-creator` / `genarrative-ai-game-creator-shell`,`release` 使用 `陶泥儿` 并保持独立 identifier 与 `-release` 主程序名,`beta-2` 派生带后缀的产品名、identifier 与主程序名,非法渠道失败关闭 |
|
||||
| 身份与端点同批注入 | 同上的渠道 `--config` 用例 | 通过;`productName` / `identifier` 与 `/<channel>-win|mac/latest.json` 来自同一次解析 |
|
||||
| 渠道产物首装包选择 | 同上的渠道 DMG 夹具用例 | 通过;`陶泥儿_<版本>_aarch64.dmg` 仍按 `<版本>_<架构>.dmg` 唯一匹配 |
|
||||
| 基线配置等于默认渠道身份 | `node apps/ai-game-creator-shell/scripts/check-config.mjs` | 通过;基线漂移与非默认渠道身份不隔离都会失败关闭 |
|
||||
| Windows 更新进程与快捷方式隔离 | `build-release.test.mjs` 渠道配置/NSIS 钩子用例 | 通过;dev/release 主程序文件名不同,release 迁移旧 `陶泥儿 Release` 安装目录与快捷方式 |
|
||||
| 全量发布脚本回归 | `node --test build-release.test.mjs release-oss.test.mjs prepare-macos-codex.test.mjs cargo-features.test.mjs` | 通过(64/64,含 macOS 入口按渠道解析产品名的守卫) |
|
||||
| AGC 自有 AppData 提权 ACL 范围 | `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` 与相似前缀 `-backup` 的反向断言) |
|
||||
| 渠道身份进入真实构建产物 | `AGC_UPDATE_CHANNEL=release npm --prefix apps/ai-game-creator-shell run build -- --no-bundle --debug` | 通过;Tauri 接受 `productName=陶泥儿` / `identifier=world.genarrative.ai-game-creator.release` 并完成构建;产物字符串实测 `陶泥儿` × 1、`agc/release-win/latest.json` × 1、`world.genarrative.ai-game-creator.release` × 1、`agc/dev-win/latest.json` × 0 |
|
||||
|
||||
Reference in New Issue
Block a user