合并master直连Codex工具链

合入master的直连Codex、受控Skill、工具桥与首页创作入口改造

保留资源画布精修、生成占位拖动与失败任务归档链路

修正三项内置AGC Skill内容指纹并保持审核包版本

对齐master合入后的Rust格式与项目开发前端测试
This commit is contained in:
2026-08-22 15:44:59 +08:00
68 changed files with 6323 additions and 1645 deletions
@@ -95,6 +95,60 @@
- 运行页已直接移除“测试切片”控制行及其本地播放/序号状态和样式,只保留游戏运行画面、信息展示与数值微调;AppSurface 合同同时锁定该控件不再渲染、对应 CSS 不再存在。
- 当前 direct 产物是多文件入口,而历史 `validate_game_html_smoke` 仍按单文件内联 HTML 契约检查;本次 direct 链路不隐藏触发该旧门禁,若要把多文件产物纳入旧门禁需另行设计读取工作区文件的验证契约。
## 7.1 默认纯转发收口(2026-08-19)
### 已确认偏差
- 虽然普通聊天已经调用 `chat_with_game_creator_direct_codex`,`direct_runtime` 仍会在每条消息前自行判断美术、在消息后强制浏览器试玩、二次整改和版本登记。
- 这使“你好”“今天多少号”等非项目消息也被包装成游戏交付任务,用户看到了“准备运行当前本地游戏”“静态烟测”等旧 Runtime 痕迹;已有游戏的普通对话同样被强制拖入完整验收。
### 收口决策
1. 普通客户端默认链路固定为 `客户端消息 -> 同一项目 Codex app-server thread -> 原样可读回复`。客户端不根据关键词、文件存在性或模型回复推断/决定“新建、续做、生成美术、试玩、修复”。Codex 回合确实改动标准游戏文件后,客户端只按磁盘事实做资源与版本投影,不把投影本身当作另一次创作流程。
2. 默认 direct turn 只负责:项目根边界、同线程复用、系统提示词/skills 注入、进程与凭据隔离、协议异常安全错误、消息显示,以及实际文件变更后的确定性客户端投影。它不自动调用陶泥儿生图、浏览器预览、static smoke、二次 LLM 或隐藏返工;没有文件变化的普通聊天不得修改 manifest、revision 或版本。
3. Codex 是唯一执行主体:它根据用户消息、系统提示词、工程结构和自身可用工具判断是否聊天、修改已有游戏、创建游戏或执行验证;客户端不得恢复 Supervisor、专业 Agent、harness 或固定游戏流程作为补偿。
4. 系统提示词必须清楚区分:非项目问题直接正常回答且不触碰工作区;项目修改按需要读写当前项目;用户明确要求生成/验收时由 Codex自行执行或如实说明工具限制。客户端不以“安全”为由把任意消息重写成生成任务。
5. 回归验收至少覆盖同一实际项目中连续发送“你好”“今天多少号”:均不得触发平台美术、预览、试玩、版本登记或文件变更;再发送一个明确项目修改请求,必须仍复用同一 Codex thread 且由 Codex 自行处理,实际变更的 `game/` 文件随后应出现在客户端“游戏代码”和“项目版本”中。
## 7.2 当前桌面端验收的内置 Codex 侧车 staging 修复(2026-08-20)
### 现场问题
- 当前 checkout 执行 `npm run agc` 后,前端 `127.0.0.1:3080`、本地 API `127.0.0.1:8082` 与 SpacetimeDB `127.0.0.1:3101` 均已健康,但桌面壳没有稳定出现。
- 原因是 `src-tauri/build.rs` 每次 Cargo 构建都无条件覆盖 `src-tauri/resources/codex/win-x64/codex.exe` 与 `manifest.json`。Tauri dev watcher 将资源写入识别为源码变化,再次启动 Cargo 构建,形成“构建 -> 覆盖约 300 MiB 侧车 -> watcher 重建”的循环。
### 修复与验收计划
1. 内置 Codex 侧车继续从锁定的 npm 原生包 stage 到正式 bundle resource,保留版本与 SHA-256 完整性清单;但仅当二进制内容实际变化时复制,且仅当清单文本变化时写入。
2. 不取消 `cargo:rerun-if-changed` 对上游侧车与声明文件的监听;上游升级仍必须触发重新 stage,运行时仍拒绝 hash 不匹配的内置可执行文件。
3. 真实回归:从干净的本次 AGC dev 进程重启,确认一次必要的首次构建后不再出现连续的 `codex.exe changed` 重建,Tauri 窗口稳定打开;再完成 direct Codex 普通对话与项目修改的客户端验收。
## 7.3 首页自动创建项目与项目内对话收口(2026-08-20)
### 收口契约
1. 首页保留单一“陶泥儿”创作输入口,并恢复“做游戏 / 做素材 / 做方案”三个创作类型,默认为“做游戏”。这三项只是用户显式选择的创作方向,不是 Agent Runtime 模式、Provider 选择或旧 Supervisor 路由;首页仍不渲染用户或助手消息气泡。
2. 每次提交非空正文或附件时,客户端对且只对本次提交调用一次 `create_automatic_local_game_project`,在系统文档目录的 `Genarrative GameAgent/` 下分配唯一 `gameagent-*` 工作区;不弹目录选择器,也不复用最近项目。
3. 工作区初始化后先把附件导入该项目,再立即进入项目开发工作台;用户原始正文作为 `initialPrompt` 原样交给 project-bound direct Codex thread,选中的 `creationType=game|art|doc` 作为独立结构化首轮上下文传入。客户端不得把类型改写为“初始意图”文本、不得把它拼进用户消息,也不得据此切换 Runtime。意图理解、是否修改工程以及后续验收均由项目内同一 Codex 自主完成,首页不运行 projectless Codex 对话。
4. 项目工作台产品文案统一使用“陶泥儿”“智能创作”,不显示“项目总控”“自动执行”“Supervisor”或“专业 Agent”。客户端只做项目创建、附件导入和确定性投影,不恢复旧多 Agent Runtime。
5. 首页的创建状态只显示在主输入区;“最近项目”使用独立静态说明,不能复用“正在创建工作区 / 正在回复 / 已回复”等全局状态。
### 验收合同
- 三个创作类型必须在桌面与窄视口下可见、可键盘操作并具有明确的选中态;切换类型同步更新输入占位与空输入提示,一次创建收口后恢复默认“做游戏”。
- 普通文本、三类创作需求和带附件需求都必须先创建项目,再在 `陶泥儿项目对话` 中出现同一条原始用户消息与 Codex 回复;首轮 direct command 必须同时携带原样 `prompt` 和受限 `creationType`,`chat_with_game_creator_home_direct_codex` 不得暴露为首页 Tauri handler。
- 连续点击或连续 Enter 只能创建一个工作区;创建进行中按钮禁用,但编辑器不得生成首页聊天气泡。
- 附件必须经 `upload_local_asset` 写入新项目后再交给项目 Codex;不得只把附件元数据留在首页,也不得把浏览器本地路径写入聊天正文。
## 7.4 真实项目验收发现的 Codex 原生组件闭包(2026-08-20)
- 真实创建项目时,Codex 0.147.0 能启动 app-server,但首轮文件修改明确失败为缺少 `codex-code-mode-host.exe`;项目只有初始化占位页,未生成游戏。
- 根因是旧 staging 只复制 `bin/codex.exe`,没有保留同版本 npm 原生包依赖的 code-mode host、`rg`、command runner、sandbox setup 和 `codex-package.json` 相对布局。
- Windows x64 内置资源现按固定白名单 stage 完整原生组件闭包;清单升级为 `genarrative-codex-sidecar.v2`,逐文件记录并校验 SHA-256,Tauri resources 保持 `bin/`、`codex-path/`、`codex-resources/` 布局。资源映射只属于 `tauri.windows.conf.json`,通用配置不得让其他平台在 Tauri build script 阶段校验 Windows 专属文件。API Key、登录状态和用户配置仍不进入安装包。
- 同次真实验收还发现 direct 项目页的可访问名称残留“项目总控”;视觉文案虽已是“陶泥儿”,读屏仍会暴露旧产品模型。direct 分支现统一使用“陶泥儿项目对话 / 陶泥儿消息 / 陶泥儿实时回复 / 陶泥儿对话内容”,旧名称只保留给显式 legacy 诊断入口。
- 修复后同一客户端已真实写入 `game/index.html`、`game/style.css`、`game/game.js`。客户端必须继续把这次真实文件变化确定性登记为游戏代码和项目版本;该步骤不启动 Supervisor、harness、平台美术或二次 LLM。
- direct 产品入口的显式“播放”只做用户授权、本地路径/权限边界和预览服务器启动,不再先执行旧 `game.static_smoke` 的 Canvas-only 形态合同;DOM、Canvas、WebGL 及外链 `game.js` 均可进入客户端运行视图。显式 legacy `/smoke` 与旧诊断入口仍保留原严格检查,不能冒充真实浏览器试玩。
## 8. 陶泥儿美术闭环与资源分类收口(2026-08-16)
### 问题
@@ -245,3 +299,61 @@
2. 若本机目录预检失败,客户端返回稳定的“本机开发者凭据存储目录未安全初始化;未创建远端凭据”分类,不请求远端创建接口、不发起美术生成、不写 operation 或账本,也不刷新登录态或自动重试。
3. 远端响应后原子写入仍可能因并发或磁盘故障失败;该极窄路径必须单独分类为“凭据已创建但未能安全保存”,提示用户在账户开发者凭据页面撤销后再试,不能自动创建第二把凭据。诊断和正式 UI 只展示上述安全摘要与恢复建议,不包含 access token、开发者凭据、响应正文、绝对路径或签名 URL。
4. 验收先在当前失败项目上恢复:对遗留的空且 owner 不匹配目录做可恢复隔离后,再复用同一项目发送“继续完成此前三消游戏”。成功标准包括本机私钥存在但不读取其内容、平台素材与版本登记完成、desktop/mobile Chromium 试玩证据和隔离进程恢复;此前已创建但无法恢复的远端孤儿凭据作为明确剩余风险,绝不自动撤销。
## 14. 审核 AGC Skill Pack、按需加载与真实工具内核(2026-08-20)
### 14.1 目标架构
普通项目链路固定为 `薄 Runtime + Codex 唯一执行 + 按需 Skill + 真实工具`。Runtime 不再通过关键词、固定步骤或产物字符串计数替 Codex 判断用户意图,也不恢复 Supervisor、专业 Agent 或 harness;它只负责工作区、凭据、不可逆副作用、进程协议和确定性客户端投影。
系统提示词只保留最小核心约束、当前项目文件的有界快照和一份审核 Skill 索引。不得再把项目中的 `.codex/skills`、`.agents/skills`、`.hermes/skills` 全文批量拼入 64 KiB 提示词,也不得把主站全部 Skill 复制给普通游戏项目。完整 `SKILL.md` 与直接引用文件由 Codex 原生 Skill 机制在命中意图后按需读取。
### 14.2 审核索引与五类 Skill
客户端内置 `agc-skill-pack.v1` 清单。每项只公开名称、用途、触发条件、所需工具、版本和内容 SHA-256;审核文件变化时必须在同次变更重算对应指纹。启动时逐文件复核清单和编译进客户端的内容,任何缺失、额外文件、路径越界或指纹不匹配都失败关闭;路径边界显式拒绝反斜杠、Windows 盘符、UNC、绝对路径和 `..`,不能因测试运行在 Linux 就把 Windows 绝对路径当作普通相对文件名。审核包只包含:
1. `agc-project-structure`:项目根、`game/`、`assets/`、`.agent/` 的职责和禁止创建平行项目的约束。
2. `taonier-art-assets`:陶泥儿标准美术包、平台来源、警告语义和真实素材使用;`grid-2x2` 与四切片只是推荐路径,不是所有游戏的完成门。
3. `agc-web-game-development`:根据当前需求自由选择 DOM、Canvas 或 WebGL,并完成可玩的 HTML/CSS/JavaScript 实现。
4. `agc-browser-playtest`:调用客户端提供的真实双视口浏览器工具,读取截图、控制台、网络、Canvas/WebGL 和交互证据后自行修复。
5. `agc-client-projection`:解释客户端如何按磁盘事实投影代码、素材、revision 和版本;Codex 不直接伪造或改写 manifest 中的平台身份。
`genarrative-external-editor-api` 的异步、凭据、operation 和 warning 语义经审核后融入 `taonier-art-assets`;不把原始主站技能目录直接暴露给游戏项目。`gpt-image-2-apimart` 只有在对应受控工具真正配置时才能作为显式备用能力,首版不以文字假装可用。`genarrative-play-type-integration`、SpacetimeDB、微信支付和其它主站工程 Skill 明确排除。
### 14.3 渐进加载实现
DirectProject app-server 启动前,把上述审核包安装到本次隔离 HOME 的 `.agents/skills/`;DirectHome 不安装项目创作 Skill,也不暴露项目工具。Codex 首轮只得到五项元数据和索引,不得到完整正文;触发后由原生 Skill 读取对应 `SKILL.md`,引用最多一层且只能命中清单文件。项目内任意 Skill 不再由 AGC 提示词构建器主动读取或拼接。
Skill 包版本与内容指纹参与 DirectProject app-server 连接池身份。客户端升级或 Skill 内容变化后必须建立新进程/新 thread,不能复用旧目录中的过期 Skill;同一版本的连续聊天仍复用同一 Codex thread。
### 14.4 真实工具与安全边界
DirectProject 仅配置客户端自身的本地 stdio MCP,首版暴露三个受控工具:
- `agc_read_skill_resource`:只读取审核清单中某个 Skill 直接声明的一层 `references/*.md`;不接受绝对路径、`..`、未声明文件、主站 Skill、项目文件或宿主文件。它补足禁用通用 shell 后的渐进引用读取能力,不扩大工作区权限。
- `taonier_prepare_game_art`:按 Codex 提供的游戏 brief 创建或恢复陶泥儿标准美术包。工具内部继续使用当前 External v1 请求、持久生成账本、稳定幂等键和 `operationId`;未知提交只轮询或以原请求/原 key 恢复,绝不因模型重试重新扣费。完整可信图集缺切片时返回 warning 并保留完整图集,不能伪造切片或阻断后续代码实现。
- `agc_browser_playtest`:由当前客户端启动 loopback 预览和受限 Chromium,对 desktop/mobile 采集真实截图、页面状态、控制台异常、失败请求、Canvas/WebGL 图片使用与有限交互探针,并把结构化证据和截图作为工具结果返回 Codex。该工具不使用旧固定玩法 harness。
MCP 子进程复用当前客户端二进制的专用无窗口模式,从工作目录取得唯一项目根;命令行不传项目路径或凭据。它只处理 MCP 和审核引用读取;真实浏览器与付费美术通过随机 loopback 地址回到持有项目上下文的客户端主进程执行,避免 Codex 隔离用户环境阻断 Chrome,也避免把 GUI 登录态复制给子进程。陶泥儿开发者 Key 只由客户端主进程按受信任 origin 从当前用户私有文件读取并在内存中使用,不进入 Codex 环境变量、系统提示词、argv、项目文件、日志或工具结果。凭据缺失时工具返回可行动的“先在客户端登录并准备本机开发者 Key”,不得假装生成成功。
DirectHome 继续禁用 MCP、命令和写入。DirectProject 仍禁用通用 shell、任意网络和多 Agent;文件修改只走 Codex 受限原生能力,外部副作用只走上述本地工具。付费生成、路径权限、文件事务、图片下载/解码、来源身份和客户端投影继续由确定性代码守住。
### 14.5 验收合同
- Rust 单测:清单五项精确、SHA-256 匹配、路径无越界;新项目没有本地 Skill 目录仍能安装审核包;DirectHome 不安装;项目中的主站/SpacetimeDB/支付 Skill 不进入系统提示词。
- 提示词测试:普通问候只包含索引,不包含任一完整 Skill 正文;美术 Skill 正文由 Codex 原生触发读取;API Key、Bearer、auth.json、宿主绝对路径不进入上下文。
- fake app-server:DirectProject 配置本地 MCP 且 DirectHome 保持 `mcp_servers={}`;连续回合复用 thread;MCP item 可完成而不是被当成协议违规;无 Supervisor/child/harness。
- MCP 协议测试:initialize、tools/list、tools/call 均为有界 JSON-RPC;未知工具、路径越界、缺凭据明确失败;美术调用复用同一账本/operation,不重复提交;浏览器调用返回双视口真实报告和截图内容。
- 回归:typecheck、AppSurface、Rust 定向与完整串行测试、编码检查、rustfmt 和 diff check 全部通过。
- 真实客户端:从当前 checkout 新建项目,由同一项目 Codex thread 自主选择陶泥儿美术 Skill、调用真实平台工具、写入游戏、调用真实浏览器试玩并按证据修复;客户端最终显示平台美术、游戏代码和项目版本。单独验证“你好”“今天多少号”不调用美术或浏览器工具、不改文件、不登记版本。
### 14.6 当前实施与验收状态(2026-08-20)
- 五项审核 Skill 已由版本化清单和逐 Skill SHA-256 编译进客户端;DirectProject 初始化后显式调用 `skills/extraRoots/set` 与 `skills/list`,缺项或解析错误直接失败。DirectHome 不安装该包。项目内 `.codex/.agents/.hermes` Skill 正文不再被系统提示词批量拼接。
- 本地 `agc_tools` MCP 已实际暴露 `agc_read_skill_resource / taonier_prepare_game_art / agc_browser_playtest` 三项工具并固定自动审批;引用读取严格限制为清单内一层 Markdown。真实 `gpt-5.6-sol max` 回合已读取 `agc-project-structure` 的直接引用并正确返回路径边界。
- 浏览器和美术副作用由随机 loopback 工具桥回到客户端主进程;真实 Codex 工具调用已得到 desktop/mobile `readyState=complete`、整体 `passed=true` 与 2 张截图。普通“你好,今天多少号”真实回合只回答日期,游戏文件、manifest、revision 均未变化。
- 开发网关会在 API Key Responses 成功响应中附带 `X-Codex-*` ChatGPT 额度头;隔离 app-server 会把它误判为余额 0。Direct conversation 现经只接受 Bearer `/responses` 的 loopback 流式代理转发,并剥离该组账户头;真实回合从 `usage-limit-exceeded` 恢复为完成。旧 ToolHost 不经过此代理。
- 2026-08-21 真实客户端复跑已由当前登录会话为所选服务端建立新的私有开发者 Key;旧失效文件只改名保留,不读取、不打印也不提交。Codex 经 `taonier_prepare_game_art` 成功生成并登记 `assets/art-spec.png`、`assets/direct-game-background.png` 与 `assets/art-spritesheet.png`,三项均带平台 Canvas 来源身份。首次回合中第三个 `art-spritesheet` operation 已以稳定幂等键受理;重启客户端后只恢复该 operation,随后再次调用完整美术包时仍只有同一账本和 operation,三个 PNG 时间戳不变、账户泥点不再下降,工具两次均返回 `status=completed`、3 个 `assetPaths`、3 张图片且无 warning。
- 同一真实项目已由 Codex 把平台背景、规范图棋子和核心图集实际接入 `game/index.html / style.css / game.js`。真实 Chromium 报告 `passed=true`:desktop/mobile 均为 `readyState=complete`、Canvas 非空、无 console error 与 exception;desktop 仅有非致命 `favicon.ico` 404。两张截图确认桌面和手机均完整显示甜点星球三消画面,且结构化运行时证据观察到平台图片进入渲染。
- 真实复跑同时暴露并修复两个收尾缺陷:DirectProject 不能沿用普通 LLM 的 180 秒整回合超时,现改为 15 分钟基础空闲窗口、MCP 工具活动期 110 分钟空闲窗口、整个 turn 120 分钟硬上限;DirectHome 与旧 ToolHost 继续保持原超时。系统提示词和浏览器整改回灌同时明确 shell/unified_exec 被安全禁用时应使用已注入的游戏文件快照与结构化证据,不得误报“没有读取工具所以无法验收”,也不得要求 Codex 直接保存 `.agent` 版本。定向回归为 Direct Runtime 35/35、Codex app-server 23/23(另 1 项真实账号测试按设计 ignored)。
- 最后一轮改后 GUI 复验在桌面控制被物理 Escape 中止后未继续自动操作;非 UI CLI 又因不继承 GUI 登录态而得到 `usage-limit-exceeded`。因此本节只把已落盘的真实生图、幂等复用和双视口浏览器证据记为已完成,不把改后最终聊天回复或新增项目版本伪报为已验收;下次从当前客户端发送普通项目消息即可复核新的等待窗口与证据回灌文案。
+48 -5
View File
@@ -45,6 +45,7 @@
- 处理:让每个固定分区在自己的 `.game-resource-plane` 中拥有独立 SVG,卡片与路径都直接使用布局逻辑坐标并共享父级 CSS scale / 原生 scroll;viewport 原生 overflow 负责本区裁剪。DOM 测量只换算本区逻辑 viewport,用于完整路径、incoming / outgoing 继续线和两端离屏隐藏,不参与端点身份或主路径坐标。每区 observer 和 RAF 各至多一个,卸载时清理。
- 验证:同时挂载至少两个分区和各自同类型关系,断言每条边只存在于对应分区 SVG;只滚动其中一分区,另一分区的逻辑 viewport 与 path 不变。另覆盖缩放后 SVG / 卡片仍在同一 plane、双向离屏继续线、两端离屏隐藏、marker、自环以及 mode / 项目切换清理。
- 关联:`apps/ai-game-creator-shell/src/view/project-development/ResourceDependencyOverlay.tsx`、`apps/ai-game-creator-shell/tests/ResourceDependencyOverlay.test.ts`、`docs/prd/【AI游戏创作】项目开发工作台PRD-2026-07-20.md`。
## 正式保存不能等待 React state 才取得草稿 CAS 的新 revision
- 现象:用户刚完成编辑就点击“保存到项目”,自动草稿保存已经成功,但正式提交仍携带旧 `expectedDraftRevision`,于是单窗口也得到 draft revision conflict;快速连续保存时还可能使用不同 commitId 重复 staging。
@@ -666,12 +667,12 @@
- 验证:`npm run test -- src/components/image-editor/ImageCanvasEditorModel.test.ts src/components/image-editor/ImageCanvasInteractionModel.test.ts`,并在多素材画布拖拽时确认参考线仍能命中邻近图层且 pointermove 不再明显掉帧。
- 关联:`src/components/image-editor/ImageCanvasEditorModel.ts`、`src/components/image-editor/ImageCanvasInteractionModel.ts`、`docs/technical/【前端架构】图片画布编辑器MVP接入方案-2026-06-11.md`。
## 图片画布视口拖动卡顿先查自动保存和小地图合帧
## 图片画布拖动卡顿先查 Stage 合帧和交互期自动保存
- 现象:素材多或序列帧多时,拖动小地图视口框或手型平移明显卡顿,像是接口慢或 CSS 动画掉帧,但网络请求不一定异常。
- 原因:`pointermove` 高频修改 `viewport` 会触发画布重渲染、小地图模型重算和工程持久化 effect;持久化链路会同步 `serializeCanvasLayout`、`JSON.stringify` 并写 sessionStorage。远端 PATCH 有防抖也挡不住本地同步缓存写入。
- 处理:把 viewport 拖动标记为临时交互;拖动中只更新画布显示,不触发项目保存、session cache 写入或封面快照上传,`pointerup` / `pointercancel` 后保存最终 viewport。小地图拖动的 `updateViewportFromMinimapDrag` 必须用 `requestAnimationFrame` 合帧,结束拖拽时 flush 最后一帧。
- 验证:`npm run test -- src/components/image-editor/useImageCanvasViewportControls.test.tsx src/components/image-editor/useImageCanvasStageInteractions.test.tsx src/components/image-editor/useImageCanvasProjectPersistence.test.tsx --reporter verbose` 应覆盖小地图拖动合帧、平移 / 小地图 viewport 交互边界,以及拖动期间不写 sessionStorage / 不调用 `saveEditorProjectLayout`。
- 现象:素材多或序列帧多时,拖动图层、生成占位、小地图视口框或手型平移明显卡顿,像是接口慢或 CSS 动画掉帧,但网络请求不一定异常。
- 原因:高刷新率输入设备会在单个屏幕帧内发出多次 `pointermove`;每次直接 `setLayers` / `setViewport` 都会触发画布重渲染、吸附或小地图模型重算和工程持久化 effect。即使 `moveLayersFromDrag` 保留未移动图层的对象引用,若 WorldView 仍在每帧重建全部图层子树,所有真实位图的 URL hook、加载态、标签和 SVG 操作也会重复执行。持久化链路还会同步 `serializeCanvasLayout`、`JSON.stringify` 并写 sessionStorage,远端 PATCH 有防抖也挡不住本地同步缓存写入。
- 处理:Stage 的图层、生成占位、框选和手型平移统一用单一在途 `requestAnimationFrame` 合并同帧输入,只应用最新坐标;结束拖拽时 flush 最后一帧,主动清理和卸载时 cancel。图层、生成占位、平移和小地图拖动一旦越过拖动阈值就标记为临时交互,拖动中不触发项目保存、session cache 写入或封面快照上传,`pointerup` / `pointercancel` 后保存最终布局。WorldView 的完整单图层节点必须按稳定 layer 对象浅比较 memo,父回调通过 latest ref 的稳定门面转发,避免未移动图层重渲染或读取陈旧闭包。小地图继续只在 viewport controls 内合帧,不要重复套 rAF。
- 验证:`npm run test -- src/components/image-editor/ImageCanvasWorldView.test.tsx src/components/image-editor/useImageCanvasViewportControls.test.tsx src/components/image-editor/useImageCanvasStageInteractions.test.tsx src/components/image-editor/useImageCanvasProjectPersistence.test.tsx --reporter verbose` 应覆盖只重渲染移动图层、稳定节点调用最新回调、同帧只保留最新坐标、结束前 flush、卸载 cancel、小地图无双重合帧、图层 / 生成占位 / 平移 / 小地图交互边界,以及拖动期间不写 sessionStorage / 不调用 `saveEditorProjectLayout`。浏览器验收必须使用多个独立 raster URL,并区分 rAF 心跳与目标实际位置变化帧;共享 data URI SVG 和包含空闲尾帧的自由 rAF 不能作为拖动流畅证据。
- 关联:`src/components/image-editor/useImageCanvasViewportControls.ts`、`src/components/image-editor/useImageCanvasStageInteractions.ts`、`src/components/image-editor/useImageCanvasProjectPersistence.ts`、`docs/technical/【前端架构】图片画布编辑器MVP接入方案-2026-06-11.md`。
## 图片编辑器宣发素材生成器刷新后不要丢快照
@@ -4215,6 +4216,27 @@
- 处理:CONNECT 一开始就为 client socket 注册 `error / close`,解析完成后为 upstream socket注册同样的双向销毁处理;DNS 返回、写 200 和开始 pipe 前都检查 client 是否已销毁。任一端 error、close 或 timeout 都幂等 destroy 两端,不把普通客户端 reset 写成错误日志。不要用进程级 `uncaughtException` 吞掉问题,也不要只增加 npm/Cargo 重试掩盖 gateway 崩溃。
- 验证:在独立 canary 和正式 gateway 上分别并发制造至少 500 次“CONNECT 后立即断开”,随后确认容器仍运行、restart count 不增加、日志无 EPIPE;再通过同一 proxy 对 npm registry 与 crates index 建立完整 TLS 隧道。切换前仍须确认 Gitea 无活跃 run 且 Runner 内层无 job 容器。
## 独立 AGC lockfile 不能丢失可选 WASM 包的 bundled 依赖节点(2026-08-21)
- 现象:`npm ci --prefix apps/ai-game-creator-shell` 在安装前失败,报告 lockfile 缺少 `@emnapi/core` / `@emnapi/runtime`;错误版本可能是 registry 当前满足 `^1.11.1` 的最新版,而不是原 lock 中曾记录的版本。
- 原因:重写或解决 `apps/ai-game-creator-shell/package-lock.json` 冲突时,保留了 `@tailwindcss/oxide-wasm32-wasi` 对 bundled `@emnapi` 包的声明,却删掉了对应嵌套 package 节点。npm 会重新解析当前 registry 版本并判定 manifest 与 lock 不同步;这不是单一 npm 版本问题,也不表示应用应直接依赖两个 `@emnapi` 包。
- 处理:只在最新目标分支执行 `npm install --package-lock-only --ignore-scripts --prefix apps/ai-game-creator-shell`,保留 npm 对 bundled 节点及 `peer` / `optional` 标记的完整规范化结果;确认子包 `package.json` 没有变化,不要手工只补报错中的两个版本。
- 验证:至少用 Jenkins 对应 npm major 和当前开发 npm 分别执行干净的 `npm ci --prefix apps/ai-game-creator-shell`,再运行 AGC typecheck、编码检查和 `git diff --check`;根目录 `npm ci` 不能替代独立子包 lock 验证。
## Windows 专属 Tauri resource 不能写进通用配置(2026-08-21)
- 现象:Linux CI 已完成 AGC `npm ci`,却在 Tauri custom build command 中报 `resources/codex/win-x64/...exe doesn't exist`;Windows 侧车的 Rust staging 受 `cfg(windows)` 保护,因此非 Windows 构建不会生成这些文件。
- 原因:Tauri 会在所有平台校验通用 `tauri.conf.json` 的 bundle resource 源路径;把 Windows x64 资源映射写进通用配置,等于要求 Linux / macOS 也预先拥有不属于其安装闭包的 Windows 可执行文件。
- 处理:通用配置只保留跨平台 bundle 项;Windows 原生侧车的完整白名单放入 Tauri 自动合并的 `tauri.windows.conf.json`。不要提交二进制占位文件,也不要让非 Windows build script 下载或伪造 Windows 资源。
- 验证:配置门禁断言通用配置没有 Windows resource、Windows 平台配置保留完整固定白名单;Linux 运行原生壳门禁必须越过 Tauri resource 校验,Windows release 仍由 build script 对 npm 原生包、SHA-256 清单和目标布局失败关闭。
## AGC Skill 指纹与相对路径校验必须跨平台一致(2026-08-21)
- 现象:内置 Skill 文件集合没有缺失,原生测试却统一报内容指纹不匹配;另一个测试在 Linux 上把 `C:\\temp\\SKILL.md` 判为安全相对路径,受控资源工具可能继续处理 Windows 盘符或反斜杠遍历形式。
- 原因:审核文件定稿后未按最终字节重新生成 manifest SHA-256;同时 `std::path::Path` 只按当前宿主语义解析路径,Linux 不会把 Windows 盘符和反斜杠视为绝对路径或分隔符。
- 处理:Skill 文件变化与 manifest 指纹更新必须同次提交,并提升审核包版本;资源引用只接受使用 `/` 的普通相对段,显式拒绝反斜杠、冒号盘符、UNC、绝对路径和父目录段,再查询审核清单。不要先把反斜杠替换成 `/` 后再做安全检查。
- 验证:逐项按排序后的 `relativePath + NUL + file bytes + NUL` 重算并核对 manifest;Rust 单测同时覆盖 POSIX 绝对路径、`..`、`C:\\...`、`C:/...`、UNC 和反斜杠相对路径,受控 MCP 工具也必须把 Windows 绝对路径投影为 `isError=true`。
## Gitea CI 预构建镜像不能只靠 tag 判断内容
- 现象:宿主已重建带日期修订 tag 的 `genarrative/gitea-project-ci` 镜像,但 `genarrative-ci` job 仍跑旧内容,或直接报 image not found;另一种危险操作是只改 runner label,没把对应镜像装入 rootless runner 的内层 Docker。
@@ -4815,3 +4837,24 @@
- 处理:只有后继事务 committed、项目/草稿/资源身份一致、旧 after 与后继 before 精确衔接、后继 after 与当前 manifest/revision 精确一致、两份候选文件与 manifest 唯一引用都验证通过时,才把旧事务标为 `superseded`;候选文件和审计记录都保留。任何证据不完整继续失败关闭。
- 门禁:同一资源存在 prepared 或 reconciliation 事务时,新的“设为正式图”提交必须先被拒绝并引导安全恢复,不能继续制造另一笔可能覆盖旧结果的提交。`committed/rolled-back/superseded` 是可继续后续提交的终态。
- 关联坑:正式文件路径会追加 commitId,重新打开 refine 时不能把整个文件 stem 当作下一次素材名,否则多次精修后超过 80 字符并阻塞提交。路径只推导显示名,且必须循环剥离历史 `--<uuid>` 后缀;确定性名称/用途校验要发生在读取候选与 staging 前,并按输入错误处理而不是进入事务恢复。
## 隔离 Codex app-server 会误吃代理的 ChatGPT 额度头(2026-08-20)
- 现象:同一自定义 Responses endpoint 和 API Key 直接 HTTP 为 200,普通用户 HOME 下的 smoke 也完成,但隔离 `CODEX_HOME/HOME` 的 app-server 在真正发请求前返回 `usageLimitExceeded`,并投影 credits balance 0。
- 原因:开发网关把 `X-Codex-*` ChatGPT 账户额度头附在 API Key Provider 响应上;隔离进程没有用户 ChatGPT 额度状态覆盖,Codex 0.147 将这些头当作本地账户限制。模型、Key、MCP 和 Skill 均不是根因。
- 处理:只为 Direct conversation 启动随机 loopback `/responses` 流式代理;它不注入 Authorization,只转发请求自带 Bearer,拒绝其它方法/路径并剥离 `X-Codex-*` 账户头。不要复制用户 `auth.json` 来掩盖问题,也不要把 Provider 切换当根因修复。
- 验证:同时记录上游直接 200、未过滤时 credits=0/usage-limit、过滤后真实 turn completed;代理测试必须证明无 Bearer 拒绝、路径收窄、正文流式保留和额度头不下传。
## Codex MCP 子进程不适合直接启动桌面浏览器(2026-08-20)
- 现象:同一 `agc_browser_playtest` 在普通进程中能返回双视口截图,但从 Codex 启动的 STDIO MCP 子进程调用时 Chrome 启动超时。
- 原因:MCP 子进程继承隔离 HOME/AppData 和 Codex 进程约束;把真实浏览器或 GUI 登录态硬塞给子进程既不稳定,也扩大凭据边界。
- 处理:STDIO MCP 只做 schema 与协议适配;浏览器和付费美术通过随机 loopback 工具桥回到持有项目、登录态和正常桌面环境的客户端主进程。桥只绑定当前项目、限制请求大小和审核工具名,返回脱敏文本与有界 PNG。
- 验证:必须从真实 Codex thread 发起 MCP 调用并观察 desktop/mobile `readyState=complete` 与两张截图;直接运行 MCP 二进制成功不能替代该链路。
## 独立 Cargo workspace 的测试增量缓存会吞噬数百 GiB(2026-08-22)
- 现象:`server-rs/target` 与 AGC `src-tauri/target` 合计超过 `231 GiB`;其中两个 `debug/incremental` 约 `158.5 GiB`,server-rs 累积 `1298` 个增量会话目录,AGC 累积 `100` 个。
- 原因:两个 Cargo workspace 拥有独立 target 和锁文件,AGC 又以 path dependency 复用若干 server-rs crate;更主要的是全量 / 分组 `cargo test` 继承增量编译,每组 crate / feature / profile hash 都可以留下新会话,Cargo 不会按仓库期望自动收缩这些历史目录。
- 处理:保留两个 workspace 的产品 / 发布边界;两边 `[profile.test]` 关闭 incremental 并固定 `debug=1`,AGC dev profile 与 server-rs 对齐调试信息级别。日常用 `npm run audit:rust-build-cache` 只读核对;需要回收时先停止 Cargo / rustc,再显式运行 `npm run clean:rust-incremental -- --apply`,只删两个固定增量目录。
- 验证:清理前后各跑一次只读审计并核对磁盘可用空间;分别运行 server-rs 与 AGC 定向 `cargo test`,确认 test profile 不再生成持久 `debug/incremental` 堆积。共享 `CARGO_TARGET_DIR` 必须另做并发启动基准,不得为节省磁盘直接改变生产产物路径。
@@ -92,7 +92,7 @@
- 吸附阈值以屏幕像素为准,换算到世界坐标后参与拖拽计算;边缘 / 中心线和等距吸附共用同一阈值。拖拽结束后只保存最终图层或生成占位布局,不保存临时参考线。
- 项目页封面和画布图片图层必须先渲染项目卡、图层外框、标题、尺寸和操作 chrome;图片换签或解码未完成时,只在图片区域显示轻量加载态,不阻塞外框和文字等低成本信息先出现。
- 素材量增大时,拖拽吸附热路径不得对所有素材做全量两两配对。边缘 / 中心线吸附保持线性扫描;等距吸附只在跨轴相交且轴向邻近的候选图层之间计算,避免大量远处素材拖慢 pointermove。
- 画布自动保存使用防抖 + 串行队列:图层拖拽、缩放、资源新增和修改结果创建后延迟保存工程快照;如果上一次 `PATCH /api/editor/projects/{projectId}` 尚未完成,只保留最新待保存快照,待当前请求结束后再发送下一次保存,避免慢保存请求并发堆积触发发布入口连接限流。手型平移和小地图拖动属于临时 viewport 交互,拖动中只更新画布显示,不触发 `serializeCanvasLayout`、sessionStorage 项目缓存写入或封面快照上传,`pointerup` / `pointercancel` 后再保存最终 viewport。每次 `PATCH /api/editor/projects/{projectId}` 都必须携带最近一次服务端权威快照或保存 ack 给出的 `expectedRevision`;缺少版本号的请求在 HTTP 写入口直接拒绝,不允许回退到无版本覆盖。接口只返回 `{ projectId, canvasId, revision, updatedAt }` 轻量 ack,不返回完整 project;前端用 ack 更新后续保存版本。生成完成或显式读取返回较新权威快照时,若同项目仍有防抖待保存或在途保存的本地布局,前端必须以新快照的资源和生成终态为权威,只重放本地几何、层序、分组、隐藏、锁定、翻转、viewport、背景色和生成面板编辑,并立即基于新 revision 入队保存;后端新增项必须合入,后端已删除的旧项不得被本地旧快照复活,本地在请求期间删除的旧项也不得复活。
- 画布自动保存使用防抖 + 串行队列:图层拖拽、缩放、资源新增和修改结果创建后延迟保存工程快照;如果上一次 `PATCH /api/editor/projects/{projectId}` 尚未完成,只保留最新待保存快照,待当前请求结束后再发送下一次保存,避免慢保存请求并发堆积触发发布入口连接限流。图层、生成占位、手型平移和小地图拖动都属于临时画布交互,拖动中只更新画布显示,不触发 `serializeCanvasLayout`、sessionStorage 项目缓存写入或封面快照上传,`pointerup` / `pointercancel` 后再保存最终布局或 viewport。每次 `PATCH /api/editor/projects/{projectId}` 都必须携带最近一次服务端权威快照或保存 ack 给出的 `expectedRevision`;缺少版本号的请求在 HTTP 写入口直接拒绝,不允许回退到无版本覆盖。接口只返回 `{ projectId, canvasId, revision, updatedAt }` 轻量 ack,不返回完整 project;前端用 ack 更新后续保存版本。生成完成或显式读取返回较新权威快照时,若同项目仍有防抖待保存或在途保存的本地布局,前端必须以新快照的资源和生成终态为权威,只重放本地几何、层序、分组、隐藏、锁定、翻转、viewport、背景色和生成面板编辑,并立即基于新 revision 入队保存;后端新增项必须合入,后端已删除的旧项不得被本地旧快照复活,本地在请求期间删除的旧项也不得复活。
- 移动端保留同一套状态模型,底部工具栏可横向滚动,侧边栏默认可收起。
- 项目页卡片默认点击打开工程;hover 项目卡片右下角显示 `...` 菜单,菜单承载重命名和删除。选择模式下项目卡片只切换选中态,不进入画布;底部批量工具栏提供全选 / 取消全选、已选数量、批量删除和退出选择模式。
@@ -219,7 +219,7 @@
- 素材面板支持按素材名、文件夹名、生成信息、用户可见模型、任务和媒体类型搜索,并支持选择模式框选。选择模式的选中集合以全部上传完成且媒体地址有效的可选素材为有效性边界,不因搜索、折叠或展开变化而收缩;只有素材被删除、进入上传中 / 失败态或媒体地址失效时才剔除对应选择及范围锚点。素材缩略图、标题、元数据和卡片空白区统一作为整行选择命中区:鼠标、键盘、触摸和笔输入单击都只切换当前素材,不替换其它已选素材;`Shift + 点击` 按当前可见顺序把连续区间增量加入现有选择,锚点当前不可见时退化为切换目标素材并建立新锚点。当前搜索结果的全选 / 取消全选只增量增删当前已展开的可见素材并保留其它选择,同时清空上次单项选择的范围锚点。触摸素材卡仍可切换选中态,但触摸列表空白区必须继续滚动,不能捕获为框选;鼠标 / 笔框选坐标必须包含列表滚动偏移,`pointerup` 提交最后坐标,`pointercancel` 只取消。内置、上传未完成、上传失败或无可读来源的素材行不得暴露可用的选择按钮。退出选择模式、关闭素材栏或切换到图层栏时必须同时清空选择锚点、选中集合和框选状态,非选择模式不得残留选中高亮。
- 素材选择模式的批量工具栏是素材列表滚动区之外的固定底栏,始终显示跨搜索与折叠状态保留的全部已选数量、当前可见素材全选 / 取消全选、下载、删除和取消;下载和删除作用于完整选中集合,不得只消费当前可见 ID。删除集合中存在当前未显示素材时,必须先用危险确认弹窗明确展示全部删除数量和未显示数量,确认目标使用打开弹窗时的素材 ID 快照;选择集合、可见集合或选择模式漂移后关闭旧确认弹窗,确认前不得执行删除。工具栏自身禁止横向溢出和滚动,空间不足时按钮在工具栏内部换行。不得把工具栏作为滚动列表末项或依赖 `position: sticky` 的自然位置。移动端进入素材选择模式时必须提高素材侧栏高度并允许素材列表纵向滚动,为固定底栏之上至少保留一张素材卡的可操作空间,同时受当前视口高度上限约束,不得在横屏或嵌入式短视口中挤占画布。选择模式隐藏单素材下载 / 重命名动作,进入时清理已有拖拽 / 投放状态,并同时阻断素材行、文件夹空白区的内部素材移动和外部文件投放以及右键菜单,避免批量意图回退成单素材操作。Provider 与 `isEditorInternalProcessingModel(...)` 识别的内部处理模型不得进入搜索索引,避免出现隐藏字段可命中或命中但无可见匹配字段;原始审计元数据只保留给服务端和后台管理读取,普通用户(包括素材 owner)不得通过响应取得。
- 图层面板支持按图层名、生成信息、用户可见模型、任务和媒体类型搜索;Provider 与内部处理模型同样不得进入搜索索引。普通用户图层快照也不得携带这些内部字段。支持选择多个图层后创建图层组,组名和 groupId 随画布布局保存。
- 小地图支持拖拽视口框,拖动时画布 viewport 跟随移动;`pointermove` 更新必须通过 `requestAnimationFrame` 合帧,结束拖拽时 flush 最后一帧,避免高频 pointermove 直接压垮 React 渲染和项目持久化链路。
- 小地图支持拖拽视口框,拖动时画布 viewport 跟随移动。Stage 中图层、生成占位、框选和手型平移的高频 `pointermove` 必须通过单一在途 `requestAnimationFrame` 合帧,同一帧只保留最新坐标;`pointerup` / `pointercancel` 必须 flush 最后坐标,主动清理或卸载必须 cancel,避免迟到回调。图层移动结果必须保留未移动 layer 的对象引用,WorldView 的完整单图层子树按该引用和选中、悬浮、生成、菜单等标量状态浅比较 memo;父级事件回调通过读取最新实现的稳定门面转发,不能因 callback identity 变化击穿全部图层 memo,也不能用自定义比较忽略回调后留下陈旧闭包。小地图保留 viewport controls 内部的单层合帧,不得在 Stage 再套一层 rAF 增加一帧延迟。性能验收使用多个独立 raster 图片 URL、外部可信 pointer 输入和实际位置变化帧,单独运行的 rAF 心跳、重复 data URI SVG 或拖动结束后的空闲帧不得计作拖动 FPS。
- 鼠标滚轮默认按设备原始 `deltaX / deltaY` 二维平移画布视口;当按住 Shift 且设备上报 `deltaX = 0` 时,视口输入适配层把 `deltaY` 映射为横向位移并将纵向位移置零,核心平移模型仍只消费归一化后的 X / Y。按住 Ctrl / Cmd 滚轮才缩放画布,并阻止浏览器页面缩放。缩放比例显示保持现有换算口径,最低可缩小到 `5%`。
- 工程刷新后能从后端恢复资源、图层布局和 viewport。
- “我的”页项目入口能进入 `/project`;项目页能列出工程、重命名 / 删除单个工程、批量选择和批量删除;点击工程后进入 `/editor/canvas?projectid=<projectId>` 并按 query 加载该工程。
@@ -183,6 +183,7 @@ Supervisor 认领该回执后,由父 run 自己为每个原 delivery 逐一创
- 模式合同:客户端 AppData 配置新增全局 `agentMode`,只接受 `codex_cli / provider`。缺省和新安装默认使用 `codex_cli`,原有 HTTP LLM Provider 路径完整保留并可显式切回 `provider`;切换只影响下一次节点请求,不新增 Runner、任务图、会话库、配置库或业务事实源。
- 调度边界:正式 DAG、manifest、Agent task/session/run 身份、队列、锁、委派、all-join、完成门、Provider lifecycle、持久 retry/handoff 与 `needs-reconciliation` 继续由现有 AGC Runtime 掌控。每个被调度节点在 `codex_cli` 模式下直接启动一次非交互 `codex exec` 充当该节点的推理 Agent;Codex 返回当前 Runtime 广告函数的结构化调用,Runtime 仍是唯一 ToolHost,不允许 CLI 自己写项目、执行命令、调用 MCP 或形成第二套 revision / verification 真相。
- 安装包侧车:Windows x64 release 固定随 Tauri resource 打包 `@openai/codex@0.147.0` 的原生 `codex.exe`;Rust build script 从 AGC 子包锁定依赖 stage 到 resource,并写入版本与 SHA-256 清单。Windows 侧车映射只写入 `tauri.windows.conf.json`,通用 `tauri.conf.json` 不得让 Linux / macOS 构建依赖未生成的 Windows 二进制。运行时只在文件摘要和 `codex-cli` 版本同时匹配清单时优先选内置侧车;缺失、损坏或版本漂移时跳过它,按既有 npm 安装、PATH 顺序回退。安装包同时携带 Apache-2.0 第三方声明;API Key、`auth.json`、Cookie、Token、用户 `CODEX_HOME`、用户配置和项目数据绝不打包。
- CLI 安全边界:CLI 固定使用 argv 启动,禁止 shell 拼接;工作目录使用本次请求专用的空临时目录,不把游戏项目绝对路径写入 prompt、stdout、stderr 或持久记录。调用固定使用 ephemeral、忽略用户配置和 exec rules、read-only sandbox、never approval,并关闭 Codex shell tool;只继承 CLI 运行和认证所需的最小环境,显式移除宿主 `CODEX_API_KEY`。用户级 Codex 登录态继续由本机 Codex 自己读取,API Key、auth 文件、Cookie、Token、`CODEX_HOME` 私有内容不得复制到项目配置、Runtime sidecar、Agent DB、conversation 或日志;stdout / stderr 无换行时也受硬上限约束,stderr 诊断只记录固定分类、字节数和 SHA-256。
- 协议边界:Runtime 把既有 `LlmRunRequest` 的消息和当前函数目录编码为有界 prompt,并从同一函数 JSON Schema 生成 Codex structured-output schema。CLI 输出转换为现有 `LlmRunResponse / LlmToolCall` 后,继续经过 native tool / MCP 参数校验、动作上限、权限、pending、receipt、验证与格式修复链;最终回复仍走现有脱敏和唯一提交路径,不新增平行响应协议。
- 取消与恢复:Codex 子进程绑定当前 Provider request lifecycle,取消、暂停、Runner draining 或 GUI owner 丢失时终止并回收当前进程;started 后没有可信终态仍沿现有 Provider reconciliation 处理。`agentMode`、CLI 可执行身份和影响输出的 Codex 参数进入 `providerConfigFingerprint`,模式切换不得消费另一模式遗留的 retry/handoff。
@@ -1158,6 +1159,15 @@ game-project/
- 发布 GUI 内的 Codex CLI 可用性探测(包括候选版本检查和 `app-server --help`)必须与实际 Codex、MCP、Runner 和项目命令一样使用 `CREATE_NO_WINDOW`;读取对话或配置状态时即使连续探测多个候选,也不能创建或闪烁控制台窗口。
- Node ESM 脚本必须用 `fileURLToPath()` 把 `import.meta.url` 转为 Windows 本地路径,禁止直接把 URL pathname 交给 `path.resolve()`;真实 agent-run smoke 的浏览器探测覆盖 Windows Chrome/Edge 固定安装位置。开发态 smoke 在旧安装版持有默认 AppData GUI owner 时使用独立 `--config-dir`,不得终止用户现有客户端。
## 2026-08-20 Direct Codex 审核 Skill Pack 与受控工具内核
- 普通项目对话只由一个 project-bound Codex app-server thread 执行。客户端系统提示词只放最小工程合同、当前游戏源码有界快照、项目 prompts 和审核 Skill 索引;不再批量读取项目 `.codex/.agents/.hermes` Skill 正文,也不恢复 Supervisor、专业 Agent 或 harness。
- 首页恢复“做游戏 / 做素材 / 做方案”三个创作类型,默认“做游戏”。该选择与设置页的 Agent Runtime 模式无关;每次首页提交仍只自动创建一个新项目并进入项目工作台。用户正文原样进入项目对话,`game|art|doc` 仅作为受限结构化首轮上下文传给同一 Codex thread,不拼接“初始意图”文案、不产生首页对话、不切换 Provider 或恢复旧 Runtime 编排。
- `agc-skill-pack.v1` 只包含项目结构、陶泥儿美术、Web 游戏实现、真实浏览器试玩、客户端资源投影五项 Skill。清单记录用途、触发条件、所需工具、版本和内容 SHA-256;任何审核文件变化都必须同步重算对应清单指纹。客户端把审核文件安装到隔离目录后通过 app-server `skills/extraRoots/set + skills/list` 注册并复核,完整正文由 Codex 原生 Skill 机制按意图加载,一层引用只能经 `agc_read_skill_resource` 读取清单内 Markdown。引用路径按平台无关规则拒绝反斜杠、盘符、UNC、绝对路径和 `..`,不能依赖当前宿主的 `std::path` 语义判断其它平台路径。
- DirectProject 只连接客户端内置的 `agc_tools` STDIO MCP,工具固定为审核引用读取、标准陶泥儿美术准备和 desktop/mobile 浏览器试玩。MCP 进程只做协议;真实浏览器和付费 External v1 调用通过随机 loopback 地址回到客户端主进程,因此不复制 GUI 登录态、开发者 Key 或项目路径到模型上下文。三项工具固定自动批准,通用 shell、任意网络、多 Agent、插件和外部 MCP 继续关闭。
- 陶泥儿生成继续复用既有私有 Key、持久幂等账本、operation 恢复、来源/下载/PNG 解码和 manifest 登记。完整可信图集缺切片可以继续,固定四切片只是推荐路径;凭据失效、来源不明或结果未知时失败关闭,不能自动换 Key 或重新扣费。
- 自定义 LLM API Key 路由只在 DirectHome/DirectProject 经 loopback `/responses` 流式代理转发。代理不注入 Key,只要求请求自带 Bearer,并剥离开发网关错误携带的 `X-Codex-*` ChatGPT 账户额度头,防止隔离 app-server 把 API Provider 误判为余额 0;旧 ToolHost 保持原 Provider 行为。
- 2026-08-12 计划拒绝恢复:结构化 `runtime.plan_update` 被 Runtime 拒绝后,下一轮 Provider 请求按请求级目录收窄到实际项目 mutation 与 `respond_to_user`(已进入协作编排的 Supervisor 保留 `agent.delegate / agent.run_status`),并明确禁止再次规划、读取、搜索或验证;后续已有真实 mutation observation 后解除临时目录,不改变持久 executable policy。
- Goal Contract 绑定 project、可信根 Run Profile、source task SHA-256 和不可变 fingerprint;同一根 Run 只允许幂等重放完全相同的合同,语义变化必须进入新根 Run。已有合同的根 Supervisor 收到 steer 时,Runtime 必须按旧 rootRunId 串行化转换并在持锁后重验 Session 当前权威 Run,再取消并确认旧 rootRunId 的静态、ready、isolated 整棵树已进入终态或 `needs-reconciliation`;旧树未停稳时拒绝启动 replacement,停稳后才在同一 Session、source 和 Run Profile 创建唯一的新根 Run,不能把新增要求塞进旧合同继续完成。合同摘要作为 `decision` 投影到共享黑板,JSON sidecar 才是权威源;黑板冲突条目和专家事实仍追加保留。
@@ -64,6 +64,31 @@ Tauri `beforeDevCommand` 默认与客户端构建并行,不能把上述检查
Windows 本地 `npm run dev` / `npm run dev:api-server` / `npm run dev:bgfilter-worker` 会用空的 `RUSTC_WRAPPER` / `CARGO_BUILD_RUSTC_WRAPPER` 覆盖 `server-rs/.cargo/config.toml` 里的 `sccache`,从而直连真实 `rustc`。完整栈和 `dev:api-server` 把 API 与 BgFilter worker 作为一个 Rust 重启单元:源码变化时先停两个进程,再先启动并验活 worker、最后启动并验活 API,避免两个 `cargo run` 并发链接同一个 Windows 可执行文件。不要把 wrapper 绕过值写成 `rustc`;Cargo 会按 wrapper 协议调用 `rustc <真实rustc路径> - ...`,最终报 `multiple input filenames provided` 并导致 api-server 无法启动。排查本地启动失败时,先看 dev 日志是否出现该错误,再确认脚本注入的 wrapper 为空。
### 本地 Rust 构建缓存与磁盘上限
`server-rs/Cargo.toml` 和 `apps/ai-game-creator-shell/src-tauri/Cargo.toml` 是两个独立 Cargo workspace;AGC 会以 path dependency 复用 `agent-runtime-core`、`platform-llm`、`platform-agent` 和 `shared-contracts`,但两边默认仍分别写入 `server-rs/target` 与 `apps/ai-game-creator-shell/src-tauri/target`。这个代码和锁文件边界继续保留,不为节省磁盘直接合并 workspace;生产构建脚本和 Tauri 发布还依赖当前 manifest / lock / target 身份。
一次性 `cargo test` 不应长期保留增量缓存。两个 workspace 的 `[profile.test]` 固定 `incremental = false`、`debug = 1`;AGC `[profile.dev]` 与 `server-rs` 对齐 `debug = 1`、`codegen-units = 256` 和非 LTO 的开发口径,保留交互式 `cargo run` 的增量编译。这样全量测试不再按每组 feature / crate hash 累积大量 `debug/incremental` 目录,同时不把每次开发启动都退化为冷编译。
仓库统一使用以下本地工具:
```bash
# 默认只读:统计两套 target 和 incremental 体积,超过默认阈值时警告
npm run audit:rust-build-cache
# 仍然只读:列出本次会清理的两个固定目录
npm run clean:rust-incremental
# 显式写入:仅删除两个 debug/incremental,不删 deps、release、源码或锁文件
npm run clean:rust-incremental -- --apply
```
审计结果为跨平台可复现的文件逻辑字节数,默认警告阈值为 `120 GiB`;Windows 稀疏文件、压缩或分配单元可使该数值与磁盘物理占用不完全一致。清理后同时使用操作系统剩余空间复核真实回收量,不把逻辑字节差值冒充物理空间。
清理工具只接受仓库内两个编译目标的固定 `debug/incremental` 路径,默认 dry-run;路径越界、根目录或目标是符号链接 / junction、仓库标记缺失,或存在活跃 `cargo` / `rustc` 进程时均失败关闭。清理后的首次测试或开发构建会变慢,属于可再生缓存预期行为。
共享 `CARGO_TARGET_DIR` 不作为默认第一阶段方案:`npm run agc` 会并发启动 server-rs 和 Tauri Cargo,两个 workspace 指向同一 target 会引入构建锁串行化。需要共享时必须先用冷 / 热启动基准证明依赖复用收益大于并发锁等待,并保持生产 `CARGO_TARGET_DIR` 显式覆盖和现有发布产物路径不变。
Windows 本地如果已在 `%LOCALAPPDATA%\Genarrative\ffmpeg\bin` 安装 FFmpeg,`npm run dev` / `npm run dev:api-server` 会自动把该目录加入本次 `api-server` 子进程 `Path`,并注入 `CHARACTER_ANIMATION_FFMPEG_PATH` / `CHARACTER_ANIMATION_FFPROBE_PATH` 的绝对路径。这样即使外层终端或长期运行的 dev 进程是在安装 FFmpeg 之前启动,角色动画抽帧也不会继续因为 `ffmpeg: program not found` 失败;若手动配置了上述环境变量或 `GENARRATIVE_CHARACTER_ANIMATION_*` 前缀变量,显式配置优先。
开发态 `npm run dev` 与 `npm run dev:api-server` 都会注入 `GENARRATIVE_DEV_PASSWORD_ENTRY_AUTO_REGISTER_ENABLED=true`,因此密码登录在本地开发环境可直接注册未知手机号账号。完整 `npm run dev` 会强制父 API 使用 `GENARRATIVE_PROCESS_ROLE=all`,忽略外层显式角色,确保本地 `api-server` 同时监听 HTTP 并消费外部生成队列;只有单模块 `npm run dev:api-server` 会保留显式 `GENARRATIVE_PROCESS_ROLE`,未设置时默认为 `all`。`all` 不内嵌 BgFilter worker;启动器总是先启动并验活独立 `GENARRATIVE_PROCESS_ROLE=bgfilter-worker` 进程,再启动父 API,并向两者注入同一个内部 base URL / Token。Linux 本地默认 `all` 角色启动前,dev 脚本会停止当前仓库、同一个 SpacetimeDB server / database 下遗留的 `GENARRATIVE_PROCESS_ROLE=external-generation-worker` 进程,避免旧 worker 二进制继续抢同一条队列并在业务写回时制造 procedure 超时;显式拆分 `api` / `external-generation-worker` 做生产式验证时不会触发这项清理。生产环境仍按 `api-server` 配置默认关闭密码自动注册,并由独立 worker 进程消费队列。