Merge remote-tracking branch 'refs/remotes/origin/master' into feat/gptimage2to2.5
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 7m17s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 7m25s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 7m34s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 7m37s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m3s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 3m23s
Project CI / Frontend tests (pull_request) Failing after 14m1s
Project CI / Repository checks (pull_request) Successful in 12m35s
Project CI / Native shell tests (pull_request) Successful in 17m2s
Project CI / Backend tests (pull_request) Successful in 17m18s
Project CI / AI game creator shell web tests (pull_request) Failing after 14m48s
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 7m17s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 7m25s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 7m34s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 7m37s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m3s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 3m23s
Project CI / Frontend tests (pull_request) Failing after 14m1s
Project CI / Repository checks (pull_request) Successful in 12m35s
Project CI / Native shell tests (pull_request) Successful in 17m2s
Project CI / Backend tests (pull_request) Successful in 17m18s
Project CI / AI game creator shell web tests (pull_request) Failing after 14m48s
This commit is contained in:
@@ -25,6 +25,8 @@
|
||||
|
||||
## AI 游戏创作与 Agent Runtime
|
||||
|
||||
- [AGC 资源 kind 枚举化契约](./technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md#2026-09-15-gamecreationapp-资源-kind-枚举化当前权威口径):GameCreationApp 资源 kind 的 Rust enum、ts-rs 绑定、Unknown 可观测性和 shell 内重构边界。
|
||||
|
||||
- [策划 Agent 生产迁移与工作区浏览](./technical/【技术方案】策划Agent生产迁移与工作区浏览-2026-09-10.md):实施中;以自由协作原型为行为基线,复用生产基建,采用阶段审批与用户工作区文件浏览。无旧 V2 会话的策划入口切换到新设计 Agent。
|
||||
|
||||
- [LLM 累计额度结算](./technical/【技术方案】LLM累计额度结算-2026-09-05.md):Router 累计额度、首次基线与原子钱包结算。
|
||||
@@ -38,6 +40,7 @@
|
||||
- [GameAgent 对话工具调用卡片](./technical/【技术方案】GameAgent对话工具调用卡片-2026-09-14.md):把右侧对话里的执行命令 / 写文件投影成 Codex 风格可折叠卡片,含采集、独立历史文件、事件字段与回读契约。
|
||||
- [DirectProject 客户端 Skill 与 MCP 扩展导入方案](./technical/【技术方案】DirectProject客户端Skill与MCP扩展导入方案-2026-08-31.md):客户端扩展导入、按独立 Skill/MCP 拆分、命名、启用和启动时注入边界。
|
||||
- [AGC 通用插件宿主与编辑器适配](./technical/【技术方案】AGC通用插件宿主与编辑器适配-2026-09-09.md):通用插件宿主、SDK、权限审计、UI 挂载和 Cocos 编辑器适配边界。
|
||||
- [AGC Unity 编辑器插件接入](./technical/【技术方案】AGC Unity编辑器插件接入-2026-09-18.md):DotCraft Attach 来源、Windows Mono 接入、项目身份、执行回执和分发边界。
|
||||
- [AGC Cocos Creator 编辑器桥接模块](<./technical/【技术方案】AGC Cocos Creator 编辑器桥接模块-2026-09-09.md>):独立 crate、feature 开关、目标校验与 Windows 注入边界。
|
||||
- [AGC 客户端更新检查与下载](./technical/【技术方案】AGC客户端更新检查与下载-2026-08-31.md):启动版本检测、OSS 清单格式和下载约定。
|
||||
- [AGC 模板库与模板建项](./technical/【技术方案】AGC模板库与模板建项-2026-09-17.md):`templates/` 前缀的模板库契约、下载安装与「用模板建项目」链路。
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,61 @@
|
||||
# 【实施计划】AGC 资源 kind Rust 枚举与 ts-rs 绑定
|
||||
|
||||
| 字段 | 值 |
|
||||
| --- | --- |
|
||||
| Milestone | `docs/project-memory/plans/【里程碑】AGC资源kind枚举化Rust绑定与内部收紧-2026-09-15.md` |
|
||||
| Status | complete |
|
||||
| Owner | Codex |
|
||||
|
||||
## 修改边界
|
||||
|
||||
允许修改:
|
||||
|
||||
- `server-rs/crates/shared-contracts` 内 GameCreationApp 资源 kind 的独立 Rust 模块;
|
||||
- shared-contracts 的可选 ts-rs 绑定 feature;
|
||||
- ai-game-creator-shell 的 shared-contracts feature 引用和生成测试入口;
|
||||
- shell 内生成的 GameCreationApp kind TypeScript 文件;
|
||||
- 对应 Rust/TS 定向测试与文档 todo 证据。
|
||||
|
||||
本切片已落地:
|
||||
|
||||
- `GameCreationAppAssetManifestEntry.kind` 由 `String` 收紧为 `GameCreationAppAssetKind`:这是公开 Rust 类型的破坏性变更,按「不写历史兼容代码」直接改类型,不加兼容层、不做数据迁移;manifest 反序列化未知值收口为 `Unknown`。
|
||||
- 上传内容推断的字体写入 `Font`,未知上传类型写入 `Unknown`;图集切片 manifest 写入 `Icon`。
|
||||
- shell 内 manifest kind 的写入侧与读取侧统一为正式枚举成员:资源登记、字体导入、direct runtime 产物、平台美术登记与恢复、manifest 必填校验、资源编辑派生、UI 设计桥接与工作流。
|
||||
- 资源编辑请求的 `sourceSubtype` 只传正式枚举成员;资源编辑内部源身份拆成「正式 kind / 项目版本 / Agent 回执」三类,项目版本与 Agent 回执不再冒充 manifest kind。
|
||||
- ts-rs 绑定改由 `cargo test export_bindings` 生成:枚举自带 `#[ts(export, export_to = …/src/contracts/generated/)]`;退役的 `BindingDTO` / `BindingChange` 不再导出,手写的 `exports_ui_editor_types` 已删除。
|
||||
- `packages/shared/src/contracts/generated/` 作为受控生成目录在 `.prettierrc.json` 中使用与 ts-rs 原始输出一致的格式选项,并在 `.gitattributes` 标记为 `linguist-generated`;生成文件仍参与 Prettier/ESLint 检查,`cargo test export_bindings` 可幂等复现且不再污染工作树。
|
||||
- `Unknown` 表示解析边界无法判定的输入;写入方可以保留该结果,但必须明确决定拒绝写入或交由后续归类,不得把它误写成某个具体 kind。
|
||||
- shell TS 资源引用边界消费生成绑定,资源 kind 集合从生成的 union 穷举派生,并为未知值保留原始值与上下文日志。
|
||||
- api-server 图片快速编辑来源校验改为严格解析 `GameCreationAppAssetKind`,只允许共享枚举的静态图片成员;删除原有 legacy/兼容字符串白名单,退役值不再放行。
|
||||
|
||||
明确不修改:
|
||||
|
||||
- `category`、`mediaType`、`source.kind`、`source.generationKind`;
|
||||
- api-server 的其他资源 taxonomy、SpacetimeDB schema、OpenAPI;本切片只改图片快速编辑的 GameCreationApp manifest 来源校验。
|
||||
- shared-contracts 的 canonical alias 表与读时自愈:alias 表已删除,严格解析和 `Unknown` 口径保持不变;
|
||||
- `packages/shared` 中重复的资源 kind 手写契约与其余前端裸 `string` 字段(后续切片)。
|
||||
|
||||
## 实现顺序
|
||||
|
||||
1. 新建独立 kind 模块,定义当前正式成员:17 个现有 canonical kind + `font` + `Unknown`,serde 使用 kebab-case。
|
||||
2. 为 enum 增加可选 ts-rs derive,默认 shared-contracts 构建不引入 ts-rs。
|
||||
3. 让 shell 的 shared-contracts 依赖打开绑定 feature;生成目录 2026-09-17 起收敛到 `packages/shared/src/contracts/generated/`(kind 是跨端契约,不再放 shell 私有目录)。
|
||||
4. 增加 Rust serde round-trip 与 Unknown 解析/序列化测试;TS 侧不再手写生成值集合,改为从生成 union 穷举派生。
|
||||
未知值通过 `parse_with_context` 收口到 `Unknown`,并把原始值与解析上下文交给壳层注册的 `app_log!` 回调(2026-09-17 起不再用 `tracing` / `kind-observability`)。
|
||||
5. 运行 shared-contracts 与 shell 定向测试,并用 `export_bindings` 复现生成文件;完成后将稳定结论回写里程碑并关闭本计划。
|
||||
|
||||
## 验证命令
|
||||
|
||||
1. `cargo fmt --all -- --check`
|
||||
2. `cargo test --locked -p shared-contracts game_creation_app --manifest-path server-rs/Cargo.toml`
|
||||
3. `cargo test --locked -p shared-contracts --features ts-bindings export_bindings --manifest-path server-rs/Cargo.toml`(生成 `packages/shared/src/contracts/generated/GameCreationAppAssetKind.ts`)
|
||||
4. `cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml export_bindings`(生成 shell 自己的 ts-rs 绑定)
|
||||
5. `npx vitest run apps/ai-game-creator-shell/tests/assetKind.test.ts packages/shared/src/contracts/gameCreationApp.test.ts`(解析 Rust 源码的 `assetKindCanonicalMapping.test.ts` 2026-09-17 已删除:手写词汇表被移除后它没有比对对象)
|
||||
6. `npm run check:encoding`
|
||||
7. `git diff --check`
|
||||
|
||||
## 风险与回滚点
|
||||
|
||||
- 风险:ts-rs 默认生成 enum/union 形态与 serde rename 不一致;必须以生成文件和 round-trip 测试为准。
|
||||
- 风险:shared-contracts 被 SpacetimeDB/WASM 使用;ts-rs 必须是 optional feature,默认构建不可依赖。
|
||||
- 回滚点:本切片仅新增 enum/绑定,不改变现有 manifest JSON 解析;若生成链路不稳定,可回滚本提交而不影响现有业务。
|
||||
@@ -0,0 +1,43 @@
|
||||
# 【实施计划】AGC 资源 kind 词汇审计与绑定架构
|
||||
|
||||
| 字段 | 值 |
|
||||
| --- | --- |
|
||||
| Milestone | `docs/project-memory/plans/【里程碑】AGC资源kind枚举化词汇审计与绑定架构-2026-09-15.md` |
|
||||
| Status | complete |
|
||||
| Owner | Codex |
|
||||
|
||||
## 修改边界
|
||||
|
||||
允许修改:
|
||||
|
||||
- 主规范中的资源 kind 当前口径;
|
||||
- `docs/project-memory/plans/` 下本任务的里程碑/实施计划;
|
||||
- `docs/project-memory/todos/` 下本任务的扫描清单;
|
||||
- 为审计提供只读扫描脚本(如确有必要,脚本也只覆盖 shell)。
|
||||
|
||||
明确不修改:
|
||||
|
||||
- 已完成的 `apps/ai-game-creator-shell` 业务收口不再属于未决范围;后续只允许按新里程碑变更;
|
||||
- server-side 代码、OpenAPI、SpacetimeDB schema;
|
||||
- MIME、`source.kind`、`generationKind` 和其他字符串领域。
|
||||
|
||||
## 实现顺序
|
||||
|
||||
1. 按“manifest asset kind / 其他字段 / 仅文本同名”三类扫描 shell 的 `kind`、`assetKind`、`asset_kind` 和 manifest 构造器。
|
||||
2. 对每个候选值回到调用上下文,标记生产写入、读取投影、协议输入、测试 fixture 或纯文本/路径。
|
||||
3. 对照 api-server 当前有效资源 kind,排除 legacy、billing/storage synthetic taxonomy 和开放字段。
|
||||
4. 记录正式候选 enum、Unknown 输入行为、保留字符串字段和后续 PR 边界。
|
||||
5. 形成下一里程碑的文件级修改顺序和验证矩阵;本里程碑结束后暂停,等待验收。
|
||||
|
||||
## 验证命令
|
||||
|
||||
1. `rg -n 'kind|assetKind|asset_kind' apps/ai-game-creator-shell/src apps/ai-game-creator-shell/src-tauri/src`
|
||||
2. `npm run check:doc-index`
|
||||
3. `npm run check:encoding`
|
||||
4. `git diff --check`
|
||||
|
||||
## 风险与回滚点
|
||||
|
||||
- 风险:同一字符串可能是 manifest kind、workflow kind 或路径名;任何未回到上下文确认的替换都禁止进入代码。
|
||||
- 风险:shared-contracts 被多个 server crate 使用;ts-rs 生成必须通过 feature/独立入口隔离默认构建。
|
||||
- 回滚点:本里程碑只有文档和审计清单变更;若词汇边界未能闭合,删除本计划和 todo,不进入代码里程碑。
|
||||
@@ -0,0 +1,51 @@
|
||||
# 【实施计划】UI设计文档引用代码上下文
|
||||
|
||||
| 字段 | 值 |
|
||||
| --- | --- |
|
||||
| Version | 1 |
|
||||
| Status | ready |
|
||||
| Owner | Codex |
|
||||
| Milestone | `docs/project-memory/plans/【里程碑】UI设计文档引用代码上下文-2026-09-14.md` |
|
||||
|
||||
## 修改边界
|
||||
|
||||
允许修改:
|
||||
|
||||
- UI Editor persistence/resource bridge/workflow/command 中的 UI JSON 文档 kind 常量与校验。
|
||||
- `packages/shared` 的 canonical kind 与 Rust 对应映射。
|
||||
- `agent/direct_codex_user_item/wire.rs` 的 UI 引用 prompt 生成。
|
||||
- 相关 Rust、TypeScript 测试和当前 UI workflow/AGC 文档。
|
||||
- `decision-log.md` 的长期决策记录。
|
||||
|
||||
明确不修改:
|
||||
|
||||
- `ui-prototype` 图片生成和图片 workflow 语义。
|
||||
- UI State schema、`render_ui_design_state_js` 输出格式和 `ui/generated-*.js` 路径规则。
|
||||
- SpacetimeDB schema、External v1 OpenAPI、非 Direct Codex Supervisor 引用行为。
|
||||
- 用户已有 `.env` 未提交修改。
|
||||
|
||||
## 实现顺序
|
||||
|
||||
1. 更新 UI workflow 主规范与项目决策,明确 `ui-design-doc` 与 `ui-prototype` 的身份边界。
|
||||
2. 在 persistence 提取并导出 UI 文档 kind/media 常量,替换 Rust UI 文档校验。
|
||||
3. 同步所有 UI JSON 资源生产者、workflow 校验、命令筛选、shared contract 与前端 bridge。
|
||||
4. 在 Direct Codex 引用渲染中调用 `generate_ui_design_code_at`;成功追加生成文件相对路径,失败追加原始错误并继续发送。
|
||||
5. 补充旧 kind、图片、成功、文档错误、多引用和 renderer 输出的测试。
|
||||
6. 执行定向验证,复核 diff 中无 fallback、迁移或无关 `.env` 修改。
|
||||
|
||||
## 验证命令
|
||||
|
||||
1. `cargo fmt --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml -- --check`
|
||||
2. `cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml ui_editor::persistence`
|
||||
3. `cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml direct_codex_user_item`
|
||||
4. 相关 shared contract Vitest 测试与前端类型检查
|
||||
5. `npm run check:doc-index`
|
||||
6. `npm run check:encoding`
|
||||
7. `git diff --check`
|
||||
|
||||
## 风险与回滚点
|
||||
|
||||
- `ui-prototype` 与 UI JSON 文档共用部分分类展示逻辑,需确保分类映射不会让图片进入文档分支。
|
||||
- `generate_ui_design_code_at` 会持有项目写锁;多引用必须顺序调用,不能并行写同一项目。
|
||||
- 生成失败继续发送是已确认语义;测试必须证明错误文本进入 prompt 而不是被转成聊天失败。
|
||||
- 若发现生产者仍写入旧 `UI`,按开发阶段合同直接修生产者和 fixture,不增加运行时兼容分支。
|
||||
@@ -0,0 +1,40 @@
|
||||
# 【里程碑】AGC 资源 kind 枚举化 Rust 绑定与内部收紧
|
||||
|
||||
| 字段 | 值 |
|
||||
| --- | --- |
|
||||
| Version | 1.0 |
|
||||
| Status | complete |
|
||||
| Date | 2026-09-15 |
|
||||
| Parent Spec | `docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md` |
|
||||
|
||||
## 目标
|
||||
|
||||
将 GameCreationApp 资源 kind 从 shell 内裸字符串收紧为 Rust `GameCreationAppAssetKind`,并生成 shell 专属 TypeScript 绑定;所有同语义内部字段使用该类型,未知输入解析为 `Unknown` 并记录日志。
|
||||
|
||||
## 范围
|
||||
|
||||
- Rust enum、serde kebab-case、`Unknown` 与 category 派生边界。
|
||||
- ts-rs feature-gated 生成入口、生成文件和 verify 门禁。
|
||||
- `packages/shared/src/contracts/gameCreationApp.ts` 中重复的资源 kind 手写契约迁入 shell 生成绑定后的删除/收口。
|
||||
- shell 内资源 kind 参数、投影、筛选、Agent 资源引用和 manifest 读写边界的类型收紧。
|
||||
|
||||
## 不在范围内
|
||||
|
||||
- server-side 其他 `asset_kind`、External API DTO、SpacetimeDB schema;仅纳入 api-server 图片快速编辑对 GameCreationApp manifest 来源的严格校验。
|
||||
- `source.kind`、`generationKind`、MIME 和文件格式。
|
||||
- 其他领域字段为配合本里程碑进行“顺手枚举化”。
|
||||
|
||||
## 依赖与前置条件
|
||||
|
||||
- 词汇审计里程碑通过并关闭所有阻塞项。
|
||||
- 生成目录、TS 导入路径、Unknown 日志字段和 writer 禁止主动写 Unknown 的规则已确认。
|
||||
|
||||
## 验收标准
|
||||
|
||||
- [x] Rust enum 与生成的 TS 绑定值逐项一致,JSON 使用 kebab-case;正式资源成员为当前 17 个 canonical kind 加 `font`,另有 `Unknown` 解析成员。TS 侧不再手写值集合,改为对生成 union 做穷举 `Record`。
|
||||
- [x] 未知输入得到 `Unknown`,日志包含原始值与调用上下文(`parse_with_context` + 壳层在 `main()` 注册的 `app_log!` 回调,见 2026-09-17 收敛)。
|
||||
- [x] 生产 writer 不再接受裸 `string` 作为 GameCreationApp kind(manifest 写入、资源登记、direct runtime、平台美术登记、资源编辑派生均只传枚举成员);`Unknown` 仅表示解析边界无法判定,调用方可拒绝或交后续归类。
|
||||
- [x] `font`、`audio`、`sound-effect`、`background-music` 均有真实生产路径(字体导入、上传音频推断、资源编辑音频派生)。
|
||||
- [x] ts-rs 绑定由 `cargo test export_bindings` 生成,生成目录加入 `.prettierignore` / eslint `ignorePatterns`,可幂等复现且不污染工作树。
|
||||
- [x] 退役的 `BindingDTO` / `BindingChange` 不再导出,手写的 `exports_ui_editor_types` 已删除。
|
||||
- [x] 旧 alias 不再由共享契约把非 canonical 输入收口成 canonical;api-server 图片快速编辑不再保留 legacy 兼容白名单,非 canonical 来源直接失败。
|
||||
@@ -0,0 +1,37 @@
|
||||
# 【里程碑】AGC 资源 kind 枚举化写入方清理与验证
|
||||
|
||||
| 字段 | 值 |
|
||||
| --- | --- |
|
||||
| Version | 1.0 |
|
||||
| Status | complete |
|
||||
| Date | 2026-09-15 |
|
||||
| Parent Spec | `docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md` |
|
||||
|
||||
## 目标
|
||||
|
||||
逐处修正 shell 内仍产生非正式 GameCreationApp kind 的生产代码;保留仅属于 workflow、generation、路径或其他领域的字符串,并为这些边界补充清晰类型/命名说明而不扩大本 PR。
|
||||
|
||||
## 范围
|
||||
|
||||
- manifest 登记、恢复、回填、资源替换、画板/图集导出、字体导入、上传推断和 Agent 资源登记。
|
||||
- shell 前端资源投影、筛选和资源引用消费方。
|
||||
- 删除 alias/fallback 生产逻辑及其只服务于旧值的测试。
|
||||
- 对仍保留的 workflow、generation、路径和其他领域字符串完成边界核对,不将其重新解释为 manifest kind。
|
||||
|
||||
## 不在范围内
|
||||
|
||||
- 不改 `source.kind`、`generationKind` 等其他字段,即使它们恰好使用同名值。
|
||||
- 不修改 server-side 代码或公开 API。
|
||||
- 不实现字体格式/MIME enum;`font` 只作为本次 manifest asset kind 成员。
|
||||
|
||||
## 依赖与前置条件
|
||||
|
||||
- Rust/TS 绑定里程碑通过。
|
||||
- 写入方扫描清单中每个 alias 都已有“manifest kind / 其他领域 / 删除”结论。
|
||||
|
||||
## 验收标准
|
||||
|
||||
- [x] 新建、导入、生成、恢复、替换路径不会写入未纳入 enum 的 manifest kind。
|
||||
- [x] 未知外部值只进入 `Unknown` 并有 trace;缺失输入的中性默认仅由明确登记入口决定。
|
||||
- [x] `source.kind` 与 `generationKind` 的既有字符串行为不变。
|
||||
- [x] 定向 Rust、TS、绑定生成、编码和 diff 检查通过。
|
||||
@@ -0,0 +1,46 @@
|
||||
# 【里程碑】AGC 资源 kind 枚举化词汇审计与绑定架构
|
||||
|
||||
| 字段 | 值 |
|
||||
| --- | --- |
|
||||
| Version | 1.0 |
|
||||
| Status | complete |
|
||||
| Date | 2026-09-15 |
|
||||
| Parent Spec | `docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md` |
|
||||
|
||||
## 目标
|
||||
|
||||
在 `apps/ai-game-creator-shell` 内建立唯一的 GameCreationApp 资源 kind 领域边界:Rust enum 是权威,TypeScript 由 `ts-rs` 生成;先完成全量词汇审计和生成架构合同,再进入业务代码替换。
|
||||
|
||||
## 范围
|
||||
|
||||
- 审计 shell 内所有可能表示 GameCreationApp 资源 kind 的字段、构造器、写入边界、筛选器、资源投影、Agent 资源引用和测试 fixture,并收紧 api-server 图片快速编辑的 manifest 来源边界。
|
||||
- 以 api-server 当前仍有效的同语义 kind 作为命名与 serde 值参考,并评估 shell 当前实际生产 kind;排除 api-server legacy、billing/storage taxonomy 和其他开放领域。
|
||||
- 确认 Rust enum、`Unknown`、kebab-case JSON 和 ts-rs 生成文件的归属、生成命令与校验门禁。
|
||||
- 形成逐项 todo:当前值、真实语义、生产/测试状态、目标 enum、是否改写、验证方式。
|
||||
|
||||
## 不在范围内
|
||||
|
||||
- 不扫描或修改 api-server 其他领域的 `asset_kind`;图片快速编辑来源校验属于本次 GameCreationApp manifest 边界,必须复用共享枚举且不得保留 legacy 白名单。
|
||||
- 不改 `mediaType`、MIME、文件扩展名、`source.kind`、`source.generationKind`、任务/工作流 kind、路径名或 tracking scope。
|
||||
- manifest writer 与前端消费方已统一到共享 Rust enum/ts-rs binding;不扩展公开契约。
|
||||
- 不实现旧 manifest migration;无法解析的输入只在共享解析边界收口为 `Unknown`,由调用方拒绝或交后续归类,不增加 alias 表或 fallback。
|
||||
|
||||
## 依赖与前置条件
|
||||
|
||||
- 主规范已确认资源 kind 候选集合、`Unknown` 语义和 shell 边界。
|
||||
- `shared-contracts` 当前被 server-rs 多个 crate 使用,ts-rs 生成能力必须 feature-gated 或由独立生成入口启用,不能污染默认 SpacetimeDB/WASM 构建。
|
||||
- 当前已有 Tauri ts-rs 生成测试可作为生成命令形态参考,但不复用 UI Editor 类型目录作为资源契约目录。
|
||||
|
||||
## 验收标准
|
||||
|
||||
- [x] shell 内 manifest 资源 kind 的生产写入点、解析点、投影点和测试 fixture 已完成审计并收口。
|
||||
- [x] 每个旧值均已标注为:正式 GameCreationApp kind、其他领域字符串、legacy/错误 fallback;没有只按 grep 结果猜测的条目。
|
||||
- [x] api-server 有效值、shell 扩展值和排除值各有明确依据。
|
||||
- [x] 生成架构不会要求 server-side 默认构建安装 ts-rs。
|
||||
- [x] todo 清单的每项都有关闭条件和对应验证证据;图片快速编辑不再维护兼容白名单,退役 kind 直接失败。
|
||||
|
||||
## 证据要求
|
||||
|
||||
- 自动化:raw kind 扫描脚本/报告、Rust/TS 生成试验、serde kebab-case round-trip 试验。
|
||||
- 文档:主规范、todo 清单、下一里程碑实施计划互相链接且无冲突。
|
||||
- 边界:至少覆盖 `font`、`audio`、`sound-effect`、`background-music`、`Unknown`,以及 `source.kind`/`generationKind` 不误收编。
|
||||
@@ -0,0 +1,49 @@
|
||||
# 【里程碑】UI设计文档引用代码上下文
|
||||
|
||||
| 字段 | 值 |
|
||||
| --- | --- |
|
||||
| Version | 1 |
|
||||
| Status | in-progress |
|
||||
| Date | 2026-09-14 |
|
||||
| Parent Spec | `docs/【技术方案】UI工作流资源桥接与Runtime执行-2026-08-24.md` |
|
||||
|
||||
## 目标
|
||||
|
||||
将可编辑 UI JSON 文档统一识别为 `ui-design-doc`,并在 Direct Codex 聊天引用该文档时复用 UI Editor 现有代码导出流程,为 LLM 提供生成的、带文档注释的 JS 代码路径或原始生成错误。
|
||||
|
||||
## 范围
|
||||
|
||||
- UI JSON 文档资产身份固定为 `kind=ui-design-doc`、`mediaType=application/json`。
|
||||
- 复用 `ui_editor::persistence::generate_ui_design_code_at` 读取并校验文档、调用 `render_ui_design_state_js`、写入 `ui/generated-*.js`。
|
||||
- Direct Codex 引用文本保留稳定 manifest 元数据,并追加代码路径或 `生成代码遇到错误{error}`。
|
||||
- 同步 Rust/TypeScript 的 UI 文档生产者、消费者、分类映射和测试。
|
||||
- `ui-prototype` 图片继续作为独立源图片类型。
|
||||
|
||||
## 不在范围内
|
||||
|
||||
- 不接受旧 `UI`、`ui`、`ui-design` 作为 UI 文档类型。
|
||||
- 不增加兼容 fallback、数据迁移或旧数据转换逻辑。
|
||||
- 不把 `ui-prototype` 图片当作 UI 文档,不从图片生成替代 JSON 文档代码。
|
||||
- 不改变 UI State schema、renderer 输出格式、项目 revision 或 manifest 阶段。
|
||||
- 不改变旧 Supervisor 非 Direct Codex 引用链路。
|
||||
|
||||
## 依赖与前置条件
|
||||
|
||||
- `generate_ui_design_code_at` 已存在并返回 `relative_path`。
|
||||
- `render_ui_design_state_js` 已生成包含文档注释的 JS 模块。
|
||||
- Direct Codex 结构化引用已传递 `resourceId`,manifest 是资源身份权威。
|
||||
|
||||
## 验收标准
|
||||
|
||||
- [ ] UI 编辑器 JSON 资源创建、加载、保存、workflow 校验和引用分支均只接受 `ui-design-doc + application/json`。
|
||||
- [ ] Direct Codex 成功引用 UI 文档时,prompt 追加 `请先阅读生成的带有文档的代码片段: {relative_path}`。
|
||||
- [ ] UI 文档生成失败时,prompt 保留原 metadata 并追加 `生成代码遇到错误{error}`,不走图片或其它文件 fallback。
|
||||
- [ ] `ui-prototype` 图片引用不触发 UI 文档代码生成。
|
||||
- [ ] 多个引用按顺序处理,单个 UI 文档失败不丢失其它引用。
|
||||
- [ ] Rust/TypeScript kind 映射一致,旧 kind 不被隐式迁移。
|
||||
|
||||
## 证据要求
|
||||
|
||||
- 自动化:persistence、direct_codex_user_item、shared contract 定向测试;`cargo fmt --check`、`npm run check:encoding`、`git diff --check`。
|
||||
- 运行时:不要求真实 Provider;测试验证生成文件路径、renderer 文档注释和 prompt 注入结果。
|
||||
- 边界:旧 kind、图片 kind、损坏 JSON、renderer 错误、多引用和路径来源均有测试。
|
||||
@@ -2,6 +2,26 @@
|
||||
|
||||
> 用途:记录已经确认、会影响后续开发的长期技术/产品/协作决策。短期讨论不要写在这里。
|
||||
> 当前口径:历史条目的旧路径、旧版本和已退役对象只用于追溯,不构成现行实现依据;如与当前代码或 `docs/README.md` 冲突,以当前代码和最新专题文档为准。
|
||||
## 2026-09-17 GameCreationApp 资源 kind 只保留一份词汇表:严格解析 + `app_log!` 留痕
|
||||
|
||||
- 背景:kind 曾经有三份实现——Rust 手写 `GAME_CREATION_APP_CANONICAL_ASSET_KINDS` + `canonical_game_creation_app_asset_kind()`(带 legacy 别名表与 `font → document` 特例)、TS 手写 `GAME_CREATION_APP_CANONICAL_ASSET_KINDS` + `GAME_CREATION_APP_LEGACY_ASSET_KINDS` + `canonicalGameCreationAppAssetKind()`、以及 ts-rs 生成的 TS union。两份手写表互相引用又各自收口,判据直接分叉(同一个 `"UI"` 一边归一成 `ui-design`、一边收口成 `unknown`),跨语言一致性只能靠正则解析源码的测试来钉。
|
||||
- 决策(唯一真源):kind 的变体、线上值、`as_str()`、`ALL`、严格解析与 ts-rs 绑定全部由 `server-rs/crates/shared-contracts/src/game_creation_app/asset_kind.rs` 的声明表派生。两份手写 canonical 列表、legacy 别名表、`canonical_*()` 函数一律删除;生成的 TS union 落在 `packages/shared/src/contracts/generated/GameCreationAppAssetKind.ts`,`packages/shared/src/contracts/gameCreationApp.ts` 只 re-export 它,运行期列表 `GAME_CREATION_APP_ASSET_KINDS` 用穷举 `Record<GameCreationAppAssetKind, true>` 守住。
|
||||
- 决策(单一解析入口):`GameCreationAppAssetKind::parse_with_context()` 是唯一公开解析入口,严格匹配降为私有 `match_canonical()`;易混的 `from_str_lossy()` 与公开 `from_str_or_unknown()` 都已删除,认不出 canonical 值只有这一处收口并留痕(读侧回捞 legacy kind 只查 `ALL` 判真值,不另开解析函数)。口径是等值匹配——不 trim、不 lowercase、不查别名、不迁移;认不出的值收口成 `Unknown`(分类落 `unclassified`)。这是有意接受的行为(历史误写的 kind 不会被"救回"正确栏目),不再提供任何兼容入口;`font` 是正式成员,不再走别名。
|
||||
- 决策(登记边界的 kind 口径):外部登记统一走 `assets::registration_asset_kind()`——空白入参落中性 `image`,非空认不出的值严格收口成 `unknown` 并留痕;三条登记边界(Tauri `register_local_asset`、画板导入、平台导入)不再各写一份 trim/兜底。`Unknown` 是无法解析的边界结果,具体写入方必须自行决定拒绝或保留待后续归类,不能静默猜成其他 kind。栅格归一化的 `source_subtype` 只接受图片族成员,文档/字体/音频等一律按 `image` 登记;Agent 回执派生物按 `Text => Document` 落 `document`。
|
||||
- 决策(判据不许散落):切片残留登记只看 `assets/art-spritesheet-slices/` 路径(不再附带 `kind == Icon`);sprite 身份比较忽略随 kind 派生的 `metadata.asset_type`;TS 侧「UI 编辑器文档资产」判据只留 `isGameCreationAppUiDesignDocAsset()` 一份,资源画布入口 / UI 编辑器桥接 / 资源引用缩略图统一调用。
|
||||
- 决策(已知代价,不补救):既有项目里无法解析的 kind 读入即 `unknown`,依赖 kind 等值比较的运行门禁会按"缺少该资源"处理。这是严格解析的必然结果,本次明确不为存量数据做迁移;将来若要迁就必须单独立项,不能改写解析边界。
|
||||
- 决策(留痕必须真的落地):原实现用 `tracing::warn!`,而 AGC 壳没有 tracing subscriber,等于没有日志。现在 `shared-contracts` 只暴露可注册回调 `set_non_canonical_asset_kind_reporter()`,AGC 壳在 `main()` 里接到 `app_log!`,日志同时含原始输入串与调用上下文;`kind-observability` feature 与 `tracing` 依赖一并删除。TS 侧对应 `parseGameCreationAppAssetKind()` 的 `console.warn`。
|
||||
- 决策(平台/画板词汇表):平台生成输入先严格解析为 `GameCreationAppAssetKind`,登记时直接写入已解析的 enum,不再保留 `platform_art_asset_manifest_kind()` 或任何平台别名/fallback 映射;图片快速编辑来源同样只允许 canonical 静态图片成员并要求 `mediaType=image`,原 `EDITOR_IMAGE_EDIT_STATIC_IMAGE_ASSET_KINDS` 兼容白名单已删除。
|
||||
- 验证:`cargo test -p shared-contracts`(含词汇表唯一性、严格性与留痕用例)、`cargo test --locked -p shared-contracts --features ts-bindings export_bindings` 后 `git diff` 为空、AGC bin 定向用例(`derived_asset_manifest_kind_is_never_unknown_for_text_derivatives`、`non_canonical_manifest_asset_kinds_report_raw_values_only`)、`npx vitest run packages/shared/src/contracts/gameCreationApp.test.ts apps/ai-game-creator-shell/tests/uiDesignResourceBridge.test.ts apps/ai-game-creator-shell/tests/appSurface.test.ts`。
|
||||
- 关联文档:[AI 游戏创作智能体 App 实施计划](../../technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md) 的 2026-09-17 节。
|
||||
|
||||
## 2026-09-16 DirectProject 引用渲染收敛到 canonical user item 深模块
|
||||
|
||||
- 背景:`agent/direct_codex_references.rs`(平行 `DirectCodexTurnReference` DTO 与渲染路径)已退役,引用身份、上限与投影收敛到 `agent/direct_codex_user_item/`;本轮 prompt 里引用只投影为 `[素材引用 resourceId=…;项目路径=…]` 摘要,`MAX_DIRECT_CODEX_REFERENCES` 归 `direct_codex_user_item/validation.rs`。
|
||||
- 决策:2026-09-14「Direct Codex 引用 UI 设计文档生成代码上下文」的 prompt 注入改落在 `agent/direct_codex_user_item/wire.rs`,入口是 `direct_codex_user_item_to_prompt`:引用命中 `ui-design-doc` + `application/json` 时顺序调用 `generate_ui_design_code_at`,成功追加 `请先阅读生成的带有文档的代码片段: {relative_path}`,失败追加原始 `生成代码遇到错误{error}`,其它引用继续处理,manifest 身份摘要不变。
|
||||
- 决策(无写副作用):只在生成本轮 prompt 时展开该上下文;历史 item 回读走 `direct_codex_user_item_to_response_item` 的纯投影,不得触发 UI 代码导出或任何项目写入。
|
||||
- 验证:`agent::direct_codex_user_item` 定向 16 条通过,覆盖成功注入、生成失败保留引用摘要、非 UI 文档不触发与历史回读不产生 `ui/generated-*.js`。
|
||||
|
||||
|
||||
## 2026-09-19 AGC Direct 删除每回合四项媒体资源请求上限
|
||||
|
||||
@@ -8896,6 +8916,12 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在
|
||||
- 决策:采用后台继续运行语义。Direct 回合由进程内项目身份锁持有,页面离开不取消;重进项目通过活动回合只读快照与 Thread Manager bootstrap/consume 恢复忙碌态和进度。左上角面板复用同一快照列出正在运行的 Direct 项目并支持进入。
|
||||
- 边界:快照不写项目文件、不进入公共 API、不跨应用重启恢复;读取失败保留上一份结果并单独提示,不改写成权限或审批失败。身份锁排他性、付费身份和项目写锁不变。
|
||||
|
||||
## 2026-09-14 Direct Codex 引用 UI 设计文档生成代码上下文
|
||||
|
||||
- 决策:UI Editor JSON 文档资产唯一使用 `kind:"ui-design-doc"` 且 `mediaType:"application/json"`;`ui-prototype` 保持图片语义,旧 `UI` / `ui` / `ui-design` 不作为该文档分支输入,不做 fallback 或迁移。
|
||||
- 决策:Direct Codex 结构化资源引用命中该 kind 时,顺序调用 UI Editor persistence 的 `generate_ui_design_code_at`,生成 `ui/generated-*.js`,并把 `请先阅读生成的带有文档的代码片段: {relative_path}` 追加到当前 prompt。生成失败不阻断本轮引用,追加原始 `生成代码遇到错误{error}`,其它引用继续处理。
|
||||
- 原因:复用 `html_renderer/mod.rs` 统一产物,确保 LLM 读取的代码包含 UI 节点元数据和文档注释;严格 kind + mediaType 判定避免图片资产误走代码生成。
|
||||
|
||||
## 2026-09-17 AGC 模板库落在 oss://agc-dev/templates/
|
||||
|
||||
- 背景:AGC 需要「真·游戏模板」库,让用户能浏览、筛选、下载模板并直接由模板创建项目,且模板内容更新不依赖客户端发版。
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# 踩坑与排障记录
|
||||
|
||||
## 2026-09-19 资源 kind 词汇收敛后,前端判据与 fixture 必须一起按 canonical 成员重写
|
||||
|
||||
- **现象**:工具栏入口的 `assetKind` 换成共享 `GameCreationAppAssetKind`(图集从平台词 `art-spritesheet` 改成 `icon-spritesheet`)后,「图集不接受用户参考」的判据仍写在旧的 `['art-spritesheet']` 字符串清单里,判据恒假:生成面板重新给图集渲染参考图选择器,原生提交再按合同显式拒绝多余参考。
|
||||
- **同类第二处**:把 `hasRegisteredArtImageAssets` 从 `kind === 'art-spritesheet'` 直接换成「kind ∈ 视觉族」会把候选 UI 原型图(`ui-design`)算成美术图片产出,提前顶掉「美术资源计划已完成,尚未生成或登记图片」;判据必须显式排除 `GAME_CREATION_APP_UI_DESIGN_ASSET_KIND`。
|
||||
- **处理(现行口径)**:前端的资源 kind 判据只比较 canonical 成员或共享契约导出的谓词,不再维护第二份字符串清单;词汇收敛时先 grep 旧词在 `src/` 与 `tests/` 两侧的落点,fixture 同步按 canonical 成员重写。
|
||||
- **易错点**:fixture 与生产代码写着同一个旧词时,单测会陪着一起变绿,用例证明不了任何事;另外 `tests/appSurface.test.ts` 不是全部同族用例,资源画布 / 画布生成参考等用例散在 `tests/*.test.ts(x)`,词汇收敛必须连这些一起跑。
|
||||
|
||||
## 2026-09-17 ts-rs 生成物换目录后,忘记同步忽略规则会让「生成物抖动」假装成代码改动
|
||||
|
||||
- **现象**:`GameCreationAppAssetKind` 的 ts-rs `export_to` 从 `apps/ai-game-creator-shell/src/contracts/generated/` 换到 `packages/shared/src/contracts/generated/` 后,任何 `cargo build` / `cargo test` 都会重写生成文件;若新目录没进 `.prettierignore` 与 `.eslintrc.cjs` 的 `ignorePatterns`,lint-staged / prettier 会把生成物重新格式化,于是每次提交都出现「生成物被改」,`cargo test export_bindings` 也不再幂等(跑完 `git diff` 不为空)。
|
||||
- **处理(现行口径)**:生成目录一律成对登记 `.prettierignore` + eslint `ignorePatterns`;改 `export_to` 时同步改这两处,并用 `cargo test --locked -p shared-contracts --features ts-bindings export_bindings --manifest-path server-rs/Cargo.toml` 后 `git diff` 为空来验证幂等。
|
||||
- **易错点**:旧的 `apps/ai-game-creator-shell/src/contracts/generated/` 目录下的同名文件不会自动删除,换目录后必须显式删除旧文件,否则会出现「两个同名 union,改动只落在一个目录」的假绿。
|
||||
## 生成草稿与异步展示边界必须按身份隔离
|
||||
|
||||
非模态生成浮层切换占位时按 draftId 分实例,卸载保留未提交/失败草稿,成功提交不再复活草稿;旧项目占位不存在时丢弃其保存回调。失败重试保留原请求输入和引用身份,引用失效不能静默过滤;修改已绑定输入须明确另起请求,不伪装成原请求重试。
|
||||
@@ -5462,11 +5474,12 @@ Cocos Creator 根目录由 `package.json.creator.version` 与普通 `assets/`
|
||||
## 资源 kind 别名只救新登记,不救存量 category(2026-09-10)
|
||||
|
||||
- 现象:真机 `What do u wanna do kitten` 的 66 项资源里 58 项落「待归类」,其中 57 项是 `kind:"ui"` 的 UI 资产,本该在「UI 交互」。
|
||||
- 成因链:`ui` 不在 `GAME_CREATION_APP_CANONICAL_ASSET_KINDS` 里、也没有别名,于是走 `canonicalGameCreationAppAssetKind` 的 `image` 兜底,再经 `image → unclassified` 被误分到「待归类」。它并不是历史遗留值——`assets.rs:1656` 的 `infer_canvas_export_asset_kind`(画板导出导入)**现在仍在写出** `ui` / `animation` / `asset`。
|
||||
- 成因链:`ui` 不在 canonical 词汇表里、也没有别名,于是落「待归类」。它并不是历史遗留值——`assets.rs` 的 `infer_canvas_export_asset_kind`(画板导出导入)当时仍在写出 `ui` / `animation` / `asset`。
|
||||
- **现行口径(2026-09-17 起,改这里之前必读)**:kind 只有一份词汇表(Rust `GameCreationAppAssetKind` 声明表 → ts-rs 生成 TS union),解析是**严格等值匹配**:不 trim、不 lowercase、不查别名、不迁移;非 canonical 原值收口成 `unknown`(分类 `unclassified`)并把**原始串 + 调用上下文**交给壳层注册的 `app_log!` 回调。**别名表已整体删除,不要再加回来**——这条现象现在的表现是「日志里能查到谁还在写旧值」,先修写入方,不要在读侧做兼容。
|
||||
- **关键陷阱(2026-09-11 已修)**:补别名只影响「今后新登记」的资产。`register_local_asset_entry`(`assets.rs`)命中同 `localPath` 的既有资产时,旧实现只覆盖 `kind` / `media_type` / `source`、**不重算 `category`**;而读取侧优先信任落盘 `category`、只在它缺失或非法时才按 `kind` 派生。所以这 57 条的落盘 `category: "unclassified"` 会一直有效,重导入也自愈不了。**修法与必须保留的不变量**:更新分支只在 `kind` 真的变化时才重派生 `category`,否则「同路径重登记且 kind 变了」会留下「新 kind + 旧分类」的错位,而陈旧的非 `unclassified` 值会被无条件信任、自愈也不触发;反过来同 kind 重登记**禁止**动 `category`,落盘分类是权威值,被 `register_local_asset_keeps_explicit_category_when_kind_is_unchanged` 钉住。
|
||||
- 为什么读取侧要信任落盘值:存在用户手动改分类的正式链路 `update_manifest_asset_classification_at`(`project/manifest.rs:1110`),读时无条件重派生会吃掉用户的手动设置。
|
||||
- 根治选项(需产品拍板):① 读时把 `unclassified` 当作「未设置」再按 kind 派生(简单但失去"我就是要 unclassified"的表达力);② 一次性回填这 57 条(保留人工设置语义,需迁移脚本);③ 只改写入侧让新素材 canonical 化(治不了存量)。
|
||||
- 另一处必须成对维护:别名表有**两份实现**——TS 侧 `packages/shared/src/contracts/gameCreationApp.ts` 的 `GAME_CREATION_APP_LEGACY_ASSET_KINDS`(读投影用)与 Rust 侧 `server-rs/crates/shared-contracts/src/game_creation_app.rs` 的 `canonical_game_creation_app_asset_kind`(写入侧按 kind 派生 category 用)。只改一边就会让落盘 category 与读侧栏目互相矛盾。交叉守卫见 `apps/ai-game-creator-shell/tests/assetKindCanonicalMapping.test.ts`(直接解析 Rust 源码比对)。
|
||||
- 成对维护点(**2026-09-17 起不再存在**):当时别名表有**两份实现**——TS 侧 `GAME_CREATION_APP_LEGACY_ASSET_KINDS` 与 Rust 侧 `canonical_game_creation_app_asset_kind`,靠 `apps/ai-game-creator-shell/tests/assetKindCanonicalMapping.test.ts` 正则解析 Rust 源码交叉钉住。现在两份手写表与那个守卫测试都已删除:唯一词汇表由 Rust 枚举声明表派生、经 ts-rs 生成 union,跨语言一致性回到**编译期**(TS 侧 `Record<GameCreationAppAssetKind, …>` 穷举,少一个成员就编译不过)。不要再引入"正则解析 Rust 源码"的跨语言守卫。
|
||||
- 真机计数守卫见 `apps/ai-game-creator-shell/tests/resourceCardPreviewRealManifest.test.ts`。
|
||||
- 关联:`apps/ai-game-creator-shell/src-tauri/src/assets.rs`、`apps/ai-game-creator-shell/src-tauri/src/project/manifest.rs`、`packages/shared/src/contracts/gameCreationApp.ts`、`server-rs/crates/shared-contracts/src/game_creation_app.rs`。
|
||||
|
||||
@@ -5475,20 +5488,20 @@ Cocos Creator 根目录由 `package.json.creator.version` 与普通 `assets/`
|
||||
- 规则(已拍板落地):`gameCreationAppAssetCategory` 在「落盘 `category === 'unclassified'` **且** 该资产 `kind` 能派生出明确的非 `unclassified` 分类」时采用派生值,其余情况信任落盘值。
|
||||
- 为什么需要这条:`register_local_asset_entry`(`assets.rs`)命中同 `localPath` 的既有资产时**只在 `kind` 变化时**重算 `category`(2026-09-11 起);所以历史上被写成 `unclassified` 的资产(典型是 `kind:"ui"` / `kind:"UI"` 因不在 canonical 目录而落到 `image → unclassified`)在补齐别名后**不会自愈**。选读时重派生而不是写迁移脚本:不需要迁移、且永久自愈(任何历史上被系统错判成 unclassified 的都会自动归位)。真机验证:`What do u wanna do kitten` 的待归类从 58 降到 1(只剩 code 类 `game-entry`),UI 交互从 2 升到 59。
|
||||
- **两个口径不能混用(2026-09-11 收口)**:`gameCreationAppAssetCategory` / `game_creation_app_asset_effective_category` 是**读显示**口径;写回 manifest 必须用 `gameCreationAppAssetPersistedCategory`(只做缺失 / 非法兜底),它等于 Rust 反序列化后的落盘原值。把自愈值回写会把「只改标签」变成静默改分类——真机上同一条 `kind:"ui"` 资产因此同时存在 `unclassified` 与 `ui-interaction` 两种落盘值。
|
||||
- **跨端必须同构**:Agent 侧资源投影(`direct_tool_bridge.rs`)走 Rust 的 `game_creation_app_asset_effective_category`,不许直接透传落盘 `category`;两侧不一致时同一条资产会出现「UI 显示 UI 交互、Agent 读到待归类」(真机 55 条)。守卫是 `assetKindCanonicalMapping.test.ts` 解析 Rust 源码里的 `EFFECTIVE_CATEGORY_CONTRACT` 决策矩阵。
|
||||
- **跨端必须同构**:Agent 侧资源投影(`direct_tool_bridge.rs`)走 Rust 的 `game_creation_app_asset_effective_category`,不许直接透传落盘 `category`;两侧不一致时同一条资产会出现「UI 显示 UI 交互、Agent 读到待归类」(真机 55 条)。**现行守卫(2026-09-17 起)**:`shared-contracts` 的 `EFFECTIVE_CATEGORY_CONTRACT` 决策矩阵用例 + `packages/shared` 的 `gameCreationApp.test.ts` 同口径用例;解析 Rust 源码的 `assetKindCanonicalMapping.test.ts` 已删除。
|
||||
- 为什么可以覆盖落盘值:落盘 `category` 的权威性来自「用户可在分类与标签面板手动设置」(`update_manifest_asset_classification_at`,`project/manifest.rs`)。收窄条件把覆盖窗口压到最小——只有当落盘值是 `unclassified`(即"没有明确分类")时才覆盖。
|
||||
- **唯一盲区**:用户**手动**把一个 kind 已能明确分类的资产设成「待归类」时,该手动值会被覆盖。这是有意接受的取舍:「手动设为待归类」意图边缘,且 kind 已经表达了分类;而漏掉这条规则,所有历史误判都无法自愈。若将来产品需要"显式待归类",应改成在 manifest 里区分"未设置"与"显式 unclassified"(例如 `category` 缺省 vs 显式写入),而不是取消本条规则。
|
||||
- 不受影响:`image` / `video` / `code` / `publication-material` 的 canonical 分类本身就是 `unclassified`,派生结果等于落盘值,规则不触发(已用断言钉住)。
|
||||
- 写入侧已同步 canonical 化:`infer_canvas_export_asset_kind`(`assets.rs`)现在直接产出 canonical kind(`ui → ui-design`、`animation → character-animation`、`asset → image`),不再依赖别名表兜底;`canvas_export_asset_kind_is_always_canonical` 用例逐分支钉死,别名表从此只承担存量兼容。
|
||||
- 写入侧已同步 canonical 化:`infer_canvas_export_asset_kind`(`assets.rs`)现在直接产出 canonical kind(`ui → ui-design`、`animation → character-animation`、`asset → image`),不再依赖别名表兜底;`canvas_export_asset_kind_is_always_canonical` 用例逐分支钉死。**2026-09-17 起别名表整体删除**,存量兼容也不做:读侧严格解析,认不出的原值只留痕。
|
||||
- 关联:`packages/shared/src/contracts/gameCreationApp.ts` 的 `gameCreationAppAssetCategory`、`apps/ai-game-creator-shell/src-tauri/src/assets.rs`、`apps/ai-game-creator-shell/tests/resourceCardPreviewRealManifest.test.ts`。
|
||||
|
||||
## 大写 `UI` / `font` 不在 alias 表 → 8 条真机 UI 资产永远落「待归类」,且自愈救不回(2026-09-11)
|
||||
|
||||
- 现象:真机 `What do u wanna do kitten` 有 8 条资产的 `kind` 是**大写** `"UI"`、`mediaType` 是 `application/json`、`localPath` 是 `ui/UI 设计 N.json`,永远停在「待归类」。
|
||||
- 成因链:写入侧写大写——`ui_editor/resource_bridge.rs` 的 `register_local_asset_at(root, &relative_path, "UI", "application/json", …)`,`workflow.rs` / `persistence.rs` 同;而 alias 表只有小写 `"ui" => "ui-design"`,于是 `"UI"` 落到 `canonical_game_creation_app_asset_kind` 的 `image` 兜底 → `image → unclassified`。
|
||||
- **为什么读时自愈救不回来**:自愈规则的前提是「派生值不是 unclassified」,而 `"UI"` 的派生值**就是** `unclassified`,规则永不触发。所以只能在 alias 表收口——别名表必须**大小写不敏感**(`UI` / `ui` / `ui-prototype` 都要落 `ui-design`),并把 `font`(`ttf / otf / woff / woff2` 上传登记的 kind,见 `commands.rs` 的 `register_local_asset_entry(root, &relative_path, "font", …)`)一并补进别名表落 `document`。
|
||||
- 守卫三层:Rust `asset_category_mapping_covers_every_canonical_kind` 逐条断言(旧断言曾把 `"UI" → unclassified` 钉死,正是这条 bug 的护栏反向加固);`ui_editor/resource_bridge.rs` 的 `bridge_is_idempotent_and_installs_source_image` 走真实生产函数 → 真实写入 → 断言落盘 `category`;TS `assetKindCanonicalMapping.test.ts` 的「写侧 kind 字面量 → 分类」直接解析写侧源码的第 3 个实参,写点换个新字面量就会红。
|
||||
- 关联:`server-rs/crates/shared-contracts/src/game_creation_app.rs`、`packages/shared/src/contracts/gameCreationApp.ts`、`apps/ai-game-creator-shell/src-tauri/src/ui_editor/resource_bridge.rs`、`apps/ai-game-creator-shell/tests/assetKindCanonicalMapping.test.ts`。
|
||||
- 成因链:写入侧写大写——`ui_editor/resource_bridge.rs` 的 `register_local_asset_at(root, &relative_path, "UI", "application/json", …)`,`workflow.rs` / `persistence.rs` 同;当时的 alias 表只有小写 `"ui" => "ui-design"`,`"UI"` 因此落 `image` 兜底 → `unclassified`。**注意 `font` 早已是正式 canonical 成员(不再靠别名落 `document`)**。
|
||||
- **为什么读时自愈救不回来**:自愈规则的前提是「派生值不是 unclassified」,而 `"UI"` 的派生值**就是** `unclassified`,规则永不触发。**现行口径(2026-09-17 起)**:不给 `"UI"` 找归一口径,而是修写入侧写 canonical 字面量;读侧严格解析,认不出的原值收口 `unknown` + `app_log!` 留痕(原始串 + 上下文)。
|
||||
- 守卫三层:Rust `asset_category_mapping_covers_every_kind` 穷举断言(旧的 `"UI" → unclassified` 断言正是这条 bug 的反向加固,已删);`ui_editor/resource_bridge.rs` 的 `bridge_is_idempotent_and_installs_source_image` 走真实生产函数 → 真实写入 → 断言落盘 `category`;TS `parseGameCreationAppAssetKind` / `console.warn` 用例钉住"非 canonical 值收口 + 留痕原值"。
|
||||
- 关联:`server-rs/crates/shared-contracts/src/game_creation_app/asset_kind.rs`、`packages/shared/src/contracts/gameCreationApp.ts`、`apps/ai-game-creator-shell/src-tauri/src/ui_editor/resource_bridge.rs`、`apps/ai-game-creator-shell/tests/assetKind.test.ts`。
|
||||
|
||||
## AGC 资源搜索栏改成「临时叫出」的浮层,工具条带与它的下移逻辑一并撤掉(2026-09-11)
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@ SpacetimeDB crate、SDK、CLI / standalone 与生成 bindings 按 `2.8.3` 对齐
|
||||
- 通用 Agent Rust 分层为 `agent-runtime-core`(catalog、执行生命周期、ToolHost/spawn/all-join/Provider 契约)、`agent-runtime-orchestration`(动态无环任务图、ready、依赖波次、返工下游闭包和受限自主扩图提案)与 `platform-agent` 游戏适配器;循环返工通过新 pass / epoch 表达,不在单张依赖图中建立回边。LLM 可经宿主结构化 function call 提出新增节点/边,编排层只生成经校验的新候选图,epoch 与持久化仍由宿主掌控。
|
||||
- DirectProject 始终连接客户端内置的 `agc_tools` STDIO MCP,并在启动时额外读取客户端扩展仓库中已启用的第三方 MCP 独立项。第三方 STDIO/HTTP 配置只写入本次隔离 `CODEX_HOME`,单项非 required,启停、重命名和内容指纹进入 app-server pool identity;完整 Plugin Runtime、hooks/apps 和单文件脚本手动指定入口仍关闭。Skill 正文与 references 由 Codex 原生按需读取;`agc_tools` 负责标准美术准备、已登记资源有界查询、视频 / 角色动画 / 音效 / BGM 的 create-or-derive、已登记图片去背景、desktop/mobile 浏览器试玩和受控 `agc_web_search`;付费资源调用仍由客户端绑定回合、幂等账本、请求上限和投影权威。
|
||||
- 2026-09-09 起,AGC 已新增遵循 OpenAI Agent Plugins 组合模型的通用 Plugin Host/SDK:Plugin、Skill 和 MCP 进入统一扩展 catalog;插件生命周期、行分隔 JSON-RPC、UI 面板、Capability Registry、权限和审计由 `plugin_host` 统一承接,Skill/MCP 仍分别交给各自现有 loader/transport;目标编辑器只通过通用 `EditorAdapter` 扩展点接入。详见 `docs/technical/【技术方案】AGC通用插件宿主与编辑器适配-2026-09-09.md`。
|
||||
- Unity 编辑器能力以 `plugins/agc-unity-editor` 内置插件提供,固定复用 Apache-2.0 的 DotCraft Attach 核心;Windows x64 / Unity Mono 接入不安装项目包。GUI、Runtime 与 DirectProject 通过现有 Runner 统一执行归属,跨进程回执与持久不确定阻断统一处理。首次打开 Unity 工程只初始化 AGC `.agent` 元数据,保留原引擎工程;详见 `docs/technical/【技术方案】AGC Unity编辑器插件接入-2026-09-18.md`。
|
||||
- DirectProject 的 Codex 原生文件、搜索、命令、图片查看和 Skill 仅在用户项目 cwd 与 `workspaceWrite(writableRoots=[project])` 内可用;原生命令允许联网以支持 npm 安装,npm 缓存位于项目内 `.npm-cache/`。多 Agent、Apps、插件、hooks、图片生成、Goals、Workspace Dependencies、Tool Suggestion 和原生浏览器/电脑控制保持关闭。app-server 使用隔离 `CODEX_HOME`,provider 凭据只由 AGC 客户端代理持有,不能进入模型上下文或 shell 环境。
|
||||
- `ui-prototype`(设计图片)与 UI 编辑器 `UI` JSON 是不同资源。白名单 `ui.workflow.run` 按页面执行 `prepare → recognize → status → finalize`,由 provider-backed 识别、合并和组件绑定持久化 State/revision,并把 `reference-ready → structure-ready → merge-ready → binding-ready → application-ready → completed` 投影到 manifest。Provider 缺失、请求失败、工具缺失、结果不匹配或仍有待审节点时保留真实阶段并返回 blocker,不得用 deterministic seed 伪造完成。
|
||||
- UI workflow 的资源桥接与 Runtime 边界以 `docs/【技术方案】UI工作流资源桥接与Runtime执行-2026-08-24.md` 和 AGC 实施计划的 2026-08-24 覆盖段为准;只生成图片、登记空 JSON 或进入普通图片画布都不构成 workflow 完成。
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
- 修改 `/api/external/v1` 时,同批更新 `docs/openapi/genarrative-external-v1.openapi.json` 与契约测试。
|
||||
- 修改 SpacetimeDB schema 时遵守字段追加/default 约束,同步 migration、表目录、生成绑定,并运行 schema 检查;删除、改名、重排或改类型前先确认迁移计划。
|
||||
- 日志不递归输出完整配置、应用状态或 provider client;新增字段默认不进入安全摘要。
|
||||
- HTTP 横切能力集中在 Axum/Tower 中间件:正常与降级路由复用追踪层;指标与 trace 使用 `MatchedPath` 模板及固定兜底,不把请求 ID、实际资源 ID 或 query 放入指标标签。在途请求通过 RAII guard 覆盖 Future 取消与 panic unwind;请求执行和响应体存活分别计量,不能把 handler 耗时当作 SSE 全生命周期。
|
||||
- 业务依赖在组合根显式装配,Axum `FromRef` 只抽取可浅拷贝的窄能力。项目元数据与 External API 鉴权不持有完整 `AppState`,测试经相同接口注入替代依赖。集中鉴权仍保留方法级 fallback、公开入口、MCP 和 body limit 顺序;Provider span 跳过完整参数,不隐藏计费、重试、幂等或事务规则。
|
||||
- 中文文案、注释和文档保持 UTF-8,优先局部补丁,不擅自翻译成英文。
|
||||
|
||||
## 文档生命周期
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
# 【待办】AGC 资源 kind 枚举化扫描清单
|
||||
|
||||
| 字段 | 值 |
|
||||
| --- | --- |
|
||||
| 状态 | open |
|
||||
| 创建日期 | 2026-09-15 |
|
||||
| 所属主规范 | `docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md` |
|
||||
| 关闭条件 | shell 内所有 GameCreationApp 资源 kind 候选均完成语义归类、代码处理决定和验证证据记录 |
|
||||
|
||||
## 扫描规则
|
||||
|
||||
只扫描 `apps/ai-game-creator-shell`。`server-rs` 只作为 api-server 有效词汇参考,不把 server-side `asset_kind` 纳入本清单迁移。
|
||||
|
||||
每个命中必须回到上下文并填写:位置、当前值、真实语义、是否进入 manifest、是否生产写入、目标类型、处理动作、验证证据。
|
||||
|
||||
## 首轮候选分组
|
||||
|
||||
### 必须审计为 GameCreationAppAssetKind
|
||||
|
||||
- `image`
|
||||
- `scene`
|
||||
- `character`
|
||||
- `character-animation`
|
||||
- `icon`
|
||||
- `icon-spritesheet`
|
||||
- `icon-spec`
|
||||
- `ui-design`
|
||||
- `ui-design-doc`
|
||||
- `publication-material`
|
||||
- `spec`
|
||||
- `video`
|
||||
- `audio`
|
||||
- `sound-effect`
|
||||
- `background-music`
|
||||
- `font`
|
||||
- `document`
|
||||
- `code`
|
||||
- `unknown`
|
||||
|
||||
### 已发现的非 canonical 候选,必须逐处判定
|
||||
|
||||
- `asset`
|
||||
- `ui`
|
||||
- `animation`
|
||||
- `game-background`
|
||||
- `character-art`
|
||||
- `game-art`
|
||||
- `illustration`
|
||||
- `art-spritesheet`
|
||||
- `art-spritesheet-slice`
|
||||
- `ui-prototype`
|
||||
- `game-entry`
|
||||
- `game-script`
|
||||
- `game-style`
|
||||
|
||||
### 明确暂不纳入本 PR
|
||||
|
||||
- `source.kind`
|
||||
- `source.generationKind`
|
||||
- MIME / `mediaType` / 文件扩展名
|
||||
- workflow、generation、task、path、tracking、plugin 等其他 kind 字段
|
||||
|
||||
## 初始文件入口
|
||||
|
||||
- `src-tauri/src/assets.rs`
|
||||
- `src-tauri/src/commands.rs`
|
||||
- `src-tauri/src/project/manifest.rs`
|
||||
- `src-tauri/src/project/resource_editor.rs`
|
||||
- `src-tauri/src/ui_editor/`
|
||||
- `src-tauri/src/agent/direct_runtime.rs`
|
||||
- `src-tauri/src/agent/direct_tool_bridge.rs`
|
||||
- `src-tauri/src/agent/generation/`
|
||||
- `src-tauri/src/agent/runtime_actions/`
|
||||
- `src/features/project-development/`
|
||||
- `src/features/project-workspace/`
|
||||
- `src/features/resource-canvas/`
|
||||
- `src/features/ui-editor/`
|
||||
|
||||
## 当前未决项
|
||||
|
||||
- [x] `asset`:确认是上传推断的兜底值,已改为无法判断时写 `Unknown`,不再回落到 `asset`。
|
||||
- [x] `art-spritesheet` / `art-spritesheet-slice`:确认是平台请求与图集 workflow 词汇;manifest 写入分别收口为 `IconSpritesheet` / `Icon`,协议标识只留在各自字符串字段。
|
||||
- [x] `game-background` / `game-art` / `illustration` / `character-art`:确认只出现在平台请求词汇;写入 manifest 前经显式转换函数收口为 `scene` / `image` / `character`。
|
||||
- [x] `ui` / `ui-prototype`:确认 UI 设计桥接与工作流已无生产 manifest writer,只写 `ui-design` / `ui-design-doc`。
|
||||
- [x] 非 canonical 原值留痕为「原始串 + 调用上下文」,由 `shared-contracts` 的可注册回调 `set_non_canonical_asset_kind_reporter()` 交给 AGC 壳的 `app_log!`(2026-09-17 起不再用 `tracing` / `kind-observability`);生产 writer 只传正式枚举成员。
|
||||
- [x] ts-rs 生成路径为 `packages/shared/src/contracts/generated/`(2026-09-17 从 `apps/ai-game-creator-shell/src/contracts/generated/` 迁出),命令为 `cargo test -p shared-contracts --features ts-bindings export_bindings`(枚举自带 `export_to`),生成目录已在 `.prettierignore` / eslint `ignorePatterns` 中保持原始格式。
|
||||
- [ ] 接入 CI verify(在 CI 中跑一次 `export_bindings` 并断言生成文件无 diff)。
|
||||
|
||||
## 已确认的 manifest kind 入口(M0 审计结果)
|
||||
|
||||
下列位置已经确认直接承载或生产 `GameCreationAppAssetManifestEntry.kind`,后续迁移必须逐项完成:
|
||||
|
||||
| 位置 | 当前事实 | 后续动作 |
|
||||
| --- | --- | --- |
|
||||
| `src-tauri/src/assets.rs:584-604` | `register_local_asset_at` 以 `&str` 接受 kind 并转交登记 | 参数改为 Rust enum;边界字符串集中解析 |
|
||||
| `src-tauri/src/assets.rs:563-566` | 普通上传根据内容推断 kind 后登记 | 推断函数返回 enum;无法判断返回 `Unknown` 并 trace,禁止 `asset` fallback |
|
||||
| `src-tauri/src/assets.rs:791-806` | 画板导出图层登记资源 | 推断结果直接使用 enum |
|
||||
| `src-tauri/src/assets.rs:916-934` | 平台资源同步从 payload `assetKind` 登记 | 入口解析成 enum;未知值 `Unknown` + trace |
|
||||
| `src-tauri/src/assets.rs:1871-1916` | manifest 新增/更新资产并写入 kind | 禁止裸字符串和隐式 alias/fallback |
|
||||
| `src-tauri/src/commands.rs:2094-2129` | Tauri `register_local_asset` 接收外部 kind | 解析边界收紧为 enum/Unknown |
|
||||
| `src-tauri/src/commands.rs:2672-2711` | 字体导入生产路径登记 `"font"` | 正式保留 `Font` enum variant |
|
||||
| `src-tauri/src/commands.rs:2784-2803` | 字体登记测试/辅助路径 | 与生产字体 kind 一致 |
|
||||
| `src-tauri/src/project/resource_editor.rs:3806-4065` | 资源派生/替换构造 manifest asset | `source_subtype` / `asset_kind` 只在确认是 manifest kind 时改 enum;operation 临时类型另行排除 |
|
||||
| `src-tauri/src/ui_editor/workflow.rs:687-749` | UI 设计文档与图片资源登记 | `ui-design-doc` / `ui-design` 使用 enum |
|
||||
| `src-tauri/src/ui_editor/resource_bridge.rs:121-139` | UI 设计文档生产登记 | 使用 `UiDesignDoc` enum variant |
|
||||
| `src-tauri/src/agent/direct_runtime.rs:2462-2469` | 恢复图集登记仍传 `"art-spritesheet"` | manifest 写入改为 `IconSpritesheet`;恢复协议字符串单独审计 |
|
||||
| `src-tauri/src/agent/generation/canvas_generation.rs:6816-6828` | 切片 manifest 条目仍写 `"art-spritesheet-slice"` | manifest 写入改为 `Icon`;切片协议标识不自动替换 |
|
||||
| `src-tauri/src/agent/direct_tool_bridge.rs:1126-1183` | Agent 资源投影读取 manifest kind | 改为消费 enum,序列化边界仍输出 kebab-case |
|
||||
| `src-tauri/src/agent/direct_codex_user_item/wire.rs:66-96` | Agent 引用投影按 manifest 身份解析资源;不再展示裸 kind | 已消费 enum;UI 文档分支只用 `UiDesignDoc` 身份判据,无字符串展示 |
|
||||
|
||||
## 已确认的 shell TS 消费方
|
||||
|
||||
这些文件目前通过 `packages/shared/src/contracts/gameCreationApp.ts` 或手写 `string` 消费资源 kind,需迁入 shell 生成绑定:
|
||||
|
||||
- `src/features/project-workspace/resourceReferences.ts`
|
||||
- `src/features/project-workspace/ResourceReferenceInput.tsx`
|
||||
- `src/features/project-workspace/SupervisorChatOnlyView.tsx`
|
||||
- `src/features/project-workspace/ProjectSupervisorView.tsx`
|
||||
- `src/features/project-workspace/ProjectWorkspaceChatPane.tsx`
|
||||
- `src/view/project-development/index.tsx`
|
||||
- `src/view/project-development/ResourceClassificationPanel.tsx`
|
||||
- `src/view/project-development/ResourceRenameDialog.tsx`
|
||||
- `src/view/project-development/resourceProjectionModel.ts`
|
||||
- `src/features/resource-canvas/resourceCanvasBottomToolbarModel.ts`
|
||||
- `src/features/resource-canvas/resourceCanvasGenerationPanelView.tsx`
|
||||
- `src/features/resource-canvas/ResourceCanvasAssetGenerationPanelView.tsx`
|
||||
- `src/features/resource-canvas/resourceVersionReplacementModel.ts`
|
||||
- `src/components/AssetImporter/utils.ts`
|
||||
- `src/components/AssetImporter/index.tsx`
|
||||
- `src/components/AssetImporter/settings.ts`
|
||||
- `src/services/clientApi.ts`
|
||||
- `src/view/ui-editor/useUiEditorPage.ts`
|
||||
- `src/features/ui-editor/uiDesignResourceBridge.ts`
|
||||
|
||||
其中 `resourceCanvasBottomToolbarModel.ts:243,258` 和 `resourceProjectionModel.ts:326` 已明确出现 `art-spritesheet` / `ui-prototype`,需回到调用链判断它们是 manifest kind 还是生成入口协议值,不能文本全局替换。
|
||||
|
||||
## 旧值生产状态初判
|
||||
|
||||
| 值 | 已发现位置 | 初判 |
|
||||
| --- | --- | --- |
|
||||
| `font` | `commands.rs:2672,2787`;UI Editor 字体登记 | 正式 manifest kind,保留 |
|
||||
| `audio` | `assets.rs:495`;上传推断与本地文件类型 | 正式 manifest kind,保留 |
|
||||
| `sound-effect` | `direct_tool_bridge.rs:104-116`;Agent 音频工具 | 正式 manifest kind,保留 |
|
||||
| `background-music` | `direct_tool_bridge.rs:104-116`;Agent 音频工具 | 正式 manifest kind,保留 |
|
||||
| `asset` | `assets.rs:537` 未知上传兜底;`assets.rs:1882` 空 kind 兜底 | 错误 fallback,改为 Unknown/显式失败后删除 |
|
||||
| `art-spritesheet` | `direct_runtime.rs:2465`;canvas generation 多处 | 既有 manifest/协议混用,逐处拆开 |
|
||||
| `art-spritesheet-slice` | `canvas_generation.rs:6818`;direct runtime 多处 | manifest kind 改为 `icon`,协议标识另留 |
|
||||
| `game-background` | canvas generation 选项与 runtime 阶段 | manifest kind 改为 `scene`,阶段标识另留 |
|
||||
| `game-art` | canvas generation 默认值/测试 | manifest kind 改为 `image`,生成请求字段另审 |
|
||||
| `illustration` | direct runtime 测试/恢复路径 | manifest kind 改为 `image`,其他用途另审 |
|
||||
| `character-art` | manifest/API 白名单与测试 | manifest kind 改为 `character`,API 参考不改 |
|
||||
| `ui-prototype` | UI workflow 检查、资源 bridge、TS 画布选项 | manifest kind 改为 `ui-design`;workflow 输入另审 |
|
||||
| `ui` | 旧 bridge/测试与外部输入 | 不再 alias;未知值进入 `Unknown`,逐处确认生产残留 |
|
||||
| `animation` | 旧映射及文本/阶段判断 | 不再 alias;仅 manifest kind 的位置改为 `character-animation` |
|
||||
| `game-entry` / `game-script` / `game-style` | runtime 代码文件登记 | manifest kind 改为 `code`;文件阶段标识不改 |
|
||||
|
||||
## 本轮明确排除的同名字段
|
||||
|
||||
以下命中不属于本 PR 的 `GameCreationAppAssetKind`,只记录边界,不修改:
|
||||
|
||||
- `source.kind`:`Uploaded / Generated / Canvas`,表达资源来源。
|
||||
- `source.generationKind`:包含 `ui-workflow.completed`、`project-file`、`icon-spritesheet` 等工作流/生成标识。
|
||||
- `mediaType`、MIME、扩展名和文件分类器。
|
||||
- Agent group、task kind、workflow stage、路径/目录名、tracking scope、插件 kind。
|
||||
|
||||
## 下一步审计动作
|
||||
|
||||
- [ ] 为每个“旧值生产状态初判”补充真实调用链和测试证据。
|
||||
- [ ] 将 manifest kind 与 generation/request kind 的复用关系改为显式转换,不共享裸字符串。
|
||||
- [ ] 确认 `Unknown` 在上传推断、外部 payload、manifest 读取三条入口的日志字段。
|
||||
- [ ] 完成 `packages/shared` import 使用方迁移清单,确认删除文件不会留下跨包引用。
|
||||
- [ ] 完成后更新本文件,关闭 M0 里程碑,再创建代码里程碑的实施计划。
|
||||
|
||||
## manifest 构造器逐处清单
|
||||
|
||||
| 位置 | 当前 kind | 生产/测试 | 决定 |
|
||||
| --- | --- | --- | --- |
|
||||
| `src-tauri/src/assets.rs:1914-1916` | 上游 `kind.to_string()` | 生产公共写入边界 | 改为接收 `GameCreationAppAssetKind`,统一负责序列化 |
|
||||
| `src-tauri/src/project/resource_editor.rs:3806-3809` | `source_subtype.to_string()` | 生产派生资源 | 先把 `source_subtype` 解析/转换为 manifest enum;临时 operation subtype 不得混入 |
|
||||
| `src-tauri/src/project/resource_editor.rs:4059-4065` | `asset_kind` | 生产派生资源 | 改为 manifest enum;调用方显式转换 |
|
||||
| `src-tauri/src/agent/generation/canvas_generation.rs:6816-6828` | `art-spritesheet-slice` | 生产切片回写 | 改为 `Icon`;只保留协议层切片标识在独立字符串字段 |
|
||||
| `src-tauri/src/ui_editor/workflow.rs:1468-1475` | 测试 helper 参数 `kind` | 测试 | helper 改为 enum,fixture 只使用正式成员 |
|
||||
| `src-tauri/src/project/manifest/recovery_tests.rs:181-183` | `character` | 测试 fixture | 改为 enum variant |
|
||||
| `src-tauri/src/agent/direct_tool_bridge.rs:3189-3192` | `art-spritesheet-slice` | 测试 fixture | 如果测试 manifest 语义,改为 `Icon`;协议测试另造明确协议字段 |
|
||||
| `src-tauri/src/agent/direct_tool_bridge.rs:3246-3249` | `character-animation` | 测试 fixture | 改为 enum variant |
|
||||
| `src-tauri/src/agent/direct_tool_bridge.rs:3297-3299` | `spec` | 测试 fixture | 改为 enum variant |
|
||||
| `src-tauri/src/agent/direct_tool_bridge.rs:3339-3342` | `ui` | 旧兼容测试 | 删除 alias 断言;改为 `Unknown` + trace 测试或移至 parser 边界测试 |
|
||||
| `src-tauri/src/project/resource_dependency_graph.rs:652-656` | `test` | 测试 fixture | 改为 `Unknown`,明确测试未知 kind 投影,不得继续写任意字符串 |
|
||||
| `src-tauri/src/commands.rs:2888-2892` | `font` | 测试 fixture | 改为 `Font` enum variant |
|
||||
|
||||
## shell TS 类型迁移清单(已发现裸 string)
|
||||
|
||||
以下字段目前仍是 `string` / `string | null`,但若其语义是 manifest `assetKind`,必须改为生成的 `GameCreationAppAssetKind`;若只是外部 API 开放值,保留并在清单中标注转换边界:
|
||||
|
||||
- `src/services/clientApi.ts:198`
|
||||
- `src/view/ui-editor/useUiEditorPage.ts:81,1077`
|
||||
- `src/components/AssetImporter/utils.ts:7,32,114`
|
||||
- `src/components/AssetImporter/index.tsx:61`
|
||||
- `src/features/resource-canvas/resourceCanvasBottomToolbarModel.ts:79`
|
||||
- `src/features/project-workspace/DeveloperProjectPanels.tsx:15`
|
||||
- `src/features/project-workspace/ResourceReferenceInput.tsx:104`
|
||||
- `src/features/resource-canvas/resourceVersionReplacementModel.ts:232-245`
|
||||
- `src/features/project-workspace/resourceReferences.ts:101-134`
|
||||
- `src/view/project-development/resourceProjectionModel.ts:319-345`
|
||||
- `src/features/ui-editor/uiDesignResourceBridge.ts:55-87`
|
||||
- `src/App.tsx:1262,10083`
|
||||
|
||||
特别处理:
|
||||
|
||||
- `resourceCanvasBottomToolbarModel.ts:243` 的 `art-spritesheet` 和 `:258` 的 `ui-prototype` 当前位于生成入口选项,需先确认该字段是否传入 manifest 登记;若只是 API/生成请求 kind,使用显式转换函数,不把旧值加入 manifest enum。
|
||||
- `resourceProjectionModel.ts:326`、`uiDesignResourceBridge.ts:87` 是直接比较 manifest asset kind 的消费点,必须跟随生成绑定迁移到 enum。
|
||||
- `SupervisorChatOnlyView.tsx`、`ProjectSupervisorView.tsx` 等仍直接从 `packages/shared` 导入 manifest 类型,需在删除旧文件前完成 shell 内导入收口。
|
||||
|
||||
## 已迁移的 TS 边界(增量)
|
||||
|
||||
- `packages/shared/src/contracts/gameCreationApp.ts`:直接 re-export Rust 生成的 `GameCreationAppAssetKind`,`parseGameCreationAppAssetKind(raw, context)` 未知输入 `console.warn` 记录 `rawKind` / `sourceContext` 并返回 `unknown`,不做旧 alias 转换;`src/contracts/assetKind.ts` 这层 shell 内重复实现已删除(2026-09-17)。
|
||||
- `src/features/project-workspace/resourceReferences.ts`:资源引用 kind 改为生成枚举类型并通过 parser 收口。
|
||||
- `src/view/project-development/index.tsx`:画布引用入口通过同一 parser 构造资源引用 kind。
|
||||
- `src/features/ui-editor/uiDesignResourceBridge.ts`:UI 原型 manifest kind 只接受 `ui-design`,UI 文档链接只接受 `ui-design-doc`;旧 `ui-prototype` 不再 alias。
|
||||
|
||||
其余 `packages/shared` import 和前端 manifest `kind: string` 字段仍未迁移,继续作为后续小切片,不在本次提交中伪装完成。
|
||||
@@ -31,21 +31,23 @@
|
||||
|
||||
## 4. 请求载荷映射
|
||||
|
||||
| 入口 | IPC | 载荷要点 |
|
||||
| --------------------- | --------------------------------- | ------------------------------------------------------------------------------------------- |
|
||||
| 生成图片 | `start_local_project_asset_generation` | `kind: 'image'`,比例 / 尺寸可调,默认 `1:1 · 1K` |
|
||||
| 生成角色形象 | 同上 | `kind: 'character'`,默认 `1:1 · 1K` |
|
||||
| 生成规范 → 图标规范 | 同上 | `kind: 'icon-spec'`,固定 `1:1 · 1K`;缺权威规范图时 `outputPath: 'assets/art-spec.png'` |
|
||||
| 生成规范 → 角色规范 | 同上 | `kind: 'spec'`,固定 `1:1 · 1K` |
|
||||
| 生成规范 → 自定义规范 | 同上 | `kind: 'spec'`,固定 `1:1 · 1K` |
|
||||
| 生成图标素材 | 同上 | `kind: 'art-spritesheet'`,默认 `1:1 · 1K`;前置:已登记 `assets/art-spec.png` |
|
||||
| 生成 UI 设计图 | 同上 | `kind: 'ui-prototype'`,默认 `16:9 · 1K`;前置同上 |
|
||||
| 生成背景音乐 | `derive_local_project_resource` | `editKind: 'background-music'`、`generationMode: 'create'`、`sourceMediaType: 'audio/mpeg'` |
|
||||
| 生成音效 | `derive_local_project_resource` | `editKind: 'sound-effect'`、其余同上 |
|
||||
| 上传 | `upload_local_asset` | `{ projectPath, fileName, mediaType, bytes }` |
|
||||
| 入口 | IPC | 载荷要点 |
|
||||
| --------------------- | -------------------------------------- | ------------------------------------------------------------------------------------------- |
|
||||
| 生成图片 | `start_local_project_asset_generation` | `kind: 'image'`,比例 / 尺寸可调,默认 `1:1 · 1K` |
|
||||
| 生成角色形象 | 同上 | `kind: 'character'`,默认 `1:1 · 1K` |
|
||||
| 生成规范 → 图标规范 | 同上 | `kind: 'icon-spec'`,固定 `1:1 · 1K`;缺权威规范图时 `outputPath: 'assets/art-spec.png'` |
|
||||
| 生成规范 → 角色规范 | 同上 | `kind: 'icon-spec'`,固定 `1:1 · 1K`;与图标规范 / 自定义规范共用同一条规范通道 |
|
||||
| 生成规范 → 自定义规范 | 同上 | `kind: 'icon-spec'`,固定 `1:1 · 1K` |
|
||||
| 生成图标素材 | 同上 | `kind: 'icon-spritesheet'`,默认 `1:1 · 1K`;前置:已登记 `assets/art-spec.png` |
|
||||
| 生成 UI 设计图 | 同上 | `kind: 'ui-design'`,默认 `16:9 · 1K`;前置同上 |
|
||||
| 生成背景音乐 | `derive_local_project_resource` | `editKind: 'background-music'`、`generationMode: 'create'`、`sourceMediaType: 'audio/mpeg'` |
|
||||
| 生成音效 | `derive_local_project_resource` | `editKind: 'sound-effect'`、其余同上 |
|
||||
| 上传 | `upload_local_asset` | `{ projectPath, fileName, mediaType, bytes }` |
|
||||
|
||||
`start_local_project_asset_generation` 的完整参数是 `{ projectPath, projectId, taskId, kind, prompt, aspectRatio, imageSize, assetName, outputPath }`(Rust `src-tauri/src/asset_generation_tasks.rs`),**提交即返回**一条任务记录(`taskId / status / phaseDetail / assetId / error` 等);生成在 `tauri::async_runtime::spawn` 出来的后台任务里跑,账本落在项目内 `.agent/runtime/asset-generation-tasks/tasks.json`,进度由 `list_local_project_asset_generations` 读回。截图面板不再「等生成结束」,所以**点「生成」即同步关闭面板**(不等 IPC),面板内不出现阶段文案;只有「点击瞬间就失败」才带草稿重开(关闭 ≠ 取消)。
|
||||
|
||||
入参 `kind` 一律是共享 `GameCreationAppAssetKind` 的 canonical 成员(`image` / `character` / `icon-spec` / `icon-spritesheet` / `ui-design` / `publication-material`);`spec` / `art-spritesheet` / `ui-prototype` 这类平台请求词汇只由 Rust 侧派生到 `source.generationKind`,不再出现在 IPC 载荷或 manifest kind 里。
|
||||
|
||||
## 4a. 本地排队与「生成任务」侧栏
|
||||
|
||||
- **本地排队**:AGC 本地 durable 输出槽按**精确动作指纹**分槽(`run_id = slot-<sha256(动作材料)>`,材料为 prompt / outputPath / 比例 / 尺寸 / assetKind / assetLabel / replaceExisting / requireSlices;不同 prompt 或素材名各自独立成槽,不再按 `outputPath` 共用;旧 `{outputPath,requireSlices}` 槽账本由同一精确动作懒迁移)。因此后端已具备并行能力,但**本批前端仍按「同一时刻只派发一条」排队**——真并行派发需要并发收口设计(配对读 + manifest CAS + 聚焦意图互不覆盖),留待下一批。所以第二条提交停在**前端本地队列**里(不调用提交 IPC,阶段显示本地排队的「排队中。」),第一条终态后由同一条循环自动补发;判据是「存在 `dispatched && 未终态` 的任务时不派发下一条」。
|
||||
@@ -66,7 +68,7 @@
|
||||
- 判据与 Rust `canonical_art_spec_reference_at` 逐字对齐(`projectHasIconSpecReference`):manifest 里必须存在 `localPath === 'assets/art-spec.png'`、`kind === 'icon-spec'`、`mediaType` 以 `image/` 开头、`source.kind === 'canvas'` 的资产。
|
||||
- 缺前置时入口**保持可点击**(`aria-disabled="true"`,不是原生 `disabled`),点击后在工具栏上沿给 `role="alert"` 的原因说明:`需要先完成并登记图标规范(assets/art-spec.png);请先用「生成规范 → 图标规范」生成`;此时**不发任何生成请求**。
|
||||
- 「图标规范」入口在缺前置时把 `outputPath` 指向 `assets/art-spec.png`,让前置条件能由工具栏自身满足;已有权威规范图时 `outputPath` 为 `null`。这条策略对应 Rust 侧硬约束:`prepare_local_project_asset_generation` 的 `replace_existing` 固定为 `false`,指向已存在文件会被拒绝(`图片生成 outputPath 已存在,禁止静默覆盖`)。
|
||||
- 已知能力缺口(本轮不扩接口,记账备查):本地 IPC 没有 ① `model` 入参(面板因此不给模型选择)、② `specType` 入参(角色规范与自定义规范共用 `spec` 通道,靠素材名与提示词区分)、③ `replaceExisting` 入参(因此不能重写已存在的权威规范图)。
|
||||
- 已知能力缺口(本轮不扩接口,记账备查):本地 IPC 没有 ① `model` 入参(面板因此不给模型选择)、② `specType` 入参(角色规范与自定义规范共用 `icon-spec` 通道,靠素材名与提示词区分)、③ `replaceExisting` 入参(因此不能重写已存在的权威规范图)。
|
||||
|
||||
## 7. 音频入口收敛
|
||||
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
# AGC Unity 编辑器插件接入
|
||||
|
||||
> 文档状态:`current`
|
||||
> 规范关系:承接 AGC 通用插件宿主与编辑器适配主规范
|
||||
|
||||
更新时间:`2026-09-18`
|
||||
|
||||
## 目标与非目标
|
||||
|
||||
将 DotCraft.Unity 0.4.3 对应的 Attach 执行核心接入 AGC 现有插件系统,使当前 Unity 项目能够探测编辑器、建立连接、执行 C# 并获得真实结果。复用既有扩展列表、内置插件开关、权限、审计、EditorAdapter 和 Agent 工具通路。
|
||||
|
||||
首期只支持 Windows x64 的 Unity Mono Editor。连接不修改项目文件、不安装 UPM 包、不启动或关闭用户编辑器。不引入 DotCraft.Harness、另一套 Agent Runtime、MCP 服务或聊天界面;截图、热重载专用工具、macOS、Linux 和 Unity CoreCLR 不属于本次交付。
|
||||
|
||||
## 来源与分发
|
||||
|
||||
源码固定为 `DotHarness/dotcraft-unity` 的 `a65f091c162ebcfde5ec9b399d188fcc57261947`(发布插件 0.4.3 的 provenance)。只吸收 Attach 与必要 Shared 源码,保留 Apache-2.0 许可、第三方声明、来源及本地修改记录;构建产物不提交。Roslyn 版本固定为 5.3.0。Windows helper 自包含分发,用户不需要预装 .NET;构建端需要 .NET 10 SDK 和 x64 C++ 工具链。
|
||||
|
||||
## 入口与行为合同
|
||||
|
||||
- Unity 项目以当前受控根目录中的普通 `ProjectSettings/ProjectVersion.txt`、`Assets/` 和 `Packages/` 识别;复用现有打开项目入口,不创建平行工作台。
|
||||
- 只有当前项目为 Unity、内置插件启用且平台适配器可用时才显示插件并向 Agent 暴露 Unity 工具。禁用或离开 Unity 项目后停止插件实例,执行入口再次检查开关和项目身份。
|
||||
- 探测只读取进程和项目身份。连接必须匹配规范化项目路径、PID、进程启动身份与实际握手;多个候选时失败,不选择任意实例。助手只接受受控项目、操作和代码,不接受任意可执行文件或 payload 路径。
|
||||
- 执行接收 UTF-8 C# 代码,最多 128 KiB,拒绝空值和 NUL。连接及执行有总期限,消息最多 2 MiB,并发执行直接拒绝,不积压写请求。
|
||||
- 成功仅由 Unity 真实执行回执决定;编译或运行错误返回结构化失败与脱敏诊断。主线程同步代码不承诺可硬中止。
|
||||
- 执行发送后超时、连接丢失、回执损坏或上游 unknown/lost 一律返回 `needs-reconciliation`、`retryAllowed=false`,阻断后续执行。停止/重启 JS 插件、断开连接和切换项目不能清除该阻断;用户核对后重启宿主才恢复。发送前参数、项目、平台或缺少 helper 的失败不进入执行不确定状态。
|
||||
- 探测不等于连接;连接不等于执行成功。Domain Reload 后重新验证身份与 generation,不能重放上一条写操作。
|
||||
- 宿主禁止 RPC 覆盖 manifest 声明的 adapter,并校验显式项目路径等于当前受控项目;缺省路径由宿主填充。编辑器路由不允许在全局锁后无界等待。切换项目使旧连接失效,旧请求回执只能归属原请求,不更新新项目连接状态。连接尝试先撤销旧连接,失败保持 disconnected。
|
||||
- GUI 项目切换采用线性化处理:已有插件执行先在受控期限内结束,再切换宿主项目和失效旧连接;切换在后台线程等待,不阻塞 UI 线程。前端项目设置与 cleanup 按顺序送达宿主,旧 cleanup 不能覆盖新项目。
|
||||
- 插件不继承 Provider 凭据。helper 使用受控可执行路径、最小环境、受限消息和超时;任意 C# 在 Unity 权限下执行,宿主 RPC 权限不构成 OS 沙箱。
|
||||
|
||||
## 模块与契约
|
||||
|
||||
插件包放在 `plugins/agc-unity-editor`,使用现有 Agent Plugins manifest 和 `agc.plugin.v1`。JS 入口通过 `host.rpc` 使用编译期注册的 `unity-editor` 适配器。AGC Runner 是 Unity 执行服务的唯一 owner:GUI 适配器复用现有经过鉴权的 Runner RPC 转发,Runtime 和 DirectProject 在同一个长寿命 Runner 中调用原生服务;不创建另一条跨进程 IPC。执行服务调用独立 Attach helper,再由上游本地协议连接 Unity。GUI 项目切换通过同一路径使连接失效;JS 或连接池重建不得重置 owner 内的不确定门闩,恢复要求核对后重启该执行 owner。
|
||||
|
||||
插件命令 `unity.editor.execute`,连接能力 `unity.editor.connection`;Agent Runtime 同名工具与 DirectProject `agc_unity_execute` 共享同一原生服务、项目检查与不确定结果阻断。面向模型的执行参数只有 `code`,项目路径由宿主注入。
|
||||
|
||||
Runner 在执行前保存请求身份,不保存代码或用户路径;GUI 完整验证确定性终态回执后才确认交付。回执丢失、损坏及插件最后一跳失败均保留持久阻断;正常并发或等待确定回执确认返回未派发失败,不误判执行不确定。Runner 自动重启和新增窗口都不清除阻断;用户核对后退出全部 AGC/Runner,再次启动客户端时,只有同时独占既有 GUI 参与锁和 Runner 实例锁才能恢复。启动、派发、读取和确认共享 80 秒客户端总期限,传给 helper 的预算扣除已用启动时间,过期请求不得派发。
|
||||
|
||||
helper 使用一行一条 JSON 请求/响应,请求包含 `id`、`method`、`params`,响应回显 `id` 与 `result` 或结构化 `error`。方法为 `detect`、`connect`、`status`、`execute`、`disconnect`;`projectPath` 始终来自受控宿主,`processId` 为可选探测约束,`timeoutMs` 不超过 60000。执行响应至少有 `ok`、`status`、`retryAllowed`、`result`/`error`,状态为 `completed`、`failed` 或 `needs-reconciliation`。detect/connect/status 结果包含 `adapter`、`connected`、`pid`、`projectPath`、`version`。
|
||||
|
||||
协议名为 `agc.unity.attach.v1`,每条请求均带 `jsonrpc: "2.0"` 和 `protocol`,id 为正整数。helper 是由原生服务持有的单个常驻子进程;Rust 服务在插件与 Runtime 之间共享,执行不确定门闩独立于 helper 生命周期。请求的 `params` 每次包含当前 `projectPath`,无单独 initialize/wait 公开方法;execute 内部完成连接、执行与有界 wait,总 deadline 包含发现、连接与等待,内部不重发 execute。detect 不进行注入。非执行方法的协议错误为 `{code, message}`;execute 的已知未发送失败同样放在结构化 result,只有带完整 `status: failed, ok: false, retryAllowed: false, dispatched: false` 的回执可判为未执行,未知错误不得据此解锁。执行成功含 `dispatched: true`;不确定结果含 `dispatched: true`。连接成功另含 `startedUtc` 与 `generation`,以实际目标身份/握手为准。
|
||||
|
||||
明确收到可信 `failed, ok: false, dispatched: true` 回执表示 Unity 已确定执行失败,不进入不确定门闩;可以由 LLM 修复代码后再执行。`retryAllowed: false` 禁止自动原样重放,不阻止确定性编译或运行错误后的修复。只有完整且匹配请求的终态回执可以支持这一判断。
|
||||
|
||||
首次通过现有打开项目入口导入 Unity 时允许沿用 AGC 的 `.agent` 元数据初始化;不修改 `Assets`、`Packages`、`ProjectSettings` 或 Unity 工程文件。此动作与只读 detect、不改文件 connect 分开。
|
||||
|
||||
不修改服务端 API、SpacetimeDB schema 或现有持久项目数据。新增插件开关沿用既有内置开关存储;不兼容或模拟 DotCraft.Harness 插件 ABI。
|
||||
|
||||
## 验收标准
|
||||
|
||||
| 条款 | 必须取得的证据 |
|
||||
| --- | --- |
|
||||
| 来源与构建 | 固定源码版本、许可、helper 构建和自包含发布检查 |
|
||||
| 插件接入 | manifest/协议测试,发现、启停、开关和项目级工具过滤测试 |
|
||||
| 执行闭环 | helper 与原生适配器定向测试,Agent 参数及结果映射测试 |
|
||||
| 失败边界 | 跨项目、并发、超时、损坏回执、不确定阻断、重启插件不解除阻断测试 |
|
||||
| 分发 | Windows 构建脚本准备 helper,staging 仅包含目标平台运行文件及许可 |
|
||||
| 运行时 | 若有可用 Unity,使用临时测试项目验证连接和无副作用 C# 回执;没有可用编辑器时明确标为未验证,不以 mock 代替实机 |
|
||||
| 仓库门禁 | 定向测试、类型检查、文档索引、编码检查及 git diff --check |
|
||||
|
||||
真实 Unity、安装包及全版本兼容验收与单元测试分别报告。
|
||||
|
||||
## 当前验证范围与复验入口
|
||||
|
||||
- .NET helper 的 27 项定向测试与 Windows x64 自包含发布通过;发布程序在最小环境中完成协议 smoke。
|
||||
- 插件 JS 的参数/消息/并发/项目切换测试通过;Unity/Cocos 打开入口、插件启停投影及开发构建参数的前端定向验证通过。
|
||||
- 原生 helper 进程测试覆盖写入阻塞、EOF、错误 id、超长帧、期限、环境隔离及不确定结果阻断。
|
||||
- 宿主 Unity 定向 8 项、PluginHost 13 项、原生工具目录 16 项和引擎识别 5 项通过;Cocos 10 项、MCP 25 项通过,两组中同一个默认忽略的 Cocos 实机用例未在本任务运行。双 feature 编译检查和调试构建通过。
|
||||
- Unity `6000.3.7f1` 的独立临时工程已完成真实连接、C# 执行、编译错误回传及修复、确定运行错误、临时对象创建/销毁、断开重连验证。项目没有安装 DotCraft UPM 包。
|
||||
- `tests/live_unity.rs` 已显式执行通过,覆盖共享原生服务、编译修复以及 Domain Reload 后重新握手和 generation 更新;它默认 ignored,避免普通测试连接开发者项目。
|
||||
- 新构建的 AGC Runner 使用独立临时配置,完成真实 Unity 执行、ACK、错误 ACK 拒绝、未确认回执的并发拒绝,以及不确定状态跨 Runner 重启保留的验证。
|
||||
- 安装包 UI smoke、其它 Unity 版本及 CoreCLR 不属于上述已验证范围;不能从单一版本实机通过推断全版本兼容。
|
||||
- Gitea 的现有 AGC web 与 Rust crates 门禁分别执行 Cocos/Unity 插件 JS 和原生 crate 测试;Linux CI 不执行 Windows Attach helper 或真实 Unity。Windows Jenkins 构建要求 PATH 可解析 .NET 10 SDK,并由 helper 构建脚本执行 .NET 测试及自包含发布;实机与安装包验收仍单独报告。
|
||||
|
||||
复验命令:
|
||||
|
||||
```powershell
|
||||
powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass -File plugins/agc-unity-editor/dotnet/build.ps1
|
||||
node --test plugins/agc-unity-editor/src/entry.test.mjs
|
||||
cargo test --locked --manifest-path plugins/agc-unity-editor/native/unity-editor-bridge/Cargo.toml
|
||||
```
|
||||
|
||||
实机复验先自行创建、打开隔离测试工程,核对其 Unity PID,并设置
|
||||
`AGC_UNITY_SMOKE_HELPER`、`AGC_UNITY_SMOKE_PROJECT`、`AGC_UNITY_SMOKE_PID` 后执行:
|
||||
|
||||
```powershell
|
||||
cargo test --locked --manifest-path plugins/agc-unity-editor/native/unity-editor-bridge/Cargo.toml --test live_unity -- --ignored --nocapture
|
||||
```
|
||||
|
||||
该实机用例会触发 Domain Reload,不能指向有未保存工作的用户工程。
|
||||
|
||||
独立评审已核对项目归属、并发拒绝、总期限、ACK 原子归属、最后一跳回执丢失、
|
||||
进程重启阻断及发布许可边界;定向证据与上述真实运行时验证共同覆盖本次接入合同。
|
||||
@@ -4,7 +4,7 @@
|
||||
> 规范关系:AGC 插件与编辑器适配主规范
|
||||
> 验收范围:插件 manifest、宿主生命周期、RPC、Capability/权限审计、UI 挂载和编辑器适配器边界
|
||||
|
||||
更新时间:`2026-09-09`
|
||||
更新时间:`2026-09-18`
|
||||
|
||||
## 目标与边界
|
||||
|
||||
@@ -19,6 +19,7 @@ apps/ai-game-creator-shell/src-tauri/src/editor_adapters.rs
|
||||
packages/agc-plugin-sdk/src/index.ts
|
||||
server-rs/crates/editor-adapter-api/src/lib.rs
|
||||
plugins/agc-cocos-editor/ (第一个编辑器插件包)
|
||||
plugins/agc-unity-editor/ (Unity Mono 编辑器插件包)
|
||||
```
|
||||
|
||||
现有 DirectProject 的 Skill/MCP 导入仍保留。它们是 Codex 扩展注入链路,不等同于本宿主管理的可运行 AGC Plugin。
|
||||
@@ -115,6 +116,13 @@ host.rpc(method, params)
|
||||
|
||||
当前 native 适配器仍由宿主在编译期链接(Cargo path 依赖);动态加载插件 native 模块不在本次范围,插件包格式与宿主协议不受此限制。
|
||||
|
||||
Unity 插件复用此扩展点,GUI 适配器通过已有 Runner RPC 转发到唯一的 Unity 执行
|
||||
服务,避免 GUI、DirectProject 与 Runtime 分别持有连接或执行不确定门闩。
|
||||
宿主 RPC 将目标 adapter 绑定到 manifest,并校验显式项目路径等于当前项目;切换
|
||||
项目使旧连接失效,禁止互斥锁后积压的请求在调用方超时后继续派发。
|
||||
Windows x64 的 Attach helper 来源、构建工具链和执行回执合同见
|
||||
[Unity 插件接入](./【技术方案】AGC Unity编辑器插件接入-2026-09-18.md)。
|
||||
|
||||
## Tauri 命令
|
||||
|
||||
`list_agc_extensions` 返回统一的 Plugin/Skill/MCP catalog;`list_agc_plugins`、`refresh_agc_plugins`、`start_agc_plugin`、`stop_agc_plugin`、`reload_agc_plugin`、`call_agc_plugin` 和 `read_agc_plugin_panel` 提供 Runtime Plugin 管理入口;`set_agc_plugin_project_path` 设置当前项目的受控上下文。编辑器适配器通过宿主 registry 和 Plugin RPC 使用,不增加编辑器专属 Tauri 命令。
|
||||
|
||||
@@ -1,5 +1,34 @@
|
||||
# AI 游戏创作智能体 App 实施计划
|
||||
|
||||
## 2026-09-17 GameCreationApp 资源 kind:唯一词汇表、严格解析与 `app_log!` 留痕
|
||||
|
||||
本节覆盖 2026-09-15 节里关于「canonical 字符串列表 / legacy 别名表 / `tracing` 留痕 / ts-rs 生成路径」的表述;枚举成员集合、「不迁移、不静默转换」的总体口径不变。
|
||||
|
||||
- **唯一词汇表**:kind 的变体、线上值(kebab-case)、`as_str()`、`ALL`、严格解析与 ts-rs 绑定全部由 `server-rs/crates/shared-contracts/src/game_creation_app/asset_kind.rs` 的声明表派生。`GAME_CREATION_APP_CANONICAL_ASSET_KINDS`、`canonical_game_creation_app_asset_kind()`(含 `font → document` 特例与 legacy 别名表)已删除;TS 侧同名的 `GAME_CREATION_APP_CANONICAL_ASSET_KINDS`、`GameCreationAppCanonicalAssetKind`、`GAME_CREATION_APP_LEGACY_ASSET_KINDS`、`canonicalGameCreationAppAssetKind()` 一并删除,仓库里不再有第二份 kind 列表。
|
||||
- **TS 生成路径**:`GameCreationAppAssetKind` 由 ts-rs 生成到 `packages/shared/src/contracts/generated/GameCreationAppAssetKind.ts`(不再是 `apps/ai-game-creator-shell/src/contracts/generated/`);`packages/shared/src/contracts/gameCreationApp.ts` 直接 re-export 该 union,运行期 kind 列表只有一份 `GAME_CREATION_APP_ASSET_KINDS`(穷举 `Record<GameCreationAppAssetKind, true>` 保证不会与生成 union 分叉)。重新生成:`cargo test --locked -p shared-contracts --features ts-bindings export_bindings --manifest-path server-rs/Cargo.toml`,之后 `git diff` 必须为空。两张生成目录的忽略规则同步登记在 `.prettierignore` 与 `.eslintrc.cjs`。
|
||||
- **严格解析只有一个入口**:`GameCreationAppAssetKind::parse_with_context(value, context)` 是唯一公开解析入口(`FromStr`、serde、所有外部边界都走它),内部严格匹配是私有 `match_canonical()`;先前那批易混名字(`from_str_lossy()`、公开的 `from_str_or_unknown()`)都已删除,认不出 canonical 值只有这一处收口 + 留痕。口径是等值匹配——不 trim、不 lowercase、不查别名、不迁移;`"UI"`、`"ui"`、`" image "`、`"art-spritesheet-slice"` 一律收口成 `unknown`(分类落 `unclassified`)。**接受 unknown 是显式决定**:留痕日志给出原始串与上下文,供回查仍在写 legacy kind 的代码;不写兼容、不做迁移。
|
||||
- **登记边界同口径**:外部登记 kind(Tauri 命令 `commands::register_local_asset`、`commands::import_canvas_asset`、平台导入)统一走 `assets::registration_asset_kind()`——空白入参按「没有信息」落中性 `image`(→「待归类」),非空但认不出的值走严格解析收口成 `Unknown` 并留痕。三条边界不再各写一份 trim/兜底分支;解析只发生在命令边界,`import_canvas_asset_at` 等内部函数直接接收 `GameCreationAppAssetKind`,不再接受字符串 kind。
|
||||
- **登记内容的 kind 必须与内容相符**:`normalize_local_project_raster_resource_at` 的源 subtype 只接受图片族成员(`image / scene / character / character-animation / icon / icon-spritesheet / icon-spec / ui-design`)。未提供或空白时按没有类型信息落 `image`;音频、视频、文档、字体、代码等非图片族值,以及未知字符串,均明确报错,不再静默改成 `image`,以暴露调用方错误。派生资源写回 manifest 时不得主动写 `Unknown`:Agent 回执派生物是 markdown 文本,按 `Text => Document` 同口径落 `document`。
|
||||
- **切片残留判据只看路径**:`register_existing_platform_art_slices_at` 判定「已有半成品切片登记」时只看 `assets/art-spritesheet-slices/` 前缀,不再附带 `kind == Icon`——历史切片刻写的是非 canonical kind,严格解析后是 `unknown`,再带 kind 判据会漏掉这些登记并静默跳过回填。
|
||||
- **sprite 身份不含展示串**:UI 工作流比较 sprite 资源身份时忽略 `metadata.asset_type`(它随 canonical kind 派生),只看真正影响渲染的字段;否则对既有 State 重跑工作流会误报「与已有 State 资源冲突」。
|
||||
- **TS 侧判据也只留一份**:`isGameCreationAppUiDesignDocAsset(asset)` 是「`kind == ui-design-doc` 且 `mediaType == application/json`」的唯一定义,资源画布入口、UI 编辑器桥接、资源引用缩略图三处统一调用它。
|
||||
- **严格口径的已知代价**:既有项目 manifest 里若存的是 legacy kind(`"UI"`、`"ui-prototype"`、`"art-spritesheet"`、`"game-background"`…),读入后就是 `unknown`,依赖 kind 等值比较的运行门禁会按「缺少该资源」处理。这是「不迁移、不 fallback」的必然结果,由项目决策接受;若将来要迁就存量数据,必须单独立项(一次性迁移或读侧白名单),不得把别名表加回解析路径。
|
||||
- **留痕走 `app_log!`**:`shared-contracts` 不再依赖 `tracing`(`kind-observability` feature 删除),改为暴露可注册回调 `set_non_canonical_asset_kind_reporter()`;AGC 壳在 `main()` 里注册成 `app_log!`,日志同时含**原始输入串**与调用上下文,用于回查还有谁在写 legacy kind。TS 侧对应 `parseGameCreationAppAssetKind()` 的 `console.warn`。
|
||||
- **分类映射**:`GAME_CREATION_APP_ASSET_CATEGORY_BY_KIND` 改为按 `GameCreationAppAssetKind` 变体穷举(含 `unknown → unclassified`),与 `GameCreationAppAssetKind::ALL` 的对齐由单测 `asset_category_mapping_covers_every_kind` 守住;TS 侧同表按生成 union 穷举。
|
||||
- **画布生成与图片快速编辑共用枚举**:`canvas.asset_generate` 的 `assetKind` 白名单直接复用 `GameCreationAppAssetKind::CANVAS_ASSET_KINDS`(当前为 `image / icon-spec / ui-design / icon-spritesheet`),工具 schema、prompt 和执行前校验均从该枚举派生,不再维护 `&[&str]` 字符串目录。图片快速编辑来源同样严格解析 `GameCreationAppAssetKind`,只允许 `is_static_image()` 的 canonical 成员并要求 `mediaType=image`;原有 `EDITOR_IMAGE_EDIT_STATIC_IMAGE_ASSET_KINDS` 兼容白名单已删除,退役值不再放行。平台适配层若仍需要其他领域的外部请求字面值,只能在发送边界显式映射;manifest 始终写入枚举的 canonical 值。
|
||||
- **版本素材替换**:`subtypeEqual` 改为枚举相等(不再经别名字符串归一),`categoryEqual` 仍用 `game_creation_app_asset_effective_category` 的读时口径。
|
||||
|
||||
## 2026-09-15 GameCreationApp 资源 kind 枚举化(当前权威口径)
|
||||
|
||||
本节覆盖并替代下方 2026-09-09 资源 kind 别名、canonical fallback 与读时自愈相关口径。当前仍在开发期,不为旧本地 manifest 提供 migration、alias 兼容或静默转换;旧值只会在解析时落入 `Unknown` 并记录结构化日志,后续按扫描清单清理产生旧值的代码。
|
||||
|
||||
本次重构范围限定在 `apps/ai-game-creator-shell` 内表达 **GameCreationApp 资源 kind** 的字段、参数、投影、筛选和 manifest 读写边界。`mediaType`、MIME、文件扩展名、`source.kind`、`source.generationKind`、任务/工作流 kind、路径名,以及 server-side 其他 `asset_kind` 不在本次重构范围内,继续使用各自现有类型。
|
||||
|
||||
Rust 侧在 `server-rs/crates/shared-contracts` 维护唯一权威 `GameCreationAppAssetKind` enum,并使用 `serde` kebab-case 序列化;`Unknown` 是正式解析结果,序列化值为 `unknown`。TypeScript 绑定由 `ts-rs` 从 Rust 生成到 `apps/ai-game-creator-shell` 内,删除 `packages/shared/src/contracts/gameCreationApp.ts` 中重复的手写 kind 契约。正常写入路径不得主动构造 `Unknown`;未知外部值进入 `Unknown` 时必须记录原始值、来源和调用上下文的 `tracing`/日志。
|
||||
|
||||
当前候选正式成员以 api-server 仍有效的资源 kind 命名为基线,并保留 shell 已实际使用的字体与通用音频语义:`image`、`scene`、`character`、`character-animation`、`icon`、`icon-spritesheet`、`icon-spec`、`ui-design`、`ui-design-doc`、`publication-material`、`spec`、`video`、`audio`、`sound-effect`、`background-music`、`font`、`document`、`code`、`unknown`。`audio` 表示通用上传音频,`sound-effect` 与 `background-music` 表示更具体的生成/资源语义,不因同属 `audio` category 而合并。`asset`、`ui`、`animation`、`game-background`、`art-spritesheet` 等旧值必须逐处审计:进入 GameCreationAppAssetKind 的生产写入改为正式成员;仅作为 workflow、generation、路径或协议标识的值保持原字段,留待后续独立 PR。
|
||||
|
||||
实施要求:先完成 shell 内 raw kind / typed kind 扫描清单与生产写入审计,再分小提交实现 Rust enum、生成绑定、内部字段收紧、写入方修正、Unknown 可观测性和旧 alias 删除。每个提交只形成一个可验证的深模块,不把不同领域的字符串类型强行合并;完成后补充 `ts-rs` 生成/校验门禁、serde round-trip、未知值日志和所有 manifest writer 的 canonical/Unknown 边界测试。
|
||||
## 游戏画布居中指引
|
||||
|
||||
开发 Agent 的系统工程提示与 `agc-web-game-development` Skill 明确约束同一 canvas 的居中只能由一方负责:Phaser `FIT + CENTER_BOTH` 配合尺寸明确的普通块级父容器,不叠加同一父容器的 Grid/Flex 居中、自动外边距或居中 transform;如由 CSS 居中则设置 Phaser `NO_CENTER`,外围页面的 Grid/Flex 不受此限制。布局修改后构建实际 dist,并在桌面、移动和 resize 下核对 canvas 对游戏父容器中心偏差不超过 1 CSS px、无溢出与意外滚动条。出现偏移先检查游戏项目的 CSS/scale,不修改 AGC 预览固定偏移掩盖问题;这些要求通过 Agent 指引执行,不新增运行时门禁或平行校验系统。
|
||||
@@ -156,9 +185,9 @@ App 界面测试中,关闭 Agent 弹窗后的迟到读取用例先等待「刷
|
||||
|
||||
## 2026-09-09 manifest 资源功能分类与自定义标签(数据层)
|
||||
|
||||
本地 manifest 资产条目末尾新增 `category`(单值,6 类 `ui-interaction / character / scene / audio / document / unclassified`,默认 `unclassified`)与 `tags`(字符串数组,默认空数组);字段始终序列化,不进 api-server、外部 OpenAPI 或 SpacetimeDB schema。默认分类由 `GAME_CREATION_APP_ASSET_CATEGORY_BY_KIND` 按 canonical kind 穷举映射:`icon / icon-spritesheet / icon-spec / ui-design → ui-interaction`,`character / character-animation → character`,`scene → scene`,`audio / sound-effect / background-music → audio`,`document / spec → document`,`image / video / code / publication-material → unclassified`;alias 表**大小写不敏感**(UI 设计资产的现役写入侧写的是大写 `"UI"`,`font` 是字体上传登记的 kind),`"UI" → ui-design → ui-interaction`、`font → document → document`;其余映射不到 canonical kind 的原始 kind(例如 `test`)才经 `canonicalGameCreationAppAssetKind` 落 `image`、归 `unclassified`。读显示口径在 TS(`gameCreationAppAssetCategory`)与 Rust(`game_creation_app_asset_effective_category`)同构,写回 manifest 必须用落盘原值 `gameCreationAppAssetPersistedCategory`。
|
||||
本地 manifest 资产条目末尾新增 `category`(单值,6 类 `ui-interaction / character / scene / audio / document / unclassified`,默认 `unclassified`)与 `tags`(字符串数组,默认空数组);字段始终序列化,不进 api-server、外部 OpenAPI 或 SpacetimeDB schema。默认分类继续由资源 kind 到 category 的显式映射决定:`icon / icon-spritesheet / icon-spec / ui-design → ui-interaction`,`character / character-animation → character`,`scene → scene`,`audio / sound-effect / background-music → audio`,`document / spec / font → document`,`image / video / code / publication-material / unknown → unclassified`。kind 枚举、未知值与写入边界以本文件顶部 2026-09-15 口径为准;本节不再定义 alias、canonical fallback 或旧 manifest 自愈。
|
||||
|
||||
历史 manifest 缺少字段时读取按 `kind` 派生分类、`tags` 取空数组;显式写入的合法分类原样保留,未知分类字符串按前向兼容退回 `kind` 派生。新建资源条目写 `kind` 派生默认值,更新既有条目保留已有 `category` / `tags`,不覆盖用户值。`tags` 归一化(trim、去空、去重)只以纯函数交付,本轮不接入写入路径。本轮不做任何 UI(画布功能画布与筛选、@ 面板标签筛选、标签管理面板)、数据迁移脚本、标签库聚合派生与 Agent 检索工具。
|
||||
开发期 manifest 只按当前枚举解析;旧字段兼容、迁移脚本与 alias 不属于当前目标。新建资源条目必须由已验证的 `GameCreationAppAssetKind` 写入;未知输入只能产生 `Unknown` 解析结果并记录日志,不能由 writer 静默改成其他 kind。`tags` 归一化(trim、去空、去重)保持现有规则。本节原有 UI、标签库和 Agent 检索范围不因本次 kind 枚举化扩大。
|
||||
|
||||
## 2026-09-08 Web 游戏 npm 与 Phaser 4 产物合同
|
||||
|
||||
@@ -1354,7 +1383,7 @@ game-project/
|
||||
|
||||
## 2026-08-17 UI Editor 项目资源 State 持久化
|
||||
|
||||
- UI 编辑器复用现有 manifest `kind: "UI"`、`mediaType: "application/json"` 资源,不增加平行 asset kind。资源文件固定为严格 `game-creator-ui-design-state.v1` JSON envelope:`projectId`、`assetId`、每资源 `revision` 和 Rust 唯一源 `State`;旧空对象、未知字段、身份错配、超限、无效内部引用和不安全相对路径均失败关闭。内部引用校验同时覆盖 `Image.target_graphic -> sprite_assets` 与 `Text.font -> font_assets`,可选引用非空时必须命中同一 State 内已登记资源。
|
||||
- UI 编辑器使用唯一的 manifest `kind: "ui-design-doc"`、`mediaType: "application/json"` 资源,不接受旧 `UI` / `ui` / `ui-design`,也不增加 fallback 或迁移。资源文件固定为严格 `game-creator-ui-design-state.v1` JSON envelope:`projectId`、`assetId`、每资源 `revision` 和 Rust 唯一源 `State`;旧空对象、未知字段、身份错配、超限、无效内部引用和不安全相对路径均失败关闭。内部引用校验同时覆盖 `Image.target_graphic -> sprite_assets` 与 `Text.font -> font_assets`,可选引用非空时必须命中同一 State 内已登记资源。
|
||||
- Tauri 专用 load/save command 只接受项目路径、期望项目 ID、manifest asset ID 和(保存时)资源 revision;Rust 按 manifest 解析受控本地路径并在项目写锁内做 CAS。相同 `State` 返回 unchanged 且不推进 project revision;不同内容安装并回读一致后才推进 revision,后续推进失败返回 `reconciliation-required`,不伪装为完整保存。
|
||||
- UI 编辑器代码导出仅写入用户项目目录下的 `ui/generated-*.js` 派生文件,绝不推进项目 revision、UI State revision、manifest 阶段或 Runtime 验证门;写入失败只返回生成错误,不得把生成文件写入冒充为项目 mutation。
|
||||
- UI State 原子安装保留最近一个可解析、canonical 的 `.previous` 恢复候选,作为最佳努力恢复来源;写入主文件前不把完整 State 语义校验重复执行一遍。主文件损坏时,恢复候选仍必须通过同一严格 schema、project/asset identity、revision、引用和 State 校验后才能安装;恢复安装与保存共用项目写锁,并在持锁后重新读取主文件,已有并发保存的有效新版本时直接返回而不安装旧副本。任一候选均不可信则停在加载错误,前端禁编辑和保存。新建 UI 资源先登记并安装合法 envelope,任一步失败补偿 manifest/文件,避免把空 JSON 留给资源卡。
|
||||
@@ -1497,7 +1526,7 @@ DirectProject 使用 `approvalPolicy=never`,避免每次原生调用再经过
|
||||
- **命令**:`read_local_project_version_resource_replacement_candidates`(只读,`asset.list`)与 `replace_local_project_version_resource`(写,`asset.register`),实现在 `src-tauri/src/project/version_resource_replacement.rs`。入参都是单个 `input` 对象、`deny_unknown_fields`:读 `{projectPath, sourceVersionId, sourceResourceId}`,写额外要求 `expectedProjectId + expectedProjectRevision + replacementResourceId`;出参 `{versionId, committedProjectRevision, replacement:{versionId, sourceResourceId, replacementResourceId, compatibility, warning}}`(**没有** `parentVersionId`,因为没有新版本)。这两个 DTO 是 Tauri 本地 DTO,**不进跨端契约**。
|
||||
- **写入语义**:持项目写锁(与删除 / 重命名 / 标签同一把)→ 锁外与锁内各复核一次 `projectId`,锁内复核 durable revision(CAS 失败报 `project-identity-conflict` / `project-revision-conflict` 且零写入)→ 走上面的绑定改写通道,放行集合固定为 `[sourceVersionId]` → 成功后推进一次项目 revision(改绑定属于 `versions` 变化,跨面快照门禁要求 revision 前进)→ 追加一条 `asset.version_binding.replace` 审计(复用既有 `append_agent_db_record`)。审计写失败会报错但不回滚,与 `asset.register` 同口径。
|
||||
- **绑定改写语义**(恒等绑定口径的硬约束):`resourceBindings` 是"该版本使用的素材集合"而不是槽位表,因此改写 = **源素材从集合里消失 + 保证替换素材在集合里**;替换素材是源版本创建之后才登记时按源素材原来的位置插回(顺序稳定),早已登记时只做摘除 —— 不能把源素材那条槽位改写成替换素材,那会撞「资源槽位重复」。
|
||||
- **准入与提示(后端权威,前端只呈现)**:**硬门禁**只有 `categoryEqual`(用 PRD §5.3 的**读时自愈**口径,Rust 侧 `game_creation_app_asset_category_with_read_time_healing` 与 `packages/shared` 的 `gameCreationAppAssetCategory` 逐分支一致并配用例锁定)与 `subtypeEqual`(canonical `kind`);`sizeSpecEqual` **降级为提示**(「格式与源素材不同」)不再拒绝 —— 它的完整判据今天不存在(manifest 没有 `width / height / durationMs`,现役写入侧几乎全写 `imageSequenceFrames: None`,实际只等于"媒体格式相等"),硬拦会误拒 `png ↔ webp` 这类最常见需求;要变成硬判据须先给 manifest asset 增尺寸字段并在写入侧回填(跨端契约变更)。
|
||||
- **准入与提示(后端权威,前端只呈现)**:**硬门禁**只有 `categoryEqual`(用 PRD §5.3 的**读时自愈**口径,Rust 侧 `game_creation_app_asset_effective_category` 与 `packages/shared` 的 `gameCreationAppAssetCategory` 逐分支一致并配用例锁定)与 `subtypeEqual`(canonical `kind`);`sizeSpecEqual` **降级为提示**(「格式与源素材不同」)不再拒绝 —— 它的完整判据今天不存在(manifest 没有 `width / height / durationMs`,现役写入侧几乎全写 `imageSequenceFrames: None`,实际只等于"媒体格式相等"),硬拦会误拒 `png ↔ webp` 这类最常见需求;要变成硬判据须先给 manifest asset 增尺寸字段并在写入侧回填(跨端契约变更)。
|
||||
- **入口**:资源卡选中工具条的宿主 `extraActions` 新增「替换素材」,判据复用现役 `isResourceUsedByCurrentVersion`(manifest 身份 + 被当前版本绑定),未绑定素材不渲染入口;不动 `ImageCanvasSelectedLayerToolbarAction` 共享 union、不改 `resourceCanvasToolbarModel` 的 `supportedActions`。候选弹窗复用 `ImageCanvasProjectAssetPickerDialog`(该弹窗在 AGC 侧首次使用),以可选 prop 扩展:`singleSelect` / `assetBlockedReasons` / `assetHints` / `renderAssetMedia` / `selectionNoun` / `errorMessage`,**默认值保持网页端美术画布行为逐字不变**。候选行渲染类型占位而不挂 `<img>`(AGC 的预览要经带 scope 的原生调度器拿 Blob URL,弹窗内没有同步 `src`)。
|
||||
- **成功后行为**:重读 manifest,**不切换版本**(没有新版本可切),**不自动重载 / 重启运行中的预览**(PRD §3.2 末条),不做运行时资源重映射。可见变化只有资源卡「当前使用」高亮移到替换素材、`@` 面板「当前版本素材」更新。
|
||||
- **已知代价(用户已确认接受)**:**替换历史不可回溯**——替换前身份只剩那条审计与 manifest 的 `.previous` 副本;需要"某版本历史上换过什么"时要另立切片(PRD §3.2 / §5.3 保留为未来合同正是为此)。
|
||||
|
||||
@@ -47,6 +47,15 @@ SpacetimeDB 版本口径:当前 Rust crate `spacetimedb`、`spacetimedb-sdk`
|
||||
npm run check:server-rs-ddd
|
||||
```
|
||||
|
||||
## 依赖装配与横切能力
|
||||
|
||||
- 启动入口负责构造共享依赖,业务入口通过 Axum `State` / `FromRef` 获取所需能力。项目元数据链路与 External API 鉴权使用窄状态;窄状态不得持有完整 `AppState`、通过 `Deref` 暴露完整配置,或提供 `root_state()` 逃逸。仅在需要替换或隔离测试的外部能力处抽取接口,生产实现仍复用现有 `spacetime-client` facade,不新建数据库访问通道。
|
||||
- 后台、External API 和编辑器路由按同一种身份策略聚合鉴权,公开登录、公开文档、公开精选读取及 MCP 保持独立边界。路由、HTTP 方法、404/405、请求大小限制、授权和错误响应合同保持不变;后台 member 的实时权限校验和资源 owner 校验继续由现有权威逻辑执行。
|
||||
- HTTP 观测使用统一 Tower 追踪层与 `MatchedPath` 模板;请求计数通过 RAII 覆盖取消与 unwind,响应体存活单独统计。具体指标合同见开发运维文档。
|
||||
- Provider 函数级追踪采用现有 tracing 能力,显式列出 provider、operation、model 等非秘密字段,跳过完整参数、配置、凭据和消息正文;异步 span 覆盖实际执行与等待,不能只记录 Future 创建。装饰与追踪保持原始成功值、错误、重试次数、流式回调和取消语义。
|
||||
- 扣费、退款、幂等、资源登记、重试判定与事务边界保持显式业务流程;不引入自动扫描 IOC 容器、通用 AOP 框架或跨外部副作用的隐式事务。
|
||||
- 验收覆盖:所有受保护路由的匿名拒绝及公开入口可访问;原有 404/405 和 body limit;窄依赖可独立构造和替换;Provider 成功/失败、异步追踪归属与脱敏;已有 API、计费和幂等回归。真实本地服务 smoke 必须记录所用数据库及依赖可用性,不能用单元测试代替运行时证据。
|
||||
|
||||
## `spacetime-client` mapper 组织
|
||||
|
||||
`spacetime-client` 的 Cargo `lib.path` 指向 `src/active.rs`,现役 mapper 聚合入口是 `src/active/mapper.rs`;原旧 facade 和 mapper 已删除。
|
||||
|
||||
@@ -808,13 +808,15 @@ OpenTelemetry 现阶段默认开启 OTLP traces / metrics / logs,但本地日
|
||||
- 应用日志按进程查看:父 API 使用 `journalctl -u genarrative-api.service`,独立 BgFilter worker 使用 `journalctl -u genarrative-bgfilter-worker.service`;Nginx 日志仍写文件。日志等级继续用 `GENARRATIVE_API_LOG` / `RUST_LOG` 控制,例如 `info,tower_http=info,spacetime_client=info`。
|
||||
- debug exporter / Rider 转发都会同时接收 traces、metrics 和 logs。
|
||||
- api-server 会随 metrics 发送进程级指标:`process.memory.usage`、`process.memory.virtual`、`process.cpu.time`、`genarrative.process.cpu.usage_percent`、`process.thread.count`、`genarrative.process.memory.private`;Windows 额外发送 `process.windows.handle.count`,Linux 额外发送 `process.unix.file_descriptor.count`。这些指标只描述当前进程,不携带请求、用户或作品 label。
|
||||
- HTTP 运行态补充发送 `genarrative.http.server.response_bodies.in_flight` 与 `genarrative.http.server.request_permits.available`,后者带低基数 `pool=default|gallery|detail|admin` label,用于区分业务 handler / 背压 permit 是否仍被占用;拼图广场热点缓存补充发送 `genarrative.puzzle_gallery.cache.*` 指标,记录 fresh hit、stale hit、未命中、后台刷新开始 / 失败、重建耗时和预序列化 data JSON 字节数。
|
||||
- HTTP 请求在途指标 `http.server.active_requests` 从进入观测中间件计数,到生成 `Response` 时结束;使用 RAII guard 保证正常返回、Future 被取消释放和 panic unwind 时都按原始 method / route 标签且仅递减一次。`http.server.request.duration` 采用同一执行区间,仅记录已生成响应的请求,不表示响应已发送到客户端,也不表示 SSE 已结束。响应体存活另由 `genarrative.http.server.response_bodies.in_flight` 统计;背压 permit 由 `genarrative.http.server.request_permits.available{pool=default|admin}` 统计。
|
||||
- 正常服务与 SpacetimeDB 不可用时的降级路由复用同一 HTTP `TraceLayer` 构造函数。请求上下文在追踪层外侧,错误归一化和响应头回写在追踪层内侧,保证提前拒绝和降级响应仍记录同一 request ID 与最终状态。
|
||||
- `platform-llm` 的普通与流式调用统一生成 `llm.request` 子 span,字段白名单为 `provider`、`operation`、`api_kind`、`model`,继承调用方当前 span;范围覆盖响应读取、流式回调和异步等待,取消释放 Future 时结束。完整 client/config、API Key、请求/响应正文不进入该 span;既有 Provider 错误和重试策略保持原样,不能用遥测包装吞掉失败或自动重放。
|
||||
- 外部 API 失败统一发送 OTLP 并落库。当前 VectorEngine 图片生成 / 编辑失败由 `platform-image` provider 输出结构化日志字段,字段包括 provider、endpoint、failure_stage、status、source、source_chain、source_chain_depth、timeout、retryable、latency_ms、prompt_chars、reference_image_count、实际 provider `image_model`、request_params 和 raw_excerpt;发生模型回退时另带 `fallback_from_model` / `fallback_to_model`。图片编辑请求参数日志还会带 reference_image_bytes_total,并在 request_params.referenceImages 中记录每个 multipart `image` part 的 fileName、mimeType 和 bytes,不记录 API key 或原始图片 bytes;`api-server` 再记录指标 `genarrative.external_api.failures{provider,failure_stage,status_class,retryable}`,并写入 `tracking_event`,`event_key = external_api_call_failure`、`module_key = external-api`、`scope_kind = module`、`scope_id = provider`。调用方能拿到身份上下文时,失败事件还会在行级 `user_id` / `owner_user_id` / `profile_id` 和 `metadata_json.userId` / `metadata_json.profileId` / `metadata_json.requestId` / `metadata_json.errorSource` 中记录触发者、草稿 / 作品作用域、请求标识和传输错误链。排障时先按 provider / failureStage / imageModel 聚合,再下钻 userId / profileId,最后结合 request 日志、errorSource 和上游响应 excerpt 判断是模型不可用、限流、超时、解析失败还是未返回图片。
|
||||
- OSS 平台适配器也输出结构化日志,覆盖 `sign_post_object`、`sign_get_object_url`、`head_object` 和 `put_object`。排查资产签名、上传或确认失败时,先按 `provider=aliyun-oss` 与 `operation` 过滤,再看 `object_key` / `key_prefix`、`status`、`status_class`、`error_kind`、`content_length`、`content_type` 和 `elapsed_ms`;角色动画逐帧额外按 `frame_index`、`operation=source_put|final_put|final_head`、`attempt/max_attempts`、`will_retry`、`oss_code` 和 `oss_request_id` 对齐同一对象的请求尝试。`请求 OSS 失败` 时,`timeout/connect/transport=true` 表示传输类失败,OSS PutObject 的 `status=400, oss_code=RequestTimeout, timeout=true`、`status=429` 或 `500–599` 表示暂时性失败,PUT 的 `status=400`、`oss_code` 为空且 `timeout=true` 或 `transport=true`(message 含「错误响应体读取失败」,即 400 错误体读取超时/断流)也会重试;除这两类例外外,其他 400、401/403/404、配置、URL 和签名错误是确定性失败,不会重试。最终帧 HEAD 失败只会重试 HEAD,不会重复 PUT。日志不得包含 AccessKey、policy、signature、Authorization header、完整 signed URL 或 OSS 错误响应体;`oss_request_id` 只用于关联 OSS 服务端排障。排查 generated 图片重复下载时,先确认前端输入是否为 `/generated-*` legacy path 或可归一化的 `https://*.oss-*.aliyuncs.com/generated-*`;正确链路应先调 `/api/assets/read-url`,再由浏览器请求 signed URL,且同一路径、同一 `refreshKey` 版本和未临近过期的 signed URL 应复用。新上传 generated 私有对象应带 `Cache-Control: public, max-age=31536000, immutable`;旧对象若只有 `ETag` / `Last-Modified`,浏览器会走 304 协商缓存而不是长期强缓存,可通过刷新 OSS 元数据或 CDN 配置补齐。
|
||||
- SpacetimeDB 观测分为两类:procedure / reducer 调用继续用 `genarrative.spacetime.procedure.*`,订阅本地 cache 读使用 `genarrative.spacetime.read.*`。`read=list_puzzle_gallery` 表示拼图广场当前从 `puzzle_gallery_card_view` 本地 cache 读取,不再每个 HTTP 请求调用 `list_puzzle_gallery` procedure。
|
||||
- 本地 Windows 直连压测的内存高水位要结合 K6 VU / 连接数解释。250 RPS 下过高 `PREALLOCATED_VUS` 可能让 300 个本地 Established 连接把 `api-server` private memory 瞬时推到 GB 级,且 `/healthz` 小响应也能复现;若压测结束后回落、`response_bodies.in_flight` 和背压 permit 未显示业务积压,应优先按连接 / 发送链路高水位处理,而不是判断为 SpacetimeDB 或 JSON 缓存泄漏。
|
||||
- Rider 的 Logs 面板只展示 log event 自身字段,不会自动展开父 span 的全部 attributes;请求完成日志会直接带 `request_id`、`http.request.method`、`http.route`、`url.scheme`、`url.path`、`http.response.status_code`、`status_class`、`latency_ms` 和 `slow_request`,完整链路继续到 Traces 面板按 trace/span 查看。
|
||||
- 指标 label 只允许低基数字段:HTTP 使用 `method`、`route`、`status_class`,SpacetimeDB 调用使用 `procedure`、`status_class`;`request_id` 只进入 trace/log attribute,不进入 metric label。
|
||||
- 指标 label 只允许低基数字段:HTTP 使用 `http.request.method`、`http.route`、`status_class`,SpacetimeDB 调用使用 `procedure`、`status_class`;`request_id` 只进入 trace/log attribute,不进入 metric label。HTTP trace、完成日志与指标共用 Axum `MatchedPath` 路由模板,例如 `/api/editor/projects/{project_id}`;未匹配路由或无路由模板的降级请求只使用 `/api/*`、`/admin/api/*`、`other` 三种固定兜底,不把实际 ID 或 query 写入 route 标签。原来按 `/api/*` 聚合的监控查询应改为按路由模板汇总。
|
||||
|
||||
常见外部服务变量:
|
||||
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
|
||||
## 目标
|
||||
|
||||
`ui-prototype` 与 `UI` 是两种不同资源,不能通过修改投影 `subtype` 混为一种资源:
|
||||
`ui-prototype` 与 `ui-design-doc` 是两种不同资源,不能通过修改投影 `subtype` 混为一种资源:
|
||||
|
||||
- `ui-prototype`:Agent 生成并登记到画布的界面设计图片。
|
||||
- `UI`:UI 编辑器使用的 JSON 资源,保存界面图、UI 树、组件绑定和 State revision。
|
||||
- `ui-design-doc`:UI 编辑器使用的 `application/json` 资源,保存界面图、UI 树、组件绑定和 State revision。
|
||||
|
||||
UI 设计文档资产必须严格满足 `kind=ui-design-doc` 与 `mediaType=application/json`;旧 `UI`、`ui`、`ui-design` 不作为兼容输入,也不提供迁移或图片 fallback。
|
||||
|
||||
自然语言生成链路必须把前者桥接为后者,并持续让 manifest 成为客户端资源投影的权威来源。游戏场景的页面清单由 Runtime 自动发现,Agent 不得凭空猜测页面。
|
||||
|
||||
@@ -35,7 +37,7 @@ Agent 通过白名单工具 `ui.workflow.run` 发起工作流。项目路径由
|
||||
|
||||
处理规则:
|
||||
|
||||
1. `prepare` 为每个页面创建确定性的 `kind=UI` JSON 资源,引用源 `ui-prototype` 和页面设计图,载入设计图尺寸与相对路径到 `ui_design_images`,并保存 State。
|
||||
1. `prepare` 为每个页面创建确定性的 `kind=ui-design-doc` JSON 资源,引用源 `ui-prototype` 和页面设计图,载入设计图尺寸与相对路径到 `ui_design_images`,并保存 State。
|
||||
2. `recognize` 依次执行 Provider 多模态结构识别、现有多树合并器、最多每批 5 项的图片/图标组件绑定,并把已登记字体的安全元数据提供给绑定器;阶段分别持久化为 `structure-ready`、`merge-ready`、`binding-ready`,重复执行从最近真实阶段恢复。
|
||||
3. `status` 只回读 State、页面阶段和 blockers,不推进项目 revision。
|
||||
4. `finalize` 只接受 `game/` 下的真实 UTF-8 文件,写入与 UI State revision 绑定的应用标记;所有页面通过应用门禁后才返回 `asset-separation` 最终阶段路由。缺少页面、资源、组件或应用标记时拒绝伪造完成。
|
||||
@@ -61,15 +63,33 @@ UI 编辑器的分离提示会对节点描述和返工备注做长度与控制
|
||||
|
||||
真实 Provider 鉴权失败时,Codex app-server 可能只返回 `codexErrorInfo=other`,而把上游 `401/403` 放在错误正文中。Runtime 必须从受控错误字段识别为 `codex-app-server-error:unauthorized`(公共摘要为 `codex-app-server-unauthorized`),只向公共运行记录暴露错误类别和指纹,不记录 Token 或上游原文。此错误不能伪造为 UI 工作流阶段完成;修复凭据后应从原有 run 的恢复边界重新执行。
|
||||
|
||||
## UI 设计文档代码引用
|
||||
|
||||
Direct Codex 聊天引用 `ui-design-doc` 时,复用 `ui_editor::persistence::generate_ui_design_code_at`。该入口只读取被引用的 JSON 文档,调用 `render_ui_design_state_js`,并写入既有 `ui/generated-*.js` 派生文件。
|
||||
|
||||
成功时在稳定 manifest 元数据后追加:
|
||||
|
||||
```text
|
||||
请先阅读生成的带有文档的代码片段: {relative_path}
|
||||
```
|
||||
|
||||
JSON 文档读取、State 校验或 renderer 失败时,在同一引用后追加原始错误:
|
||||
|
||||
```text
|
||||
生成代码遇到错误{error}
|
||||
```
|
||||
|
||||
错误不阻断本轮 Direct Codex prompt,其它引用继续按顺序处理;不从图片或其它文件 fallback,不把生成文件登记为正式 manifest 资产,也不推进项目 revision。
|
||||
|
||||
## 画布跳转与客户端更新
|
||||
|
||||
点击画布中的 `ui-prototype` 时,工作台调用 `ensure_ui_design_resource_for_prototype`:
|
||||
|
||||
- 按 manifest asset id、`source.resourceId`、`source.assetObjectId` 识别已有关联,避免重复创建。
|
||||
- 没有关联时原子创建 `ui/UI 设计 N.json`,登记 `kind=UI`、`application/json`,并把原型图作为首张页面设计图载入 State。
|
||||
- 没有关联时原子创建 `ui/UI 设计 N.json`,登记 `kind=ui-design-doc`、`application/json`,并把原型图作为首张页面设计图载入 State。
|
||||
- 成功后通过 `onManifestChange` 更新客户端资源投影,再打开 UI 编辑器;普通桥接从 `reference-analysis` 开始。
|
||||
|
||||
点击已有 `UI` 资源直接打开 UI 编辑器。若 manifest 阶段为 `ui-workflow.completed`,工作台自动打开该资源的 `asset-separation` 阶段(最远步骤为 2),交给用户做最终检查和手动调整。
|
||||
点击已有 `ui-design-doc` 资源直接打开 UI 编辑器。若 manifest 阶段为 `ui-workflow.completed`,工作台自动打开该资源的 `asset-separation` 阶段(最远步骤为 2),交给用户做最终检查和手动调整。
|
||||
|
||||
自动切分达到返工上限的 problematic 节点会随分离 DTO 返回每节点的 `problem_history`,并由编辑器回写为 `component_status = NeedReview(...)`。`SeparationOverview` 只读取 UI State 中的状态来计数和定位;该结果仍按“已尽力完成”报告成功并执行既有 finalize,剩余节点由用户在概览定位后手动处理或再次发起分离。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user