Merge remote-tracking branch 'origin/master' into fix/wrong-report
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m25s
Project CI / AI game creator shell Rust crates (pull_request) Failing after 53s
Project CI / Backend tests (pull_request) Failing after 21s
Project CI / Frontend tests (pull_request) Successful in 2m25s
Project CI / Repository checks (pull_request) Failing after 14s
Project CI / AI game creator shell web tests (pull_request) Successful in 1m45s
Project CI / Native shell tests (pull_request) Successful in 5m48s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 10m34s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 11m18s

# Conflicts:
#	docs/project-memory/shared-memory/decision-log.md
#	docs/project-memory/shared-memory/pitfalls.md
This commit is contained in:
2026-10-02 12:19:13 +08:00
152 changed files with 12511 additions and 1096 deletions
@@ -55,7 +55,8 @@
## 模型绑定 Agent 执行模式
- 后台 AGC 模型目录每项新增 `agentMode`,只接受 `codex` 与 `cc`;缺少该字段的历史目录按 `codex` 解释,后台新增模型默认 `codex`。
- 后台 AGC 模型目录每项新增 `agentMode`,接受 `codex`、`cc` 与 `anthropic`;缺少该字段的历史目录按 `codex` 解释,后台新增模型默认 `codex`。`anthropic` 是 2026-10-01 新增的显式 Anthropic Messages 协议值,`cc` 保留为同一 Claude 执行器的历史别名(两者都映射到 `claude_code_cli`),新目录项应直接写 `anthropic`。
- 2026-10-01 补充:`cc`/`anthropic` 一律经平台 LLM 网关的独立 Anthropic 路由 `POST /api/llm/anthropic/{*path}`,客户端 `ANTHROPIC_BASE_URL` 为 `{apiBaseUrl}/api/llm/anthropic`,不得再用配置里的 `llm.baseUrl`(那是 Router 地址,平台不会把账号 Router key 下发给客户端)。Claude Agent SDK 自己拼 `{base}/v1/messages` 并带 `authorization: bearer` 与 `anthropic-version`,网关据此转发上游 `{routerBase}/v1/messages`。
- `codex` 仍表示现有 AGC Codex app-server 执行链路;`cc` 表示 AGC 客户端启动随包的 Claude Agent SDK sidecar,模型的 `modelId` 原样作为 Claude Agent SDK 的模型标识,不把 Claude 协议伪装成 OpenAI Responses。sidecar 随 AGC 安装包携带 SDK 及匹配平台的 Claude Code runtime,用户不需要预先安装 `claude` 命令。
- `/api/llm/models` 的启用模型摘要返回 `agentMode`,后台完整目录、管理 DTO 和客户端目录保持同一绑定快照。客户端在选择模型时同时持久化模型 ID 与执行模式;默认模型变化、模型被停用或目录刷新回退时一并更新执行模式。
- 客户端设置保存不得把后台模型绑定覆盖回 Codex。旧客户端配置缺少执行模式时继续按 Codex 运行;旧后台响应缺少 `agentMode` 时客户端按 Codex 兼容。
@@ -1,5 +1,13 @@
# AI 游戏创作智能体 App 实施计划
## 2026-10-01 项目文件列举的范围与并发边界
`agc_list_project_files` 的项目内 `path` 在遍历时限制到目标文件、目标目录及其必要祖先;不递归无关子树,也不读取无关条目的元数据。Agent 的控制面、敏感文件和快照排除规则在读取条目元数据之前生效;通用 UI 文件树保持原有可见范围。引擎生成目录仍按项目根身份排除,不能因定向列举改变判定基准。
文件列举是实时观察,不是文件系统快照。枚举后消失的文件或待进入目录(`NotFound`)跳过;权限、非目录和其它 IO 错误保留路径及原因,不统一吞错或重试。目标不存在时继续返回空列表;符号链接和 Windows 重解析点不得作为遍历入口。过滤后按项目相对路径排序,再计算 `total`、`offset`、`limit` 和 `nextOffset`;多次分页之间的并发变更不承诺快照一致性。
本修复不调整项目写锁等待、写入许可、项目外读取或工具 DTO。验收通过受控的枚举/元数据间隙释放真实项目锁,并覆盖定向范围、消失目录、真实 IO 错误、受保护路径、链接、引擎目录及分页;不依赖概率性循环碰撞。
## 2026-09-29 Codex 私有运行目录路径解析
新建的私有运行目录先确认是普通目录并收紧权限,再解析真实路径,后续 `codex-home`、`workspace` 和隔离用户目录均在真实路径下创建,避免 macOS 系统临时目录的符号链接阻断启动。Windows 扩展 UNC 路径 `\\?\UNC\server\share\...` 必须转换为 `\\server\share\...`,盘符路径才直接去掉 `\\?\` 前缀;转换后保留绝对路径语义。私有子目录仍执行原有祖先符号链接与 reparse point 检查。
@@ -116,6 +124,7 @@ UI 编辑器的“分析参考图”步骤、Rust 命令 `suggest_ui_design_sema
- 对客户端刚创建且内容仍匹配可信模板的 Web 脚手架,在正式生成前由宿主执行受控依赖准备和真实 Vite 构建。依赖安装禁用生命周期脚本;不自动安装或覆盖导入/用户修改过的工程。
- 准备凭证的 `ready` 只证明初次环境准备成功,不代表当前游戏已验收,后续正常修改不得因此重新安装。`preparing` 中断恢复必须证明原拥有者已结束且其执行子树已回收;身份或归属未知时保留阻断,不重复执行。
- 输出明确区分“Node/npm 构建能力通过”与“本项目 Vite 构建通过”;任何一步失败保留可行动错误,不降级为预检成功。
- 首页必须区分宿主预检阻塞与 Tauri IPC 调用失败:Rust 返回的安全错误码可透传到状态栏;无错误码的瞬态 IPC 失败只允许一次有界重试后显示独立的客户端连接故障,不得统一伪装成 Node/npm 或浏览器故障。预检仍保持失败关闭,不得因为展示错误变得可绕过。
- 安装载荷提供相同的安全预检 CLI,验证无系统 Node 的独立运行、缺包/篡改失败关闭。NSIS 解包载荷 smoke 与真实安装器注册流程分开报告,不覆盖当前用户的既有安装。
### 跑酷固定基线
@@ -504,6 +513,11 @@ npm 游戏的可预览产物固定为对应 package 目录下的 `dist/index.htm
## 2026-08-25 账户 / 项目画布 / 本地素材导入
- 账户素材库总量不作为客户端查询、预览或按 ID 导入的拒绝条件。账户查询继续先读取后端快照,再按静态图片、文件夹与关键词筛选并分页;`offset` 接受可表示的非负整数,超过结果总数返回空页,`limit` 保持 1–100(默认 100),结果保留 `total / offset / limit / nextOffset`。Direct MCP 的关键词匹配素材名或文件夹名,Runtime 保留现有素材名匹配语义。
- Runtime 下发给模型的 `asset.library.list` strict 原生函数 schema 必须与执行层分页边界一致;验收须校验 `build_agent_runtime_native_function_tools` 生成的完整函数参数,确认 `offset=501/600` 可用、负数和非整数偏移及 `limit>100` 被拒绝,同时保留可选字段的 `null` 语义。直接调用 observation 函数不能替代模型可见 schema 的验证;定向用例为 `account_asset_native_function_schema_accepts_later_pages`。
- 账户查询只把当前页安全元数据作为工具文本返回,不把全库作为附件交给 Agent。指定 ID 导入仍先读取账号快照再选取目标;单批数量、下载体积、账号/项目归属、会话、媒体类型和原子登记校验保持有效。绑定画布资源数量与项目文件发现的既有边界不随账户总量限制解除而放宽。无需后端 API、DTO、数据库或持久化迁移;全库传输与解析开销由后续 #574 的服务端分页及按 ID 读取处理,不阻塞 #549 的客户端修复。
- 平台账号导入在下载后重新校验会话并取得身份租约,租约覆盖本地写入、manifest 登记与 revision 推进;提交过程不得再次读取同一登录态互斥锁,避免在身份保护内自锁。身份变更仍须在取得租约时拒绝,取消写入许可仍不得写入。
- 验收覆盖 500/501 项账户快照、按文件夹/关键词查询、偏移超过 500 的后续页、越界空页和大库指定 ID 导入,并复核无效 ID/不支持媒体拒绝、安全投影、取消写入和账号切换。使用 `agent_asset_import_tests`、`account_asset`、`semantic_resource_tools_reject_unreviewed_or_inconsistent_arguments`、`cancelled_import_write_permit`、`platform_session::tests` 定向 Rust 用例及提示词合同测试;模拟平台证据与真实账号验证分别记录。
- 素材读取区分三类来源:`asset.list` / `agc_list_registered_assets` 是当前项目本地 manifest,`agc_list_project_files` / `file.list` 只发现项目目录中实际存在但可能未登记的文件,`asset.library.list` 是当前登录账号素材库,项目画布资源读取是当前网页项目/画布的完整图片清单;账户素材库不能替代项目画布清单。
- Agent 只接收稳定素材 ID、类型、尺寸和项目相对路径等安全投影。客户端负责重新校验账号/项目归属、换签下载、媒体校验,以及 manifest/画布原子登记;不得向 Agent 暴露绝对路径、签名 URL、objectKey、token 或 Cookie。
- `canvas.asset_import` 支持账户/画布资源 ID 和项目内本地相对路径。项目文件发现结果以 `assetImportable` 明确区分当前可登记的已识别图片、字体、音频、视频、文档、代码与**引擎资源**(Cocos Creator 的模型、动画、场景/预制体、材质/特效、图集与压缩纹理容器)与其它文件;Agent 只能提交前者。引擎资源在资源画布上是**只读预览**:模型出缩略图、序列化资源出结构摘要、客户端解不了的容器出类型卡,不承接编辑与派生;`.meta`、`library/`、`temp/` 等引擎生成物仍然只可发现、不可登记。导入拒绝路径穿越、`.agent`、符号链接/reparse point 及敏感配置文件;外部宿主文件须由 UI 原生文件选择器授权后导入,不开放任意绝对路径。
@@ -1612,6 +1626,22 @@ DirectProject 使用 `approvalPolicy=never`,避免每次原生调用再经过
- **素材重命名 UI**:新增 `ResourceRenameDialog`,入口在资源卡选中工具条的 `extraActions`(与「分类与标签」并列),只输入新文件名。前端严格按 `deny_unknown_fields` 只传 `{ projectPath, assetId, newFileName }`;成功后复用 `reloadManifestAfterAssetCommand` 这条既有 manifest 重载路径刷新资源卡与 `@` 面板显示名。资料性边界沿用 Rust 侧口径:不改游戏源码里对旧 `assets/<name>` 的引用。
- **过渡 allowlist 收敛**:`check-config.mjs` 的 `allowedUncalledTauriCommands` 删除 `normalize_local_project_raster_resource`——该命令在 C3 之后的选中工具条里已有真实前端调用方,不再是「无人调用」的过渡项。
- **验证**:AGC 前端全量 1080 passed / 4 skipped / 5 failed(5 条失败全部是 C3 交互改造后仍待更新的既有用例,与本包改动无关:`renders immutable manifest versions…`、`keeps the resource toolbar and canvas interactive…`、`loads registered documents, art media, video, and audio…`、`moves historical resource positions…`,以及 `projectResourceLiveIntegration` 的一条选中按钮选择器);本包新增的 25 条测试(标签库 5、筛选条 3、参考图弹窗 6、参考图模型 7、重命名 2、版本判定 5、版本切换 3,其中 5 条落在共享契约与共享组件目录)全部通过;共享美术画布组件 1385 passed;`cargo check --all-targets` 通过;`asset_rename` 9 passed;`npm run check:encoding` 与 `git diff --check` 干净。
## 素材导入与资源提交的项目锁等待
- 本地素材导入、账户素材下载后的本地提交、资源编辑资产提交及其已完成结果恢复必须吸收短暂项目写锁争用;等待沿用现有有界预算与类型化失败分类。耗尽时报告可读取的持锁方身份,身份不可读时明确说明,不推断锁无人持有。Windows 删除挂起与 ACL 的现有终态判据保持不变。
- 同步取锁、等待、提交和释放在同一个阻塞任务内完成,不占用异步 runtime worker。等待不持有平台登录态互斥锁;取得项目锁后再验证账号身份并持有身份租约覆盖本地提交。导入的原始 WritePermit 在等待后重新校验,取消或过期的许可不能提交。
- 项目锁内重新读取 manifest 与 revision,复核项目和资源身份,保持并行提交无更新丢失。跨进程排他、同线程重入和现有残留回收判据不变,不新增同 PID 豁免。
- 资源编辑继续使用原 operation、幂等键、账本和 staging;本地提交争用不得重发远端生成。阻塞提交开始后,operation 与项目提交互斥 guard 归阻塞任务所有,即使等待它的异步调用被取消也不能提前释放它们。网络请求不在项目写锁内执行。
- 不改变 API、DTO、账本 schema 或已有项目数据,不要求迁移;其它零等待入口按各自专题处理。本节覆盖下文旧事项中本地/账户素材导入与资源提交的部分。
- 验收证据:三条入口在 conversation.write 持锁时等待后成功;等待期间单线程 runtime 心跳继续推进;取消导入零写入;并行提交 manifest/revision 完整;耗尽、权限拒绝、活跨进程锁和残留回收沿用锁测试;远端已完成的资源编辑恢复保持同 operation 且零新增远端请求。真实 Windows 删除挂起行为仍需 Windows 环境验证。
| 行为 | 自动化证据入口 |
| --- | --- |
| 导入等待、账号切换与许可取消 | `commands::agent_asset_import_tests`、`direct_tool_bridge::tests::cancelled_import_write_permit_keeps_files_manifest_and_revision_unchanged` |
| Runtime 与切图登记不阻塞 worker | `runtime_local_import_waits_without_blocking_worker`、`cut_image_registration_waits_without_blocking_worker` |
| 并行提交、超时恢复、取消时互斥生命周期 | `project_mutation_lock_serializes_independent_asset_commits_without_lost_updates`、`resource_commit_timeout_preserves_staging_and_resumes_original_operation`、`cancelled_resource_commit_wait_keeps_operation_and_project_guards` |
| 已下载结果和已提交回包复用、权限与跨进程边界 | `downloaded_resource_commit_and_replay_wait_without_new_remote_work`、`resource_editor::background_removal_tests`、`project_lock_recovery`、`project::write_lock` |
## 2026-09-10 Direct 写通道项目锁等待、持锁方可诊断与权限分类
- `agc_write_file` 是用户直接触发、失败即整轮无法落盘的项目写入通道,原先却用零等待 `acquire_project_write_lock`:任何重叠都在 24-42ms 内被判成“项目正在被其他写操作占用”,而 `file.write / file.patch / file.delete` 等入口用的是约 10 秒有界等待。现统一为 `acquire_game_creator_agent_runtime_project_write_lock_with_wait`:短暂重叠排队等成功,只有预算耗尽才报出带持锁方身份的错误;同一轮并行写多个文件按同一把锁串行。这是 2026-07-22 同一形状修复在 Direct 通道上的补齐,与 2026-08-13 一节“这些结果统一投影为争用并进入既有有界等待”的口径一致。**失败耗时是判据**:几十毫秒说明该入口没等,不是锁没释放。