合并最新主分支并保留策划 Agent 解耦清理
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 7m32s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 7m40s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 7m41s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 7m49s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m50s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 3m23s
Project CI / Repository checks (pull_request) Successful in 4m46s
Project CI / Frontend tests (pull_request) Failing after 9m45s
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
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 7m32s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 7m40s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 7m41s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 7m49s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m50s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 3m23s
Project CI / Repository checks (pull_request) Successful in 4m46s
Project CI / Frontend tests (pull_request) Failing after 9m45s
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
合入 master 的资源类型枚举、编辑器插件、项目快照和发布渠道更新。 保留策划 V1/V2 退役结果,并整合模板建项竞态保护。 解决策划入口及文档冲突,保留当前 Design Agent 与 DirectCodex 链路。
This commit is contained in:
+4
-1
@@ -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):已完成;当前策划入口统一使用 Design Agent,采用阶段审批与用户工作区文件浏览。旧 V1/V2 会话、命令、专用展示和测试不再作为兼容目标。
|
||||
|
||||
- [LLM 累计额度结算](./technical/【技术方案】LLM累计额度结算-2026-09-05.md):Router 累计额度、首次基线与原子钱包结算。
|
||||
@@ -38,8 +40,9 @@
|
||||
- [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-08-31.md):启动版本检测、固定 dev 服务、OSS 清单与官网最新客户端下载。
|
||||
- [AGC 模板库与模板建项](./technical/【技术方案】AGC模板库与模板建项-2026-09-17.md):`templates/` 前缀的模板库契约、下载安装与「用模板建项目」链路。
|
||||
- [DirectProject 本轮附件路径映射](./technical/【技术方案】DirectProject本轮附件路径映射-2026-08-31.md):Direct 首轮只映射附件原名与项目相对路径,不灌正文、不区别 GDD。
|
||||
- [Direct 回合行为审计账本](./technical/【技术方案】Direct回合行为审计账本-2026-08-31.md):Direct GUI 回合把 native 读 / MCP / 写文件落成项目内有界时间线,用于判断有没有打开本轮附件。
|
||||
|
||||
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,32 @@
|
||||
# 项目自动上传与后台工程下载实施计划
|
||||
|
||||
| 字段 | 值 |
|
||||
| --- | --- |
|
||||
| Milestone | `docs/project-memory/plans/【里程碑】项目自动上传与后台工程下载-2026-09-19.md` |
|
||||
| Status | implemented-awaiting-runtime-validation |
|
||||
| Owner | 当前任务 Agent |
|
||||
|
||||
## 修改边界
|
||||
|
||||
- 客户端 project_snapshot 与实际窗口生命周期、相关定向测试。
|
||||
- shared-contracts 快照清单及后台 DTO、platform-oss 的受控清单枚举、api-server 管理员列表与 ZIP 下载、后台权限映射。
|
||||
- api-server 快照存储配置解析:默认目标与素材 bucket 分离,只有凭据可回退;不变更部署配置或搬迁对象。
|
||||
- admin-web 项目列表、现有路由/导航/API client 与相应测试。
|
||||
- 主规范、运维说明及必要共享约定。不修改 SpacetimeDB、External API、用户会话权威或线上配置。
|
||||
|
||||
## 实现顺序
|
||||
|
||||
1. 评审主规范与本里程碑,复现客户端项目枚举故障。
|
||||
2. 并行实现后台列表/ZIP、后台 UI;客户端只修已证实上传缺陷并补清单元数据。
|
||||
3. 集成契约、运行定向测试和 UI smoke,核查真实清单可还原目录;按证据更新验收状态。
|
||||
|
||||
## 验证命令
|
||||
|
||||
- `cargo test --locked -p platform-oss`、`cargo test --locked -p api-server project_snapshot`、`cargo test --locked -p shared-contracts`(server-rs)。
|
||||
- `cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml project_snapshot`。
|
||||
- `npm run admin-web:typecheck`、`npm run admin-web:build`、后台相关 Vitest。
|
||||
- `npm run check:encoding`、`npm run check:doc-index`、`git diff --check`。
|
||||
|
||||
## 风险与回滚
|
||||
|
||||
旧清单无完整性声明,只能标记未知;完整工程含项目源码、素材和配置,排除依赖/构建缓存、凭据、会话与运行日志。下载失败不修改 OSS 或清单。本轮按用户授权提交推送,不部署;代码可独立回退。
|
||||
@@ -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 错误、多引用和路径来源均有测试。
|
||||
@@ -0,0 +1,55 @@
|
||||
# 项目自动上传与后台工程下载
|
||||
|
||||
| 字段 | 值 |
|
||||
| --- | --- |
|
||||
| Version | 1.0 |
|
||||
| Status | implemented-awaiting-runtime-validation |
|
||||
| Date | 2026-09-19 |
|
||||
| Parent Spec | `docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md` 的项目快照上传与后台工程下载合同 |
|
||||
|
||||
## 目标与范围
|
||||
|
||||
修复实际项目自动上传的已证实故障,并让有权限的后台管理员按项目查看远端快照、一键下载按原始目录还原的工程 ZIP。
|
||||
|
||||
## 不在范围内
|
||||
|
||||
客户端上传 UI、跨设备恢复、版本历史、数据库 schema、线上部署、自动补传全部未打开项目。
|
||||
|
||||
## 依赖与前置条件
|
||||
|
||||
延续现有私有 OSS 项目快照、平台会话与后台权限。真实 bucket 已只读确认只有两份历史模板清单;上传根因必须经确定性复现后修正。
|
||||
|
||||
## 验收标准
|
||||
|
||||
- [ ] 正式项目窗口可被同步调度识别;周期与关闭触发保持有界,失败有项目级诊断。
|
||||
- [ ] 未单独配置快照目标时仍使用 agc-dev,只复用资源存储凭据;显式快照目标保持有效,不迁移现存对象。
|
||||
- [ ] 后台列表显示项目名/ID、用户 ID、同步时间、文件数、体积和完整性,支持刷新与分页。
|
||||
- [ ] ZIP 按清单还原相对路径;不含对象存储摘要目录;空文件可上传与导出。
|
||||
- [ ] 清单名称/完整性变化在无内容差异时也提交,partial 可恢复 ready,历史缺字段不冒充 ready。
|
||||
- [ ] 缺失、损坏、越界路径和非完整清单失败关闭;历史未声明完整性的清单明确标记,允许导出已有文件但不称为完整工程。
|
||||
- [ ] 无后台权限不能读取项目或 ZIP;不泄漏凭据;ZIP 构建有体积、并发和临时文件清理边界。
|
||||
- [ ] 定向 Rust 测试、后台类型检查/构建、UI smoke、编码、文档索引和 diff 检查完成,运行时证据与未验证部分分别列出。
|
||||
|
||||
## 证据要求
|
||||
|
||||
自动化覆盖窗口身份、上传零字节、清单统计、目录还原、路径与校验和校验、后台路由权限。运行时优先只读现有 OSS 清单;测试不上传真实用户工程、不修改线上数据。
|
||||
|
||||
## 已取得证据
|
||||
|
||||
| 层次 | 结果 |
|
||||
| --- | --- |
|
||||
| 客户端 Rust `project_snapshot` | 22 通过、1 忽略(写入式真实上传 smoke 未运行);含排队退出等待回归 |
|
||||
| 客户端前端生命周期与启动器 | 3 文件、10 测试通过;完整 AGC typecheck、skill-pack、check-config 通过 |
|
||||
| 后台页面、API client、路由与样式 | 44 测试通过;admin-web typecheck/build 通过 |
|
||||
| 后端快照与权限 | 14 定向测试通过;未认证路由矩阵与页签映射 2 测试通过 |
|
||||
| 默认存储目标 | 真实 AppConfig::from_env 配置回归 1 通过 |
|
||||
| OSS 存储层 | 全量 55 测试通过,含签名、特殊字符路径、读取上限与零字节 |
|
||||
| 真实 OSS 只读导出 | `project_snapshots_live_readonly_list_and_archive` 通过;limit=1 分页、2 清单、12 文件、73,424 字节,ZIP 解压路径/长度/摘要全匹配、临时文件清理通过;两份均为历史 unverified |
|
||||
| 浏览器 smoke | 模拟 API 的 1280 桌面与 390 窄屏通过;下载按钮可见,无整页横向溢出;中文 ZIP 文件名、Authorization、409 错误呈现通过 |
|
||||
| 通用门禁 | 编码、文档索引、production-ops、Rust 格式、客户端 Prettier 与 diff 检查通过 |
|
||||
|
||||
## 剩余验证与环境边界
|
||||
|
||||
`npm run dev:api-server -- --api-port 4198 --bgfilter-worker-port 4199 --api-timeout-seconds 600` 编译成功,但当前工作区配置的本地数据库 `xushi-p4wfr` 在 `127.0.0.1:3101` 返回 404,启动认证投影无法完成,故 `/healthz` 及完整 HTTP smoke 未通过。仅本任务启动的 API/worker 已停止;没有清库、迁移数据库、改 `.env` 或替换其它项目的验证目标。
|
||||
|
||||
尚未替换安装版、构建新客户端发布包或部署;提交推送按用户本轮授权执行。当前条款已有上述自动化与只读存储证据,最终验收仍等待当前工作区数据库就绪后的 HTTP 联调,以及新客户端的隔离实机自动上传验证;完成后再关闭里程碑并清理两份计划。
|
||||
@@ -3,6 +3,40 @@
|
||||
> 用途:记录已经确认、会影响后续开发的长期技术/产品/协作决策。短期讨论不要写在这里。
|
||||
> 当前口径(2026-09-18):历史条目的旧路径、旧版本和已退役对象只用于追溯,不构成现行实现依据。策划 Agent V1/V2 的 Runtime、专用命令、审批卡、展示适配和旧测试已删除;当前策划入口统一使用 Design Agent。如与当前代码或 `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 删除每回合四项媒体资源请求上限
|
||||
|
||||
- 背景:2026-08-24 引入的单回合四项上限以「整个 agent run(一条用户消息到回合结束)」为窗口,计数只增不减、请求完成不释放额度;autonomous 游戏构建要求 agent 不停下跑完整局,额度耗尽后的报错实际是终态,与技能的三次重试纪律冲突,现场表现为长时间无效重试。2026-09-18 先将不计费的抠图豁免,但付费 create/derive 仍受同一窗口问题影响。
|
||||
- 决策:整体删除该上限机制。移除 `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` 互斥保证,成本控制由服务端计费与泥点余额兜底,客户端不再按回合计数设限。
|
||||
- 验证方式:`cargo check`(ai-game-creator-shell src-tauri)通过,203 项警告与基线一致;无测试断言该上限,未新增测试。
|
||||
|
||||
## 2026-09-18 AGC Direct 抠图不占每回合四项付费媒体额度
|
||||
|
||||
- 状态:2026-09-19 起该上限机制整体删除(见上条),本条目仅作追溯。
|
||||
- 背景:2026-08-24 起 `agc_create_or_derive_resource` 与 `agc_remove_background` 共用每回合四项媒体资源请求上限。抠图服务端持久化 `generation_cost_mud_points: 0`(不计费),bgfilter 实测单张约 1 秒,上限导致一回合抠超过四张时后续请求被直接拒绝、agent 反复无效重试。
|
||||
- 决策:`agc_remove_background` 不再经过 `resource_request_ids` 计数,直接按回合身份与请求指纹确定性派生 operation/idempotency id(与 map 复用结果一致),同指纹重试与 pending 对账语义不变。付费的 create/derive(含 `agc_edit_image` 委托)维持四项上限与原有报错文案,且抠图请求不再挤占其额度。
|
||||
- 验证方式:`cargo check`(ai-game-creator-shell src-tauri)与 `git diff --check` 通过;未新增测试。
|
||||
|
||||
## 2026-09-18 Provider 瞬态重试次数严格按设置执行(游戏开发 Agent 与策划 Agent 不再被档位收进区间)
|
||||
|
||||
- 背景:AGC 客户端此前把 `agentLlm.<agent>.maxRetries` 按运行档位重新收进固定区间——`autonomous-game-build` 档位(自主构建的游戏开发 Agent 及其继承档位的专业子 Agent)被抬到 12~16,`standard` 档位(含立项策划入口的策划 Agent 与普通 Agent 对话)被压到最多 3;瞬态分类里的上游 400 还在同一预算上再收窄到 2 次。现场把 `maxRetries` 设成 5 时,游戏开发与策划两条链路都不按设置执行。
|
||||
@@ -8822,11 +8856,12 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在
|
||||
- 验证方式:`npx vitest run apps/ai-game-creator-shell/tests/appSurface.test.ts`(423 passed,含新增 6 条:栏目分流与总览不渲染、UI 栏 5 个入口载荷、前置缺失可点击说明且零请求、角色栏 2 个入口、音频入口走既有链路、上传 + 配对读清单,另 1 条工具栏与 Dock 的 CSS 几何契约);`resourceCanvasBottomToolbar.test.tsx` 15 passed(新增);`resourceCanvasGenerationEntry.test.tsx` 11 passed(新增单类型用例 1 条);`projectResourceLiveIntegration.test.tsx` 25 passed(「生成素材」面板改名断言同步更新);`npm run agc:typecheck` 全绿(**其中的 `check-config.mjs` 报错已因本轮落地调用方而消失**)、`npm run check:encoding`、`git diff --check` 干净。未 commit。
|
||||
- 关联文档:`docs/prd/【AI游戏创作】项目开发工作台PRD-2026-07-20.md`(§3.10 / §7.9 / §8)、`docs/technical/【AGC】栏目画布底部工具栏入口矩阵-2026-09-13.md`、`docs/technical/【测试用例】AGC资源工作台V3端到端验收-2026-09-11.md`(S11 / S11a / §7.3)。
|
||||
|
||||
## 2026-09-13 Cocos 插件按当前项目类型暴露
|
||||
## 2026-09-20 Cocos 与 Unity 插件独立于工程类型
|
||||
|
||||
- 决策:`agc-cocos-editor` 只有在当前受控项目通过 Cocos Creator 根目录识别(`package.json.creator.version` + 普通 `assets/`)时才暴露插件、面板和 Cocos 工具;无项目或其它项目类型均隐藏并失败关闭。
|
||||
- 决策:项目切换离开 Cocos 时立即停止已运行的插件实例;启动、面板读取、插件 RPC、Runtime execute 和 DirectProject MCP 工具目录/执行入口全部再次校验项目类型。Cocos 编辑器操作优先经内置插件入口,禁止回退到项目 `extensions/`、`package.json` 插件或第三方 MCP。
|
||||
- 验证:新增 builtin/plugin host 项目级门禁测试,Direct MCP fixture 补最小 Cocos 工程结构;Rust 定向测试、显式 `cocos-editor-execute` feature 编译、编码检查和 `git diff --check` 已执行。
|
||||
- 决策:`agc-cocos-editor` 与 `agc-unity-editor` 的插件列表、启动、面板、插件 RPC、Runtime 与 DirectProject 工具暴露不按当前工程类型过滤;无项目、普通 AGC、Godot、Cocos、Unity 上下文遵循同一套 enable、原生适配器、平台与 feature 规则。前端根据宿主列表中各插件状态分别自动启动,不按项目类型二选一,也不自动展开面板。
|
||||
- 决策:跨工程类型切换保留插件实例及管理能力,继续更新受控项目上下文、失效旧连接并隔离旧请求回执。实际编辑器操作仍要求当前受控项目匹配真实引擎工程与编辑器目标;显式跨项目路径、缺失项目、无目标进程、身份或握手不匹配均在派发前失败,权限、并发、期限与执行不确定阻断保持有效。
|
||||
- 边界:插件可见和工具可调用不能证明任意非引擎目录可成为编辑器执行目标;不改变项目类型、导入或持久数据。Cocos 编辑器操作继续使用内置插件,禁止回退到项目 `extensions/`、`package.json` 插件或第三方 MCP。
|
||||
- 验收口径:分别取得宿主/内置开关、工具目录、前端启动投影与真实目标拒绝证据;真实编辑器、安装包和 CI 与定向测试分层报告。
|
||||
|
||||
## 2026-09-14 DirectProject Codex 取消路径白名单并启用完整 sandbox
|
||||
|
||||
@@ -8883,6 +8918,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,23 @@
|
||||
# 踩坑与排障记录
|
||||
|
||||
## AGC 自动同步必须绑定真实项目生命周期
|
||||
|
||||
- 正式客户端在单窗口中用 React 状态打开/切换工程,窗口 URL 不代表当前工程。原生后台同步应读取由当前窗口显式登记的活动工程;首次打开、离开、切换、关窗及退出等待分别验证,不能只用携带 `projectPath` 的独立测试窗口证明正式入口可用。
|
||||
- 增量文件没有变化不等于远端清单没有变化。项目名和完整性元数据也参与提交判据,避免临时跳过恢复后永久停留在 partial,或新出现超限文件后仍显示 ready。历史清单缺少完整性字段属于未知,不能默认成完整。
|
||||
- ZIP 导出按一次冻结清单恢复相对路径并逐文件核验;直接下载内容寻址的 OSS 目录不能得到可用工程。源码/素材归档不包含依赖缓存、凭据和 AGC 对话运行状态。
|
||||
|
||||
## 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 +5480,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 +5494,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 完成。
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
|
||||
- AGC 批量追加素材标签由原生在一次项目写锁与 revision CAS 下合并各项原标签,先校验全批再写 manifest;前端不能循环单素材分类命令,不回传展示层推导的分类或旧标签全集,以免部分写入或覆盖未编辑字段。
|
||||
|
||||
- AGC 平台服务固定为 `https://dev.genarrative.world`,会话凭据按 origin 隔离。发布渠道为 `dev/release/自定义名称`,Windows/Mac 是系统,OSS 的 `<channel>-win/mac` 仅是延续既有地址的分区。官网通过服务端 `GENARRATIVE_CLIENT_DOWNLOAD_CHANNEL`(默认 dev)选择渠道,公开同源 `/api/client-downloads` 汇总其各系统首装包与真实版本;未发布隐藏,单系统失败不影响其它下载,不跨渠道补齐。发布先上传 EXE/DMG 再写对应分区清单,不维护会互相覆盖的共享 OSS 索引。主站 Vite 代理复用实际 `runtimeServerTarget`。完整约定见 AGC 客户端更新检查与下载专题。
|
||||
- AGC 模板库灰度复用 `agc:template-library`:未配置关闭,已配置时遵循现有灰度启停、用户 ID/标签和比例规则;服务端返回权威结论,客户端入口和原生清单/下载/建项均执行门禁,主体切换丢弃旧异步结果。公开 OSS 不是保密边界,已创建项目不受影响。
|
||||
|
||||
- 画布卡片类型与信息角标共用 `CanvasCardCornerActions`;菜单收纳共用 `OverflowActions`,宿主决定展示数量和资源命令。AGC 选中菜单前 5 项直显,Web 默认不折叠;浮层 portal 继续接入现有画布关闭与滚轮归属判据。
|
||||
- 修改范围保持聚焦;优先扩展现有系统、页面、组件、DTO 和脚本,不新建平行入口或业务真相。
|
||||
- UI 开发优先复用现有公共组件;跨页面或跨端重复的视觉/交互模式应沉淀到 `packages/shared`,由现有页面迁移使用,禁止在业务页复制同类 UI。共享组件只承载通用表现与交互,不下沉领域规则、后端副作用或正式业务状态。
|
||||
@@ -32,6 +35,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. 音频入口收敛
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ plugins/agc-cocos-editor/
|
||||
|
||||
宿主按 `AGC_PLUGIN_WORKSPACE`、随包 `<resource_dir>/plugins`、开发构建仓库 `plugins/` 的顺序解析工作区;插件包内的 `native/payload` 由构建脚本随包映射,生成的 DLL 不入库。插件协议、权限和面板挂载全部复用通用宿主,Cocos 专属逻辑只存在于本插件包:进程名与 `--project` 解析、Creator 版本校验、named pipe 协议和 Windows 注入。
|
||||
|
||||
该插件是**内置插件**:随客户端分发、不能卸载,只能通过 `set_agc_plugin_enabled` 控制是否可用。除开关和 feature 外,还必须满足“当前受控项目已识别为 Cocos Creator 项目”这一门禁;没有当前项目或项目类型不是 Cocos 时,插件不出现在插件列表、面板、Agent 工具目录或 MCP tools/list 中,启动、面板读取、RPC 和编辑器执行也会失败关闭。项目切换离开 Cocos 后,已运行实例立即停止。Cocos 编辑器操作统一优先通过该内置插件的 `cocos.editor.execute` / `cocos.editor.operation`(DirectProject 对应 `agc_cocos_execute`);不得改走项目目录 `extensions/`、`package.json` 插件或第三方 MCP。开关状态保存在 AppData `extensions/builtin-plugins.json`,隔离 MCP 每次 tools/list 都向绑定宿主询问当前状态与项目门禁。
|
||||
该插件是**内置插件**:随客户端分发、不能卸载,只能通过 `set_agc_plugin_enabled` 控制是否可用。插件列表、启动、面板读取、插件 RPC、Agent 工具目录和 MCP tools/list 不按当前工程类型过滤;无当前项目或非 Cocos 项目仍沿用相同的开关、原生适配器、平台和 feature 规则。项目切换不因工程类型不同而停止插件,仍更新受控项目上下文并失效旧连接。实际编辑器操作必须取得当前受控项目对应的真实 Creator 目标并通过原有目录、PID、版本与握手校验;无项目或非引擎目录不能仅凭工具可见就通过执行校验。Cocos 编辑器操作统一优先通过该内置插件的 `cocos.editor.execute` / `cocos.editor.operation`(DirectProject 对应 `agc_cocos_execute`);不得改走项目目录 `extensions/`、`package.json` 插件或第三方 MCP。开关状态保存在 AppData `extensions/builtin-plugins.json`,隔离 MCP 每次 tools/list 都向绑定宿主询问当前可用状态,不自行按工程类型过滤。
|
||||
|
||||
## AGC 项目打开入口
|
||||
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
# AGC Unity 编辑器插件接入
|
||||
|
||||
> 文档状态:`current`
|
||||
> 规范关系:承接 AGC 通用插件宿主与编辑器适配主规范
|
||||
|
||||
更新时间:`2026-09-20`
|
||||
|
||||
## 目标与非目标
|
||||
|
||||
将 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/` 识别;复用现有打开项目入口,不创建平行工作台。
|
||||
- 插件列表、启动、面板、插件 RPC 和 Agent 工具暴露不按当前工程类型过滤;无项目或非 Unity 项目也沿用相同的内置开关及平台适配器规则。禁用会停止插件实例,跨工程类型切换保留插件管理能力并失效旧连接。前端按宿主列表中各插件自身状态投影自动启动,不因项目类型在 Cocos/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 原子归属、最后一跳回执丢失、
|
||||
进程重启阻断及发布许可边界;定向证据与上述真实运行时验证共同覆盖本次接入合同。
|
||||
@@ -1,13 +1,21 @@
|
||||
# AGC 客户端更新检查与下载
|
||||
|
||||
更新时间:`2026-09-17`
|
||||
更新时间:`2026-09-20`
|
||||
|
||||
本文件是 AGC 客户端自动更新的主规范:更新能力由 Tauri 官方插件 `tauri-plugin-updater` 承担,并按下文渠道分发。
|
||||
|
||||
## 目标
|
||||
|
||||
- 客户端自动更新改用 Tauri 官方 `tauri-plugin-updater`:清单请求、版本比较、更新包下载、签名校验、安装与退出全部在原生侧完成;前端只负责触发、展示和渠道选择。
|
||||
- 更新按渠道分发。当前渠道集合为 `dev-win`(Windows x64)与 `dev-mac`(macOS);构建管线按渠道产出并上传清单,客户端只读取自己渠道的清单。
|
||||
- 更新按渠道分发。渠道为 `dev`、`release` 或自定义名称;Windows/macOS 是独立的系统维度,每个渠道分别维护各系统已发布的版本、清单和安装包。客户端只读取构建时确定的渠道及系统对应的清单。
|
||||
|
||||
## 渠道与网站配置合同
|
||||
|
||||
- 构建参数 `AGC_UPDATE_CHANNEL` 默认 `dev`,支持 `release` 和自定义小写名称;名称符合 `[a-z][a-z0-9-]{0,31}`,不能以连字符结尾,不能为 `win/mac/windows/macos/darwin/linux` 或以 `-win/-mac` 结尾。构建目标独立决定系统和架构。
|
||||
- 为延续已发布客户端地址,OSS 继续使用 `agc/<channel>-win/` 和 `agc/<channel>-mac/` 作为物理分区;`dev-win/dev-mac` 是分区键,不是可填写的渠道。每个分区独立维护 `latest.json` 与版本目录,发布 release 不覆盖 dev。旧 `agc/latest.json` 迁移桥与其版本高水位仅属于 dev 的 Windows 分区。
|
||||
- 网站由服务端配置 `GENARRATIVE_CLIENT_DOWNLOAD_CHANNEL` 选择检测渠道,默认 `dev`;更改后重启 API 服务生效。`GET /api/client-downloads` 返回该渠道 Windows/macOS 的真实已发布版本。请求参数不能覆盖配置或指定 URL;配置非法时失败关闭,不悄悄改读 dev。
|
||||
- 同一渠道中不同系统仍可具有不同 release 版本;未发布的系统隐藏,单系统失败不影响另一系统。不会从其他渠道补齐缺失版本。
|
||||
- 验收必须覆盖 dev/release/自定义渠道各自端点和对象地址、独立版本、非法名称、旧 dev 地址延续、release 不写旧迁移桥、网站配置贯通、跨渠道链接拒绝和部分失败。
|
||||
- 更新链路的信任来源从「清单里的 sha256 + 受信域名」升级为「发布签名 + 受信域名」:清单里的 `signature` 由构建期私钥生成,客户端用内置公钥校验,校验不过就拒绝安装。
|
||||
|
||||
## 非目标
|
||||
@@ -30,12 +38,24 @@
|
||||
|
||||
## 必须成立的行为
|
||||
|
||||
### 官网下载与客户端服务地址
|
||||
|
||||
- 官网首页提供无需登录的「下载客户端」入口,桌面和移动视口均可访问;入口打开独立下载面板,复用平台按钮、弹窗和状态组件。
|
||||
- 每次打开下载面板请求同源公开 `GET /api/client-downloads`,后端并行读取配置渠道的 `<channel>-win/latest.json` 与 `<channel>-mac/latest.json` 并汇总已发布平台,网页和接口均禁用缓存。平台列表与每项版本完全来自清单;不在网页写死版本或猜测文件名。
|
||||
- 接口返回 `{ downloads: [{ platform, architecture, version, downloadUrl }], unavailablePlatforms: [] }`,平台为 `windows` / `macos`,架构为 `x86_64` / `aarch64`;Windows 仅支持 x86_64,Mac 按清单实际提供的架构展示 Apple Silicon / Intel 下载项。DTO 由 `shared-contracts` 与 `packages/shared` 对齐,不接受请求参数指定上游 URL,不触及 SpacetimeDB。
|
||||
- 渠道清单新增可选 `downloads` 字典,键与 updater 平台键一致,值为 `{ url }`,只登记首装包。Windows `.exe` 可同时用于首装和更新;macOS 首装必须为 `.dmg`,不得将 `.app.tar.gz` 当首装包。已发布且没有 `downloads` 字段的 Windows 清单可读取既有 `platforms.windows-x86_64.url`;Mac 没有首装元数据时隐藏,不推导 DMG 地址。
|
||||
- 渠道 404 视为尚未发布并隐藏该平台;两端均未发布时显示空状态。单渠道请求失败、超时或格式非法时保留另一端有效下载项,同时提示部分平台暂不可用并允许重试;没有任何有效项且存在失败时返回可读 502。关闭面板取消请求,迟到响应不能覆盖下一次打开的状态。
|
||||
- 每个上游请求总超时 10 秒、响应体上限 128 KiB、不跟随重定向、不附加用户凭据;返回的链接仅接受固定 OSS 来源、对应 `/agc/<channel>-win|mac/<version>/` 分区下的 HTTPS `.exe` / `.dmg` 对象,架构键必须属于对应系统。不提供陈旧、未知来源或版本不匹配的下载地址,不泄露上游正文。
|
||||
- AGC 开发态和正式包的平台服务地址统一固定为 `https://dev.genarrative.world`;登录页不提供服务器选择或自定义地址。旧的服务器偏好不能覆盖固定地址;已有会话仍按 origin 隔离,不能将其他服务的凭据迁往 dev。自定义 LLM 配置不属于平台服务器选择。
|
||||
- access token 与 origin 一起保存;已有 dev origin 的 token 保留。没有 origin 的旧 token 一律清除,因为旧版可以单独修改服务器偏好,偏好不能证明 token 来源。随后仅使用 dev 自己的 refresh cookie 恢复或重新登录;原生会话回写同样绑定 dev origin。
|
||||
- 验收覆盖固定 dev 的登录/会话与请求行为、旧服务器偏好、首页入口挂载、动态最新版本链接、清单失败与重试、关闭取消、桌面和移动布局,以及公开清单和安装包的真实可读性。
|
||||
|
||||
### 正常路径
|
||||
|
||||
- 正式包启动时检查一次渠道清单;仅当清单版本高于当前版本时显示更新提示,提示包含目标版本与发布说明。
|
||||
- 用户确认后下载更新包:下载期间显示进度与已下载字节数;下载完成后按平台安装。
|
||||
- Windows 使用静默安装模式(NSIS `quiet`),安装启动成功后客户端退出并由安装程序重启新版本;macOS 由客户端在安装完成后重启进程接管新版本。
|
||||
- 渠道在构建期确定并烘焙进产物:`dev-win` 产物只读 `dev-win` 清单,`dev-mac` 产物只读 `dev-mac` 清单,同一份二进制不会在运行期跨渠道切换。
|
||||
- 渠道与系统在构建期确定并烘焙进产物:如 dev 的 Windows 产物只读 `dev-win` 分区,release 的 Mac 产物只读 `release-mac` 分区,同一份二进制不会在运行期跨渠道切换。
|
||||
- 开发态(`npm run agc` / `agc:serve` 由 Vite dev server 提供前端)不检查更新、不显示更新入口,也不下载任何更新包。
|
||||
|
||||
### 失败、重试与幂等
|
||||
@@ -66,23 +86,26 @@
|
||||
"signature": "<.sig 文件内容>",
|
||||
"url": "https://<oss>/agc/dev-win/0.1.48/<安装包文件名>"
|
||||
}
|
||||
},
|
||||
"downloads": {
|
||||
"windows-x86_64": { "url": "https://<oss>/agc/dev-win/0.1.48/<安装包文件名>" }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- 渠道与平台映射:
|
||||
- 渠道与平台分区映射(`<channel>` 为 dev、release 或自定义名称):
|
||||
|
||||
| 渠道 | 构建目标 | 清单平台键 | 更新包 | 清单地址 |
|
||||
| 系统 | 构建目标 | 清单平台键 | 更新包 | 清单地址 |
|
||||
| --------- | ------------------------ | ---------------------------------------------- | ------------------------ | ------------------------------------ |
|
||||
| `dev-win` | `x86_64-pc-windows-msvc` | `windows-x86_64` | NSIS `.exe` + `.exe.sig` | `<OSS base>/agc/dev-win/latest.json` |
|
||||
| `dev-mac` | `aarch64-apple-darwin` 或 `x86_64-apple-darwin` | 对应 `darwin-aarch64` 或 `darwin-x86_64` | `*.app.tar.gz` + `.sig` | `<OSS base>/agc/dev-mac/latest.json` |
|
||||
| Windows | `x86_64-pc-windows-msvc` | `windows-x86_64` | NSIS `.exe` + `.exe.sig` | `<OSS base>/agc/<channel>-win/latest.json` |
|
||||
| macOS | `aarch64-apple-darwin` 或 `x86_64-apple-darwin` | 对应 `darwin-aarch64` 或 `darwin-x86_64` | `*.app.tar.gz` + `.sig` | `<OSS base>/agc/<channel>-mac/latest.json` |
|
||||
|
||||
- 对象布局:清单固定写成 `agc/<channel>/latest.json`;安装包与签名写成 `agc/<channel>/<version>/<file>` 与 `<file>.sig`。
|
||||
- 对象布局:清单固定写成 `agc/<channel>-win|mac/latest.json`;安装包与签名写成同一分区的 `<version>/<file>` 与 `<file>.sig`。
|
||||
- macOS 当前采用单架构包:Apple Silicon 使用 `aarch64-apple-darwin`,Intel 使用 `x86_64-apple-darwin`;每次生成的清单只登记本次实际构建的架构,不把单架构原生 Codex 资源挂到另一架构。`universal-apple-darwin` 在版本读取/写入、构建和清单生成之前拒绝。
|
||||
- 渠道清单以实际运行架构为键。两种单架构构建不可轮流覆盖同一个 `latest.json` 并宣称双架构均可更新;当前不实现跨构建合并,Intel 发布需先完成其构建验证与多架构清单发布方案。
|
||||
- 构建期要求:打开 `bundle.createUpdaterArtifacts` 以生成 `.sig`;构建环境提供签名私钥与密码(私钥内容不得入库);公钥写入客户端配置。公钥在首个带更新能力的版本发布后不可更换,更换等于放弃自动更新(只能手动重装)。
|
||||
- 版本递增按渠道独立进行:发布脚本读取该渠道远端 `latest.json` 的 `version`,与本地版本取较高者递增 patch;两个渠道的版本号互不影响。
|
||||
- 版本高水位:发布脚本取「渠道清单版本」与「旧协议迁移指针版本」(迁移窗口内)中的较大值再递增。只看渠道清单会在渠道启用初期把版本链改小 —— 2026-09-17 首次渠道发布即把旧指针的 0.1.57 退回 0.1.48,随后以显式 0.1.60 纠偏;迁移窗口结束(旧指针 404)后自动只剩渠道清单,`dev-mac` 不参与旧指针比较。
|
||||
- 版本递增按渠道及系统分区独立进行:发布脚本读取该分区远端 `latest.json` 的 `version`,与本地版本取较高者递增 patch;不同分区的远端版本互不影响。
|
||||
- 版本高水位:仅 dev 的 Windows 分区在迁移窗口内取「分区清单版本」与「旧协议迁移指针版本」较大值再递增,避免已发布旧客户端版本倒退。迁移窗口结束(旧指针 404)后只读分区清单;release、自定义渠道与所有 Mac 分区均不参与旧指针比较。
|
||||
- 迁移(旧协议 → 渠道清单):
|
||||
- 迁移起点:已发布客户端(含当前线上版本)内置自研清单地址 `agc/latest.json`(sha256 格式),下载与安装由自研 Rust 命令完成。
|
||||
- 迁移策略见「未决问题与决策」。迁移完成后,自研清单解析、下载命令、下载进度事件以及为此放行的 CSP / HTTP 白名单条目按「四不写」整条删除,不留兼容分支与墓碑说明。
|
||||
@@ -91,16 +114,33 @@
|
||||
|
||||
- 发布入口:`npm run ai-game-creator-shell:release:upload`(构建 + 按渠道上传);仅构建不发布的 smoke 使用 `--no-bundle` 分支,不读远端版本、不改版本、不生成清单。
|
||||
- 发布入口只解析一次目标,优先级为 CLI `--target value` / `--target=value` / `-t value`、`AGC_BUILD_TARGET`、Windows 默认值;重复/空目标与不支持目标失败关闭。版本高水位、构建 feature/渠道端点、bundle 路径、产物后缀、清单平台键及摘要必须消费同一个发布上下文,不能分别回读默认目标。
|
||||
- 渠道由构建参数显式指定,并按目标平台校验:Windows 目标只允许 `dev-win`,macOS 目标只允许 `dev-mac`;未显式指定时按目标平台取默认渠道。
|
||||
- 渠道由 `AGC_UPDATE_CHANNEL` 显式指定,默认 dev;Windows 与 macOS 目标均支持 dev、release 和自定义渠道,目标校验独立进行。
|
||||
- 定时调度只在本轮到达的提交包含 AGC 相关路径(客户端、共享包、`server-rs/crates`、AGC 插件、桌面壳图标、根依赖清单)时才触发渠道发布;纯文档或流水线自身的提交只跑 Full Build,不推高客户端版本号。判定失败或勾选强制触发时按"需要发布"处理。
|
||||
- 更新摘要自动生成:发布脚本用渠道清单里的 `commit` 字段(上一次发布的提交)到本次提交之间、且只覆盖客户端相关路径的提交列表生成 `notes`(每条 `- 提交标题(短 SHA)`,最多 12 条、主题 80 字、整体 900 字,超出折叠或截断),同时写入旧协议清单的 `releaseNotes` 和归档文件 `release-notes.txt`。`AGC_UPDATE_RELEASE_NOTES` 非空时以手动文案为准;无法判定起点(缺少上次 `commit` 或本地没有该提交)时不写摘要。清单缺少 `commit` 时回退用上一次成功构建的 `COMMIT_HASH`(CI 通过 `AGC_UPDATE_PREVIOUS_COMMIT` 传入)作为锚点,因此首次启用摘要或更换渠道后也能立即产出摘要。锚点仍不可得(清单读取失败或没有 CI 锚点)时降级为「最近客户端改动」列表并注明可能与上一版重复 —— 摘要属于附注,任何情况下都不允许因为它让发布失败。
|
||||
- 清单里的 `commit` 是非标准字段:更新插件忽略未知字段,发布脚本用它定位下一次摘要的起点。
|
||||
- 上传:安装包与 `.sig` 上传到 `agc/<channel>/<version>/`,清单以 `--force` 覆盖上传到 `agc/<channel>/latest.json`,保证 latest 指针与清单内 URL 指向已存在的对象。
|
||||
- 上传:安装包与 `.sig` 上传到 `agc/<channel>-win|mac/<version>/`,清单以 `--force` 覆盖上传到对应分区的 `latest.json`,保证 latest 指针与清单内 URL 指向已存在的对象。
|
||||
- 首装发布:发布脚本生成 `downloads`,Windows 复用已选 NSIS `.exe`,Mac 选择本次版本和目标架构匹配的非空 `.dmg`;缺失、歧义或版本/架构不匹配时失败,不发布带悬空地址的清单。上传顺序为更新包、签名及首装包全部成功后再更新渠道清单,Windows 相同对象只上传一次。`dry-run` 不写 OSS。各渠道独立写自己的清单,由 BFF 汇总,Windows 与 Mac 发布不会覆盖彼此的下载项;Mac 跨架构合并仍遵循现有单架构发布约束。
|
||||
- Jenkins 流水线需要新增渠道参数与签名凭据;签名私钥与密码只以受保护凭据注入当前进程,不写入 workspace、日志或归档产物。
|
||||
- 归档证据:安装包、`.sig`、渠道清单与源码 commit。
|
||||
|
||||
## 验收标准与证据
|
||||
|
||||
渠道与系统分离的定向验证覆盖发布脚本、上传计划、网站配置贯通及跨渠道链接拒绝:`build-release.test.mjs`、`release-oss.test.mjs`、`platform-oss client_downloads` 和 `api-server client_download`。本地隔离数据库的 API smoke 验证 `/healthz` 成功、配置 release 时仅读取 release 分区、查询参数不能覆盖渠道、未发布版本返回空列表且 `no-store`;这不代表已构建或上传 release 安装包。真实 Windows/macOS 安装、签名和更新仍由发布验收单独执行。
|
||||
|
||||
官网下载与固定服务地址已于 `2026-09-19` 完成源码验收:
|
||||
|
||||
| 条款 | 验收方式 | 结果 |
|
||||
| --- | --- | --- |
|
||||
| 固定 dev、旧凭据来源隔离与登录恢复 | HTTP/API/存储定向测试、登录会话界面测试、AGC 类型检查 | 通过;无 origin token 不发送,dev cookie 恢复链保留 |
|
||||
| 动态链接、失败重试、取消与重开竞态 | 下载组件与站点壳定向 Vitest、Web 类型检查 | 通过;桌面与移动首页均挂载入口 |
|
||||
| 已发布平台自动出现与各平台独立版本 | 多平台聚合测试、组件测试及桌面/320px 浏览器受控清单 | 通过;未发布隐藏,重新打开后展示 Windows、Apple Silicon、Intel 的对应版本与链接,部分失败仍可下载有效项 |
|
||||
| 首装元数据、DMG 选择与上传顺序 | 发布脚本 39 项临时夹具测试 | 通过;限定当版/当架构唯一非空 DMG,更新包/签名/首装包先于 latest,失败不更新指针,dry-run 不执行上传 |
|
||||
| 清单传输与下载地址边界 | platform-oss 12 项与 api-server 3 项 `client_downloads` 定向 Cargo 测试 | 通过;含双渠道并行、部分失败、残缺 Windows 清单、响应体超时、大小上限、重定向与非法来源 |
|
||||
| 官网同源完整链路 | 标准本地后端 `/healthz`、匿名 `/api/client-downloads`、Vite 同源代理与真实浏览器 | 健康检查 200,下载接口 200/no-store;真实列表保留 Windows 0.1.73、隐藏未发布 Mac;桌面和窄屏可操作 |
|
||||
| 发布对象可读取 | 公开清单、安装包 HEAD 与 Range | 当日 Windows 0.1.73 清单 200,安装包 104867522 字节、Range 206 且为 EXE;macOS 清单 404,不展示下载 |
|
||||
|
||||
本次未构建或安装新客户端包,未上传或部署官网;Mac 浏览器证据使用受控清单,不能替代 Mac 原生构建、签名与安装验证。真实安装升级及生产部署后的 smoke 属于发布验收。
|
||||
|
||||
已获得的证据:
|
||||
|
||||
| 条款 | 验收方式 | 证据 |
|
||||
@@ -131,8 +171,8 @@
|
||||
- macOS 采用单架构包,只登记实际构建架构;Intel 真机构建与跨架构清单合并未验收,不公开宣称双架构分发就绪。
|
||||
- 旧客户端迁移桥:保留一个版本周期。渠道清单上线后,发布管线同时把旧的 `agc/latest.json`(sha256 格式)指向 `dev-win` 最新安装包,让已发布客户端自动升级到新协议;下个周期整条删除。
|
||||
- 签名密钥:由本仓库维护者生成并保管,私钥保存在仓库外(`%USERPROFILE%\.tauri\genarrative-agc-updater.key`),只有公钥进入客户端配置;Jenkins 用受保护凭据 `AgcUpdaterSigningKey` 与 `AgcUpdaterSigningKeyPassword` 注入为 Tauri 打包器读取的 `TAURI_SIGNING_PRIVATE_KEY` 与 `TAURI_SIGNING_PRIVATE_KEY_PASSWORD`,本机可用 `TAURI_SIGNING_PRIVATE_KEY_PATH` 指向同一私钥。当前密钥不带密码;首次发布前仍可重新生成,首次发布后不可更换。
|
||||
- macOS 发布方式:`dev-mac` 产物在本机 mac 上执行发布入口上传,Jenkins 暂不新增 macOS 节点;macOS 代码签名与公证凭据未确认前,相关闭环记为未验证项,不静默通过。
|
||||
- macOS 发布方式:对应渠道的 Mac 产物在本机 mac 上执行发布入口上传,Jenkins 暂不新增 macOS 节点;macOS 代码签名与公证凭据未确认前,相关闭环记为未验证项,不静默通过。
|
||||
|
||||
待办:
|
||||
|
||||
- macOS `dev-mac` 渠道落地(macOS 构建机、签名与公证、安装后重启验证、是否接入 Jenkins macOS 节点)暂缓,由后续独立变更单独完成;在此之前 `dev-mac` 渠道只有构建与清单能力,不发布。
|
||||
- macOS 实际发布(macOS 构建机、签名与公证、安装后重启验证、是否接入 Jenkins macOS 节点)仍需独立验证;代码中的渠道与分区支持不等于已有 Mac 安装包发布。
|
||||
|
||||
@@ -8,6 +8,17 @@ AGC 客户端接入公共 OSS 上的**游戏模板库**(真·游戏模板,
|
||||
- 客户端侧:Rust `template_library` 模块(读清单、下载、安装、建项目)+ 模板库全屏页 + 首页模板推荐 + 左侧导航入口。
|
||||
- 不在本次范围:模板制作工具、模板审核、模板计费、增量更新、已建项目的模板回填。
|
||||
|
||||
## 模板库灰度访问
|
||||
|
||||
- 后台现有灰度发布页登记 `agc:template-library`,控制整个模板库;复用用户 ID 白名单、用户标签、拒绝名单和稳定用户分桶比例,不新增数据库表或字段。未配置此 Gate 时默认关闭;已配置且停用灰度时遵循现有语义全量开放,启用灰度时拒绝名单优先于白名单及比例。
|
||||
- `/api/runtime/frontend-config` 增加 `agcTemplateLibraryEnabled`,按认证主体返回服务端权威结论。客户端尚未得到结果、匿名或请求失败时关闭入口;权限结果不作为离线缓存。
|
||||
- 登录、主体变化、窗口重新获得焦点和每次模板操作时刷新权限,不承诺后台修改的实时推送。未获准时首页模板推荐和左侧模板库导航隐藏,不读取 OSS 清单;已在模板页检测到失去权限时回到首页。原生命令明确拒绝或权限检查失败后同样清空并关闭入口。账号切换或退出后立即清空前一主体的清单、操作状态和可见性,旧异步响应不能恢复权限或导航。
|
||||
- 原生清单读取、下载和模板建项命令均独立核对当前平台会话及服务端权限,不能依靠前端隐藏;远端等待后的会话变化必须拒绝,安装和建项写入使用当前会话身份保护。已缓存清单和已安装模板不能绕过权限。
|
||||
- 此灰度控制当前客户端的产品功能,不承诺公开 OSS 模板内容的保密性,也不限制已创建项目的正常打开和编辑。旧客户端升级后才接入此控制。
|
||||
- 验收覆盖缺省关闭、明确全量、允许/拒绝名单、标签和比例、请求失败、缓存绕过、原生命令阻断、首页/导航/模板页以及账号切换竞态。
|
||||
- 验证入口:后台灰度页面测试、`useTemplateLibrary.test.tsx`、AppSurface 实际挂载的 template 用例、原生 `template_library` 测试和后端 `frontend_runtime_config` 测试。退出开始使用既有平台会话代次立即撤销,建项返回、revision 读取和预览核验后的旧回调均不得导航或登记最近项目;同主体 token 轮换不误撤销原生身份。
|
||||
- 本地隔离数据库已验证 Gate 经后台 API 保存后可重新读回,匿名运行时配置为 false;后台受控浏览器 smoke 验证桌面和 320px 布局及保存确认交互。线上 OSS 下载和正式安装包登录后的端到端操作不由这些测试替代。
|
||||
|
||||
## OSS 契约
|
||||
|
||||
```text
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
> 规范关系:AGC 插件与编辑器适配主规范
|
||||
> 验收范围:插件 manifest、宿主生命周期、RPC、Capability/权限审计、UI 挂载和编辑器适配器边界
|
||||
|
||||
更新时间:`2026-09-09`
|
||||
更新时间:`2026-09-20`
|
||||
|
||||
## 目标与边界
|
||||
|
||||
@@ -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。
|
||||
@@ -71,7 +72,16 @@ OpenAI 的标准模型是“Plugin 作为可安装包,组合 Skills、可选 M
|
||||
|
||||
Windows 与 macOS 构建都将内置插件的清单、JS 入口与面板复制到应用资源目录;staging 每次重建,避免已删除插件或跨目标原生 payload 残留。macOS 不携带 Windows native payload。Cocos 进程桥接仍仅按既有 Windows 平台实现提供,插件文件可被发现不代表 macOS 已支持编辑器控制;JS 入口的系统 Node 前提不变。
|
||||
|
||||
Cocos 插件对用户可见与可启动必须同时满足当前为 Cocos 项目、宿主已注册 `cocos-editor` 原生适配器;没有适配器时从插件/扩展列表隐藏,直接启动或读取面板也在产生子进程前拒绝。正式适配器仅在 Windows 且编译 `cocos-editor-execute` 时注册;Agent 工具使用相同平台与 feature 门禁。前端只按后端列表投影判断是否自动启动,不自行推断平台能力。
|
||||
Cocos 与 Unity 插件的可见性、启动、面板、插件 RPC 和 Agent 工具暴露不按当前工程类型过滤;无当前项目以及普通 AGC、Godot、Cocos、Unity 项目使用同一套插件可用性规则。宿主必须已注册插件声明的原生适配器;没有适配器时从插件/扩展列表隐藏,直接启动或读取面板也在产生子进程前拒绝。正式适配器与 Agent 工具继续受各自平台和编译 feature 约束,禁用开关继续阻止启动与工具执行。前端只按后端列表投影判断是否自动启动,不自行推断平台能力或再次按工程类型过滤。
|
||||
|
||||
### 工程上下文与真实编辑器目标
|
||||
|
||||
- 工程类型只用于工程识别及对应工程工作流,不作为 `agc-cocos-editor` / `agc-unity-editor` 的管理、面板或工具目录门禁。Runtime、DirectProject MCP、工具策略快照和模型上下文使用一致规则;工具已暴露不代表真实编辑器已连接或操作已成功。
|
||||
- 前端对宿主列表中的 Cocos 与 Unity 插件分别根据适配器支持、启用、Runtime 入口和运行状态投影自动启动,不按项目类型二选一;自动启动不自动展开编辑器面板。
|
||||
- 项目切换不因新工程类型不同而停止插件或隐藏工具;当前受控项目上下文仍须按既有顺序更新,旧编辑器连接失效。旧请求与回执保留原项目归属,不能更新新项目连接状态。
|
||||
- 实际编辑器操作仍须取得有效的当前受控项目和与之匹配的真实编辑器目标。宿主注入项目路径,显式路径必须与当前受控项目一致;适配器继续校验真实工程结构、目标 PID、进程身份、版本与握手。无项目、不匹配的工程目录、无编辑器或不支持的平台均应在发送编辑器操作前明确失败,不回退到其它项目或任意编辑器进程。
|
||||
- 插件启用状态、manifest 适配器绑定、`editor.rpc` 权限、超时与并发拒绝、执行结果不确定阻断均保持原合同。取消工程类型过滤不增加自动重试,不清除项目切换或重启插件前已经产生的不确定状态。
|
||||
- 不新增或迁移项目类型、内置插件开关、API/DTO、SpacetimeDB schema 或持久项目数据;不扩大 Cocos/Unity 原生适配器的平台支持,也不把任意非引擎目录解释为可执行的编辑器工程。
|
||||
|
||||
### 内置插件与可用开关
|
||||
|
||||
@@ -115,6 +125,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 命令。
|
||||
@@ -133,6 +150,7 @@ OpenAI 官方 Plugins 文档将 Skills、MCP Server 和可选 UI 定义为同一
|
||||
- Rust:manifest 路径/权限校验、目录扫描、权限拒绝和通用适配器 registry 边界单测;`cargo check --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml`。
|
||||
- 前端:`agc-plugin-sdk` TypeScript 编译、宿主服务类型检查,以及 `PluginPanelHost` 的挂载/卸载测试。
|
||||
- 内置插件开关:`builtin_plugins` 单测覆盖默认值、持久化往返、坏文件失败关闭,以及“禁用后工具目录里不再出现该工具”;`plugin_host` 单测覆盖禁用后不能启动、启用后回到 stopped。
|
||||
- 工程类型独立性:覆盖无当前项目、普通 AGC、Godot、Cocos、Unity 上下文中的插件列表、启动、面板、RPC 与 Runtime/DirectProject 工具目录一致性;项目切换不因类型变化停止插件。保留禁用开关、缺失原生适配器、平台/feature、显式跨项目路径拒绝与真实编辑器目标校验的独立反例;非引擎目录不能仅因工具可见就通过实际操作校验。
|
||||
- 插件工作区:`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml` 覆盖工作区扫描与 manifest 启用状态;`cargo test --manifest-path plugins/agc-cocos-editor/native/cocos-editor-bridge/Cargo.toml` 覆盖 Cocos 适配器;`node --test plugins/agc-cocos-editor/src/entry.test.mjs` 覆盖插件入口协议与 manifest 一致性。
|
||||
- 通用仓库门禁:`npm run check:encoding`、`git diff --check`;发布前仍需单独执行 AGC package smoke 和安装包 smoke。
|
||||
|
||||
|
||||
@@ -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 指引执行,不新增运行时门禁或平行校验系统。
|
||||
@@ -40,6 +69,10 @@
|
||||
- 当前素材名以现有正式命名链路为准:生成时 assetName 参与落盘名称,重命名更新文件名;卡片消费正式资源 label,不从临时输入或历史任务名覆盖后续重命名,不新增平行显示名持久化。若原有命名链路丢失 assetName,则修复原链路,而非只在卡片本地伪造。文档卡不显示任何正文摘要,但详情原文与 JSON 识别读取不变。
|
||||
- 验收覆盖空素材项目进入工具、真实引用入参、成功/失败/重试与迟到响应、占位移动后落点、全类型名称、文档详情、当前栏目重排/撤销、不同缩放的多选移动/撤销以及其他栏目不变。自动化、真实客户端和真实 Provider 验证分别报告;未实际运行的路径不得标为通过。
|
||||
|
||||
## 平台服务与官网分发
|
||||
|
||||
客户端平台服务固定为 dev,登录页不提供服务器选择。凭据按 origin 隔离迁移;官网下载入口汇总最新渠道清单,自动展示已有首装包的 Windows/Mac 平台及架构。完整合同见 [AGC 客户端更新检查与下载](./【技术方案】AGC客户端更新检查与下载-2026-08-31.md) 的“官网下载与客户端服务地址”。
|
||||
|
||||
## 策划 Agent 批量局部修改
|
||||
|
||||
`patch_file` 的所有 edits 均匹配同一份原文件,参数顺序不影响结果。完成唯一匹配与不重叠校验后,按原文起点升序拼接未修改片段与替换文本,最后一次性写入;任一校验失败时不写文件。回归用例覆盖乱序 edits、中文内容与替换长度增减,并核对完整落盘内容。此行为仅属于策划 Agent 文件工具。
|
||||
@@ -156,9 +189,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 产物合同
|
||||
|
||||
@@ -203,7 +236,7 @@ npm 游戏的可预览产物固定为对应 package 目录下的 `dist/index.htm
|
||||
|
||||
- `agc_tools` 新增 `agc_list_registered_assets` 与 `agc_create_or_derive_resource`。前者按 `kind / assetId / offset / limit` 有界查询客户端权威 manifest,并可显式返回角色动画正式序列帧的稳定 objectKey、assetObjectId 和尺寸;结果不包含完整 manifest、prompt、model、provider route、签名 URL、宿主路径或凭据。后者只接受 `kind / mode / sourceLocalAssetId / prompt / assetName`,`create` 仅允许无源视频、音效和背景音乐,`derive` 必须引用当前项目已登记的 localAssetId,角色动画固定为 derive。
|
||||
- `prompt` 上限按 `kind` 分别生效,且工具 schema、MCP 校验、客户端工具桥与提交校验共用同一权威口径(`resource_edit_prompt_max_chars`):背景音乐 140、音效 1900、视频与角色动画 4000、图片编辑 32000。schema 逐 kind 声明 `maxLength` 并在 `prompt` 描述里写明数字,超限必须在发起任何桥请求与付费提交之前失败并回报真实上限;`sourceLocalAssetId` 不是当前项目已登记资源时,错误文案必须直接给出 `agc_list_registered_assets` 与 `agc_list_project_files` → `agc_import_account_assets.localPaths` 两步后续动作。
|
||||
- 项目路径、projectId、当前 revision、源文件路径与媒体类型、operationId、Idempotency-Key、登录态、项目锁、付费提交、轮询恢复、下载校验与 manifest 事务全部由客户端持有。模型不能提交或覆盖这些字段。同一 Direct `clientTurnId + 规范语义参数` 生成稳定 UUID v4 身份;单回合同参重试复用原 operation,不同请求串行且最多四项。跨回合存在完全匹配的 pending 账本时优先恢复原 operation,不能换键重发。
|
||||
- 项目路径、projectId、当前 revision、源文件路径与媒体类型、operationId、Idempotency-Key、登录态、项目锁、付费提交、轮询恢复、下载校验与 manifest 事务全部由客户端持有。模型不能提交或覆盖这些字段。同一 Direct `clientTurnId + 规范语义参数` 生成稳定 UUID v4 身份;单回合同参重试复用原 operation,不同请求串行提交,不设每回合计数上限(2026-09-19 起,见决策记录)。跨回合存在完全匹配的 pending 账本时优先恢复原 operation,不能换键重发。
|
||||
- 资源查询同时投影未完成 operation 的安全状态。媒体工具成功只返回 operation、本地相对路径、资源类型、Canvas/resource/asset/task 身份、正式序列帧以及脱敏后的 `warnings / sliceWarnings`;错误继续使用统一脱敏边界。客户端资源账本持久化 completed 结果的两类告警,committed replay 不能把历史告警伪装成空集合。
|
||||
- 角色动画、视频、音效和背景音乐在构造新的远端请求前统一准备当前项目同名画布与素材目录上下文,并在端点支持时携带 `projectId / assetFolderId / canvasCompletion`。角色动画 placeholder 使用源图片真实宽高,避免非方形角色进入画布时失真;正式 resource/asset 与序列帧继续直接复用 External 返回身份,不从首帧伪造重复资源。已有冻结 request body 或已受理 operation 保持不变,不因本次升级重建请求或重复扣费。
|
||||
- 抠图通过新增 `agc_remove_background` 语义工具开放:模型只提交当前 manifest 的图片 `sourceLocalAssetId` 与结果名称;客户端解析稳定 `resourceId`,准备同名画布/素材目录并生成稳定 operation/idempotency 身份。普通登录态使用账号鉴权的 `/api/editor/images/background-removals`,ExternalDeveloper 模式使用 External v1 `/api/external/v1/editor/images/background-removals`;客户端接收异步受理后轮询任务状态,下载完成媒体并登记到本地 manifest,未知结果保留同一 operation 供恢复。抠图服务仍由客户端和服务端负责源校验、BgFilter、素材登记与画布事务,Codex 不获得内部 worker、凭据或任意 API 调用权。
|
||||
@@ -1354,7 +1387,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 +1530,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 保留为未来合同正是为此)。
|
||||
@@ -1583,23 +1616,23 @@ Direct 回合的所有权属于进程内项目身份锁,不属于当前页面
|
||||
### 目标与非目标
|
||||
|
||||
- 目标:AGC 在项目工作区打开期间按固定周期把用户项目增量上传到 OSS `agc-dev`,并在项目关闭时立即补一次同步;重复内容不重复上传,远端占用跟随当前清单收敛。
|
||||
- 非目标:不做云端下载/恢复、不做跨设备合并、不保留多版本历史、不新增面向用户的上传界面、不修改 `/api/external/v1` 与 OpenAPI、不新增 SpacetimeDB 表。
|
||||
- 非目标:不做客户端云端恢复、不做跨设备合并、不保留多版本历史、不新增面向用户的上传界面、不修改 `/api/external/v1` 与 OpenAPI、不新增 SpacetimeDB 表。
|
||||
- 非目标:不把 OSS AccessKey 放进客户端;客户端不直连 OSS。
|
||||
|
||||
### 参与入口、状态与跨模块边界
|
||||
|
||||
- 触发入口有两个:工作区窗口 `main` 存活期间的周期定时器、工作区窗口关闭事件(`CloseRequested`)。两者共用同一个进程内同步器,同一项目的同步串行执行,周期触发在已有同步进行时直接让位,不排队堆积。
|
||||
- 应用退出(`RunEvent::Exit`)不重复发起同步:该时刻窗口已销毁,按窗口重新枚举项目只会得到空集;退出路径只负责在有界预算(15 秒)内等待在途同步收尾,让关窗触发的那一次同步能写完索引再退出。
|
||||
- 触发入口为项目生命周期登记、已登记项目的周期定时器及窗口关闭事件(`CloseRequested`)。它们共用同一个进程内同步器,同一项目的同步串行执行,周期触发在已有同步进行时直接让位,不排队堆积。
|
||||
- 应用退出(`RunEvent::Exit`)不重复发起同步;退出路径只负责在有界预算(15 秒)内等待在途同步收尾,让关窗触发的那一次同步有机会写完索引再退出。超过预算不能声明最后状态已经上传。
|
||||
- 客户端扫描、差异对比、索引持久化与上传编排都在 Tauri Rust 进程(`src-tauri/src/project_snapshot/`);WebView 只读状态,不参与差异计算。
|
||||
- 本地索引是增量对比的唯一依据:`<AppData>/project-snapshots/<projectId>/index.json` 保存上次成功同步的相对路径、校验和、字节数和修改时间。项目根使用现有 manifest 的稳定 `project_id` 作为远端身份,路径不再作为身份。
|
||||
- 可观测性按产品口径收敛到本机日志:同步结果、失败分类、延后与跳过计数只写入 AppData 诊断日志(`project_snapshot.sync.*` 前缀),客户端界面不暴露上传状态、时间线或入口按钮。`read_local_project_snapshot_state` 与 `sync_local_project_snapshot` 两条命令仅作为 native-only 的排障与联调入口登记,不在渲染层调用。
|
||||
- 远端写入经 `api-server`,客户端只持平台登录态 Access Token。两条登录态路由:`POST /api/agc/project-snapshots/files`(单文件,正文为原始字节,元数据走查询串)与 `POST /api/agc/project-snapshots/manifest`(本次同步后的完整清单)。
|
||||
- 对象键与清单由服务端决定:文件键为 `agc/project-snapshots/v1/{userId}/{projectId}/files/{sizeBytes}-{checksumDigest}/{relPath}`,清单键为 `agc/project-snapshots/v1/{userId}/{projectId}/manifest.json`。键里带字节数与摘要,因此"对象已存在且长度一致"可以作为内容一致的判据;路径按原始大小写保留,不走 `put_object` 的低位规范化。`agc` 前缀继续是服务端专用私有前缀,通用对象键解析与客户端直传票据都不覆盖它。
|
||||
- 目标 bucket 使用独立配置 `GENARRATIVE_AGC_PROJECT_SNAPSHOT_OSS_BUCKET` / `_ENDPOINT` / `_ACCESS_KEY_ID` / `_ACCESS_KEY_SECRET`,默认 `agc-dev` + `oss-rg-china-mainland.aliyuncs.com`,未配置时回退 `ALIYUN_OSS_*`;与"资源 bucket 与备份 bucket 分离"的既有口径一致。
|
||||
- 目标 bucket 使用独立配置 `GENARRATIVE_AGC_PROJECT_SNAPSHOT_OSS_BUCKET` / `_ENDPOINT` / `_ACCESS_KEY_ID` / `_ACCESS_KEY_SECRET`,默认 `agc-dev` + `oss-rg-china-mainland.aliyuncs.com`。只允许凭据回退 `ALIYUN_OSS_ACCESS_KEY_ID` / `_ACCESS_KEY_SECRET`;bucket 与 endpoint 不跟随资源存储的 `ALIYUN_OSS_BUCKET` / `_ENDPOINT`,避免默认写入其它 bucket。显式快照目标配置继续优先;不自动搬迁其它 bucket 的现存数据。
|
||||
|
||||
### 正常、失败、重试与幂等行为
|
||||
|
||||
- 差异对比口径:先按 `相对路径 + 字节数 + 修改时间` 判定是否候选变更,命中旧记录则复用已存 `sha256`,只有 `(size, mtime)` 变化才重算摘要。产出新增、修改、删除三类集合,只上传新增与修改的文件。
|
||||
- 差异对比口径:先按 `相对路径 + 字节数 + 修改时间` 判定是否候选变更,命中旧记录则复用已存 `fnv1a64`,只有 `(size, mtime)` 变化才重算摘要。产出新增、修改、删除三类集合,只上传新增与修改的文件;清单元数据变化单独提交。
|
||||
- 每次成功同步的最后一步上传该项目的 `manifest.json`(当前全量文件清单:相对路径、摘要、字节数、同步序号)。清单描述的是项目当前全量内容,因此清单体积就是该项目在 OSS 上的常驻占用。
|
||||
- 远端回收:清单写入成功后,服务端读取上一版清单,按 `(路径, 字节数, 摘要)` 反推出不再被当前清单引用的对象键并删除。只处理上一版清单登记过的键,不做 LIST,因此不可能误删其它项目或其它功能的对象;单次最多回收 2000 个对象,剩余部分留到下一次清单写入继续;上一版清单读不到或解析失败时整轮跳过回收(fail-closed)。单个删除失败只记日志,不影响本次同步语义。
|
||||
- 因此本功能是"当前状态镜像 + 清单",不保留历史版本:同一路径的内容变化会覆盖式替换远端对象,回滚能力不在本轮范围内。
|
||||
@@ -1623,6 +1656,18 @@ Direct 回合的所有权属于进程内项目身份锁,不属于当前页面
|
||||
- 运行时 smoke:AGC 开发态打开项目、观察索引写入与同步日志、关闭工作区窗口后确认关闭触发的那次同步执行;报告为"客户端 diff 已验证 / 服务端已配置环境联调"两层,不合并成一句"已通"。
|
||||
- 边界:新增日志与错误文案不含 Access Token、AccessKey、绝对路径与项目内容。
|
||||
|
||||
### 后台工程列表与下载
|
||||
|
||||
- 正式客户端在单窗口内切换启动器和项目,不以窗口 URL 判断活动项目。前端把当前窗口的已打开项目登记给原生同步器;打开后发起首轮同步,离开/切换项目和物理关窗为旧项目补同步,周期扫描只读这份窗口登记。重复登记同一路径不重复发起;注册失败写诊断,不能假装已登记。
|
||||
- 清单补充可选 `projectName` 与 `pendingFiles`:名称来自本地 manifest;`pendingFiles` 是本轮失败、延后、并发变动与非策略排除的跳过文件数量。`0` 表示扫描范围已同步;大文件等被跳过不能标成完整。旧清单字段缺失表示完整性未知,维持可读取兼容,不反写旧清单。
|
||||
- 项目名称或完整性发生变化时,即使文件内容没有差异也要提交新清单;本机索引记录上次已提交的这两个字段。实际客户端下一次正常同步可补齐历史清单元数据;后台只读访问不迁移旧清单。缺失 `pendingFiles` 不能默认成 0,临时跳过原因消失后允许无文件上传的 `partial → ready` 转换。
|
||||
- 后台增加“项目工程”入口,仅 owner 及拥有 `project-snapshots` 页签权限的管理员可访问。`GET /admin/api/project-snapshots?cursor=&limit=20` 读取私有 OSS 清单并返回 `{items,nextCursor}`;单页最多 100 个,游标由服务端校验,目录与清单读取有界。条目为 `{userId,projectId,projectName,syncRevision,syncedAtMs,fileCount,totalBytes,status}`,状态为 `ready / partial / unverified`,名称缺失时显示 projectId。
|
||||
- `GET /admin/api/project-snapshots/{userId}/{projectId}/download` 只读取该用户/项目的固定清单与其引用对象,返回 `application/zip` 附件。ZIP 中路径直接使用原始相对路径,不包含 userId、摘要目录或 OSS 前缀;名称使用经过安全处理的项目名和 revision。下载固定本次读到的清单,远端并发回收导致对象缺失则整体失败,不能静默遗漏。
|
||||
- `partial` 快照下载返回 409;`unverified` 历史快照可导出已同步文件,列表明确显示“完整性未知”,动作称“下载已存文件”。`ready` 才显示“下载完整工程”。ZIP 构建核验每一文件的长度与 fnv1a64 摘要,拒绝穿越、绝对路径、重复/大小写冲突路径、非法项目身份;缺失或损坏整体失败,不返回成功的残缺 ZIP。
|
||||
- ZIP 使用服务端临时文件并限制并发,不将 2 GiB 工程整体驻留内存;成功、失败、客户端取消均清理临时文件。单文件、总量、文件数沿用上传上限,超限明确拒绝。零字节工程文件可以上传和导出。OSS 凭据与签名不下发浏览器,列表失败保留错误而非伪造空列表。
|
||||
- 工程归档范围与上传策略一致:源码、素材及引擎配置按原路径保存,依赖/构建缓存、凭据、`.agent` 会话与运行日志排除;此 ZIP 不声明能恢复 AGC 对话历史。后台读取需要目标前缀的 ListObjects 与 GetObject 权限,不新增数据库表,不改 External API。
|
||||
- 验收覆盖真实单窗口生命周期登记、首次/增量/零字节上传、后台列表分页和权限、ZIP 解压目录及摘要、部分/历史清单、缺失对象、路径拒绝、下载取消清理,并分别报告定向测试和真实环境证据。
|
||||
|
||||
### 未决问题
|
||||
|
||||
- 用户侧看不到同步状态与失败原因(界面按产品口径不暴露),排障只能读 AppData 诊断日志或调用 native-only 命令;如果后续要支持用户自助排查,需要先确认是否允许在客户端出现上传相关 UI。
|
||||
|
||||
@@ -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 已删除。
|
||||
@@ -55,11 +64,18 @@ npm run check:server-rs-ddd
|
||||
|
||||
## API 路由分组
|
||||
|
||||
### AGC 项目工程后台读取
|
||||
|
||||
`GET /admin/api/project-snapshots` 与 `GET /admin/api/project-snapshots/{userId}/{projectId}/download` 复用后台鉴权,要求 owner 或 `project-snapshots` 页签权限。数据来自私有 OSS 项目清单,不复用图片编辑器项目表、不新增 SpacetimeDB schema。`platform-oss` 只提供固定 AGC 前缀下的有界目录枚举和对象读取,`api-server` 负责列表投影、归档与下载响应,后台 DTO 留在 `shared-contracts/admin`。
|
||||
|
||||
列表按清单中的 `pendingFiles` 区分 `ready / partial / unverified`;历史字段缺失必须为 `unverified`。下载冻结本次清单,按原始目录构造 ZIP;逐项核对长度和摘要,部分同步、对象缺失、损坏或危险路径不能返回完整工程。客户端不接触 OSS 凭据。完整契约见 [AGC 实施计划](./technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md) 的“后台工程列表与下载”。
|
||||
|
||||
路由树由 `server-rs/crates/api-server/src/app.rs` 统一构造。当前主要分组:
|
||||
|
||||
- 健康检查:`GET /healthz`、`GET /readyz`。
|
||||
- 后台管理:`/admin/api/*`,现役路由包括登录与账号管理、Dashboard / 概览、HTTP debug、埋点、表查询、通用 feature gate、编辑器定价与素材 / 精选管理,以及账号侧兑换码、邀请码、任务、钱包、充值与退款管理;不再挂载旧创作入口配置、旧作品互动或旧玩法运营路由。环境变量管理员固定作为 owner,持久化 member 每次请求按当前 `enabled`、`token_version` 和一级 Tab 权限实时校验;账号管理仅 owner 可访问,未登记权限映射的新后台路由对 member 默认拒绝。完整权限矩阵见 [`docs/technical/【后台管理】多账号与Tab访问权限方案-2026-07-14.md`](./technical/【后台管理】多账号与Tab访问权限方案-2026-07-14.md),Dashboard 指标口径见 [`docs/technical/【后台管理】Dashboard运营看板方案-2026-06-23.md`](./technical/【后台管理】Dashboard运营看板方案-2026-06-23.md)。
|
||||
- 通用灰度控制面固定为后台 `#gray-release` 与 `GET/PUT /admin/api/feature-gates`;页面固定目标只登记现役功能,不读取旧 `/admin/api/creation-entry/config`,也不恢复 `creation-entry:*` 动态目标。
|
||||
- AGC 模板库使用 `agc:template-library`,不新增 schema;`GET /api/runtime/frontend-config` 追加账号相关的 `agcTemplateLibraryEnabled`,匿名和 Gate 缺失为 false,存在配置时复用通用灰度规则。响应设置 `Cache-Control: no-store` 与 `Vary: Authorization`,客户端原生操作独立检查权限。官网公开 `GET /api/client-downloads` 则读取服务端 `GENARRATIVE_CLIENT_DOWNLOAD_CHANNEL`(默认 dev)对应的 Windows/macOS 分区,渠道与系统独立,不从请求 query 接受 URL 或渠道覆盖。
|
||||
- 认证与账号:`/api/auth/*`、`/api/profile/me`,包括短信、密码、微信、refresh session、多端会话和登出。
|
||||
- 个人中心:`/api/profile/*`,包括钱包流水、任务、领奖、充值、反馈、邀请和兑换等账号侧能力。
|
||||
- 平台基础能力:`/api/llm/*`、`/api/speech/volcengine/*`,只保留通用 LLM 和语音代理。
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# 本地开发验证与生产运维
|
||||
|
||||
## 官网客户端下载联调
|
||||
|
||||
主站 Vite 将 `/api/client-downloads` 转发到当前 `runtimeServerTarget`。通过 `npm run dev:api-server` 与 `npm run dev:web` 联调时,先确认运行日志与 `.app/dev-stack.json` 的实际 API 地址,检查 `/healthz`,再从 Vite 同源访问 `/api/client-downloads`;正常应返回 `downloads` 平台列表、`unavailablePlatforms` 和 `Cache-Control: no-store`,不能落入 SPA HTML fallback。渠道 404 表示未发布,单端失败只影响对应平台;公网 OSS 清单没有官网 CORS,浏览器不直接读取该清单。
|
||||
|
||||
## 构建回归的隔离与发布文件权限
|
||||
|
||||
Git hook 的临时仓库测试必须清除子进程继承的仓库定位环境(例如 `GIT_DIR`、`GIT_WORK_TREE`、`GIT_INDEX_FILE`);仅设置 `cwd` 不能隔离 Git。回归应从带这些变量的外层仓库运行,验证外层引用、索引与配置不变。临时测试文件必须留在独立目录并清理,不得通过测试生成主仓库提交或覆盖 ESLint、Prettier 配置。修复 lint 配置时保留原有规则、忽略范围与零警告门禁,不以关闭规则代替排障。
|
||||
@@ -544,6 +548,12 @@ curl -fsS --max-time 5 http://127.0.0.1/api/editor/showcase/resources >/dev/null
|
||||
|
||||
### AGC 项目快照上传目标
|
||||
|
||||
后台“项目工程”(`/admin/#project-snapshots`)按项目列出远端快照。完整快照提供“下载完整工程”,按原始目录返回 ZIP;未完成同步的项目暂不可下载,旧清单缺少完整性声明时显示“完整性未知”,只能“下载已存文件”。不要直接把 OSS 的 `files/{size}-{digest}/` 目录下载当成工程。
|
||||
|
||||
自动上传以原生登记的活动工程为准:打开即首传、每 300 秒周期同步、切换/关闭补传。排障同时核对 AppData `project-snapshots` 索引、`project_snapshot.sync.*` 日志和远端清单;只有测试项目的历史清单不能证明现役项目同步生效。前端在同一窗口内切项目时必须登记生命周期,不能只检查 URL 是否包含 `projectPath`。
|
||||
|
||||
后台枚举另外需要 AGC 私有前缀的 `ListObjects`(RAM `oss:ListObjects`,限制 prefix)与 `GetObject` 权限;下载不需要写入权限。客户端修复、后台页面与 api-server 必须分别发布才能在安装版和线上后台使用。本地定向测试及页面模拟不能代替发布后的真实上传与 ZIP 下载验收。
|
||||
|
||||
AGC 客户端按周期与项目关闭时机把用户项目增量上传到 `agc-dev`。客户端只持有平台登录态 Access
|
||||
Token,经 `POST /api/agc/project-snapshots/files`(单文件原始字节)与
|
||||
`POST /api/agc/project-snapshots/manifest`(本次同步清单)交给 `api-server`,由服务端写入私有前缀
|
||||
@@ -808,13 +818,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/*` 聚合的监控查询应改为按路由模板汇总。
|
||||
|
||||
常见外部服务变量:
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user