Compare commits

..

85 Commits

Author SHA1 Message Date
k88936 5383af4cc5 Merge pull request 'refactor/整理现有的string-typed资源类型' (#388) from feat/agc-organize-assetkind into master
Project CI / AI game creator shell Rust shard 4/4 (push) Successful in 7m7s
Project CI / AI game creator shell Rust shard 3/4 (push) Successful in 7m13s
Project CI / AI game creator shell Rust shard 1/4 (push) Successful in 7m19s
Project CI / AI game creator shell Rust shard 2/4 (push) Successful in 8m1s
Project CI / AI game creator shell Rust crates (push) Successful in 1m17s
Project CI / AI game creator shell Rust smoke (push) Successful in 1m53s
Project CI / Repository checks (push) Successful in 4m49s
Project CI / Frontend tests (push) Successful in 5m47s
Project CI / Backend tests (push) Successful in 7m37s
Project CI / Native shell tests (push) Successful in 8m4s
Project CI / AI game creator shell web tests (push) Successful in 3m3s
Reviewed-on: #388
2026-09-19 03:51:32 +08:00
k88936 47f7cb2bf1 修复 AGC 前端资源 kind 判据与用例的 canonical 残留
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 7m1s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 7m6s
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 7m14s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 7m52s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 1m31s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m50s
Project CI / Repository checks (pull_request) Successful in 4m44s
Project CI / Frontend tests (pull_request) Successful in 6m20s
Project CI / Backend tests (pull_request) Successful in 8m27s
Project CI / Native shell tests (pull_request) Successful in 8m15s
Project CI / AI game creator shell web tests (pull_request) Successful in 3m10s
- resource-canvas/resourceCanvasAssetGenerationReferenceModel.ts:「图集不接受用户参考」判据改用 canonical icon-spritesheet,删除残留平台词的字符串清单。
- view/project-development/index.tsx:美术摘要的图片产出判据显式排除 ui-design,候选 UI 原型图不再顶掉「仅完成计划」。
- tests/appSurface/project-development.suite.ts:generateCall 支持按素材名定位,规范 / 图集 / UI 设计图入口断言改用 canonical kind。
- tests/appSurface/project-assets.suite.ts:/asset-register 与开发面板用例改用 canonical kind,面板默认值按 unknown 断言。
- tests/resourceCanvasAssetGenerationReferences.test.tsx:夹具与提交断言改用 icon-spritesheet / ui-design。
- docs/technical/【AGC】栏目画布底部工具栏入口矩阵-2026-09-13.md:载荷表与规范通道说明改用 canonical kind,并写明平台请求词汇只留在 source.generationKind。
- docs/project-memory/shared-memory/pitfalls.md:记录前端 kind 判据与 fixture 必须一起按 canonical 成员重写。
2026-09-19 03:21:37 +08:00
k88936 603650fbf4 修复 AGC 资源 kind 收敛后的 Rust 默认值与工具栏用例
- agent/runtime_tools/media.rs:asset_kind 只在入参未声明(空白)时落通道默认值,显式认不出的值保持 Unknown 交给下游失败关闭。
- tests/project.rs:规范图 / 图集用例的入参改传 canonical kind(icon-spec / icon-spritesheet),用例名与断言同步。
2026-09-19 03:21:25 +08:00
k88936 5d20f5bfeb 修复 AGC 资源 kind 枚举化后的编译与字符串回退
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Failing after 7m9s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Failing after 7m20s
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Failing after 7m24s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 8m10s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 1m39s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m54s
Project CI / Repository checks (pull_request) Failing after 4m43s
Project CI / Frontend tests (pull_request) Failing after 4m51s
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
- canvas_generation:参考素材合同四个 helper 改收 GameCreationAppAssetKind,删除 ui-prototype/game-background/art-spritesheet 字符串比较

- direct_runtime:删除 game-background / art-spritesheet 的参考合同字符串映射,直接传枚举

- resource_editor:音效/BGM 编辑类型判据改为比较 ResourceEditSourceKind::Manifest(BackgroundMusic),不再拼字符串 haystack

- assets/commands:画板导入 kind 解析上移到 Tauri 命令边界,import_canvas_asset_at 只接收枚举

- 测试与批量标签脚手架:kind 参数由字符串改为 GameCreationAppAssetKind,恢复编译期穷举保护

- 技术方案:登记边界同口径改为描述命令边界解析
2026-09-19 02:38:30 +08:00
k88936 af38de9fd1 Merge remote-tracking branch 'origin/master' into feat/agc-organize-assetkind
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Failing after 3m23s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Failing after 3m1s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Failing after 2m41s
Project CI / AI game creator shell Rust smoke (pull_request) Failing after 2m20s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Failing after 2m38s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 3m25s
Project CI / AI game creator shell web tests (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
2026-09-19 01:54:10 +08:00
k88936 18252e24b8 合并主线并保留资源kind枚举收口
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Has been cancelled
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 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
合并 origin/master 的 AGC 画布参考与项目能力更新

解决 canvas 生成恢复与任务模型冲突并继续使用共享 GameCreationAppAssetKind

保留 run_id、generationKind 与外部协议字符串的独立边界
2026-09-19 01:50:09 +08:00
lhk229 1ce2c10107 删除客户端每回合四项媒体资源请求上限 (#427)
Project CI / AI game creator shell Rust shard 3/4 (push) Successful in 7m10s
Project CI / AI game creator shell Rust shard 1/4 (push) Successful in 7m28s
Project CI / AI game creator shell Rust shard 4/4 (push) Successful in 7m32s
Project CI / AI game creator shell Rust shard 2/4 (push) Successful in 7m48s
Project CI / AI game creator shell Rust smoke (push) Successful in 2m1s
Project CI / AI game creator shell Rust crates (push) Successful in 1m58s
Project CI / Repository checks (push) Successful in 5m46s
Project CI / Frontend tests (push) Successful in 7m8s
Project CI / Backend tests (push) Successful in 9m19s
Project CI / Native shell tests (push) Successful in 9m42s
Project CI / AI game creator shell web tests (push) Successful in 5m5s
- direct_tool_bridge.rs 删除 DIRECT_TOOL_BRIDGE_MAX_RESOURCE_CALLS_PER_TURN 常量、回合授权状态的 resource_request_ids 计数 map 与 resource_request_ids() 方法
- agc_create_or_derive_resource(含 agc_edit_image 委托)与 agc_remove_background 统一按回合身份与请求指纹确定性派生 operation/idempotency id,同指纹重试复用与 pending 对账语义不变
- 付费提交串行仍由 resource_generation_gate 互斥保证,成本控制交由服务端计费与泥点余额兜底
- 决策记录新增 2026-09-19 删除上限条目,2026-09-18 抠图豁免条目标记为仅作追溯
- 实施计划文档同步改为「不同请求串行提交,不设每回合计数上限」

Reviewed-on: #427
Co-authored-by: Linghong <ink29535@proton.me>
Co-committed-by: Linghong <ink29535@proton.me>
2026-09-19 01:44:48 +08:00
k88936 48caa23997 收紧AGC资源kind枚举边界
canvas生成与运行时统一使用共享GameCreationAppAssetKind

删除平台kind兼容映射与退役kind拒绝测试

更新资源kind审计里程碑与绑定文档
2026-09-19 01:28:27 +08:00
lhk229 ea141d9f17 修复持久目标模式切换测试的异步竞态
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
Project CI / AI game creator shell Rust shard 1/4 (push) Successful in 5m11s
Project CI / AI game creator shell Rust shard 3/4 (push) Successful in 5m4s
Project CI / AI game creator shell Rust shard 2/4 (push) Successful in 5m50s
Project CI / AI game creator shell Rust smoke (push) Successful in 1m59s
Project CI / AI game creator shell Rust crates (push) Successful in 2m28s
Project CI / AI game creator shell Rust shard 4/4 (push) Successful in 4m37s
Project CI / Backend tests (push) Has been cancelled
Project CI / Native shell tests (push) Has been cancelled
Project CI / Frontend tests (push) Has been cancelled
Project CI / AI game creator shell web tests (push) Has been cancelled
Project CI / Repository checks (push) Has been cancelled
- developer-agent-window.suite.ts 在切换目标模式前等待按钮脱离 disabled,避免读取历史链路在途时点击落空导致 aria-pressed 断言偶发失败
2026-09-19 01:21:05 +08:00
lhk229 769740a46d Merge pull request '取消抠图工具的每回合四项媒体请求限制' (#426) from codex/remove-bg-turn-limit into master
Project CI / AI game creator shell Rust shard 3/4 (push) Successful in 6m56s
Project CI / AI game creator shell Rust shard 1/4 (push) Successful in 7m15s
Project CI / AI game creator shell Rust shard 2/4 (push) Successful in 7m24s
Project CI / AI game creator shell Rust shard 4/4 (push) Successful in 7m21s
Project CI / AI game creator shell Rust smoke (push) Successful in 2m25s
Project CI / AI game creator shell Rust crates (push) Successful in 2m55s
Project CI / Repository checks (push) Successful in 15m5s
Project CI / Backend tests (push) Successful in 18m40s
Project CI / Native shell tests (push) Successful in 20m39s
Project CI / Frontend tests (push) Failing after 19m35s
Project CI / AI game creator shell web tests (push) Successful in 13m6s
Reviewed-on: #426
2026-09-19 00:29:51 +08:00
lhk229 b472b9eec9 取消抠图工具的每回合四项媒体请求限制
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
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 shard 1/4 (pull_request) Has been cancelled
agc_remove_background 不再经过 resource_request_ids 付费计数,直接按回合身份与请求指纹确定性派生 id

抠图请求不再挤占付费 create/derive 的四项额度,幂等复用与 pending 对账语义不变

create_or_derive(含 agc_edit_image 委托)路径逐字节不变

决策记录补充 2026-09-18 抠图豁免条目

实施计划文档同步注明抠图不占四项额度
2026-09-19 00:14:01 +08:00
k88936 0d5940433d 删除资源 kind 兼容白名单
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 4m4s
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
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Has been cancelled
服务端图片快速编辑改用共享枚举静态图片判定

移除退役 kind 的兼容放行与冗余回归测试

清理客户端恒假 art-spritesheet 判断并统一远端 kind 解析

同步 AGC kind 里程碑、实施计划与决策记录
2026-09-18 17:09:36 +08:00
k88936 e5fd454bb3 收紧 AGC 资源 kind 类型边界并统一族判据
- 将 manifest 与本地导入回执的资源 kind 改为 ts-rs 生成绑定

- 集中音频与视觉资源族判据并复用 Rust 枚举方法

- 放宽 Unknown 未解析语义并清理上传类型墓碑注释

- 标记共享生成绑定并同步项目决策与实施计划
2026-09-18 15:21:19 +08:00
k88936 03d7bca9a5 Merge remote-tracking branch 'origin/master' into feat/agc-organize-assetkind
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 6m43s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 6m28s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m18s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 6m5s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m47s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 5m42s
Project CI / Repository checks (pull_request) Successful in 6m2s
Project CI / Frontend tests (pull_request) Successful in 8m48s
Project CI / Native shell tests (pull_request) Successful in 9m37s
Project CI / Backend tests (pull_request) Successful in 10m34s
Project CI / AI game creator shell web tests (pull_request) Successful in 5m29s
2026-09-18 10:43:00 +08:00
k88936 2abad3b537 修复失败测试
测试现在直接从 AGENT_RUNTIME_CANVAS_ASSET_KINDS 派生期望值,避免再次漂移。
2026-09-18 10:42:40 +08:00
k88936 fc5cea43ac Merge remote-tracking branch 'origin/master' into feat/agc-organize-assetkind
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Failing after 5m34s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 5m33s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Failing after 5m47s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m56s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 4m20s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m27s
Project CI / Repository checks (pull_request) Successful in 5m58s
Project CI / Frontend tests (pull_request) Successful in 6m49s
Project CI / Native shell tests (pull_request) Successful in 10m59s
Project CI / Backend tests (pull_request) Successful in 12m9s
Project CI / AI game creator shell web tests (pull_request) Successful in 5m5s
2026-09-18 01:55:16 +08:00
k88936 c2ab9674a0 合并资源编辑与当前主线改动
Project CI / Backend tests (pull_request) Has been cancelled
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 / 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
保留资源 kind 强类型与栅格 subtype 严格校验

合并抠图模式、幂等账本、恢复轮询和 PNG 透明通道校验

修正共享资源枚举在 Cocos 登记与抠图桥接中的类型传递

保留双方模板库、项目快照、发布和 Provider 重试改动
2026-09-18 01:48:13 +08:00
k88936 72cd0747a4 拒绝栅格资源 subtype 静默降级
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
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Has been cancelled
非图片族和未知 sourceSubtype 改为明确报错
补充栅格正规化回归测试并同步规范
2026-09-17 23:06:30 +08:00
k88936 3d4c7929c3 统一画布生成 kind 为共享枚举
工具白名单与 schema 改用 GameCreationAppAssetKind
canonical 输入在生成适配边界映射旧账本值
2026-09-17 22:52:38 +08:00
k88936 8dce016552 修正 manifest kind 留痕去重范围
按 manifest 来源与资产身份去重
避免不同项目相同 ID 互相抑制日志
2026-09-17 19:18:07 +08:00
k88936 64879cfcdd 合并资源规范与画布 JSON 功能
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 7m2s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 7m4s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 7m20s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 7m21s
Project CI / Backend tests (pull_request) Failing after 14s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m52s
Project CI / Repository checks (pull_request) Failing after 11s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 3m5s
Project CI / Frontend tests (pull_request) Failing after 5m26s
Project CI / AI game creator shell web tests (pull_request) Failing after 4m11s
Project CI / Native shell tests (pull_request) Successful in 10m40s
合并 canonical 资源 kind 校验与按类型提示词上限。\n保留 UI JSON 预览识别、严格 UI 文档持久化和画布编辑入口。\n修复合并后 Rust 资源 kind 测试夹具并补齐定向回归用例。
2026-09-17 18:28:19 +08:00
k88936 6853ec5388 资源 kind 严格口径的文档补齐:单一解析入口与登记边界
- docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md:2026-09-17 节改为唯一解析入口 `parse_with_context()`(内部私有 `match_canonical()`,`from_str_lossy` / 公开 `from_str_or_unknown` 均已删除),并新增登记边界同口径、登记内容 kind 必须与内容相符、切片残留判据只看路径、sprite 身份不含展示串、TS 判据只留一份与「严格口径已知代价、不迁移」六条。
- docs/project-memory/shared-memory/decision-log.md:同一节补上单一解析入口、登记边界 kind 口径、判据不许散落、已知代价不补救四条决策,并把验证命令更新为实际跑过的定向用例。
2026-09-17 16:30:25 +08:00
k88936 796ad7bb51 资源 kind 只保留一个公开解析入口
- server-rs/crates/shared-contracts/src/game_creation_app/asset_kind.rs:删掉公开的 `from_str_or_unknown()`(`from_str_lossy` 的残留命名),严格匹配降级为私有 `match_canonical()`;`parse_with_context()` 成为唯一公开解析入口,`FromStr`、serde 与所有边界一律走它,认不出 canonical 值只有这一处收口并留痕。
- server-rs/crates/shared-contracts/src/game_creation_app/asset_kind.rs:词汇表用例改走唯一入口,并断言每个非 canonical 变体都留痕。
- apps/ai-game-creator-shell/src-tauri/src/project/manifest.rs:读侧回捞 legacy kind 时不再调用第二个解析函数,直接用唯一词汇表 `ALL` 判真值(`unknown` 本身是成员,自然跳过)。
2026-09-17 16:27:48 +08:00
k88936 20b34918d3 UI 编辑器桥接用例改回真实成功路径
- apps/ai-game-creator-shell/tests/appSurface/project-development.suite.ts:`ensure_ui_design_resource_for_prototype` 的 mock 从返回 `null` 改为返回真实形状的桥接结果(asset + manifest + committedProjectRevision + created),并新增 `data-resource-view-state === 'resources.ui-editor'` 断言,让用例真的覆盖它名字里的成功路径而不是被组件吞进错误分支。
2026-09-17 16:19:38 +08:00
k88936 04e5512777 UI 编辑器文档资产的 kind + mediaType 判据收敛到共享契约唯一实现
- packages/shared/src/contracts/gameCreationApp.ts:新增 `isGameCreationAppUiDesignDocAsset(asset)`,`kind` 严格解析后再比文档 kind、`mediaType` 比 `application/json`,这是该判据的唯一定义。
- packages/shared/src/contracts/gameCreationApp.test.ts:补用例钉住判据——只满足一半(kind 对 / mediaType 不符、mediaType 对 / kind 不是文档)与 legacy kind(`UI`、`ui`、带空格、大写)一律返回 false。
- apps/ai-game-creator-shell/src/view/project-development/index.tsx:桥接结果校验与「自动打开 ui-workflow 完成资源」两处改用共享判据,删掉本地 kind/mediaType 双条件。
- apps/ai-game-creator-shell/src/features/ui-editor/uiDesignResourceBridge.ts:`findLinkedUiDesignResource` 的过滤条件改用共享判据。
- apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx:缩略图文档分支改用共享判据(原来只看 mediaType,kind 不同也能命中)。
2026-09-17 16:19:26 +08:00
k88936 0510cd8d9c AGC 壳把资源 kind 的登记与解析边界统一到严格口径
- assets.rs:新增 `registration_asset_kind()`,空白入参落中性 `image`、非空认不出严格收口成 `Unknown` 并留痕;`import_canvas_asset_at` 改走该函数。
- commands.rs:`imported_platform_asset_kind` 与 `register_local_asset` 一并委托给 `registration_asset_kind()`,删掉两处各写一遍的 trim/严格解析分支。
- agent/generation/canvas_generation.rs:切片残留登记判据改为只看 `assets/art-spritesheet-slices/` 路径——历史切片刻的 kind 是非 canonical 值,严格解析后收口成 `unknown`,再带 kind 判据会漏掉半成品登记并静默跳过回填;补平台词汇映射用例钉住别名与未映射值落点。
- project/resource_editor.rs:栅格归一化的源 subtype 收口到图片族成员(音频/视频/文档/字体等一律按图片登记),Agent 回执派生物写回 `Document` 而不再主动写 `Unknown`;补派生 kind 用例。
- ui_editor/workflow.rs:新增 `same_sprite_asset_identity()`,比较 sprite 身份时忽略随 kind 派生的 `metadata.asset_type`,避免对既有 State 重跑工作流误报资源冲突。
2026-09-17 16:19:00 +08:00
k88936 7a237431e0 资源 kind 单源与严格口径的文档同步
- docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md:新增 2026-09-17 权威节,写明唯一词汇表、严格解析、app_log! 留痕与生成目录搬家。
- docs/prd/【AI游戏创作】项目开发工作台PRD-2026-07-20.md:删掉「alias 表大小写不敏感」的旧口径,改为严格等值解析 + 原始串留痕,并把跨端守卫改为编译期绑定。
- docs/project-memory/shared-memory/decision-log.md:新增 2026-09-17 条目记录四项决策与验证命令。
- docs/project-memory/shared-memory/pitfalls.md:新增 ts-rs 生成目录搬家后必须同步忽略规则的坑;旧别名表相关条目补上现行口径,避免后人照旧重加别名表。
- docs/project-memory/plans/ / todos/:把 kind-observability、壳内生成目录、已删除的交叉守卫用例等过期描述改成当前口径。
2026-09-17 15:46:58 +08:00
k88936 6ed3772ff5 资源 kind 用例与 fixture 跟随严格口径(非 canonical 值一律停在待归类)
- packages/shared/src/contracts/gameCreationApp.test.ts:新增严格解析用例(认不出的原值 console.warn 留痕、返回 unknown),分类映射与自愈用例改用 canonical ui-design / icon,并断言 kind:'ui' 收口成 unknown 后落 unclassified。
- tests/resourceTypePanel.test.tsx / tests/resourceClassificationPanel.test.tsx:自愈用例的 fixture kind 由 ui 改为 ui-design,让「显示口径 ≠ 落盘口径」这条判据继续真的被验证。
- tests/projectResourceLiveIntegration.test.tsx:fixture kind 改为 ui-design;用例按 canonical UI 设计图带「(待视觉验收)」的标签定位按钮,并把用例名与注释改回真实口径。
- tests/resourceCardPreviewRealManifest.test.ts:真机 61 条资产的取证结论改为严格口径——57 条 ui 与 game-entry 停在待归类,明确栏目只由落盘 category 决定;自愈断言改用 ui-design。
- tests/appSurface/home.suite.ts / project-development.suite.ts:fixture 里的 art-spritesheet / game-background / animation / ui-prototype / ui 改为 canonical icon-spritesheet / scene / character-animation / ui-design / icon。
- tests/projectResourceProjectionModel.test.ts / projectResourceLiveUpdateModel.test.ts:fixture kind 由 game-entry / asset 改为 code / image。
2026-09-17 15:46:43 +08:00
k88936 a86ead93e4 资源登记草稿的推断 kind 收敛到 canonical 词汇
- projectArtifactSummaries.ts:inferProjectFileAssetDraft 的 json 分支由 data 改为 document、判不出扩展名时由 asset 改为 unknown,与 Rust 侧 uploaded_asset_kind 同口径——/asset-register 的 kind 会原样进 register_local_asset 的严格解析,写非 canonical 值只会被判成认不出并留痕。
2026-09-17 15:46:34 +08:00
k88936 b0ce384b8d 前端资源 kind 改为只消费 Rust 生成的 union,删除壳内第二份实现
- packages/shared/src/contracts/gameCreationApp.ts:删除手写 GAME_CREATION_APP_CANONICAL_ASSET_KINDS、GameCreationAppCanonicalAssetKind、GAME_CREATION_APP_LEGACY_ASSET_KINDS 与 canonicalGameCreationAppAssetKind(),改为 re-export ts-rs 生成的 union。
- packages/shared/src/contracts/gameCreationApp.ts:新增穷举 GAME_CREATION_APP_ASSET_KIND_MEMBERS / GAME_CREATION_APP_ASSET_KINDS、isGameCreationAppAssetKind 与严格解析 parseGameCreationAppAssetKind(认不出的原值 console.warn 留痕并返回 unknown)。
- packages/shared/src/contracts/gameCreationApp.ts:分类映射表与 gameCreationAppAssetCategoryForKind 改按生成 union 穷举,unknown 落 unclassified。
- packages/shared/src/contracts/generated/GameCreationAppAssetKind.ts:ts-rs 生成物从壳内私有目录搬到 packages/shared(跨端契约目录)。
- apps/ai-game-creator-shell/src/contracts/assetKind.ts:删除这份壳内重复实现,消费方改从 packages/shared 导入。
- apps/ai-game-creator-shell/src/features/project-workspace/resourceReferences.ts / features/ui-editor/uiDesignResourceBridge.ts / view/project-development/index.tsx:导入点改到 packages/shared 的同一份 parser 与常量。
- apps/ai-game-creator-shell/tests/assetKindCanonicalMapping.test.ts:删除「正则解析 Rust 源码比对两份手写表」的守卫用例,跨语言一致性改由生成 union 在编译期保证。
- .prettierignore / .eslintrc.cjs:忽略规则跟着生成目录一起搬到 packages/shared/src/contracts/generated。
2026-09-17 15:45:24 +08:00
k88936 b56566f40e AGC 壳把资源 kind 留痕接到 app_log! 并把各解析边界统一为严格口径
- main.rs:新增 register_non_canonical_asset_kind_reporter(),把 shared-contracts 的原始串与上下文落到 app_log!,按 (原始串, 上下文) 去重;main() 启动时注册。
- commands.rs:imported_platform_asset_kind 改为直接 parse_with_context,不再先经别名表收口;用例改为断言 UI / ui / mystery / game-art / ui-prototype 等非 canonical 值一律落 unknown。
- assets.rs:画板/上传等用例的 kind 断言改用 GameCreationAppAssetKind::ALL 穷举口径。
- project/manifest.rs:读 manifest 的留痕去重键由「只有原始 kind」改成「原始 kind + 资产身份」,避免第二个写旧值的资产被静默吞掉。
- project/manifest.rs:from_str_lossy 调用点改名 from_str_or_unknown。
- agent/generation/canvas_generation.rs:画板 assetKind 的兜底分支改为 parse_with_context,非 canonical 值留痕收口为 unknown。
- project/version_resource_replacement.rs:subtypeEqual 改为 canonical kind 直接比较,去掉中间归一。
2026-09-17 15:44:02 +08:00
k88936 6782d0ea23 GameCreationApp 资源 kind 词汇表收敛为 Rust 单源并接上可注册留痕回调
- asset_kind.rs:新增声明宏,由一张 kind 表派生出枚举、线上值 as_str、ALL、严格解析与 ts-rs 绑定,仓库里不再有第二份 kind 列表。
- asset_kind.rs:from_str_lossy 改名 from_str_or_unknown 并去掉 trim / lowercase 归一,parse_with_context 只做严格等值匹配,认不出的原值不查别名、不迁移。
- asset_kind.rs:留痕改为可注册回调 set_non_canonical_asset_kind_reporter,把原始串与调用上下文交给壳层日志,未注册时静默。
- game_creation_app.rs:删除手写 GAME_CREATION_APP_CANONICAL_ASSET_KINDS 与 canonical_game_creation_app_asset_kind 别名表(含 font → document 特例),分类映射表按枚举成员穷举。
- shared-contracts/Cargo.toml:删除 kind-observability feature 与 tracing 依赖,留痕不再靠 tracing。
- api-server/editor_project.rs:图片编辑白名单注释改成「API 兼容面」,不再自称 kind 别名表。
2026-09-17 15:43:51 +08:00
k88936 e6092dda6f Merge remote-tracking branch 'origin/master' into feat/agc-organize-assetkind
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 6m6s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 3m19s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 6m23s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 6m9s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 5m55s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m36s
Project CI / Repository checks (pull_request) Successful in 5m36s
Project CI / Frontend tests (pull_request) Failing after 7m10s
Project CI / Backend tests (pull_request) Successful in 13m10s
Project CI / Native shell tests (pull_request) Successful in 11m34s
Project CI / AI game creator shell web tests (pull_request) Successful in 5m38s
# Conflicts:
#	docs/project-memory/shared-memory/decision-log.md
2026-09-17 13:52:45 +08:00
k88936 5f13698129 asset.list 的 kind 过滤改为拒绝非 canonical 值
- direct_tool_bridge.rs:`kind` 收口后既不是 canonical、也不是字面 `unknown` 时直接返回工具错误并带上原值,不再静默过滤出空列表。
- direct_tool_bridge.rs:新增用例,钉住"项目访问前就报错"与"字面 `unknown` 仍是合法过滤值"。
- direct_tools_mcp.rs:schema 描述改为必须是 canonical kind、非 canonical 值会被拒绝。
2026-09-17 13:42:22 +08:00
k88936 29ba9a358e 字体 kind 提升为 canonical 并去掉 font 别名
- game_creation_app.rs:`GAME_CREATION_APP_CANONICAL_ASSET_KINDS` 加入 `font`(17 → 18 项),分类表补 `font → document`,删除 `"font" => "document"` 别名。
- gameCreationApp.ts:TS 侧同步加入 `font`、删除别名表条目、补 `font: 'document'` 分类,并同步别名表注释。
- 测试:两侧用例改为断言 `font` 是 canonical 成员(大小写仍不敏感)、栏目仍是 document。
- 理由:字体上传写入侧直接落 `font`,再把它当别名会让「落盘值集合」与「canonical 集合」分叉;严格解析下写入侧的值必须本身就是 canonical。
2026-09-17 13:42:05 +08:00
k88936 3ab56e6cfa 非 canonical 资源 kind 严格收口并留痕原始串
- manifest.rs:读 manifest 时若存在 `unknown` kind,从原始 JSON 回捞 `assets[].kind` 原值,连同资产 ID、路径写进应用日志;同一原值每进程只记一次,避免刷屏。
- recovery_tests.rs:新增用例钉住回捞范围(只报非 canonical 值,跳过 canonical 与字面 `unknown`;结构异常返回空表)。
- commands.rs:`imported_platform_asset_kind` 收口平台 `assetKind` 时,非 canonical 原值一并留痕,供后续定位平台侧 legacy 写入点。
- shared-contracts/Cargo.toml:`ts-bindings` 不再顺带打开 `kind-observability`,改由 AGC 壳显式声明,日志开关不再随绑定需求被动启停。
- 口径:kind 保持严格解析(无 trim/lowercase、无别名表、无迁移),认不出的值一律收口 `unknown` 并留痕,不做 fallback。
2026-09-17 13:41:41 +08:00
k88936 56c4faa8ee 清理项目视觉资产判断里已不可达的旧 kind 字面量
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 4m58s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 4m44s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 4m26s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m3s
Project CI / Backend tests (pull_request) Failing after 10s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 4m0s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m50s
Project CI / Repository checks (pull_request) Failing after 14s
Project CI / Frontend tests (pull_request) Successful in 6m3s
Project CI / AI game creator shell web tests (pull_request) Successful in 6m3s
Project CI / Native shell tests (pull_request) Successful in 11m11s
- projectAssetSummaries.ts:`isProjectVisualAsset` 去掉 `sprite` / `ui` / `background` 三个旧 kind 判断。
- 理由:manifest kind 由 Rust 枚举序列化,只会是 canonical 成员或 `unknown`,这三个旧字面量在 TS 侧永远无法命中;图像与视频资产仍由 mediaType 分支覆盖。
2026-09-16 23:31:01 +08:00
k88936 d23c808376 新建 UI 设计资源复用无冲突编号规则
- ui_editor/resource_bridge.rs:`next_ui_design_path` 提升为 `pub(crate)` 并补注释,作为两个写入侧唯一的「UI 设计 N」命名规则。
- commands.rs:`create_ui_design_resource` 不再按已登记文档数直接取名,改为复用该规则,resourceId 与文件名同一编号。
- tests/project.rs:新增已存在 `ui/UI 设计 1.json` 时仍能创建并落到编号 2 的回归用例。
2026-09-16 23:24:15 +08:00
k88936 41930b858e 修正陶泥儿运行态图片筛选残留的旧 kind 字面量
- direct_runtime/mod.rs:`direct_game_sources_referenced_taonier_assets` 的 manifest 兜底由 `art-spritesheet | art-spritesheet-slice | game-background` 改为 `IconSpritesheet | Icon | Scene`,恢复对项目自定义图集与背景的收录。
- direct_runtime/mod.rs:同处与 `direct_registered_taonier_runtime_image_paths` 的「切片不得绕过严格校验」排除条件改用 `GameCreationAppAssetKind::Icon`,并顺手把 `icon-spec` 比较改为枚举成员。
- 理由:kind 收紧为枚举后 `as_str()` 只会返回 canonical 名,旧字面量恒不命中,兜底筛选与切片排除同时失效。
2026-09-16 23:13:21 +08:00
k88936 9dccf5318e UI 原型 kind 判断改用共享常量
- uiDesignResourceBridge.ts:原型 kind 比较由裸字符串 `'ui-design'` 改为 `GAME_CREATION_APP_UI_DESIGN_ASSET_KIND`,与 manifest kind 契约保持同一处定义。
2026-09-16 23:10:59 +08:00
k88936 f216381619 修正 UI 编辑器入口对 canonical ui-design 原型的判断
- packages/shared:新增 `GAME_CREATION_APP_UI_DESIGN_ASSET_KIND`(`ui-design`)并让 canonical kind 列表与分类表引用它,避免散落裸字符串。
- project-development/index.tsx:`openResourceUiEditor` 与 `selectedResourceOpensUiEditor` 的原型判断由旧值 `ui-prototype` 改为该常量,恢复原型图的「UI 编辑器」入口。
- resourceProjectionModel.ts:`isPendingUiPrototype` 同步改用该常量,恢复待视觉验收标注。
- project-development.suite.ts:候选界面图 fixture 改用 canonical kind,并补一条原型图打开 UI 编辑器桥接的回归用例(去掉修正即转红)。
2026-09-16 23:10:31 +08:00
k88936 d454d3fa4b 修正 asset.list 工具示例 kind 到 canonical 词汇
- direct_tools_mcp.rs:`agc_list_registered_assets` 的 kind 过滤示例把旧值 `art-spritesheet-slice` 换成 canonical 的 `icon-spritesheet`。
- 理由:manifest kind 收紧为枚举后,旧值在过滤前已收口为 `unknown`,按示例传参只会得到空结果。
2026-09-16 23:03:44 +08:00
k88936 a5ee45aa4e 构建脚本依赖不再打开 shared-contracts 的 ts-bindings
- Cargo.toml:`[build-dependencies]` 的 shared-contracts 去掉 `features = ["ts-bindings"]`,只保留 `[dependencies]` 那份。
- build.rs 只用 `GameCreationAppAgentGroup` 与 `new_game_creation_app_seed_tasks`,不需要 ts-rs 导出,没必要让构建脚本图额外编译 ts-rs。
2026-09-16 23:01:51 +08:00
k88936 d333f783fe 修正资源 kind 解析边界对非字符串输入的日志
- assetKind.ts:非字符串输入不再走 `String(raw)` 字符串化,改为记录 `rawType` 并直接收口为 `unknown`。
- assetKind.test.ts:新增非字符串输入用例,钉住新的日志形状。
2026-09-16 23:00:42 +08:00
k88936 faab318127 删除资源引用缩略图里已不可达的 ui kind 分支
- ResourceReferenceInput 缩略图:删掉 `kind === 'ui'` 判断与只服务它的 `kind` 变量,UI 设计文档仍由 `mediaType === 'application/json'` 识别。
- 理由:manifest kind 由 Rust 枚举序列化,只会是 canonical 成员或 `unknown`,该分支永远无法命中。
2026-09-16 23:00:07 +08:00
k88936 a4296a4bdd 合并 origin/master 并收敛 DirectProject 引用渲染到 canonical user item
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 7m17s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 7m15s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 7m45s
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Failing after 7m59s
Project CI / Backend tests (pull_request) Failing after 10s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m8s
Project CI / Repository checks (pull_request) Failing after 9s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m48s
Project CI / AI game creator shell web tests (pull_request) Successful in 6m24s
Project CI / Frontend tests (pull_request) Successful in 15m29s
Project CI / Native shell tests (pull_request) Successful in 19m38s
- .eslintrc.cjs 冲突取双方 ignore 并集,保留 contracts/generated/** 与 project-workspace/generated/**。
- 实施计划文档冲突保留双方内容:2026-09-15 资源 kind 枚举化权威口径与 master 新增计划段并存。
- resourceReferences.ts 冲突合并双方 import:kind 解析入口与 canonical DirectCodexUserItem 类型同时保留。
- project-development.suite.ts 冲突合并双方 import:UI 设计文档 kind/mediaType 常量与 ProjectSupervisorView 同时保留。
- decision-log.md 冲突取双方条目,并补记 DirectProject 引用渲染收敛到 canonical user item 的决策。
- 接受 master 退役 agent/direct_codex_references.rs,把 UI 设计文档引用生成代码上下文的 prompt 注入迁入 agent/direct_codex_user_item/wire.rs。
- assets.rs 资源登记 kind 参数收紧为 GameCreationAppAssetKind,相应测试 fixture 改用正式枚举成员。
- 同步 project-memory 实施计划、里程碑与扫描清单中的模块路径。
2026-09-16 21:01:20 +08:00
k88936 7eee89ded3 同步 AGC 资源 kind 枚举化的实施计划、里程碑与扫描清单
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 5m22s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 5m16s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 5m4s
Project CI / Backend tests (pull_request) Failing after 10s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m39s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 4m40s
Project CI / Repository checks (pull_request) Failing after 11s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m1s
Project CI / AI game creator shell web tests (pull_request) Successful in 3m3s
Project CI / Frontend tests (pull_request) Successful in 4m35s
Project CI / Native shell tests (pull_request) Successful in 6m44s
- 实施计划:记录已落地内容(kind 由 `String` 收紧为枚举的破坏性变更、写入与读取统一正式成员、资源编辑源身份词汇表、`cargo test export_bindings` 生成路径、TS 穷举派生)
- 实施计划:修正「明确不修改」与验证命令,去掉与当前代码不符的表述
- 里程碑:验收标准除旧 alias 读边界一项外全部勾选,并补记 ts-rs 生成与退役类型导出两项证据
- 扫描清单:把「当前未决项」逐条落成结论(`asset`、`art-spritesheet*`、`game-*`、`ui*`、`Unknown` trace、生成路径),只保留 CI verify 接入一项待办
2026-09-16 19:08:28 +08:00
k88936 f9bc2d917c AGC 资源 kind 集合改为从生成 union 穷举派生
- assetKind.ts:新增 `GAME_CREATION_APP_ASSET_KIND_MEMBERS: Record<GameCreationAppAssetKind, true>`,生成 union 增删成员时会直接编译报错
- assetKind.ts:`GAME_CREATION_APP_ASSET_KINDS` 由该表派生,不再手写第二份字面量列表
- assetKind.ts:新增 `isGameCreationAppAssetKind` 类型守卫,`parseGameCreationAppAssetKind` 复用它
- view/project-development/index.tsx:资源引用的 `sourceSubtype` 只传正式 kind 成员,任务产物等非 manifest 来源传 `null`
- tests/assetKindCanonicalMapping.test.ts:两侧 kind 目录比对前先展开 Rust 常量引用(`ui-design-doc` 是常量),修正此前恒失败的两条;删除测试体里游离的 `'font',` 表达式
2026-09-16 19:07:58 +08:00
k88936 b96cd4b7c2 ts-rs 绑定统一走 cargo test export_bindings,删除退役类型导出
- asset_kind.rs:`GameCreationAppAssetKind` 自带 `#[ts(export, export_to = ../apps/ai-game-creator-shell/src/contracts/generated/)]`,`cargo test export_bindings` 即可复现生成文件
- binding.rs:删除手写的 `exports_ui_editor_types` 测试,不再由测试就地重写生成文件或重建退役类型
- binding.rs:`BindingChange` / `BindingDTO` 去掉 `TS` derive 与 `ts(export_to)`,只作为内部结构使用,不再导出退役的前端绑定
- binding.rs:清理仅为该测试存在的 `ts_rs` / `GameCreationAppAssetKind` 导入
- .prettierignore、.eslintrc.cjs:忽略 `src/contracts/generated/`,保留 ts-rs 原始格式使生成幂等且不污染工作树
- GameCreationAppAssetKind.ts:按生成器原始格式更新(与上述路径一致,无内容漂移)
2026-09-16 19:07:33 +08:00
k88936 f185d21f55 资源编辑源身份改用独立词汇表,只传正式 kind 成员
- resource_editor.rs:新增 `ResourceEditSourceKind`,把源身份拆成 `Manifest(GameCreationAppAssetKind)` / `ProjectVersion` / `AgentResultText`
- resource_editor.rs:`ResourceEditSourceSnapshot.asset_kind` 由 `String` 收紧为该枚举,项目版本与 Agent 回执不再冒充 manifest kind
- resource_editor.rs:`infer_resource_edit_source_asset_kind` 直接返回枚举成员,`art-image` / `svg` / `text` 收口为 `Image` / `Image` / `Document`
- resource_editor.rs:栅格源归一化只接受正式枚举成员,`task-artifact` 特判删除,未知值按 `Image` 收口
- resource_editor.rs:账本、HTTP 载荷与提示词边界改用 `as_str()`,manifest 写回改用 `manifest_kind()`
- resource_editor.rs:`source_subtype` 字段补充「只接受 manifest 正式 kind」的文档说明,测试 fixture 同步改用枚举成员
2026-09-16 19:07:23 +08:00
k88936 a61b0cce81 收敛 AGC 资源 kind 写入与读取到正式枚举成员
- assets.rs:`register_local_asset_at` / `register_local_asset_entry` 改为接收 `GameCreationAppAssetKind`,画板导入与画板同步在边界解析 kind
- assets.rs:`infer_canvas_export_asset_kind` 直接返回枚举成员,去掉仅供兜底的 canonical 归一
- commands.rs:资源登记按 `asset.register` 上下文解析 kind,字体导入写 `Font`,本地文件类型表与平台导入归一改用枚举
- direct_runtime.rs:直连游戏工程产物统一写 `Code`,图集切片读取按 `Icon` 叠加切片路径判定,陶泥儿美术身份改收枚举
- canvas_generation.rs:新增 `platform_art_asset_manifest_kind` 收口平台美术请求词汇,切片登记 category 改用 `Icon.as_str()`
- manifest.rs:必填视觉资产校验改用 `IconSpec` / `UiDesign` / `IconSpritesheet`,修正此前与写入侧对不上的比对
- project_gates.rs、autonomous_policy.rs、recovery_scan.rs、direct_tool_bridge.rs、ui_editor workflow/persistence/resource_bridge:读取侧与 fixture 改用正式枚举成员
- tests:资源相关 fixture 与断言改用正式枚举成员
2026-09-16 19:07:12 +08:00
k88936 2a75a2d2c8 回退资源 kind 绑定断言的误改
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
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Has been cancelled
ts-rs 导出内容是双引号,测试重新生成后再校验,恢复双引号断言。
2026-09-16 17:05:03 +08:00
k88936 512f669f57 修正资源引用入口的源码断言
正则改为匹配 parseGameCreationAppAssetKind(selectedResource.subtype) 的新调用形状。
2026-09-16 16:59:51 +08:00
k88936 21dbbb4c3c 清理资源桥接测试的旧 kind fixture
将有效分类投影用例的资源 kind 改为 UiDesign 枚举与 ui-design 断言。

移除遗留 ui 字符串 fixture,使 AGC 壳测试恢复编译。
2026-09-16 16:53:27 +08:00
k88936 55d0c99e2b 修正资源 kind 转义测试期望
转义后的 ui-design 应解析为 UiDesign 枚举。
2026-09-15 20:57:14 +08:00
k88936 3907a8bf74 补齐资源 kind 字符串字段转换
资源编辑请求中的 sourceSubtype 统一从 AssetKind 显式转换字符串。
2026-09-15 20:52:53 +08:00
k88936 46dfa2cffb 修复资源枚举迁移后的测试类型错误
将字体、角色和资源图 fixture 改为 AssetKind 枚举。

将资源 kind 回传到字符串字段时显式使用 to_string。
2026-09-15 20:45:55 +08:00
k88936 97e2b26900 简化资源引用 kind 来源
引用资源时直接解析已存在的 subtype,移除无效 category 回退。
2026-09-15 20:14:13 +08:00
k88936 39e33f7a5b 更新上传资源 kind 枚举测试
按 Font 与 Unknown 返回值修正上传类型断言。

使用枚举字符串视图校验 canonical kind 集合。
2026-09-15 20:01:20 +08:00
k88936 040f646480 统一 ts-rs workspace 依赖版本
在 server-rs workspace 集中声明 ts-rs 版本。

shared-contracts 通过 workspace 依赖引用可选 ts-rs。
2026-09-15 19:53:06 +08:00
k88936 8b007c637d 修正图集切片读取侧枚举判断
恢复校验和测试筛选统一识别 Icon 资源 kind。

部分登记探测限定在图集切片路径,避免误判普通图标。
2026-09-15 19:48:48 +08:00
k88936 f0a62c6306 迁移资源桥接测试 fixture 到枚举
将图集切片、角色动画和规格资源 fixture 改用对应 AssetKind 变体。
2026-09-15 19:45:51 +08:00
k88936 30edfee00e 修复 Codex 资源引用测试 fixture
将 manifest 资源 kind 字符串 fixture 迁移为 Character 枚举。
2026-09-15 19:41:41 +08:00
k88936 c2da8e184e 修正 UI 工作流源资源枚举校验
工作流源图校验与 fixture 统一使用 UiDesign。

更新失败提示中的 manifest kind 名称。
2026-09-15 19:36:29 +08:00
k88936 a19319d815 修正 UI 原型资源桥接枚举使用
生产校验与测试 fixture 改用 GameCreationAppAssetKind::UiDesign。

保留 ui-prototype 作为本地文件路径标识。
2026-09-15 19:35:04 +08:00
k88936 d07ea186fa 收紧资源 kind 测试专用导入
仅在测试构建中导入 GameCreationAppAssetKind,避免正式构建产生未使用警告。
2026-09-15 19:33:13 +08:00
k88936 80caec373a 修正资源 kind 绑定测试断言
按 ts-rs 生成的单引号联合成员校验绑定内容。
2026-09-15 19:32:12 +08:00
k88936 3caefd6716 修复资源 kind 转义字符串反序列化
为 AssetKindVisitor 增加 visit_string 转发。

补充 JSON 转义 kind 的反序列化回归测试。
2026-09-15 19:31:21 +08:00
k88936 4d0dd2d721 收紧 UI 资源桥接的 manifest kind
UI 原型与文档链接改用生成枚举边界
删除 ui-prototype 的主动 alias 使用并更新测试清单
2026-09-15 18:06:27 +08:00
k88936 2befaaef9d 接入 AGC shell TS 资源 kind 边界
新增消费 Rust 生成绑定的未知值解析模块
迁移资源引用与画布引用入口并补充日志测试
更新逐项迁移清单与实施计划
2026-09-15 18:00:34 +08:00
k88936 20b0bf4dd7 补充 AGC manifest 未知 kind 验收
验证旧值读取为 Unknown 且序列化为 unknown
明确不执行 alias 迁移
2026-09-15 17:50:33 +08:00
k88936 b4fd8d9b8b 收紧 AGC manifest 资源 kind 字段
将 manifest 条目 kind 改为 Rust 枚举并把未知值收口为 Unknown
修正字体上传与图集切片的正式资源 kind
保持 source.kind 与 generationKind 等其他字符串字段不变
2026-09-15 17:37:28 +08:00
k88936 fe85fa2a62 建立 AGC 资源 kind Rust 枚举与 TypeScript 绑定
新增 GameCreationAppAssetKind 及 Unknown 解析边界
通过 ts-rs 生成 shell 专属 TypeScript 联合类型
补充未知值上下文日志与 Rust/绑定生成测试
2026-09-15 16:20:52 +08:00
k88936 b14a533b17 新增AGC资源kind绑定实施计划
限定首个代码切片为 Rust enum 与 ts-rs 生成边界。

明确不修改 manifest 字段和其他资源字符串领域。

列出绑定、serde round-trip 与定向验证门禁。
2026-09-15 15:29:37 +08:00
k88936 42969b2218 细化AGC资源kind构造器审计
补充 Rust manifest 构造器逐处迁移清单。

补充 shell TypeScript 裸 assetKind 消费方清单。

区分图集、工作流和 manifest kind 的处理边界。
2026-09-15 15:24:46 +08:00
k88936 c4ee75a1af 补充AGC资源kind词汇审计清单
记录 manifest kind 的 Rust 写入边界与 TypeScript 消费方。

区分资源 kind 与 source/generation/workflow 等字符串领域。

标注 font、audio、sound-effect、background-music 及旧值的生产状态。

通过文档索引、编码与 diff 检查。
2026-09-15 15:19:58 +08:00
k88936 6f2137cbb0 补充AGC资源kind枚举化规范
新增资源 kind 枚举化主规范与边界。

新增词汇审计、Rust 绑定、写入清理三个里程碑。

新增 shell-only 资源 kind 扫描 todo 清单。

通过文档索引、编码与 diff 检查。
2026-09-15 15:12:24 +08:00
k88936 70a2246e8b 移除 UI 文档引用新增测试
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 4m30s
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 4m59s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 4m24s
Project CI / Backend tests (pull_request) Failing after 11s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m50s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Failing after 4m28s
Project CI / Repository checks (pull_request) Failing after 13s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m7s
Project CI / AI game creator shell web tests (pull_request) Failing after 3m22s
Project CI / Frontend tests (pull_request) Failing after 3m51s
Project CI / Native shell tests (pull_request) Successful in 7m4s
删除 Direct Codex UI 文档 fixture 与专门测试用例

保留生产引用逻辑和现有业务测试
2026-09-14 21:41:53 +08:00
k88936 b7e3dac661 统一引用 UI 文档资产类型常量
前端入口、资源桥接与引用预览统一使用共享常量

Rust 持久化与测试复用共享契约常量

补齐 UI 编辑器入口 fixture 的新资产类型
2026-09-14 21:36:43 +08:00
k88936 2e4a1996c8 同步 UI 编辑器入口测试资产类型
将项目开发 UI 编辑器回程测试 fixture 更新为 ui-design-doc
2026-09-14 21:12:03 +08:00
k88936 fe4e952853 更新 UI 文档资源编辑器入口
将 ui-design-doc 资源纳入选中资源的 UI 编辑器按钮判定

保留 ui-prototype 图片资源的编辑器桥接入口
2026-09-14 21:04:08 +08:00
k88936 18654b6806 同步 UI 文档资产共享契约与前端识别
共享契约新增 ui-design-doc 分类及中英文映射

前端编辑器与资源桥接严格识别文档资产

更新技术方案、实施计划和长期决策记录
2026-09-14 20:45:04 +08:00
k88936 ee7d00c0b1 统一 UI 编辑器文档资产类型
新增 ui-design-doc 与 application/json 常量

创建、桥接、工作流和持久化统一使用严格资产类型
2026-09-14 20:44:49 +08:00
k88936 9cd1a94369 接入 UI 文档引用代码上下文生成
Direct Codex 引用 ui-design-doc 时生成带文档的 JS 文件

生成成功或失败信息追加到当前 prompt

补充成功、失败与 ui-prototype 隔离测试
2026-09-14 20:44:49 +08:00
k88936 470e85c0ff Add UI-specific prompt rendering for design assets in resource references 2026-09-14 20:44:49 +08:00
223 changed files with 4524 additions and 10854 deletions
+3
View File
@@ -23,3 +23,6 @@
*.meta text *.meta text
*.anim text *.anim text
*.controller text *.controller text
# Rust ts-rs 生成的共享契约:保留在仓库中供 TS 消费,但不作为手写源文件统计。
packages/shared/src/contracts/generated/** linguist-generated=true
+4 -22
View File
@@ -221,7 +221,8 @@ jobs:
- name: Run AI game creator shell agent-run smoke - name: Run AI game creator shell agent-run smoke
run: npm run check:native-shells:agc-rust-smoke run: npm run check:native-shells:agc-rust-smoke
# AGC 壳依赖的共享 / 平台和编辑器插件 crate 各自预热独立 manifest,再运行对应测试。 # AGC 壳依赖的共享 / 平台 crate 测试用的是 server-rs workspace 与两个无锁独立 crate
# 的 manifest,属另一套依赖图,因此单独一个 job 预热、单独跑。
ai-game-creator-shell-rust-crates: ai-game-creator-shell-rust-crates:
name: AI game creator shell Rust crates name: AI game creator shell Rust crates
runs-on: genarrative-ci runs-on: genarrative-ci
@@ -262,15 +263,13 @@ jobs:
# `cargo test --manifest-path` 单独跑这两个 crate。不在这里预热的话,这两条测试 # `cargo test --manifest-path` 单独跑这两个 crate。不在这里预热的话,这两条测试
# 会在测试阶段自己 `Updating crates.io index`crates.io 一抖动整条 job 就红 # 会在测试阶段自己 `Updating crates.io index`crates.io 一抖动整条 job 就红
# (见 #327 / PR #316 run 1950)。 # (见 #327 / PR #316 run 1950)。
# Cocos 插件也使用独立且未提交的锁文件,一并预热。 # 两个 crate 都没有提交 Cargo.lock,所以这里只能做不带锁标志的 fetch:
# 这些 crate 都没有提交 Cargo.lock,所以这里只能做不带锁标志的 fetch:
# 加锁标志会因为缺少锁文件直接失败。生成的 Cargo.lock 落在两个 crate 目录内, # 加锁标志会因为缺少锁文件直接失败。生成的 Cargo.lock 落在两个 crate 目录内,
# 已被各自的 .gitignore 忽略,只留在容器里;随后的测试阶段因此能用锁定版本 # 已被各自的 .gitignore 忽略,只留在容器里;随后的测试阶段因此能用锁定版本
# 解析,不再触碰 registry index。 # 解析,不再触碰 registry index。
for manifest_path in \ for manifest_path in \
server-rs/crates/agent-runtime-core/Cargo.toml \ server-rs/crates/agent-runtime-core/Cargo.toml \
server-rs/crates/agent-runtime-orchestration/Cargo.toml \ server-rs/crates/agent-runtime-orchestration/Cargo.toml; do
plugins/agc-cocos-editor/native/cocos-editor-bridge/Cargo.toml; do
for attempt in $(seq 1 5); do for attempt in $(seq 1 5); do
if cargo fetch \ if cargo fetch \
--target x86_64-unknown-linux-gnu \ --target x86_64-unknown-linux-gnu \
@@ -285,23 +284,6 @@ jobs:
done done
done done
- name: Prepare Unity plugin Rust dependencies
shell: bash
run: |
set -euo pipefail
for attempt in $(seq 1 5); do
if cargo fetch --locked \
--target x86_64-unknown-linux-gnu \
--manifest-path plugins/agc-unity-editor/native/unity-editor-bridge/Cargo.toml; then
break
fi
if [[ "${attempt}" -eq 5 ]]; then
echo 'Unity plugin Cargo dependency fetch failed after 5 attempts.' >&2
exit 1
fi
sleep $((attempt * 2))
done
- name: Run AI game creator shell shared crate gates - name: Run AI game creator shell shared crate gates
run: npm run check:native-shells:agc-rust-crates run: npm run check:native-shells:agc-rust-crates
-4
View File
@@ -48,10 +48,6 @@ temp*build*/
/apps/ai-game-creator-shell/src-tauri/resources/codex/mac-native/manifest.json /apps/ai-game-creator-shell/src-tauri/resources/codex/mac-native/manifest.json
/apps/ai-game-creator-shell/src-tauri/resources/codex/mac-native/NOTICE.md /apps/ai-game-creator-shell/src-tauri/resources/codex/mac-native/NOTICE.md
/plugins/agc-cocos-editor/native/payload/ /plugins/agc-cocos-editor/native/payload/
/plugins/agc-unity-editor/dotnet/**/bin/
/plugins/agc-unity-editor/dotnet/**/obj/
/plugins/agc-unity-editor/dotnet/publish/
/plugins/agc-unity-editor/dotnet/native-build/
/apps/ai-game-creator-shell/logs/ /apps/ai-game-creator-shell/logs/
/apps/ai-game-creator-shell/.llm-drafts/ /apps/ai-game-creator-shell/.llm-drafts/
/apps/ai-game-creator-shell/game-creator.config.local.json /apps/ai-game-creator-shell/game-creator.config.local.json
+10 -1
View File
@@ -1,5 +1,14 @@
{ {
"singleQuote": true, "singleQuote": true,
"semi": true, "semi": true,
"trailingComma": "all" "trailingComma": "all",
"overrides": [
{
"files": "packages/shared/src/contracts/generated/**/*.ts",
"options": {
"printWidth": 1000,
"singleQuote": false
}
}
]
} }
@@ -676,11 +676,11 @@ async function runSelfTest() {
designFoundationAssetCall?.arguments?.input?.outputPath === designFoundationAssetCall?.arguments?.input?.outputPath ===
'assets/ui-prototype.png' && 'assets/ui-prototype.png' &&
designFoundationAssetCall.arguments.input.aspectRatio === '16:9' && designFoundationAssetCall.arguments.input.aspectRatio === '16:9' &&
designFoundationAssetCall.arguments.input.assetKind === 'ui-prototype' && designFoundationAssetCall.arguments.input.assetKind === 'ui-design' &&
artAssetPlanAssetCall?.arguments?.input?.outputPath === artAssetPlanAssetCall?.arguments?.input?.outputPath ===
'assets/art-spritesheet.png' && 'assets/art-spritesheet.png' &&
artAssetPlanAssetCall.arguments.input.aspectRatio === '1:1' && artAssetPlanAssetCall.arguments.input.aspectRatio === '1:1' &&
artAssetPlanAssetCall.arguments.input.assetKind === 'art-spritesheet', artAssetPlanAssetCall.arguments.input.assetKind === 'icon-spritesheet',
'self-test-visual-assets-invalid', 'self-test-visual-assets-invalid',
); );
@@ -70,7 +70,7 @@ const requiredFormalArtifactSpecs = [
{ path: 'game/balance.json', kind: 'json' }, { path: 'game/balance.json', kind: 'json' },
{ path: 'assets/manifest.art.json', kind: 'json' }, { path: 'assets/manifest.art.json', kind: 'json' },
{ path: 'assets/manifest.audio.json', kind: 'json' }, { path: 'assets/manifest.audio.json', kind: 'json' },
{ path: 'game/index.html', kind: 'game-entry' }, { path: 'game/index.html', kind: 'file' },
{ path: 'exports/README.md', kind: 'file' }, { path: 'exports/README.md', kind: 'file' },
]; ];
const editorImageArtifactSpecs = [ const editorImageArtifactSpecs = [
@@ -105,7 +105,6 @@ export const agcReleasePathPatterns = [
'packages/', 'packages/',
'server-rs/crates/', 'server-rs/crates/',
'plugins/agc-cocos-editor/', 'plugins/agc-cocos-editor/',
'plugins/agc-unity-editor/',
'apps/desktop-shell/src-tauri/icons/', 'apps/desktop-shell/src-tauri/icons/',
'package.json', 'package.json',
'package-lock.json', 'package-lock.json',
@@ -344,11 +344,7 @@ test('Windows remains the default and explicit Windows overrides macOS environme
context, context,
{ {
spawn: (_binary, command) => { spawn: (_binary, command) => {
assert.ok( assert.ok(command.includes('--features=cocos-editor-execute'));
command.includes(
'--features=cocos-editor-execute,unity-editor-execute',
),
);
assert.ok(command.includes('user-config.json')); assert.ok(command.includes('user-config.json'));
const configIndex = command.lastIndexOf('--config'); const configIndex = command.lastIndexOf('--config');
const config = JSON.parse( const config = JSON.parse(
@@ -19,6 +19,6 @@ export function withDefaultCargoFeatures(argv, features) {
export function defaultEditorFeatures(target) { export function defaultEditorFeatures(target) {
return target === 'win32' || target.includes('windows') return target === 'win32' || target.includes('windows')
? ['cocos-editor-execute', 'unity-editor-execute'] ? ['cocos-editor-execute']
: []; : [];
} }
@@ -9,7 +9,7 @@ test('Windows release includes the same editor feature as development', () => {
buildTauriBuildArguments([], 'x86_64-pc-windows-msvc', 'win32'), buildTauriBuildArguments([], 'x86_64-pc-windows-msvc', 'win32'),
[ [
'build', 'build',
'--features=cocos-editor-execute,unity-editor-execute', '--features=cocos-editor-execute',
'--target', '--target',
'x86_64-pc-windows-msvc', 'x86_64-pc-windows-msvc',
], ],
@@ -143,6 +143,7 @@ const allowedUncalledTauriCommands = [
'reload_agc_plugin', 'reload_agc_plugin',
'call_agc_plugin', 'call_agc_plugin',
'read_agc_plugin_panel', 'read_agc_plugin_panel',
'set_agc_plugin_project_path',
'set_agc_plugin_enabled', 'set_agc_plugin_enabled',
]; ];
const sourceExtensions = new Set([ const sourceExtensions = new Set([
@@ -290,7 +290,7 @@ function deterministicArtManifest(
{ {
id: 'garden-guardians-spritesheet', id: 'garden-guardians-spritesheet',
path: 'assets/art-spritesheet.png', path: 'assets/art-spritesheet.png',
kind: 'art-spritesheet', kind: 'icon-spritesheet',
usage: ['defenders', 'enemies', 'battlefield-ui'], usage: ['defenders', 'enemies', 'battlefield-ui'],
source: 'canvas', source: 'canvas',
status: 'ready', status: 'ready',
@@ -710,7 +710,7 @@ function canvasAssetCall(agentId) {
outputPath: 'assets/ui-prototype.png', outputPath: 'assets/ui-prototype.png',
aspectRatio: '16:9', aspectRatio: '16:9',
imageSize: '2K', imageSize: '2K',
assetKind: 'ui-prototype', assetKind: 'ui-design',
assetLabel: '游戏横屏界面原型图', assetLabel: '游戏横屏界面原型图',
replaceExisting: false, replaceExisting: false,
}); });
@@ -721,7 +721,7 @@ function canvasAssetCall(agentId) {
outputPath: 'assets/art-spritesheet.png', outputPath: 'assets/art-spritesheet.png',
aspectRatio: '1:1', aspectRatio: '1:1',
imageSize: '1K', imageSize: '1K',
assetKind: 'art-spritesheet', assetKind: 'icon-spritesheet',
assetLabel: '游戏首版核心美术素材', assetLabel: '游戏首版核心美术素材',
replaceExisting: false, replaceExisting: false,
sliceMode: 'connected-components', sliceMode: 'connected-components',
@@ -830,12 +830,12 @@ function missingGeneratedVisualAssetObservation(context, agentId) {
}, },
'design-foundation': { 'design-foundation': {
path: 'assets/ui-prototype.png', path: 'assets/ui-prototype.png',
kind: 'ui-prototype', kind: 'ui-design',
summary: '策划界面原型图尚未按正式视觉流程生成并登记,不能完成任务', summary: '策划界面原型图尚未按正式视觉流程生成并登记,不能完成任务',
}, },
'art-asset-plan': { 'art-asset-plan': {
path: 'assets/art-spritesheet.png', path: 'assets/art-spritesheet.png',
kind: 'art-spritesheet', kind: 'icon-spritesheet',
summary: '首版美术素材图尚未按正式视觉流程生成并登记,不能完成任务', summary: '首版美术素材图尚未按正式视觉流程生成并登记,不能完成任务',
}, },
}[agentId]; }[agentId];
@@ -2667,7 +2667,7 @@ function createDeterministicCanvasFixture(apiKey) {
asset: { asset: {
assetId: `asset-${sliceImageId}`, assetId: `asset-${sliceImageId}`,
assetObjectId: sliceAssetObjectId, assetObjectId: sliceAssetObjectId,
assetKind: 'art-spritesheet-slice', assetKind: 'icon',
projectId, projectId,
taskId, taskId,
}, },
@@ -2707,7 +2707,7 @@ function createDeterministicCanvasFixture(apiKey) {
spritesheetAsset: { spritesheetAsset: {
assetId: `asset-${imageId}`, assetId: `asset-${imageId}`,
assetObjectId, assetObjectId,
assetKind: 'art-spritesheet', assetKind: 'icon-spritesheet',
projectId, projectId,
taskId, taskId,
}, },
@@ -2749,7 +2749,7 @@ function createDeterministicCanvasFixture(apiKey) {
const assetObjectId = `asset-object-${imageId}`; const assetObjectId = `asset-object-${imageId}`;
const resourceId = `resource-${imageId}`; const resourceId = `resource-${imageId}`;
const assetKind = const assetKind =
typeof body?.assetKind === 'string' ? body.assetKind : 'game-art'; typeof body?.assetKind === 'string' ? body.assetKind : 'image';
images.set(imageId, { images.set(imageId, {
...image, ...image,
objectKey, objectKey,
@@ -1,10 +1,7 @@
import { resolve } from 'node:path'; import { resolve } from 'node:path';
import { fileURLToPath } from 'node:url'; import { fileURLToPath } from 'node:url';
import { import { withDefaultCargoFeatures } from './cargo-features.mjs';
defaultEditorFeatures,
withDefaultCargoFeatures,
} from './cargo-features.mjs';
import { import {
readAgcDevEndpoint, readAgcDevEndpoint,
resolveAgcDevEndpoint, resolveAgcDevEndpoint,
@@ -50,8 +47,9 @@ function buildTauriArguments(argv, devUrl = readAgcDevEndpoint().url) {
]; ];
} }
// 开发和发行构建使用同一平台编辑器 feature 集合。 // `agc_cocos_execute` 与 Cocos 编辑器适配器只在 `cocos-editor-execute` feature
// 可用 AGC_DEV_CARGO_FEATURES(逗号分隔)覆盖,传空串即关闭。 // 注册。开发构建默认在 Windows 打开它,否则 Agent 的工具清单里根本没有该工具,
// 只能退化成改写脚本。可用 AGC_DEV_CARGO_FEATURES(逗号分隔)覆盖,传空串即关闭。
function readDevCargoFeatures(env = process.env) { function readDevCargoFeatures(env = process.env) {
const override = env.AGC_DEV_CARGO_FEATURES; const override = env.AGC_DEV_CARGO_FEATURES;
if (override !== undefined) { if (override !== undefined) {
@@ -60,7 +58,7 @@ function readDevCargoFeatures(env = process.env) {
.map((value) => value.trim()) .map((value) => value.trim())
.filter(Boolean); .filter(Boolean);
} }
return defaultEditorFeatures(process.platform); return process.platform === 'win32' ? ['cocos-editor-execute'] : [];
} }
function withDevCargoFeatures(argv, features = readDevCargoFeatures()) { function withDevCargoFeatures(argv, features = readDevCargoFeatures()) {
+1 -11
View File
@@ -1793,7 +1793,6 @@ dependencies = [
"ttf-parser", "ttf-parser",
"typed_floats", "typed_floats",
"unicode-normalization", "unicode-normalization",
"unity-editor-bridge",
"url", "url",
"uuid", "uuid",
"windows-sys 0.61.2", "windows-sys 0.61.2",
@@ -5017,6 +5016,7 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"sha2", "sha2",
"ts-rs",
] ]
[[package]] [[package]]
@@ -6408,16 +6408,6 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
[[package]]
name = "unity-editor-bridge"
version = "0.1.0"
dependencies = [
"editor-adapter-api",
"serde",
"serde_json",
"windows-sys 0.61.2",
]
[[package]] [[package]]
name = "unsafe-libyaml" name = "unsafe-libyaml"
version = "0.2.11" version = "0.2.11"
@@ -12,7 +12,6 @@ template-library-fixtures = []
cocos-editor = ["cocos-editor-bridge/process-discovery"] cocos-editor = ["cocos-editor-bridge/process-discovery"]
cocos-editor-execute = ["cocos-editor", "cocos-editor-bridge/windows-bootstrap"] cocos-editor-execute = ["cocos-editor", "cocos-editor-bridge/windows-bootstrap"]
cocos-editor-injection = ["cocos-editor-execute", "cocos-editor-bridge/windows-injection"] cocos-editor-injection = ["cocos-editor-execute", "cocos-editor-bridge/windows-injection"]
unity-editor-execute = []
[build-dependencies] [build-dependencies]
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
@@ -28,7 +27,6 @@ nalgebra = { version = "0.35.0", features = ["serde-serialize"] }
agent-runtime-core = { path = "../../../server-rs/crates/agent-runtime-core" } agent-runtime-core = { path = "../../../server-rs/crates/agent-runtime-core" }
cocos-editor-bridge = { path = "../../../plugins/agc-cocos-editor/native/cocos-editor-bridge", default-features = false } cocos-editor-bridge = { path = "../../../plugins/agc-cocos-editor/native/cocos-editor-bridge", default-features = false }
editor-adapter-api = { path = "../../../server-rs/crates/editor-adapter-api" } editor-adapter-api = { path = "../../../server-rs/crates/editor-adapter-api" }
unity-editor-bridge = { path = "../../../plugins/agc-unity-editor/native/unity-editor-bridge" }
base64 = "0.22" base64 = "0.22"
axum = "0.8" axum = "0.8"
chromiumoxide = "0.9.1" chromiumoxide = "0.9.1"
@@ -58,7 +56,7 @@ platform-agent = { path = "../../../server-rs/crates/platform-agent" }
portable-pty = "0.9" portable-pty = "0.9"
reqwest = { version = "0.12", default-features = false, features = ["json", "multipart", "native-tls", "stream"] } reqwest = { version = "0.12", default-features = false, features = ["json", "multipart", "native-tls", "stream"] }
regex = "1" regex = "1"
shared-contracts = { path = "../../../server-rs/crates/shared-contracts", default-features = false } shared-contracts = { path = "../../../server-rs/crates/shared-contracts", default-features = false, features = ["ts-bindings"] }
tauri = { version = "2.11.2", features = [] } tauri = { version = "2.11.2", features = [] }
tauri-plugin-dialog = "2.7.1" tauri-plugin-dialog = "2.7.1"
tauri-plugin-http = { version = "2.5.9", default-features = false, features = ["charset", "cookies", "http2", "rustls-tls"] } tauri-plugin-http = { version = "2.5.9", default-features = false, features = ["charset", "cookies", "http2", "rustls-tls"] }
+1 -109
View File
@@ -196,7 +196,6 @@ fn main() {
); );
let manifest_path = manifest_dir.join("prompts/runtime/manifest.json"); let manifest_path = manifest_dir.join("prompts/runtime/manifest.json");
stage_bundled_codex_cli(&manifest_dir); stage_bundled_codex_cli(&manifest_dir);
prepare_unity_editor_helper(&manifest_dir);
stage_plugin_workspace(&manifest_dir); stage_plugin_workspace(&manifest_dir);
stage_cocos_editor_payload(&manifest_dir); stage_cocos_editor_payload(&manifest_dir);
let compiled = runtime_prompt_bundle::compile_manifest(&manifest_path) let compiled = runtime_prompt_bundle::compile_manifest(&manifest_path)
@@ -267,107 +266,6 @@ fn stage_cocos_editor_payload(manifest_dir: &std::path::Path) {
#[cfg(not(windows))] #[cfg(not(windows))]
fn stage_cocos_editor_payload(_manifest_dir: &std::path::Path) {} fn stage_cocos_editor_payload(_manifest_dir: &std::path::Path) {}
/// Unity helper 是插件的随包运行文件。内容指纹避免每次 Cargo 检查都重新发布 .NET。
fn prepare_unity_editor_helper(manifest_dir: &std::path::Path) {
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_UNITY_EDITOR_EXECUTE");
let target = env::var("TARGET").expect("Cargo TARGET");
if env::var_os("CARGO_FEATURE_UNITY_EDITOR_EXECUTE").is_none()
|| target != "x86_64-pc-windows-msvc"
{
return;
}
let root = manifest_dir.join("../../../plugins/agc-unity-editor/dotnet");
let mut sources = Vec::new();
collect_unity_helper_sources(&root, &mut sources);
sources.sort();
let mut fingerprint = Sha256::new();
for source in &sources {
println!("cargo:rerun-if-changed={}", source.display());
fingerprint.update(
source
.strip_prefix(&root)
.expect("helper source")
.to_string_lossy()
.as_bytes(),
);
fingerprint.update([0]);
fingerprint.update(fs::read(source).expect("读取 Unity helper 源文件失败"));
}
let fingerprint = format!("{:x}", fingerprint.finalize());
let publish = root.join("publish/win-x64");
let executable = publish.join("Agc.Unity.Attach.exe");
let stamp = publish.join(".agc-source.sha256");
println!("cargo:rerun-if-changed={}", executable.display());
if unity_helper_publish_complete(&publish)
&& fs::read_to_string(&stamp).ok().as_deref() == Some(&fingerprint)
{
return;
}
assert!(
cfg!(windows),
"构建 Unity 插件 helper 需要 Windows .NET 10 与 x64 C++ 工具链"
);
let status = std::process::Command::new("powershell.exe")
.args([
"-NoProfile",
"-NonInteractive",
"-ExecutionPolicy",
"Bypass",
"-File",
])
.arg(root.join("build.ps1"))
.current_dir(&root)
.status()
.expect("无法启动 Unity helper 构建脚本");
assert!(
status.success() && unity_helper_publish_complete(&publish),
"Unity helper 构建失败或缺少运行文件/许可"
);
fs::write(stamp, fingerprint).expect("写入 Unity helper 构建指纹失败");
}
fn unity_helper_publish_complete(publish: &std::path::Path) -> bool {
[
"Agc.Unity.Attach.exe",
"NOTICE",
"THIRD-PARTY-NOTICES.txt",
"licenses/DotCraft-Apache-2.0.txt",
"licenses/Roslyn-MIT.txt",
"licenses/upstream.json",
"licenses/dotnet-LICENSE.TXT",
"licenses/dotnet-THIRD-PARTY-NOTICES.TXT",
"licenses/microsoft.codeanalysis.common-ThirdPartyNotices.rtf",
"licenses/microsoft.codeanalysis.csharp-ThirdPartyNotices.rtf",
]
.iter()
.all(|name| {
fs::symlink_metadata(publish.join(name)).is_ok_and(|metadata| {
metadata.is_file() && !metadata.file_type().is_symlink() && metadata.len() > 0
})
})
}
fn collect_unity_helper_sources(root: &std::path::Path, sources: &mut Vec<PathBuf>) {
for entry in fs::read_dir(root)
.expect("Unity helper 源码目录缺失")
.flatten()
{
let kind = entry.file_type().expect("读取 Unity helper 源文件类型失败");
assert!(!kind.is_symlink(), "Unity helper 源码不允许符号链接");
let name = entry.file_name();
if kind.is_dir() {
if !matches!(
name.to_str(),
Some("bin" | "obj" | "publish" | "native-build")
) {
collect_unity_helper_sources(&entry.path(), sources);
}
} else if kind.is_file() {
sources.push(entry.path());
}
}
}
/// 把 `plugins/` 工作区里的插件包随包映射到应用资源目录。 /// 把 `plugins/` 工作区里的插件包随包映射到应用资源目录。
/// ///
/// 只复制插件运行需要的清单、入口、面板和 native payload,不复制 native 源码、 /// 只复制插件运行需要的清单、入口、面板和 native payload,不复制 native 源码、
@@ -415,15 +313,9 @@ fn stage_plugin_workspace(manifest_dir: &std::path::Path) {
for relative in [ for relative in [
std::path::PathBuf::from("src"), std::path::PathBuf::from("src"),
std::path::PathBuf::from("panels"), std::path::PathBuf::from("panels"),
std::path::PathBuf::from("skills"),
std::path::PathBuf::from("native/payload"), std::path::PathBuf::from("native/payload"),
std::path::PathBuf::from("dotnet/publish/win-x64"),
] { ] {
if (relative == std::path::Path::new("native/payload") && !target.contains("windows")) if relative == std::path::Path::new("native/payload") && !target.contains("windows") {
|| (relative == std::path::Path::new("dotnet/publish/win-x64")
&& (target != "x86_64-pc-windows-msvc"
|| env::var_os("CARGO_FEATURE_UNITY_EDITOR_EXECUTE").is_none()))
{
continue; continue;
} }
copy_plugin_tree(&plugin_root.join(&relative), &destination.join(&relative)); copy_plugin_tree(&plugin_root.join(&relative), &destination.join(&relative));
@@ -63,7 +63,7 @@
"agents/openai.yaml", "agents/openai.yaml",
"references/platform-art-contract.md" "references/platform-art-contract.md"
], ],
"sha256": "47ac742d9b88e5d6cd9833484ab212152578e58ae27f7add312fd1d78183385c" "sha256": "6668bf1aa69601bcc65c97fdcd879c699c3139befcd70805d95614997f6e44e9"
}, },
{ {
"name": "agc-web-game-development", "name": "agc-web-game-development",
@@ -19,13 +19,13 @@ image, UI design image, or publication material; use `agc_edit_image` for an
edit of an existing registered image; use `taonier_prepare_game_art` only for edit of an existing registered image; use `taonier_prepare_game_art` only for
the complete game-art package and its canonical slices. the complete game-art package and its canonical slices.
With `agc_generate_image`, `kind="character"` and `kind="art-spritesheet"` With `agc_generate_image`, `kind="character"` and `kind="icon-spritesheet"`
generate the subject on a solid-colour background and automatically matte it generate the subject on a solid-colour background and automatically matte it
away afterwards, producing transparent-background results; write the prompt away afterwards, producing transparent-background results; write the prompt
for the subject only, never for a scene. `kind="image"` keeps the rendered for the subject only, never for a scene. `kind="image"` keeps the rendered
frame without extra processing. frame without extra processing.
When `agc_generate_image` is used with `kind="art-spritesheet"`, `sliceMode` is When `agc_generate_image` is used with `kind="icon-spritesheet"`, `sliceMode` is
required and has no default, so decide it explicitly: required and has no default, so decide it explicitly:
- Use `sliceMode="grid"` with `gridX` and `gridY` (1-32 each) only when the user - Use `sliceMode="grid"` with `gridX` and `gridY` (1-32 each) only when the user
@@ -1198,7 +1198,7 @@ mod tests {
"tool": "agc_generate_image", "tool": "agc_generate_image",
"arguments": { "arguments": {
"prompt": prompt, "prompt": prompt,
"kind": "art-spritesheet", "kind": "icon-spritesheet",
"sliceMode": "connected-components", "sliceMode": "connected-components",
"sliceCount": 8, "sliceCount": 8,
"screenColor": "#CFEFFF" "screenColor": "#CFEFFF"
@@ -1,6 +1,10 @@
use super::model::{DirectCodexUserContentPart, DirectCodexUserItem}; use super::model::{DirectCodexUserContentPart, DirectCodexUserItem, DirectCodexUserMessageItem};
use super::validation::validate_direct_codex_user_item; use super::validation::validate_direct_codex_user_item;
use crate::agent::{read_manifest_for_project, sanitize_attachment_local_path}; use crate::agent::{read_manifest_for_project, sanitize_attachment_local_path};
use crate::ui_editor::persistence::{
generate_ui_design_code_at, GenerateUiDesignCodeInput, UI_DESIGN_DOC_ASSET_KIND,
UI_DESIGN_DOC_MEDIA_TYPE,
};
use serde_json::Value; use serde_json::Value;
use std::path::Path; use std::path::Path;
@@ -111,29 +115,165 @@ pub(crate) fn direct_codex_user_item_to_prompt(
item: &DirectCodexUserItem, item: &DirectCodexUserItem,
) -> Result<String, String> { ) -> Result<String, String> {
let wire = direct_codex_user_item_to_wire_input(root, item)?; let wire = direct_codex_user_item_to_wire_input(root, item)?;
wire.as_array() let DirectCodexUserItem::Message(message) = item;
let mut prompt = wire
.as_array()
.ok_or_else(|| "DirectProject user item wire input 不是数组".to_string()) .ok_or_else(|| "DirectProject user item wire input 不是数组".to_string())
.map(|parts| { .and_then(|parts| {
parts parts
.iter() .iter()
.filter_map(|part| part.get("text").and_then(Value::as_str)) .map(|part| {
.collect::<String>() part.get("text")
}) .and_then(Value::as_str)
.and_then(|prompt| { .ok_or_else(|| "DirectProject user item wire part 缺少 text".to_string())
if prompt.trim().is_empty() { })
Err("DirectProject user item 不能转换为空 prompt".to_string()) .collect::<Result<String, String>>()
} else { })?;
Ok(prompt) if let Some(code_context) = render_ui_design_code_context(root, message)? {
prompt.push('\n');
prompt.push_str(&code_context);
}
if prompt.trim().is_empty() {
return Err("DirectProject user item 不能转换为空 prompt".to_string());
}
Ok(prompt)
}
/// 本轮 prompt 的 UI 设计文档引用上下文:复用 UI Editor 代码导出,把带文档注释的
/// JS 片段路径交给模型;生成失败只追加原始错误,不阻断本轮引用,其它引用继续处理。
///
/// 只在生成本轮 prompt 时展开:历史 item 回读走 `direct_codex_user_item_to_response_item`
/// 的纯投影,不得在这里产生项目写副作用。
fn render_ui_design_code_context(
root: &Path,
message: &DirectCodexUserMessageItem,
) -> Result<Option<String>, String> {
let referenced_ids = message
.content
.iter()
.filter_map(|part| match part {
DirectCodexUserContentPart::AgcResourceReference { resource_id } => {
Some(resource_id.trim())
} }
_ => None,
}) })
.collect::<Vec<_>>();
if referenced_ids.is_empty() {
return Ok(None);
}
let manifest = read_manifest_for_project(root)?;
let mut lines = Vec::new();
for resource_id in referenced_ids {
let is_ui_design_doc = manifest.assets.iter().any(|asset| {
asset.id == resource_id
&& asset.kind == UI_DESIGN_DOC_ASSET_KIND
&& asset.media_type == UI_DESIGN_DOC_MEDIA_TYPE
});
if !is_ui_design_doc {
continue;
}
lines.push(
match generate_ui_design_code_at(GenerateUiDesignCodeInput {
project_path: root.to_string_lossy().into_owned(),
expected_project_id: manifest.project_id.clone(),
asset_id: resource_id.to_string(),
}) {
Ok(result) => format!("请先阅读生成的带有文档的代码片段: {}", result.relative_path),
Err(error) => format!("生成代码遇到错误{error}"),
},
);
}
if lines.is_empty() {
return Ok(None);
}
Ok(Some(lines.join("\n")))
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::direct_codex_user_item_to_response_item; use super::{direct_codex_user_item_to_prompt, direct_codex_user_item_to_response_item};
use crate::ui_editor::persistence::UI_DESIGN_DOC_MEDIA_TYPE;
use serde_json::json; use serde_json::json;
use shared_contracts::game_creation_app::{
GameCreationAppAssetKind, GameCreationAppAssetSource, GameCreationAppAssetSourceKind,
};
use std::path::Path; use std::path::Path;
const PROMPT_CONTEXT_PROJECT_ID: &str = "direct-prompt-context-project";
fn prompt_context_project() -> tempfile::TempDir {
let directory = tempfile::tempdir().expect("temp project");
crate::init_local_game_project_at(
directory.path(),
PROMPT_CONTEXT_PROJECT_ID,
"Direct prompt 上下文测试",
)
.expect("init project");
directory
}
fn register_fixture_asset(
root: &Path,
relative_path: &str,
kind: GameCreationAppAssetKind,
media_type: &str,
) -> String {
let absolute_path = crate::resolve_local_project_path(root, relative_path)
.expect("resolve fixture asset path");
std::fs::create_dir_all(absolute_path.parent().expect("fixture asset parent"))
.expect("create fixture asset parent");
std::fs::write(&absolute_path, b"{}").expect("write fixture asset file");
crate::assets::register_local_asset_at(
root,
relative_path,
kind,
media_type,
"prompt-context-test",
GameCreationAppAssetSource {
kind: GameCreationAppAssetSourceKind::Generated,
canvas_project_id: None,
resource_id: Some("prompt-context".to_string()),
asset_object_id: None,
task_id: None,
prompt: None,
model: None,
generation_route: None,
generation_kind: None,
reference_resource_ids: Vec::new(),
},
)
.expect("register fixture asset")
.id
}
fn ui_design_doc_fixture(initialize_state: bool) -> (tempfile::TempDir, String) {
let directory = prompt_context_project();
let asset_id = register_fixture_asset(
directory.path(),
"ui/design.json",
GameCreationAppAssetKind::UiDesignDoc,
UI_DESIGN_DOC_MEDIA_TYPE,
);
if initialize_state {
crate::ui_editor::persistence::initialize_ui_design_state_at(
directory.path(),
PROMPT_CONTEXT_PROJECT_ID,
&asset_id,
)
.expect("initialize UI design state");
}
(directory, asset_id)
}
fn user_item_with_resource_reference(asset_id: &str) -> serde_json::Value {
json!({
"type": "message",
"role": "user",
"id": "turn-1:user",
"content": [{"type": "agc_resource_reference", "resourceId": asset_id}],
})
}
#[test] #[test]
fn standard_response_item_passes_through_without_agc_private_parts() { fn standard_response_item_passes_through_without_agc_private_parts() {
let item = json!({ let item = json!({
@@ -174,4 +314,81 @@ mod tests {
.expect_err("history item without type must fail"); .expect_err("history item without type must fail");
assert!(error.contains("缺少 type"), "{error}"); assert!(error.contains("缺少 type"), "{error}");
} }
#[test]
fn ui_design_doc_reference_appends_generated_code_context() {
let (project, asset_id) = ui_design_doc_fixture(true);
let item: super::DirectCodexUserItem =
serde_json::from_value(user_item_with_resource_reference(&asset_id))
.expect("canonical user item");
let prompt =
direct_codex_user_item_to_prompt(project.path(), &item).expect("prompt projection");
assert!(
prompt.contains(&format!(
"[素材引用 resourceId={asset_id};项目路径=ui/design.json]"
)),
"{prompt}"
);
assert!(
prompt.contains("请先阅读生成的带有文档的代码片段: ui/generated-"),
"{prompt}"
);
}
#[test]
fn history_projection_never_writes_generated_ui_design_code() {
let (project, asset_id) = ui_design_doc_fixture(true);
let item = user_item_with_resource_reference(&asset_id);
direct_codex_user_item_to_response_item(project.path(), &item).expect("history projection");
let generated_root =
crate::resolve_local_project_path(project.path(), "ui").expect("resolve ui directory");
let generated_files = std::fs::read_dir(generated_root)
.expect("read ui directory")
.filter_map(|entry| entry.ok())
.filter(|entry| {
entry
.file_name()
.to_string_lossy()
.starts_with("generated-")
})
.count();
assert_eq!(
generated_files, 0,
"历史回读只做纯投影,不得生成 UI 设计代码"
);
}
#[test]
fn ui_design_generation_failure_keeps_reference_and_reports_error() {
let (project, asset_id) = ui_design_doc_fixture(false);
let item: super::DirectCodexUserItem =
serde_json::from_value(user_item_with_resource_reference(&asset_id))
.expect("canonical user item");
let prompt =
direct_codex_user_item_to_prompt(project.path(), &item).expect("prompt projection");
assert!(prompt.contains("素材引用 resourceId="), "{prompt}");
assert!(prompt.contains("生成代码遇到错误"), "{prompt}");
}
#[test]
fn other_asset_kind_reference_does_not_generate_ui_design_code() {
let project = prompt_context_project();
let asset_id = register_fixture_asset(
project.path(),
"assets/hero.png",
GameCreationAppAssetKind::Character,
"image/png",
);
let item: super::DirectCodexUserItem =
serde_json::from_value(user_item_with_resource_reference(&asset_id))
.expect("canonical user item");
let prompt =
direct_codex_user_item_to_prompt(project.path(), &item).expect("prompt projection");
assert!(prompt.contains("素材引用 resourceId="), "{prompt}");
assert!(
!prompt.contains("请先阅读生成的带有文档的代码片段"),
"{prompt}"
);
assert!(!prompt.contains("生成代码遇到错误"), "{prompt}");
}
} }
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
@@ -75,14 +75,7 @@ pub(crate) fn run_direct_tools_mcp_if_requested(args: &[String]) -> Option<i32>
async fn direct_tools_mcp_specs() -> Value { async fn direct_tools_mcp_specs() -> Value {
let mut cocos_editor_available = false; let mut cocos_editor_available = false;
let mut unity_editor_available = false; if cfg!(all(windows, feature = "cocos-editor-execute")) {
if cfg!(all(windows, feature = "cocos-editor-execute"))
|| cfg!(all(
windows,
target_arch = "x86_64",
feature = "unity-editor-execute"
))
{
// 每次 tools/list 询问绑定的宿主;失败时不广告可选插件工具。 // 每次 tools/list 询问绑定的宿主;失败时不广告可选插件工具。
if let Ok(result) = tokio::time::timeout( if let Ok(result) = tokio::time::timeout(
std::time::Duration::from_secs(5), std::time::Duration::from_secs(5),
@@ -103,22 +96,10 @@ async fn direct_tools_mcp_specs() -> Value {
.iter() .iter()
.any(|tool| tool == crate::builtin_plugins::AGC_COCOS_EDITOR_TOOL_NAME) .any(|tool| tool == crate::builtin_plugins::AGC_COCOS_EDITOR_TOOL_NAME)
}); });
unity_editor_available = availability
.as_ref()
.and_then(|v| v["tools"].as_array())
.is_some_and(|tools| {
tools
.iter()
.any(|tool| tool == crate::builtin_plugins::AGC_UNITY_EDITOR_TOOL_NAME)
});
} }
} }
} }
direct_tools_mcp_specs_for_plugins( direct_tools_mcp_specs_for(controlled_web_search_enabled(), cocos_editor_available)
controlled_web_search_enabled(),
cocos_editor_available,
unity_editor_available,
)
} }
/// 工具 kind(wire 值)对应的提示词上限。 /// 工具 kind(wire 值)对应的提示词上限。
@@ -147,16 +128,7 @@ fn resource_tool_prompt_schema_max_chars() -> usize {
.unwrap_or(0) .unwrap_or(0)
} }
#[cfg(test)] fn direct_tools_mcp_specs_for(controlled_web_search: bool, _cocos_editor_available: bool) -> Value {
fn direct_tools_mcp_specs_for(controlled_web_search: bool, cocos_editor_available: bool) -> Value {
direct_tools_mcp_specs_for_plugins(controlled_web_search, cocos_editor_available, false)
}
fn direct_tools_mcp_specs_for_plugins(
controlled_web_search: bool,
_cocos_editor_available: bool,
_unity_editor_available: bool,
) -> Value {
let tools = vec![ let tools = vec![
json!({ json!({
"name": "client.session.info", "name": "client.session.info",
@@ -275,7 +247,7 @@ fn direct_tools_mcp_specs_for_plugins(
"type": "string", "type": "string",
"enum": PLATFORM_ART_ASSET_GENERATION_KINDS, "enum": PLATFORM_ART_ASSET_GENERATION_KINDS,
"default": "image", "default": "image",
"description": "image=普通新图(不做额外处理),character=角色图(纯色底生成后自动抠图,产出透明背景立绘,prompt 只描述角色主体),spec/icon-spec=统一视觉规范图(spec 是服务端同义词,客户端统一登记为 icon-spec),ui-prototype=完整 UI 设计图,art-spritesheet=透明游戏素材图集(纯色底生成后自动抠图并切片,项目须已有 icon-spec 规范图),publication-material=发布宣传图" "description": "image=普通新图(不做额外处理),character=角色图(纯色底生成后自动抠图,产出透明背景立绘,prompt 只描述角色主体),icon-spec=统一视觉规范图ui-design=完整 UI 设计图,icon-spritesheet=透明游戏素材图集(纯色底生成后自动抠图并切片,项目须已有 icon-spec 规范图),publication-material=发布宣传图"
}, },
"aspectRatio": { "aspectRatio": {
"type": "string", "type": "string",
@@ -301,7 +273,7 @@ fn direct_tools_mcp_specs_for_plugins(
"sliceMode": { "sliceMode": {
"type": "string", "type": "string",
"enum": ["connected-components", "grid"], "enum": ["connected-components", "grid"],
"description": "仅 kind=art-spritesheet 生效,且必填、没有默认值:需求明确要求等分网格、固定槽位或指定行列数时传 grid,并用 gridX/gridY 传入来自需求本身的行列数;自由排布、数量不定或只要求一张图集时传 connected-components,需要约束素材张数时用 sliceCount。省略、与 kind 不匹配或与 gridX/gridY 互相矛盾时客户端直接拒绝,不会替你选择" "description": "仅 kind=icon-spritesheet 生效,且必填、没有默认值:需求明确要求等分网格、固定槽位或指定行列数时传 grid,并用 gridX/gridY 传入来自需求本身的行列数;自由排布、数量不定或只要求一张图集时传 connected-components,需要约束素材张数时用 sliceCount。省略、与 kind 不匹配或与 gridX/gridY 互相矛盾时客户端直接拒绝,不会替你选择"
}, },
"gridX": { "gridX": {
"type": "integer", "type": "integer",
@@ -319,11 +291,11 @@ fn direct_tools_mcp_specs_for_plugins(
"type": "integer", "type": "integer",
"minimum": 1, "minimum": 1,
"maximum": 256, "maximum": 256,
"description": "只与 kind=art-spritesheet 且 sliceMode=connected-components 同时提供,用于约束目标素材张数;省略时按图像内容自动识别" "description": "只与 kind=icon-spritesheet 且 sliceMode=connected-components 同时提供,用于约束目标素材张数;省略时按图像内容自动识别"
}, },
"screenColor": { "screenColor": {
"type": "string", "type": "string",
"description": "抠图纯色背景,仅 kind=character(角色形象)和 kind=art-spritesheet(图标素材)生效,其它 kind 携带会被拒绝。生成时把主体置于该纯色背景上,回图后据此抠除背景。取值只能是 auto 或下列色板 hex 之一,传值只填 hex 本身、不要附带色名:#CFEFFF(浅雾蓝)、#B0C2E0(浅钢蓝)、#FFD6C2(暖浅桃色)、#E6D8FF(淡薰衣草紫)、#F4D8E8(浅粉灰)、#7FB3FF(中度天蓝)、#FFF2A8(浅柠黄)、#CFFFE1(淡薄荷绿)、#D8DEE8(浅中性灰)、#D8D2E8(淡灰紫)、#A8F7F0(高对比浅青)、#A0BBA0(灰竹绿);auto 时由服务端自动选色。手动指定时不能与角色或素材本体的颜色接近" "description": "抠图纯色背景,仅 kind=character(角色形象)和 kind=icon-spritesheet(图标素材)生效,其它 kind 携带会被拒绝。生成时把主体置于该纯色背景上,回图后据此抠除背景。取值只能是 auto 或下列色板 hex 之一,传值只填 hex 本身、不要附带色名:#CFEFFF(浅雾蓝)、#B0C2E0(浅钢蓝)、#FFD6C2(暖浅桃色)、#E6D8FF(淡薰衣草紫)、#F4D8E8(浅粉灰)、#7FB3FF(中度天蓝)、#FFF2A8(浅柠黄)、#CFFFE1(淡薄荷绿)、#D8DEE8(浅中性灰)、#D8D2E8(淡灰紫)、#A8F7F0(高对比浅青)、#A0BBA0(灰竹绿);auto 时由服务端自动选色。手动指定时不能与角色或素材本体的颜色接近"
} }
}, },
"required": ["prompt"], "required": ["prompt"],
@@ -369,7 +341,7 @@ fn direct_tools_mcp_specs_for_plugins(
"type": "string", "type": "string",
"minLength": 1, "minLength": 1,
"maxLength": 80, "maxLength": 80,
"description": "可选的 manifest 资源 kind 精确过滤,例如 video、character-animation、sound-effect、background-music 或 art-spritesheet-slice" "description": "可选的 manifest 资源 kind 精确过滤,必须是 canonical kind例如 video、character-animation、sound-effect、background-music、icon-spritesheet);传非 canonical 值会被拒绝并报错,不会静默返回空列表"
}, },
"assetId": { "assetId": {
"type": "string", "type": "string",
@@ -596,14 +568,6 @@ fn direct_tools_mcp_specs_for_plugins(
.cloned(), .cloned(),
); );
} }
#[cfg(all(windows, target_arch = "x86_64", feature = "unity-editor-execute"))]
if _unity_editor_available {
tools.push(json!({
"name": "agc_unity_execute",
"description": "在当前项目已打开的 Windows x64 Unity Mono Editor 执行 C#,可使用 return 返回值。仅提交 code;宿主绑定项目及进程。needs-reconciliation 或超时后禁止自动重发。",
"inputSchema": {"type":"object", "properties":{"code":{"type":"string", "minLength":1, "maxLength":131072}}, "required":["code"], "additionalProperties":false}
}));
}
if controlled_web_search { if controlled_web_search {
tools.push(json!({ tools.push(json!({
"name": "agc_web_search", "name": "agc_web_search",
@@ -691,24 +655,6 @@ async fn call_agc_cocos_execute(arguments: &Value) -> Value {
call_client_tool_bridge("agc_cocos_execute", arguments).await call_client_tool_bridge("agc_cocos_execute", arguments).await
} }
#[cfg(all(windows, target_arch = "x86_64", feature = "unity-editor-execute"))]
async fn call_agc_unity_execute(arguments: &Value) -> Value {
let validated = validate_tool_object_fields(arguments, &["code"]).and_then(|()| {
let code = arguments
.get("code")
.and_then(Value::as_str)
.ok_or_else(|| "code 必须是 C# 代码".to_string())?;
if code.trim().is_empty() || code.len() > 131072 || code.contains('\0') {
return Err("code 不能为空、包含 NUL 或超过 128 KiB".to_string());
}
Ok(())
});
if let Err(error) = validated {
return mcp_tool_result(error, Vec::new(), true);
}
call_client_tool_bridge("agc_unity_execute", arguments).await
}
fn mcp_success(id: Value, result: Value) -> Value { fn mcp_success(id: Value, result: Value) -> Value {
json!({ "jsonrpc": "2.0", "id": id, "result": result }) json!({ "jsonrpc": "2.0", "id": id, "result": result })
} }
@@ -1811,8 +1757,6 @@ async fn handle_direct_tools_mcp_request(root: &Path, request: Value) -> Option<
"agc_write_file" => call_agc_write_file(&arguments).await, "agc_write_file" => call_agc_write_file(&arguments).await,
#[cfg(all(windows, feature = "cocos-editor-execute"))] #[cfg(all(windows, feature = "cocos-editor-execute"))]
"agc_cocos_execute" => call_agc_cocos_execute(&arguments).await, "agc_cocos_execute" => call_agc_cocos_execute(&arguments).await,
#[cfg(all(windows, target_arch = "x86_64", feature = "unity-editor-execute"))]
"agc_unity_execute" => call_agc_unity_execute(&arguments).await,
#[cfg(all(windows, feature = "cocos-editor-execute"))] #[cfg(all(windows, feature = "cocos-editor-execute"))]
operation if cocos_editor_bridge::is_cocos_operation(operation) => { operation if cocos_editor_bridge::is_cocos_operation(operation) => {
call_client_tool_bridge(operation, &arguments).await call_client_tool_bridge(operation, &arguments).await
@@ -2579,7 +2523,7 @@ mod tests {
// 目录外的 kind 必须在本地拒绝:既不下发 bridge,也不产生任何计费副作用。 // 目录外的 kind 必须在本地拒绝:既不下发 bridge,也不产生任何计费副作用。
let unsupported_kind = call_agc_generate_image(&json!({ let unsupported_kind = call_agc_generate_image(&json!({
"prompt": "像素月光主角", "prompt": "像素月光主角",
"kind": "game-art" "kind": "future-kind"
})) }))
.await; .await;
assert_eq!(unsupported_kind["isError"], json!(true)); assert_eq!(unsupported_kind["isError"], json!(true));
@@ -2589,7 +2533,7 @@ mod tests {
let oversized_prompt = call_agc_generate_image(&json!({ let oversized_prompt = call_agc_generate_image(&json!({
"prompt": "x".repeat(DIRECT_TOOLS_MCP_MAX_IMAGE_PROMPT_CHARS + 1), "prompt": "x".repeat(DIRECT_TOOLS_MCP_MAX_IMAGE_PROMPT_CHARS + 1),
"kind": "art-spritesheet" "kind": "icon-spritesheet"
})) }))
.await; .await;
assert_eq!(oversized_prompt["isError"], json!(true)); assert_eq!(oversized_prompt["isError"], json!(true));
@@ -2953,12 +2897,12 @@ mod tests {
fn tool_chain_image_asset(id: &str, local_path: &str) -> GameCreationAppAssetManifestEntry { fn tool_chain_image_asset(id: &str, local_path: &str) -> GameCreationAppAssetManifestEntry {
GameCreationAppAssetManifestEntry { GameCreationAppAssetManifestEntry {
id: id.to_string(), id: id.to_string(),
kind: "image".to_string(), kind: GameCreationAppAssetKind::Image,
media_type: "image/png".to_string(), media_type: "image/png".to_string(),
local_path: local_path.to_string(), local_path: local_path.to_string(),
image_sequence_frames: None, image_sequence_frames: None,
image_sequence_duration_ms: None, image_sequence_duration_ms: None,
category: game_creation_app_asset_category_for_kind("image"), category: game_creation_app_asset_category_for_kind(GameCreationAppAssetKind::Image),
tags: Vec::new(), tags: Vec::new(),
source: GameCreationAppAssetSource { source: GameCreationAppAssetSource {
kind: GameCreationAppAssetSourceKind::Canvas, kind: GameCreationAppAssetSourceKind::Canvas,
File diff suppressed because it is too large Load Diff
@@ -31,9 +31,9 @@ fn is_direct_platform_art_generation_runtime_context(
context: &PlatformArtGenerationRuntimeContext, context: &PlatformArtGenerationRuntimeContext,
) -> bool { ) -> bool {
let asset_kind = match context.run_id.as_str() { let asset_kind = match context.run_id.as_str() {
"art-spec" => "icon-spec", "art-spec" => GameCreationAppAssetKind::IconSpec,
"game-background" => "game-background", "game-background" => GameCreationAppAssetKind::Scene,
"art-spritesheet" => "art-spritesheet", "art-spritesheet" => GameCreationAppAssetKind::IconSpritesheet,
_ => return false, _ => return false,
}; };
context.agent_id == "direct-codex-art" context.agent_id == "direct-codex-art"
@@ -42,7 +42,11 @@ fn is_direct_platform_art_generation_runtime_context(
&& context.source == "direct-codex" && context.source == "direct-codex"
&& context.action_id == format!("direct-taonier-{}", context.run_id) && context.action_id == format!("direct-taonier-{}", context.run_id)
&& context.action_fingerprint && context.action_fingerprint
== format!("direct-taonier-art-v1:{asset_kind}:{}", context.run_id) == format!(
"direct-taonier-art-v1:{}:{}",
asset_kind.as_str(),
context.run_id
)
} }
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]

Some files were not shown because too many files have changed in this diff Show More