Merge branch 'master' into fix/chat-status-lost
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust smoke (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled

This commit is contained in:
2026-09-18 00:31:44 +08:00
83 changed files with 6505 additions and 738 deletions
@@ -82,6 +82,7 @@
- 上一条的两个键不能合成单一 `darwin-universal` 键:更新插件按运行时实际架构解析清单键(Apple Silicon 命中 `darwin-aarch64`Intel 命中 `darwin-x86_64`),不存在自动命中 `darwin-universal` 的情形。将来真要单独发该键,必须在客户端同时设置自定义 target,否则清单里这一项永远不会被读取。
- 构建期要求:打开 `bundle.createUpdaterArtifacts` 以生成 `.sig`;构建环境提供签名私钥与密码(私钥内容不得入库);公钥写入客户端配置。公钥在首个带更新能力的版本发布后不可更换,更换等于放弃自动更新(只能手动重装)。
- 版本递增按渠道独立进行:发布脚本读取该渠道远端 `latest.json``version`,与本地版本取较高者递增 patch;两个渠道的版本号互不影响。
- 版本高水位:发布脚本取「渠道清单版本」与「旧协议迁移指针版本」(迁移窗口内)中的较大值再递增。只看渠道清单会在渠道启用初期把版本链改小 —— 2026-09-17 首次渠道发布即把旧指针的 0.1.57 退回 0.1.48,随后以显式 0.1.60 纠偏;迁移窗口结束(旧指针 404)后自动只剩渠道清单,`dev-mac` 不参与旧指针比较。
- 迁移(旧协议 → 渠道清单):
- 迁移起点:已发布客户端(含当前线上版本)内置自研清单地址 `agc/latest.json`(sha256 格式),下载与安装由自研 Rust 命令完成。
- 迁移策略见「未决问题与决策」。迁移完成后,自研清单解析、下载命令、下载进度事件以及为此放行的 CSP / HTTP 白名单条目按「四不写」整条删除,不留兼容分支与墓碑说明。
@@ -90,6 +91,9 @@
- 发布入口:`npm run ai-game-creator-shell:release:upload`(构建 + 按渠道上传);仅构建不发布的 smoke 使用 `--no-bundle` 分支,不读远端版本、不改版本、不生成清单。
- 渠道由构建参数显式指定,并按目标平台校验:Windows 目标只允许 `dev-win`macOS 目标只允许 `dev-mac`;未显式指定时按目标平台取默认渠道。
- 定时调度只在本轮到达的提交包含 AGC 相关路径(客户端、共享包、`server-rs/crates`、AGC 插件、桌面壳图标、根依赖清单)时才触发渠道发布;纯文档或流水线自身的提交只跑 Full Build,不推高客户端版本号。判定失败或勾选强制触发时按"需要发布"处理。
- 更新摘要自动生成:发布脚本用渠道清单里的 `commit` 字段(上一次发布的提交)到本次提交之间、且只覆盖客户端相关路径的提交列表生成 `notes`(每条 `- 提交标题(短 SHA`,最多 12 条、主题 80 字、整体 900 字,超出折叠或截断),同时写入旧协议清单的 `releaseNotes` 和归档文件 `release-notes.txt``AGC_UPDATE_RELEASE_NOTES` 非空时以手动文案为准;无法判定起点(缺少上次 `commit` 或本地没有该提交)时不写摘要。清单缺少 `commit` 时回退用上一次成功构建的 `COMMIT_HASH`CI 通过 `AGC_UPDATE_PREVIOUS_COMMIT` 传入)作为锚点,因此首次启用摘要或更换渠道后也能立即产出摘要。锚点仍不可得(清单读取失败或没有 CI 锚点)时降级为「最近客户端改动」列表并注明可能与上一版重复 —— 摘要属于附注,任何情况下都不允许因为它让发布失败。
- 清单里的 `commit` 是非标准字段:更新插件忽略未知字段,发布脚本用它定位下一次摘要的起点。
- 上传:安装包与 `.sig` 上传到 `agc/<channel>/<version>/`,清单以 `--force` 覆盖上传到 `agc/<channel>/latest.json`,保证 latest 指针与清单内 URL 指向已存在的对象。
- Jenkins 流水线需要新增渠道参数与签名凭据;签名私钥与密码只以受保护凭据注入当前进程,不写入 workspace、日志或归档产物。
- 归档证据:安装包、`.sig`、渠道清单与源码 commit。
@@ -98,24 +102,26 @@
已获得的证据:
| 条款 | 验收方式 | 证据 |
| -------------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| 渠道与端点映射、渠道校验 | `node --test apps/ai-game-creator-shell/scripts/build-release.test.mjs` | 通过(默认渠道、错配失败关闭、未知渠道失败关闭) |
| universal 包挂两个平台键 | 同上 + 本地发布烟测(伪造 bundle) | 通过(两键同 URL 同签名,不生成迁移清单) |
| 缺签名时失败关闭 | 同上 | 通过 |
| 开发态不检查更新 | `vitest run apps/ai-game-creator-shell/tests/appUpdate.test.ts` | 通过(开关关闭时不请求清单) |
| 旧自研链路整条删除 | 代码检索无残留命令、事件与白名单条目 | 通过(`download_agc_update` / 下载事件 / 清单常量均无残留) |
| 清单与对象布局符合渠道约定 | `Genarrative-Agc-Windows-Build` #682026-09-17SUCCESS | 通过:`agc/dev-win/latest.json` = 0.1.48 + `windows-x86_64``agc/dev-win/0.1.48/陶泥儿_0.1.48_x64-setup.exe` 与同名 `.sig` 公网可读 |
| 清单签名与签名对象一致 | 取回 `.sig` 对象与渠道清单 `signature` 比对 | 通过(逐字相同,420 字节) |
| 安装包与清单登记一致 | 下载安装包实算 SHA-256 与尺寸后与迁移桥清单比对 | 通过(size `104678031`、sha256 `1f67…4fd0` 一致) |
| 旧协议迁移桥 | 公网读取 `agc/latest.json` | 通过(0.1.48`downloadUrl` 指向同一对象,含 `sha256` / `size`) |
| 条款 | 验收方式 | 证据 |
| ---------------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| 渠道与端点映射、渠道校验 | `node --test apps/ai-game-creator-shell/scripts/build-release.test.mjs` | 通过(默认渠道、错配失败关闭、未知渠道失败关闭) |
| universal 包挂两个平台键 | 同上 + 本地发布烟测(伪造 bundle) | 通过(两键同 URL 同签名,不生成迁移清单) |
| 缺签名时失败关闭 | 同上 | 通过 |
| 开发态不检查更新 | `vitest run apps/ai-game-creator-shell/tests/appUpdate.test.ts` | 通过(开关关闭时不请求清单) |
| 旧自研链路整条删除 | 代码检索无残留命令、事件与白名单条目 | 通过(`download_agc_update` / 下载事件 / 清单常量均无残留) |
| 清单与对象布局符合渠道约定 | `Genarrative-Agc-Windows-Build` #682026-09-17SUCCESS | 通过:`agc/dev-win/latest.json` = 0.1.48 + `windows-x86_64``agc/dev-win/0.1.48/陶泥儿_0.1.48_x64-setup.exe` 与同名 `.sig` 公网可读 |
| 清单签名与签名对象一致 | 取回 `.sig` 对象与渠道清单 `signature` 比对 | 通过(逐字相同,420 字节) |
| 安装包与清单登记一致 | 下载安装包实算 SHA-256 与尺寸后与迁移桥清单比对 | 通过(size `104678031`、sha256 `1f67…4fd0` 一致) |
| 旧协议迁移桥 | 公网读取 `agc/latest.json` | 通过(0.1.48`downloadUrl` 指向同一对象,含 `sha256` / `size`) |
| 真实更新闭环(含升级后重启) | 0.1.47 客户端按提示下载安装并重启 | 通过(2026-09-17 用户实测:提示 → 下载 → 安装 → 关于页显示新版本,再次检查为已是最新) |
| 更新摘要端到端展示 | 公网读取渠道清单 `notes` 与客户端更新提示 | 通过(2026-09-17 用户实测:0.1.62 清单带 8 条自动摘要,客户端提示正常显示多行内容) |
待执行证据(首次渠道发布后回填):
| 条款 | 验收方式 | 证据 |
| ---------------------------- | --------------------------------------------------------------------- | ------ |
| 真实更新闭环(含升级后重启) | 0.1.47 客户端升级到新版本,再启动不再提示;`npm run agc` 仍无更新入口 | 待执行 |
| 签名校验失败拒绝安装 | 篡改渠道清单 `signature` 后观察客户端拒绝安装的表现 | 待执行 |
| 条款 | 验收方式 | 证据 |
| -------------------- | --------------------------------------------------- | ------ |
| 签名校验失败拒绝安装 | 篡改渠道清单 `signature` 后观察客户端拒绝安装的表现 | 待执行 |
| 签名校验失败拒绝安装 | 篡改渠道清单 `signature` 后观察客户端拒绝安装的表现 | 待执行 |
## 未决问题与决策
@@ -61,10 +61,25 @@ OpenAPI 与客户端工具的对外说明只描述模式用途、参数约束和
}
```
客户端保留旧参数调用;新字段不填时不改变旧调用语义。客户端不读取图片、不自动选色、不把 `auto` 改写为具体颜色,使用原有 Bearer 认证、幂等键和队列返回模型
客户端保留旧参数调用;新字段不填时不改变模式语义。客户端不自动选色、不把 `auto` 改写为具体颜色;源资源校验、认证、异步任务查询、结果下载和本地登记由客户端负责
工具 schema、桥接参数校验和随包 `agc-client-projection` Skill/契约说明必须保持一致。模式与颜色属于请求意图,必须参与客户端幂等指纹;同一图片与名称的不同模式不能复用同一次请求。缺省 complex 且没有颜色时保留既有指纹。主站在默认值归一化之前计算 External 请求指纹,缺失的新字段不序列化,避免旧请求重放发生冲突。
客户端提交前建立的本地项目绑定会返回主站远端 `projectId``assetFolderId`,抠图请求必须使用这两个远端身份;本地 manifest `projectId` 仅用于绑定和本地状态,不能直接提交给主站。
### 本地结果与恢复合同
`agc_remove_background` 复用本地资源编辑账本,类型为 `background-removal`。源图片保持不变,抠图结果作为新资源写入项目。模式和背景色随账本持久化并参与请求指纹,其它编辑类型的历史指纹保持不变。
1. 客户端建立源图片的正式资源绑定,在提交前保存 operation、幂等键和请求意图。普通登录态提交 `/api/editor/images/background-removals`,从 `data.queueState.operationId` 读取受理身份;开发者模式提交 External v1 对应路由,从 `data.operationId` 读取身份。
2. 受理后持续查询账号路由 `/api/runtime/external-generation/jobs/{operationId}` 或 External v1 对应状态路由。`queued``running` 只描述远端返回状态;固定进度值、本地文件缺失或 pending 清单为空均不能证明 BgFilter 排队。
3. 远端 completed 后按稳定资源身份换取有效下载 URL,校验结果为带 alpha 通道的有效 PNG,随后复用 staging、manifest 和 revision 提交。只在本地登记完成后向 Agent 返回 `completed``operationId``resource.localAssetId`、相对路径和安全告警,不暴露临时 URL 或凭据。
4. 轮询中断、超时或下载失败保留已受理 operation;`agc_list_registered_assets.pendingOperations` 与客户端恢复面板可见。相同源资源、结果名称、模式和颜色的后续调用优先恢复同一任务,不再次提交。不同账号不能恢复原账号任务;切回原账号后按既有恢复规则续接。
5. 远端 failed 明确失败;提交响应不确定且无法确认 operation 时进入人工对账状态,不自动换键重发。失败/未知均不得伪造透明图或自动切换本地抠图方式。
6. 升级前仅返回 queued、没有本地账本的任务不自动迁移;已有远端结果须通过正式资源查询和导入恢复,不据旧回执重新发起付费请求。
本修复只扩展 AGC 客户端现有工作流,不修改主站队列、BgFilter 或 SpacetimeDB schema。验收覆盖账号与开发者两种响应封装、queued/running/completed、已受理中断恢复不重复 POST、远端失败不登记结果,以及既有资源编辑回归。
## 实施任务
### 任务一:冻结 BgFilter 契约
@@ -93,6 +108,13 @@ OpenAPI 与客户端工具的对外说明只描述模式用途、参数约束和
## 验收证据
2026-09-17 客户端闭环验证:
- `cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --bin genarrative-ai-game-creator-shell project::resource_editor:: -- --test-threads=1` 通过。新增 HTTP fixture 覆盖开发者 queued/running/completed、账号 HTTP 200 queueState 与 `data.job`、换签下载、PNG alpha 校验、原图保留和新资源提交。
- 已受理任务的首次轮询失败后,pending 保留模式与颜色;恢复只查询原 operation,整个流程只 POST 一次,成功后清除 pending。远端 failed 不新增结果资源。既有账号隔离、提交原子性和崩溃恢复用例通过。
- `cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --bin genarrative-ai-game-creator-shell agent::direct_tool_bridge::tests -- --test-threads=1`、AGC 类型检查、技能包校验、Rust 格式、编码、文档索引与 diff 检查通过。
- 本轮未运行真实登录客户端 → 本地主站 → BgFilter 的端到端 smoke;当前本地后端已停止,自动化证据使用模拟 HTTP 服务。此前 BgFilter 成功日志只证明上游处理完成,不证明主站结果持久化或客户端导入成功。
2026-09-16 实测:
- 主站 `cargo test -p api-server background_removal`:36 项通过,覆盖非法请求入队前拒绝、缺省 complex、队列参数保留、旧请求指纹、父侧内部 RPC 和 provider multipart。
@@ -12,6 +12,10 @@
## 资源画布交互与工作台状态同步
- 未完成抠图的恢复项在现有类型行显示账本中的复杂/平面背景模式;平面模式显示已记录的自动背景色或颜色值,缺失模式/颜色不补默认值,恢复仍按原 operation 身份执行。
- 活动回合初始空快照、首次成功读取的空结果及禁用后的空态保持同一数组引用;快照签名初值与空态重置值均为 `[]`。无原生 invoke 的窗口测试只期待首次状态发布,异步空结果测试显式控制请求完成,不以初始空数组作为请求已完成的证据。
- 活动回合轮询的初始空快照与后续空结果保持同一引用;停用或切换读取器使旧请求失效,晚到快照不得恢复已停用的活动回合或覆盖新轮询结果。无原生读取器时窗口只发布一次空状态,不通过额外空数组触发重复发布。
- 工作台向窗口标题栏发布正在运行的项目时,输入未变化不得形成重复发布与清理的渲染循环;打开项目动作始终使用当前工作台处理逻辑,退出工作台后清除其标题栏状态。
- 资源子画布(含「所有资源」)保留空白处左键框选、资源卡左键选中/拖动、触摸板双指平移及捏合缩放;右键按住空白处或资源卡拖动时平移画布,不改变资源选择与布局。中键和空格抓手继续可用。总览保留既有左键平移,并支持右键平移。
- 画布接管的右键手势不弹出原生菜单;输入框、媒体操作、工具条和独立浮层不被画布抢占。指针取消、捕获丢失或窗口失焦后终止平移,不能继续跟随指针。
@@ -21,6 +25,8 @@
## 资源卡选中工具栏与导出
- AGC 选中工具栏按既有动作顺序最多直接显示前 5 项(不计分隔线),剩余动作进入「更多」。悬停、点击及键盘均可展开独立纵向浮层,优先向上展开,窗口顶边空间不足时向下避让;浮层限制在窗口内,超高时自行滚动,不带动画布。动作执行、点击外部、Escape 或换选资源后关闭;禁用状态和原处理链路保持不变。Web 美术画布默认不折叠。
- 「素材类型」与「信息」不占工具栏名额,改为资源卡右上角的类型标签和信息圆钮,与 Web 美术画布共用卡片控件。未选中卡片可直接打开信息;类型入口仅对 manifest 资产可用。控件不触发卡片拖拽或多选,信息面板仍复用运行页签的字段。
- 共享选中工具栏按实际显示的快速编辑、编辑动作、改造、导出与宿主动作组生成分隔线;空组不产生分隔线,不依赖宿主 CSS 隐藏重复线。
- AGC 所有具有本地文件路径的素材都显示带文字的「导出」按钮,位于工具栏末组的「删除素材」之前,两者之间不插入分隔线;「重命名」继续保留在前面的常规动作组。工具栏宽度上限为 `min(92vw, 800px)`,窄屏仍可横向滚动。图片、视频、音频、动画、UI、文档及其它文件共用 `isResourceCanvasExportable`,不按媒体类型限制导出;无文件路径及虚拟项目版本不提供文件导出入口。
- 导出继续复用 `saveProjectResourcesToDisk`:原生保存对话框选择路径,`save_local_project_asset_file` 复制原始文件字节,不转图片、不重编码、不另建 IPC。后端继续校验源文件、敏感路径和目标路径;取消不写文件,失败通过工作台提示。
@@ -148,7 +154,7 @@ npm 游戏的可预览产物固定为对应 package 目录下的 `dist/index.htm
- 素材读取区分三类来源:`asset.list` / `agc_list_registered_assets` 是当前项目本地 manifest`agc_list_project_files` / `file.list` 只发现项目目录中实际存在但可能未登记的文件,`asset.library.list` 是当前登录账号素材库,项目画布资源读取是当前网页项目/画布的完整图片清单;账户素材库不能替代项目画布清单。
- Agent 只接收稳定素材 ID、类型、尺寸和项目相对路径等安全投影。客户端负责重新校验账号/项目归属、换签下载、媒体校验,以及 manifest/画布原子登记;不得向 Agent 暴露绝对路径、签名 URL、objectKey、token 或 Cookie。
- `canvas.asset_import` 支持账户/画布资源 ID 和项目内本地相对路径。项目文件发现结果以 `assetImportable` 明确区分当前可登记的已识别图片、字体、音频、视频、文档代码文件与其它文件;Agent 只能提交前者。导入拒绝路径穿越、`.agent`、符号链接/reparse point 及敏感配置文件;外部宿主文件须由 UI 原生文件选择器授权后导入,不开放任意绝对路径。
- `canvas.asset_import` 支持账户/画布资源 ID 和项目内本地相对路径。项目文件发现结果以 `assetImportable` 明确区分当前可登记的已识别图片、字体、音频、视频、文档代码与**引擎资源**Cocos Creator 的模型、动画、场景/预制体、材质/特效、图集与压缩纹理容器)与其它文件;Agent 只能提交前者。引擎资源在资源画布上是**只读预览**:模型出缩略图、序列化资源出结构摘要、客户端解不了的容器出类型卡,不承接编辑与派生;`.meta``library/``temp/` 等引擎生成物仍然只可发现、不可登记。导入拒绝路径穿越、`.agent`、符号链接/reparse point 及敏感配置文件;外部宿主文件须由 UI 原生文件选择器授权后导入,不开放任意绝对路径。
- Runtime `asset.list``file.list` 的详情使用文件上下文上限,而不是普通工具短摘要上限,确保有界候选/目录清单不会因前部内容较长而整体丢失;`asset.list` 超出 48 项或 `file.list` 超出 40 项时仍显式返回剩余数量,Agent 再按候选父目录(例如 `assets``game/assets`)缩小范围查询。
- 结果仅返回成功/跳过/失败数量、安全 ID、相对路径、来源、脱敏失败摘要和实际 `revisionAdvanceCount`;幂等跳过不得虚增 revision,部分失败仍须准确记录已发生的 revision 变化。
- 普通 Prompt 上下文与错误诊断必须使用分离的脱敏边界:Prompt 继续对疑似凭据行整体隐藏;错误诊断保留 HTTP 状态以及 `code / field / message / reason / detail` 等安全字段,仅替换 Token、Cookie、私钥、配置名、URL 和宿主路径等敏感值。`agc_create_or_derive_resource.assetName` 是必填的人类可读资源显示名称,不接受项目路径、URL、objectKey、Token 或其它凭据。
@@ -160,7 +166,7 @@ npm 游戏的可预览产物固定为对应 package 目录下的 `dist/index.htm
- 项目路径、projectId、当前 revision、源文件路径与媒体类型、operationId、Idempotency-Key、登录态、项目锁、付费提交、轮询恢复、下载校验与 manifest 事务全部由客户端持有。模型不能提交或覆盖这些字段。同一 Direct `clientTurnId + 规范语义参数` 生成稳定 UUID v4 身份;单回合同参重试复用原 operation,不同请求串行且最多四项。跨回合存在完全匹配的 pending 账本时优先恢复原 operation,不能换键重发。
- 资源查询同时投影未完成 operation 的安全状态。媒体工具成功只返回 operation、本地相对路径、资源类型、Canvas/resource/asset/task 身份、正式序列帧以及脱敏后的 `warnings / sliceWarnings`;错误继续使用统一脱敏边界。客户端资源账本持久化 completed 结果的两类告警,committed replay 不能把历史告警伪装成空集合。
- 角色动画、视频、音效和背景音乐在构造新的远端请求前统一准备当前项目同名画布与素材目录上下文,并在端点支持时携带 `projectId / assetFolderId / canvasCompletion`。角色动画 placeholder 使用源图片真实宽高,避免非方形角色进入画布时失真;正式 resource/asset 与序列帧继续直接复用 External 返回身份,不从首帧伪造重复资源。已有冻结 request body 或已受理 operation 保持不变,不因本次升级重建请求或重复扣费。
- 抠图通过新增 `agc_remove_background` 语义工具开放:模型只提交当前 manifest 的图片 `sourceLocalAssetId` 与结果名称;客户端解析稳定 `resourceId`,准备同名画布/素材目录并生成稳定 operation/idempotency 身份,调用 External v1 `/api/external/v1/editor/images/background-removals` 后只返回有界队列状态。抠图服务仍由客户端和服务端负责源校验、BgFilter、素材登记与画布事务,Codex 不获得内部 worker、凭据或任意 API 调用权。
- 抠图通过新增 `agc_remove_background` 语义工具开放:模型只提交当前 manifest 的图片 `sourceLocalAssetId` 与结果名称;客户端解析稳定 `resourceId`,准备同名画布/素材目录并生成稳定 operation/idempotency 身份。普通登录态使用账号鉴权的 `/api/editor/images/background-removals`ExternalDeveloper 模式使用 External v1 `/api/external/v1/editor/images/background-removals`;客户端接收异步受理后轮询任务状态,下载完成媒体并登记到本地 manifest,未知结果保留同一 operation 供恢复。抠图服务仍由客户端和服务端负责源校验、BgFilter、素材登记与画布事务,Codex 不获得内部 worker、凭据或任意 API 调用权。
## 2026-08-23 AGC 资源生成补齐(视频 / 动画 / 音效 / 背景音乐)