Compare commits

...

96 Commits

Author SHA1 Message Date
lhk229 e69865a3b5 修复回归
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 7m15s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 7m22s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 7m22s
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 7m45s
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust smoke (pull_request) Has been cancelled
2026-09-19 00:09:13 +08:00
lhk229 43b7396909 修复资源界面测试并清理退役策划残留
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 5m57s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 5m26s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m10s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 5m21s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m15s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 4m32s
Project CI / Backend tests (pull_request) Successful in 9m36s
Project CI / Repository checks (pull_request) Successful in 9m13s
Project CI / Frontend tests (pull_request) Successful in 9m42s
Project CI / Native shell tests (pull_request) Successful in 11m55s
Project CI / AI game creator shell web tests (pull_request) Successful in 7m59s
更新资源卡片断言与 Lexical 提示词输入,恢复生成任务异步状态及轮询收尾验证。
删除旧策划别名和不可达错误映射,更新阶段审批注释。
保留旧项目无报错新开 Design 会话并继续的行为。
资源界面修复后完整界面测试 448 通过、17 跳过;审查清理后 Runtime 模型 27 项及 Design Agent 4 项测试通过,类型和配置检查通过。
2026-09-18 11:46:34 +00:00
lhk229 8909b18a15 恢复合并中被回退的 Direct 前端架构
Project CI / AI game creator shell Rust smoke (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Has been cancelled
恢复主分支的线程事件消费、聊天投影、历史锚点与分页模块。
恢复过程折叠、工具卡片计时以及对应测试和测试桩。
保留策划 V1/V2 退役清理及 Design Agent 总控面板修复。
修正 Direct 验证文档中的测试入口。
验证通过:60 个 Direct 单元测试、69 个相关界面测试、4 个 Design Agent 测试及静态检查。
完整界面测试仍有 8 个资源 UI 测试失败,涉及旧卡片断言和提示词输入方式,本次未修改。
2026-09-18 11:30:56 +00:00
lhk229 5a712910b7 移除策划页面多余的总控状态面板
Design Agent 激活时不再渲染旧总控运行状态面板。
在现有策划会话测试中补充总控状态面板不显示的断言。
2026-09-18 11:22:00 +00:00
lhk229 90b707727c 修正合并后残留的 Direct 旧命令调用
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 7m16s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 7m22s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 7m41s
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 7m42s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m57s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m5s
Project CI / Repository checks (pull_request) Failing after 5m23s
Project CI / Frontend tests (pull_request) Failing after 6m37s
Project CI / Native shell tests (pull_request) Successful in 9m25s
Project CI / Backend tests (pull_request) Successful in 9m38s
Project CI / AI game creator shell web tests (pull_request) Failing after 5m23s
删除前端对已移除 Direct 命令的回读

更新回合流类型注释
2026-09-18 09:44:50 +00:00
lhk229 4efaec42ea 清理退役策划测试并更新现状文档
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 6m1s
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 6m30s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 6m1s
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust smoke (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
删除旧 hydrate 命令的无效测试桩

将策划 V1/V2 技术方案和共享记忆标记为历史

明确当前策划入口统一使用 Design Agent
2026-09-18 09:00:08 +00:00
lhk229 945b3efa6f 合并最新主分支变更
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust smoke (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Has been cancelled
合入 origin/master 的 Direct、资源画布、工具展示和运行时更新
保留策划 Agent V1/V2 退役删除结果
冲突文件继续采用当前分支的策划退役边界
2026-09-18 08:32:03 +00:00
lhk229 bd40ca45f1 合并最新主分支并保留策划退役清理
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust smoke (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
合入 origin/master 的现役 Direct、Mac 随包资源、配置和测试变更
保留策划 Agent V1/V2 退役删除结果
仅在重叠文件保留当前分支的策划解耦代码
不额外处理 master 自身已有缺陷
2026-09-18 08:04:10 +00:00
suzmii 9a21690fe9 Merge pull request '修复 AGC 画布生成、卡片展示与布局交互' (#412) from feat/agc-canvas-acceptance into master
Project CI / AI game creator shell Rust shard 1/4 (push) Successful in 5m52s
Project CI / AI game creator shell Rust shard 2/4 (push) Successful in 5m56s
Project CI / AI game creator shell Rust shard 3/4 (push) Successful in 4m29s
Project CI / AI game creator shell Rust shard 4/4 (push) Successful in 5m8s
Project CI / AI game creator shell Rust smoke (push) Successful in 2m7s
Project CI / AI game creator shell Rust crates (push) Successful in 2m27s
Project CI / Frontend tests (push) Successful in 8m33s
Project CI / Repository checks (push) Successful in 10m19s
Project CI / AI game creator shell web tests (push) Successful in 6m51s
Project CI / Backend tests (push) Successful in 18m39s
Project CI / Native shell tests (push) Successful in 20m53s
2026-09-18 15:50:44 +08:00
suzmii deff6319e2 合并主线项目创建目录选择更新
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 6m53s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 6m31s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 7m12s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m5s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 4m54s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m12s
Project CI / Backend tests (pull_request) Successful in 9m37s
Project CI / Native shell tests (pull_request) Successful in 12m21s
Project CI / Repository checks (pull_request) Successful in 11m10s
Project CI / AI game creator shell web tests (pull_request) Successful in 12m51s
Project CI / Frontend tests (pull_request) Successful in 23m14s
合入 master ee33af7b7 的项目目录选择与模板建项说明。
保留本批画布和对话修复,自动合并无冲突,类型检查通过。
2026-09-18 15:48:10 +08:00
suzmii 2257a78d6b 收口思考等待反馈与紧凑过程样式及失败状态
思考展开时隐藏重复预览并使用灯泡图标,首个响应前显示临时思考提示。
统一分钟内小数和分钟以上整数秒,保持内外过程的紧凑间距与正文层级。
失败工具与分组显示错误色,非零退出码不再误判为成功。
补齐状态、格式、样式和交互回归,本批其余需求留待后续PR。
2026-09-18 15:46:30 +08:00
suzmii a0f6b7c67d 统一思考与执行过程折叠样式及中文耗时
思考展开复用安全Markdown渲染,折叠显示浅色单行纯文本预览与右侧箭头。
共享过程摘要组件,执行过程按真实操作数显示统计并保留各组独立计时。
工具、整轮、生成任务和策划耗时统一为中文时分秒格式。
补齐格式与Markdown回归、更新已有界面断言并验证窄屏键盘操作。
2026-09-18 14:34:10 +08:00
kdletters ee33af7b75 补充模板建项命令的项目创建目录说明
Project CI / AI game creator shell Rust shard 1/4 (push) Successful in 6m4s
Project CI / AI game creator shell Rust shard 2/4 (push) Successful in 6m4s
Project CI / AI game creator shell Rust shard 3/4 (push) Successful in 6m13s
Project CI / AI game creator shell Rust smoke (push) Successful in 3m3s
Project CI / AI game creator shell Rust crates (push) Successful in 2m8s
Project CI / AI game creator shell Rust shard 4/4 (push) Successful in 6m0s
Project CI / Frontend tests (push) Successful in 10m59s
Project CI / Repository checks (push) Successful in 10m54s
Project CI / Native shell tests (push) Successful in 13m12s
Project CI / Backend tests (push) Successful in 14m33s
Project CI / AI game creator shell web tests (push) Successful in 5m37s
- 模板库技术方案的命令表补记 create_automatic_local_game_project_from_template 支持 projectsRoot 覆盖,未指定时仍是应用数据目录
2026-09-18 14:30:02 +08:00
kdletters be370cc615 AGC 支持用户自选项目创建目录
Project CI / AI game creator shell Rust shard 1/4 (push) Successful in 7m12s
Project CI / AI game creator shell Rust shard 2/4 (push) Successful in 7m17s
Project CI / AI game creator shell Rust shard 3/4 (push) Successful in 7m26s
Project CI / AI game creator shell Rust shard 4/4 (push) Successful in 7m37s
Project CI / AI game creator shell Rust smoke (push) Successful in 1m57s
Project CI / AI game creator shell Rust crates (push) Successful in 2m10s
Project CI / Frontend tests (push) Successful in 6m4s
Project CI / Native shell tests (push) Successful in 8m58s
Project CI / Backend tests (push) Has been cancelled
Project CI / AI game creator shell web tests (push) Has been cancelled
Project CI / Repository checks (push) Has been cancelled
- 新增设置「工作区」分类,承载「项目创建目录」的选择与恢复默认入口
- 自动建项命令新增可选 projectsRoot,未指定时沿用 AppData projects 默认目录
- 新增项目创建目录校验与解析:只接受目录选择器返回且通过私有路径门禁的既有目录
- 目录选择器新增可选 title 参数,用于「选择项目创建目录」文案
- 首页自动建项与模板建项在建项时携带用户选定的项目创建目录
- 客户端本地保存项目创建目录偏好,建项时重新校验,不作为授权凭据
- 补充设置页工作区、首页建项与目录偏好单测
- 修复项目开发视图缺失的 Shapes 图标导入,恢复 agc:typecheck 通过
- 同步实施计划、决策日志与排障记忆文档
2026-09-18 14:10:05 +08:00
suzmii 21b059bd41 修正工具组独立计时并移除重复整轮耗时
每个工具组只计算自身调用跨度,已完成组立即停止增长与进行中标记。
整轮总耗时仅在回合状态或完成小结显示一次,单工具仍按百毫秒动态更新。
补齐前组已完成后组运行、边界缺失与倒序的回归及浏览器证据。
2026-09-18 13:45:27 +08:00
suzmii 2d90b73b94 合并主线Mac运行资源与发布门禁更新
合入 origin/master b137f1759,保留画布验收与计时返修。
同步主线0.1.67版本及Mac随包资源、插件能力和发布目标检查。
合并双方排障说明,不提交个人依赖锁文件改动。
2026-09-18 13:27:28 +08:00
suzmii cd8f480719 修复生成草稿隔离与回合计时恢复及布局排队
按占位身份隔离生成面板并保存草稿,阻止改变失败请求输入后伪装重试。
保留用户真实发送时间,按既有用户条目身份恢复空运行态回合的终态边界。
修复跨栏目整理队列覆盖及多选拖动预览起点漂移。
补齐六项 review 发现的回归、原生绑定、交叉审查及浏览器验收记录。
2026-09-18 13:25:18 +08:00
suzmii b137f17599 Merge pull request '修复Mac客户端随包Codex与插件资源缺失' (#417) from fix/mac-bundled-runtime into master
Project CI / AI game creator shell Rust shard 3/4 (push) Successful in 6m26s
Project CI / AI game creator shell Rust shard 1/4 (push) Successful in 6m40s
Project CI / AI game creator shell Rust shard 2/4 (push) Successful in 6m35s
Project CI / AI game creator shell Rust shard 4/4 (push) Successful in 4m41s
Project CI / AI game creator shell Rust smoke (push) Successful in 1m56s
Project CI / AI game creator shell Rust crates (push) Successful in 2m22s
Project CI / Backend tests (push) Successful in 9m16s
Project CI / Repository checks (push) Successful in 7m2s
Project CI / Frontend tests (push) Successful in 8m12s
Project CI / Native shell tests (push) Successful in 11m13s
Project CI / AI game creator shell web tests (push) Successful in 5m37s
Reviewed-on: #417
2026-09-18 12:48:00 +08:00
suzmii 2ffccb844c 修复对话动态计时与初始消息重复并补齐游戏居中指引
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 5m51s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 5m45s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 5m31s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m3s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m4s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 4m38s
Project CI / Repository checks (pull_request) Successful in 5m39s
Project CI / Frontend tests (pull_request) Successful in 7m45s
Project CI / Backend tests (pull_request) Successful in 10m3s
Project CI / Native shell tests (pull_request) Successful in 8m54s
Project CI / AI game creator shell web tests (pull_request) Failing after 5m31s
区分整轮总耗时与工具实际阶段时间,以百毫秒刷新一位小数并冻结终态。
修复正式与乐观用户消息到达时初始占位重复,保留真实同文多次发送。
在开发 Agent 系统提示与 Skill 明确禁止 Phaser 和 CSS 双重居中。
补齐原生事件、前端回归与验收文档,保留未完成项和远程 CI 风险。
2026-09-18 12:17:28 +08:00
suzmii 16c905b51b 修复发布目标与插件能力门禁并同步版本0.1.67
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 7m21s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 7m27s
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 7m28s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 7m46s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m53s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 3m14s
Project CI / Backend tests (pull_request) Successful in 8m6s
Project CI / Native shell tests (pull_request) Successful in 8m11s
Project CI / Repository checks (pull_request) Successful in 5m57s
Project CI / Frontend tests (pull_request) Successful in 7m53s
Project CI / AI game creator shell web tests (pull_request) Successful in 4m38s
统一显式目标对应的版本读取、构建渠道、产物目录和更新清单
无原生适配器时隐藏Cocos插件并阻止自动启动
同步单架构更新规范并增加发布和插件回归测试
更新版本与锁文件到0.1.67并记录Mac安装包验证结果
2026-09-18 12:15:00 +08:00
suzmii 6f012d419a 修复Mac客户端随包运行依赖缺失
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 5m37s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 5m46s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 5m28s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m43s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m40s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 5m20s
Project CI / Frontend tests (pull_request) Successful in 7m41s
Project CI / Repository checks (pull_request) Successful in 7m41s
Project CI / Native shell tests (pull_request) Successful in 11m20s
Project CI / Backend tests (pull_request) Successful in 12m11s
Project CI / AI game creator shell web tests (pull_request) Successful in 4m12s
统一Codex平台布局并补齐macOS原生组件、完整性清单和资源加载路径
补齐macOS插件资源并保留Windows专属原生桥接边界
增加隔离安装包验证、平台配置门禁与侧车回归测试
声明macOS 15最低系统版本并同步规范及Windows待验收计划
2026-09-18 11:11:07 +08:00
suzmii 1bd153d7f2 合并主线对话状态与抠图背景色更新
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 4m56s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Failing after 6m9s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 5m28s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m33s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m23s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 4m39s
Project CI / Repository checks (pull_request) Successful in 4m50s
Project CI / Backend tests (pull_request) Successful in 8m38s
Project CI / Frontend tests (pull_request) Successful in 8m2s
Project CI / AI game creator shell web tests (pull_request) Successful in 8m11s
Project CI / Native shell tests (pull_request) Successful in 15m27s
合入 master a2e6f205d,保留远端功能分支已有合并历史。
融合生成选项的参考素材、目标栏目与抠图背景色字段。
保留主线统一线程状态与重试策略,完成前端及原生定向验证。
2026-09-18 10:31:55 +08:00
lhk229 a2e6f205d6 修复最终回复失败测试重试超时
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 7m5s
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 7m17s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 7m18s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 7m41s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 1m31s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m26s
Project CI / Repository checks (pull_request) Successful in 4m2s
Project CI / Frontend tests (pull_request) Successful in 5m29s
Project CI / Backend tests (pull_request) Successful in 8m18s
Project CI / Native shell tests (pull_request) Successful in 9m38s
Project CI / AI game creator shell web tests (pull_request) Successful in 5m10s
Project CI / AI game creator shell Rust shard 1/4 (push) Successful in 6m44s
Project CI / AI game creator shell Rust shard 2/4 (push) Successful in 6m26s
Project CI / AI game creator shell Rust shard 3/4 (push) Successful in 5m13s
Project CI / AI game creator shell Rust smoke (push) Successful in 1m59s
Project CI / AI game creator shell Rust shard 4/4 (push) Successful in 4m25s
Project CI / AI game creator shell Rust crates (push) Successful in 1m19s
Project CI / Repository checks (push) Successful in 4m54s
Project CI / Frontend tests (push) Successful in 5m52s
Project CI / Backend tests (push) Successful in 7m4s
Project CI / AI game creator shell web tests (push) Successful in 2m38s
Project CI / Native shell tests (push) Successful in 8m0s
最终回复失败测试显式关闭 Provider 重试

让非法回复 mock 按实际请求次数监听

同步运行态公共失败审计测试的 mock 参数
2026-09-18 04:55:05 +08:00
k88936 30c377d0f0 保留唯一的thread manager作为direct project的状态来源 (#384)
Project CI / AI game creator shell Rust shard 1/4 (push) Successful in 6m21s
Project CI / AI game creator shell Rust smoke (push) Successful in 1m51s
Project CI / AI game creator shell Rust shard 3/4 (push) Successful in 5m3s
Project CI / AI game creator shell Rust shard 2/4 (push) Failing after 5m54s
Project CI / AI game creator shell Rust shard 4/4 (push) Successful in 4m28s
Project CI / AI game creator shell Rust crates (push) Successful in 1m53s
Project CI / Repository checks (push) Successful in 5m33s
Project CI / Frontend tests (push) Successful in 7m20s
Project CI / Native shell tests (push) Successful in 8m29s
Project CI / Backend tests (push) Successful in 8m57s
Project CI / AI game creator shell web tests (push) Successful in 3m16s
说明: 在把工作交给段哥前还没有实现direct project聊天页面的迁移, 导致在 #375 里用很复杂的实现又做了一套事件流, 实测还有会话丢失的bug, 我在这里把数据获取的部分迁移到 #367 上

---------

Co-authored-by: 孔令弘 <ink29535@proton.me>
Reviewed-on: https://git.genarrative.world/git/GenarrativeAI/Genarrative/pulls/384
Reviewed-by: 孔令弘 <ink29535@proton.me>
Co-authored-by: 王德宇 <kvtodev@outlook.com>
Co-committed-by: 王德宇 <kvtodev@outlook.com>
2026-09-18 02:13:50 +08:00
lhk229 1c6e4c1e74 AGC生图工具暴露抠图背景色并补齐相关说明 (#414)
Project CI / AI game creator shell Rust shard 3/4 (push) Successful in 6m52s
Project CI / AI game creator shell Rust shard 2/4 (push) Successful in 7m10s
Project CI / AI game creator shell Rust shard 1/4 (push) Successful in 7m20s
Project CI / AI game creator shell Rust shard 4/4 (push) Successful in 5m50s
Project CI / AI game creator shell Rust smoke (push) Successful in 2m12s
Project CI / AI game creator shell Rust crates (push) Successful in 2m13s
Project CI / Repository checks (push) Successful in 6m17s
Project CI / Frontend tests (push) Successful in 7m21s
Project CI / Backend tests (push) Successful in 9m49s
Project CI / AI game creator shell web tests (push) Successful in 2m41s
Project CI / Native shell tests (push) Successful in 11m8s
agc_generate_image 新增 screenColor 参数,仅 kind=character/art-spritesheet 生效,说明含 12 色板 hex 与不得接近本体颜色的约束
screenColor 计入 standalone 生成动作身份,None 时跳过序列化,未使用该字段的请求身份与升级前逐字节一致
character 生图请求体按需注入 screenColor,art-spritesheet 图集把硬编码 auto 改为透传归一化值
bridge 侧只校验 auto/#RRGGBB 格式并统一大写,色板白名单交由服务端 400 权威校验,其它 kind 携带直接拒绝
修复 sliceCount 悬空指引:MCP schema 与双层字段白名单补齐,1-256 校验后透传至图集生成请求
精简 agc_generate_image 工具说明,删除美术包限制与客户端职责两段样板句
审计投影同步记录 screenColor,补充 bridge 归一化、动作身份指纹与工具目录契约测试

Reviewed-on: https://git.genarrative.world/git/GenarrativeAI/Genarrative/pulls/414
Co-authored-by: Linghong <ink29535@proton.me>
Co-committed-by: Linghong <ink29535@proton.me>
2026-09-18 01:14:02 +08:00
lhk229 f5a333b839 Merge branch 'master' into feat/agc-canvas-acceptance
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust smoke (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
2026-09-18 01:04:04 +08:00
kdletters 2e15a70b14 Provider 瞬态重试次数严格按设置执行
Project CI / AI game creator shell Rust shard 3/4 (push) Successful in 7m26s
Project CI / AI game creator shell Rust shard 2/4 (push) Successful in 7m38s
Project CI / AI game creator shell Rust shard 1/4 (push) Successful in 7m46s
Project CI / AI game creator shell Rust shard 4/4 (push) Successful in 8m4s
Project CI / AI game creator shell Rust smoke (push) Successful in 2m19s
Project CI / AI game creator shell Rust crates (push) Successful in 2m13s
Project CI / Backend tests (push) Successful in 10m11s
Project CI / Frontend tests (push) Successful in 12m57s
Project CI / Repository checks (push) Successful in 15m23s
Project CI / AI game creator shell web tests (push) Successful in 9m18s
Project CI / Native shell tests (push) Successful in 22m24s
删除自主构建档位 12~16 的重试区间与 standard 档位 3 次上限,maxRetries 严格决定物理重试次数
上游 400 不再单独收窄到 2 次,与其它瞬态错误共用设置里的同一份预算
运行档位改为只决定上游 400 是否算瞬态,重试次数不再被档位改写
重写档位重试用例为设置值直取,同步 upstream-400 用例
decision-log 记录本次口径变更与本机既有失败边界
2026-09-18 00:01:40 +08:00
suzmii 20b1fd63de 合并最新主线抠图链路与开发监听修复
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 6m44s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 6m55s
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 7m3s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m9s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m30s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 4m41s
Project CI / Native shell tests (pull_request) Successful in 15m5s
Project CI / Repository checks (pull_request) Successful in 16m54s
Project CI / Backend tests (pull_request) Successful in 19m49s
Project CI / Frontend tests (pull_request) Successful in 23m33s
Project CI / AI game creator shell web tests (pull_request) Successful in 11m6s
合入master的抠图账本链路、Vite监听边界及窗口测试更新

保留画布占位参考生成、资源展示与批量标签追加功能

合并态通过137项定向测试、AGC类型检查及Rust全目标编译
2026-09-17 22:18:23 +08:00
lhk229 3de9341a9c 合并最新主分支并保留策划退役清理
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 4m30s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 4m44s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m37s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 5m6s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 5m9s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m26s
Project CI / Native shell tests (pull_request) Successful in 19m40s
Project CI / Frontend tests (pull_request) Successful in 21m8s
Project CI / Repository checks (pull_request) Successful in 21m29s
Project CI / Backend tests (pull_request) Successful in 27m41s
Project CI / AI game creator shell web tests (pull_request) Successful in 19m50s
合并 origin/master 的最新功能与测试变更

保留已删除的策划 Agent V1/V2 运行时和旧 GDD 入口

仅解决资源预览类型冲突,不恢复退役策划调用
2026-09-17 14:10:46 +00:00
suzmii 105591bac5 支持画布与资源面板多选素材批量追加标签
复用标签编辑器并冻结整组选中素材,保留原标签与素材类型

原生批量校验后一次保存,覆盖权限、版本冲突与无变化边界

修复保存输入锁和切项目迟到回包,补齐混合选择入口原因

新增前后端回归并记录本地验证及待真实客户端验收事项
2026-09-17 21:51:59 +08:00
lhk229 195b7dd5dd 修复抠图401 404问题 (#394)
Project CI / AI game creator shell Rust shard 3/4 (push) Successful in 7m34s
Project CI / AI game creator shell Rust shard 2/4 (push) Successful in 7m39s
Project CI / AI game creator shell Rust shard 1/4 (push) Successful in 7m50s
Project CI / AI game creator shell Rust shard 4/4 (push) Successful in 7m56s
Project CI / AI game creator shell Rust smoke (push) Successful in 2m31s
Project CI / AI game creator shell Rust crates (push) Successful in 3m19s
Project CI / Native shell tests (push) Successful in 16m33s
Project CI / Backend tests (push) Successful in 17m56s
Project CI / Repository checks (push) Successful in 15m2s
Project CI / Frontend tests (push) Successful in 23m48s
Project CI / AI game creator shell web tests (push) Successful in 23m11s
Reviewed-on: https://git.genarrative.world/git/GenarrativeAI/Genarrative/pulls/394
Co-authored-by: Linghong <ink29535@proton.me>
Co-committed-by: Linghong <ink29535@proton.me>
2026-09-17 21:37:23 +08:00
suzmii da44d66dc8 明确多选素材批量追加标签的行为合同
限定追加语义、冻结对象、原子保存与类型保留边界

记录已评审里程碑及前后端并行实现计划
2026-09-17 21:12:42 +08:00
suzmii 0a85c4f87e 合并主线资源菜单和引擎预览功能
合入PR410的常用操作收纳与卡片信息类型入口

保留本分支资源名称、文档图标、占位生成与批量移动能力

整合引擎结构摘要与当前图集测试契约
2026-09-17 21:06:15 +08:00
suzmii efce7b102f 对齐主线图集契约与窗口同步测试要求
补齐图集切分声明与工具目录字段边界断言

更新原生HTTP权限守卫及稳定空快照发布次数期望

修正末尾空行并记录CI排查证据,保留待远程验证状态
2026-09-17 21:01:26 +08:00
suzmii db5edc948c 合并最新主分支并修复画布静态检查问题
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 7m19s
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Failing after 7m30s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 7m28s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Failing after 7m41s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m11s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m10s
Project CI / Native shell tests (pull_request) Failing after 4m28s
Project CI / Frontend tests (pull_request) Failing after 5m12s
Project CI / Backend tests (pull_request) Successful in 7m17s
Project CI / Repository checks (pull_request) Failing after 5m43s
Project CI / AI game creator shell web tests (pull_request) Failing after 4m34s
合入master的更新摘要、策划运行边界及图集契约调整

保留画布生成引用占位、资源卡展示与批量布局功能

修正导入顺序、未使用项和稳定回调依赖
2026-09-17 20:15:38 +08:00
suzmii 45c3780bf5 记录画布验收修复的验证证据与待验边界
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust smoke (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
登记自动化回归和独立评审结论

保留真实客户端与付费生成待验项及远程写入确认边界
2026-09-17 19:46:49 +08:00
suzmii 6fcf42e4ac 修 appSurface 生成任务用例的异步排空:等阶段合并、等轮询退出
- 阶段文案与徽标改用 waitFor:本地队列的「排队中。」先于后端记录合并,同步断言在整套连跑时抢跑
- 用例收尾连等两个 poll 周期(2s)并断言账本读计数不再增长,确认这条轮询链在本用例内退出
- 留在线上的轮询醒来会打进下一个用例的 spy(宿主按调用时读 __TAURI__),故排空放在用例内,未动全局 harness
- 未改生产:后台任务跨面板保活保持原样
2026-09-17 19:44:48 +08:00
suzmii e0f9f811b7 生成浮层居中定位与画布安全带高度
补回 transform translateX(-50%):锚点给的是占位卡中心,少了它浮层整体右偏半个面板宽
高度只按画布安全带分配:装得下时挂在卡下面,装不下时与卡顶边对齐盖住占位,不再压成一百多像素
reveal 的面板高度按当前缩放从屏幕 px 折回世界坐标,占位与浮层并集参与可见性
浮层宽度并入可见性并集,靠边卡片不再把浮层切掉一半
新增真实矩形模拟用例(画布高 568)核对浮层高度与落点不越出安全带
2026-09-17 19:35:41 +08:00
suzmii 03b5c1c9f4 补画布生成入口宿主生命周期验收:占位提交、同 operation 重试与成功落点
- 新增测试文件 resourceCanvasGenerationHostLifecycle.test.tsx,渲染真实 ProjectDevelopmentView
- 覆盖音频入口:点工具出占位、提交后占位进入 submitted(后台仍在跑时的中间态)
- 覆盖失败后原请求重试:复用同一 operationId 与幂等键,不会变成新的付费生成
- 覆盖成功后落点:结果卡按占位位置落盘(手动接管),占位随之被撤掉
- 原生命令全部走假实现,不触发任何真实 Provider 调用
2026-09-17 19:20:31 +08:00
suzmii 58992330aa 生成浮层面板 chrome 与画布安全高度修复
浮层复用模态的面板类:边框圆角底色内边距与 header 排布不再缺失
高度上界按真实画布可用底边算(画布高减退底栏安全区与顶边),空间紧时收紧并内部滚动
提交动作行固定在浮层底部,避免长表单把提交按钮顶到底栏下面
新增浮层高度模型测试、结构 CSS 钉子与浮层 chrome 断言
新增宿主级整合用例:图片按正式归类落点并用占位最新位置、音频失败保留与幂等重试
2026-09-17 19:08:34 +08:00
suzmii 2c687b01a4 补齐生成结果分类与占位交互验收合同
明确原生目标分类、音频幂等及画布浮层可见性
2026-09-17 19:08:34 +08:00
suzmii c0e377f479 测试助手同时支持纯文本与引用输入区
appSurface 图集/图标规范入口的提示词仍是 textarea,helper 不能只走 Lexical 编辑器 API
两种字段分别用原生 change 与编辑器 update,读回同样两种口径
补 targetCategory 随任务保存与恢复的断言
2026-09-17 19:01:35 +08:00
suzmii 6001b87215 画布生成按入口栏目落盘目标分类
GUI 生成命令新增可选 targetCategory:generate_local_project_asset 与 start_local_project_asset_generation 经 options 传入完成登记
PlatformArtAssetGenerationOptions 增加 target_category,Agent 与 Direct 路径保持 None,仍按 kind 派生默认分类
新建条目与同 kind 重登记都按显式目标分类写入 manifest 既有 category 字段,不新增字段、不改数据结构
目标分类只接受 GameCreationAppAssetCategory 的六个合法值,version 与 all 等栏目伪值在提交前失败关闭
target_category 刻意不进 standalone 指纹与 durable 请求快照,分类只影响本地 manifest 落点,避免在途账本换槽重复 POST,同任务幂等恢复由调用方继续用同一栏目提交
补用例:kind=image 带 targetCategory=character 落到 character 而不是 unclassified、非法栏目值不产生生成请求、登记入口的显式分类与不传时的原 kind 派生行为
2026-09-17 18:58:53 +08:00
suzmii b08ab6ee66 生成占位可见性、落点与音频提交身份修复
打开生成浮层时把占位与浮层整块带进安全区(避开顶栏底栏),只做最小视口平移不改缩放
落点意图改为按草稿 ID 的 Map,避免并发完成互相覆盖;坐标在落点时刻取占位最新位置
落点 section 改用资源正式归类后的 category,修复图片落待归类、规范落文档时静默跳过
音频与背景音乐提交绑定占位与 operationId:在途时拒绝再次提交,失败保留输入并可同 operation 重试
宿主记录收起浮层时的草稿与音频提交身份,重开占位接着编辑而不是回到空表单
生成任务新增入口栏目 targetCategory 走原生可选入参,前端不据此伪分类
补可见性平移的定向测试
2026-09-17 18:50:29 +08:00
suzmii 7f80012d7f 清理占位重开状态里不再读取的动作 ID
生成浮层的草稿、错误与占位归属统一按 draftId 判等,动作 ID 已无读取方,删掉避免留下死状态
2026-09-17 18:50:29 +08:00
suzmii fbe95591d5 校准布局撤销作用域的行为说明
明确切模式后新操作会替换旧撤销栈但不会跨写布局
2026-09-17 18:31:16 +08:00
suzmii d222aad2ec 参考素材改为提交前预检并补参考链路用例
参考解析前增加纯本地预检:清单归属、受控路径与文件、媒体类型、可解码位图全部通过后才允许产生任何上传副作用,避免第一张参考已上传、第二张坏图才失败
明确拒绝 SVG 等矢量参考,媒体类型或文件扩展名任一命中即拒,本次不做矢量转换,坏图同样在本地失败关闭
asset.upload 门禁提前到预检阶段,显式拒绝该命令的项目连第一个上传凭证都不会签发
预检与实际上传共用同一份本地判据 helper,不新建平行流程,上传侧仍按同一判据重新读取与解码
补参考合同与恢复的账本用例:icon-spec 带用户参考、game-background 规范图加用户参考、图集超限、空白引用写入失败
补提交侧用例:拒绝路径、未登记、非图片、缺失文件、超限、SVG 与坏图,并断言零上传凭证与零生成 POST,反向验证同一张合格参考单独提交确实会签发凭证
补 asset.upload 拒绝用例,以及清单校验与 Direct 身份校验接受用户参考、拒绝用户参考顶替规范引用的覆盖
2026-09-17 18:28:19 +08:00
suzmii 13b28ebbc7 生成占位与卡下独立浮层,修复引用选择被焦点陷阱阻断
工具点击先在当前栏目创建临时占位卡,生成浮层挂在占位下沿;图片、音效、背景音乐入口一致
占位按项目与草稿 ID 归属宿主临时状态:可拖动、提交绑定任务 ID、成功结果落到占位最新位置
删除占位只隐藏展示,关闭浮层不冒充取消后台任务;失败保留占位与输入引用供重试
生成面板改为非模态浮层:ThemedModal 焦点陷阱曾阻断 portal 到 body 的引用选择器,点选不生效
引用选择器定位加顶边钳制,搜索收窄与键盘选择可用;不再越出视口
参考候选与陈旧引用校验排除 SVG(原生解码不支持),其余 image 类型不额外收窄
任务创建处对参考资产 ID 去重;补浮层真实组件整合、占位模型与拖动、参考模型回归测试
2026-09-17 18:22:39 +08:00
suzmii 30648e6b93 画布修复:重算意图各占队列槽、撤销不跨排序模式、整理判据与落盘同源
- 显式整理与「关系图首次就绪」各占一个队列槽,系统重算不再改写用户已按下的那笔整理
- 资源签名同步覆盖排队中的每一笔资源意图,先落盘的那笔不会把后一笔留成过期签名
- 撤销栈按「项目 + 排序模式」隔离:切模式后不会把另一份 sidecar 的坐标写过去
- 整理的「有没有变化」判据与落盘同源,目标栏目还有在途/排队手动落点时也算一次真实变化
- 删除本次改动退役且已无调用方的 resourceBookAllBandLocalPoint 与布局 dragX/dragY
- 补回归:排队中整理不被覆盖、切模式撤销不跨写、在途拖动后整理照常生效、分类变更后拖动按新栏目落盘
2026-09-17 18:18:32 +08:00
suzmii 9dd1052374 明确参考图片格式与上传前整组校验边界
排除不可解码SVG参考并约束上传权限与账号归属判据
2026-09-17 18:18:32 +08:00
suzmii aec9568c39 接通画布生成参考素材的原生链路
新增 referenceAssetIds 原生入参:start_local_project_asset_generation 与 generate_local_project_asset 经 prepare_local_project_asset_generation 统一收口当前项目 manifest 图片素材 id
PlatformArtAssetGenerationOptions 增加 reference_asset_ids,GUI、agent 桥、media 观察与 Direct 运行时构造点显式传空
参考解析固定规范图前置在前、用户参考按给出顺序随后,按远端资源 ID 去重,普通生成总量 5 张、有规范前置 4 张用户参考,图集拒绝额外参考而非静默丢弃
参考素材复用 manifest 到本地文件、图片解码、内容 hash、当前账号 binding 上传的既有通道,历史账号遗留远端 ID 不再复用
retained 阶段与清单校验改为与提交同一套请求合同:icon-spec、ui-prototype、game-background 允许正确引用,art-spritesheet 仍只接受唯一规范引用
修复 Part::file_name 的生命周期错误与 4 处测试构造点少传参考参数
2026-09-17 17:57:53 +08:00
suzmii 0a1f0e0b26 画布布局收口:整理只动当前栏目、多选拖动一笔提交与一次撤销
- 整理画布重排目标栏目内全部素材(含手动坐标与被筛选隐藏的卡),「所有资源」页覆盖全部栏目
- 栏外坐标逐值保留:不再把其他栏目的自动坐标丢给重算,避免被顺带规整成规范槽位
- 手动标记纳入历史快照与相等判定,撤销整理恢复原坐标与原手动标记
- 新增批量坐标写入入口:多选拖动与撤销都只排一笔 CAS、只压一条历史
- 多选拖动按同一位移整批跟随,取消 / 捕获丢失 / 失焦回滚,切项目丢弃进行中的位移
- 补测试:栏外自动坐标保留、all 页整理范围、批量撤销与取消边界
2026-09-17 17:47:11 +08:00
suzmii 5c31ae91ca 返修资源卡完整名悬停入口并收短文档卡注释
- 完整资源名改挂在覆盖整卡、真正命中指针的选中按钮 title 上,名称条自身不再挂悬停不到的 title

- 无障碍名保持原有 aria-label 不变,长名仍是 CSS 单行省略

- 断言改为校验选中按钮 title,并钉住名称条不挂 title

- 文档卡分支注释只写当前行为,去掉旧实现说明
2026-09-17 17:37:48 +08:00
suzmii 3ba6168c6a 同步资源卡名称与画布布局交互产品合同
统一卡面名称和文档图标展示要求

明确当前栏目整理与多选移动的撤销边界
2026-09-17 17:15:38 +08:00
suzmii 2628b83d4b 画布资源卡统一显示正式资源名并简化文档卡卡面
- 资源卡新增卡面名称条,所有类型卡统一显示正式资源 label,长名单行省略、完整名进 title

- 文档卡卡面改为居中图标,不再把正文前几行铺在卡面上,正文只在独立详情浮层读取

- 删除卡面正文摘要的取文本 helper 与行数/长度常量,移除对应 CSS 规则不留墓碑

- 名称条按媒体卡让出右下播放钮位置,替换血缘角标上移避免遮住名称

- 新增资源卡名称与文档卡卡面用例,并同步重命名链路与卡面正文的既有断言
2026-09-17 17:08:42 +08:00
suzmii a7b2b0e23b 画布图片生成支持真实参考图引用
新增参考图模型:候选为当前项目已登记图片,用户参考上限普通生成 5 张、带规范前置 4 张、图集为 0
生成浮层复用资源引用输入组件,提示词里的 @ 引用直接产出当前 manifest 资产 ID 作为参考
生成任务与队列新增 referenceAssetIds,派发时以 referenceAssetIds 交给原生侧解析账号绑定
图集入口不呈现参考选择器,超限在提交前给出原因并挡住提交,不做静默截断
补充参考模型、面板接线与队列派发的定向测试
2026-09-17 16:59:49 +08:00
suzmii ef982fdb78 拆分原生引用与前端生成并行实现边界
使用独立工作树处理原生引用,固定引用资产ID接缝
2026-09-17 16:59:48 +08:00
suzmii 91b65f94ca 确保工作树测试读取本地共享组件源码
补齐共享包测试别名以避免复用依赖指向其他工作树

记录工作树依赖复用的解析检查要求
2026-09-17 16:18:17 +08:00
suzmii 70513cf049 按规范评审固定参考上限并放行实现
普通生成最多五张参考,图集拒绝额外参考

复用现有引用快照并核验恢复校验,明确里程碑验收边界
2026-09-17 16:09:14 +08:00
suzmii 87aed0b765 补齐画布任务身份与引用持久化边界
明确参考图片入参、账号绑定与恢复校验

固定栏目整理撤销、多选范围与素材名称来源
2026-09-17 16:06:57 +08:00
suzmii 733a7015af 明确画布验收修复范围与行为合同
统一生成占位与参考、资源卡展示和布局交互的验收要求

补充单里程碑并行实现计划和独立评审门禁
2026-09-17 16:02:37 +08:00
lhk229 3e3b35713d 合并最新主分支并清理新增策划耦合
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust smoke (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Has been cancelled
合入 master 的聊天界面、回合控制及运行时更新
解决七处合并冲突,保持退役策划 V1/V2 链路删除
将新增界面判断连接到 Design Agent 状态并移除旧 GDD 测试依赖
保留现役文档建造指令、回合终止及推理档设置
2026-09-17 02:37:48 +00:00
lhk229 ea34cbdea6 合并远程分支并解决提交历史分叉
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 5m44s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Failing after 5m21s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 5m21s
Project CI / Backend tests (pull_request) Failing after 10s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Failing after 5m47s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m50s
Project CI / Repository checks (pull_request) Failing after 11s
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
合并 origin/rm/design-v2 的 master 合并记录
保留本地已合入的 master 更新及策划 Agent 清理成果
合并前后文件树一致,仅统一双方提交历史
2026-09-17 02:29:46 +00:00
lhk229 f957a545bf Merge remote-tracking branch 'origin/master' into rm/design-v2 2026-09-15 15:52:12 +00:00
lhk229 c2064836ce Merge branch 'master' into rm/design-v2
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust smoke (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
2026-09-15 20:59:09 +08:00
lhk229 8e6fb7d078 更新退役GDD样式测试
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 4m31s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 4m35s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m58s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 5m2s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 4m5s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m15s
Project CI / Frontend tests (pull_request) Successful in 4m35s
Project CI / Repository checks (pull_request) Successful in 4m3s
Project CI / Native shell tests (pull_request) Successful in 7m5s
Project CI / Backend tests (pull_request) Successful in 8m2s
Project CI / AI game creator shell web tests (pull_request) Successful in 3m12s
删除对已移除 GDD 审批弹层选择器的旧断言

保留现役窗口覆盖层样式校验
2026-09-15 08:56:16 +00:00
lhk229 94bd7310a9 更新 Design Agent 运行时说明
移除随包提示词中的旧 project-planning 部署描述

改为当前 Design Agent Runtime 的单 Agent 运行口径
2026-09-15 08:15:15 +00:00
lhk229 1d50f4fef5 清理策划样例路径残留
将通用 file.read 证据测试改用中性 design.md 样例

确保现役代码和测试不再引用旧 Fast GDD 路径
2026-09-15 08:12:32 +00:00
lhk229 23bb0bf131 Merge remote-tracking branch 'origin/master' into rm/design-v2
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 4m39s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 4m27s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m35s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 4m56s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 4m18s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 1m57s
Project CI / Frontend tests (pull_request) Failing after 3m31s
Project CI / Repository checks (pull_request) Failing after 3m25s
Project CI / Native shell tests (pull_request) Successful in 6m48s
Project CI / AI game creator shell web tests (pull_request) Failing after 3m16s
Project CI / Backend tests (pull_request) Successful in 7m26s
2026-09-15 08:09:21 +00:00
lhk229 758ef5ceec 清理旧Fast GDD命名残留
将通用验收证据和委派测试中的旧 GDD 路径改为中性产物

保留做游戏 Agent 的通用证据回执逻辑
2026-09-15 08:07:12 +00:00
lhk229 ea843641e8 清理退役策划提示词入口
删除 Supervisor playbook 中旧 project-planning 委派说明

保留通用协作与回执规则
2026-09-15 08:04:27 +00:00
lhk229 26d31d73e2 清理退役策划注释残留
移除静态委派验收中的旧 plan.submit_gdd 说明

保持通用委派返工判定语义不变
2026-09-15 08:01:36 +00:00
lhk229 2bce007a0a 收口退役策划运行时分流
移除旧策划 source、plan.submit_gdd 专用卡和相关前端提交分支

保留通用 Supervisor 提交与做游戏 DAG 路由

同步临时计划文档的实际删除边界
2026-09-15 07:58:03 +00:00
lhk229 337cb39340 删除退役策划事件测试
移除 planning-session-v2-stream 订阅注销测试

保留通用 Tauri 事件订阅竞态回归覆盖
2026-09-15 07:43:39 +00:00
lhk229 6d4f7a976f 清理旧策划委派语义
删除 project-planning 的澄清与用户修订跳转说明

保留做游戏 Agent 的静态委派返工语义

更新运行时诊断测试中的旧策划身份夹具
2026-09-15 07:41:25 +00:00
lhk229 12092ceb50 删除策划专用文件与GDD命令
移除旧 Fast GDD 打开命令及 Tauri 注册

删除规划目录和 GDD 投影的专用文件保护分支

保留通用 Agent 控制面与 DirectCodex 文件安全边界
2026-09-15 07:27:30 +00:00
lhk229 bcbf398b65 移除退役策划界面样式
删除旧 GDD 审批卡与策划窄条的孤儿 CSS

更新聊天布局测试以覆盖现役 DirectCodex 选择器

保留设计 Agent 和通用项目工作台表现
2026-09-15 07:05:46 +00:00
lhk229 151c61ad08 清理退役策划测试夹具
删除策划 V2 与批准 GDD 的旧测试数据和调用模拟

保留现役设计 Agent 与 DirectCodex 的界面测试

移除测试中对退役规划命令的断言
2026-09-15 07:00:00 +00:00
lhk229 79b49519b6 删除退役GDD交付入口
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust smoke (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
移除已批准 fast GDD 自动转建游戏流程

清理工作台与首页创建控制器中的旧策划回调

保留 DirectCodex 正常做游戏入口
2026-09-15 06:41:41 +00:00
lhk229 ec2180f281 删除策划V2会话状态链路
移除 App 内策划 V2 会话、GDD 同步与审批状态

删除策划 V2 类型转换模块和退役 GDD 状态类型

保留现役设计 Agent 会话恢复与项目运行时入口
2026-09-15 06:38:29 +00:00
lhk229 341080f42d 收紧退役策划与Supervisor清理边界
明确Supervisor产品运行链路已退役

将做游戏和做素材统一收口到DirectCodex

保留16 Agent DAG仅到编译所需范围
2026-09-15 05:49:54 +00:00
lhk229 45401de57e 解耦设计Agent与策划V2状态
为 Design Agent 增加独立 active、瞬态回复和 reasoning 状态

保留策划 V2 会话自身的状态与消息动画链路

统一项目总控轮询使用两条策划 lane 的合并状态

移除 Design Agent 对旧 planning lane ref 的共享依赖
2026-09-15 05:03:38 +00:00
lhk229 908d248f27 Merge remote-tracking branch 'origin/master' into rm/design-v2
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust smoke (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
2026-09-15 04:49:59 +00:00
lhk229 65598b9886 补充退役策划Agent解耦清理计划
新增退役策划 Agent V1/V2 解耦清理里程碑规范

新增分提交实施计划、修改边界与验收命令

明确不主动清理做游戏 Supervisor 与 16 Agent DAG
2026-09-15 04:49:49 +00:00
lhk229 64ab959d4f 移除退役策划 V2 流式事件订阅
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Failing after 3m3s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Failing after 2m47s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Failing after 2m48s
Project CI / Backend tests (pull_request) Failing after 16s
Project CI / AI game creator shell Rust smoke (pull_request) Failing after 2m2s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Failing after 2m26s
Project CI / Repository checks (pull_request) Failing after 11s
Project CI / AI game creator shell web tests (pull_request) Failing after 1m7s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 3m33s
Project CI / Native shell tests (pull_request) Failing after 3m17s
Project CI / Frontend tests (pull_request) Successful in 3m42s
删除 planning-session-v2-stream 事件监听与旧实时回复错误处理

保留新版 Design Agent 事件订阅链路
2026-09-15 02:42:03 +00:00
lhk229 9833a53e06 Merge remote-tracking branch 'origin/master' into rm/design-v2
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Failing after 3m2s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Failing after 3m6s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Failing after 3m7s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Failing after 3m10s
Project CI / AI game creator shell Rust smoke (pull_request) Failing after 1m57s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m39s
Project CI / Native shell tests (pull_request) Failing after 3m35s
Project CI / AI game creator shell web tests (pull_request) Failing after 1m6s
Project CI / Repository checks (pull_request) Successful in 2m49s
Project CI / Frontend tests (pull_request) Successful in 4m4s
Project CI / Backend tests (pull_request) Successful in 7m22s
2026-09-15 02:27:25 +00:00
lhk229 0847b1bb83 Merge remote-tracking branch 'origin/rm/design-v2' into rm/design-v2
Project CI / Repository checks (pull_request) Successful in 2m42s
Project CI / Frontend tests (pull_request) Successful in 3m0s
Project CI / Native shell tests (pull_request) Failing after 3m51s
Project CI / Backend tests (pull_request) Successful in 5m46s
2026-09-14 07:23:48 +00:00
lhk229 8f691d4c8c Merge branch 'master' into rm/design-v2
Project CI / Repository checks (pull_request) Failing after 3m20s
Project CI / Frontend tests (pull_request) Failing after 2m42s
Project CI / Native shell tests (pull_request) Failing after 3m57s
Project CI / Backend tests (pull_request) Successful in 6m23s
2026-09-14 15:22:30 +08:00
lhk229 d3b9f326f0 删除孤立的策划 GDD 模型模块
移除已无调用方的 planning_gdd_model.rs 及模块导出

删除仅依赖退役提交错误类型的无效判定函数
2026-09-14 07:20:13 +00:00
lhk229 7eb2326a76 移除退役策划 V2 运行态刷新入口
Project CI / Repository checks (pull_request) Failing after 2m22s
Project CI / Frontend tests (pull_request) Failing after 3m7s
Project CI / Native shell tests (pull_request) Failing after 3m47s
Project CI / Backend tests (pull_request) Successful in 6m38s
删除旧版策划状态随项目总控运行态刷新的专用 effect

移除仅服务该 effect 的 planningLane 判定模块
2026-09-14 06:30:07 +00:00
lhk229 9fc28790a4 移除退役策划 V2 运行面板参数
删除项目总控运行面板中已无调用方的 GDD 审批状态参数
2026-09-14 06:26:54 +00:00
lhk229 cea45a608d 删除退役策划 V2 前端审批面板
移除旧版 GDD 审批卡和策划运行条组件

项目总控视图仅保留新版 Design Agent 与通用运行面板
2026-09-14 06:23:16 +00:00
lhk229 ee03ade156 Merge remote-tracking branch 'origin/master' into rm/design-v2
Project CI / Repository checks (pull_request) Failing after 3m24s
Project CI / Frontend tests (pull_request) Failing after 3m2s
Project CI / Backend tests (pull_request) Successful in 6m55s
Project CI / Native shell tests (pull_request) Failing after 4m20s
2026-09-14 06:19:46 +00:00
lhk229 4933c6c380 删除退役策划 V2 前端测试契约
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
移除 Plan GDD 审批测试套件及注册入口
2026-09-14 06:15:13 +00:00
lhk229 931f3eae0a 删除退役策划 V2 Rust Runtime
移除 Planning V2 协议模块与 Tauri 命令注册

保留新版 Design Agent、做游戏 Agent 与共享运行时
2026-09-14 06:07:20 +00:00
lhk229 c5f8fa1ef6 清理旧策划 V1 残留注释
删除已失效的 --plan 策划自动应答说明
2026-09-14 05:54:24 +00:00
244 changed files with 27173 additions and 15065 deletions
+6
View File
@@ -41,6 +41,12 @@ temp*build*/
/apps/ai-game-creator-shell/src-tauri/resources/codex/win-x64/codex-resources/
/apps/ai-game-creator-shell/src-tauri/resources/codex/win-x64/codex-package.json
/apps/ai-game-creator-shell/src-tauri/resources/plugins/
/apps/ai-game-creator-shell/src-tauri/resources/codex/mac-native/bin/
/apps/ai-game-creator-shell/src-tauri/resources/codex/mac-native/codex-path/
/apps/ai-game-creator-shell/src-tauri/resources/codex/mac-native/codex-resources/
/apps/ai-game-creator-shell/src-tauri/resources/codex/mac-native/codex-package.json
/apps/ai-game-creator-shell/src-tauri/resources/codex/mac-native/manifest.json
/apps/ai-game-creator-shell/src-tauri/resources/codex/mac-native/NOTICE.md
/plugins/agc-cocos-editor/native/payload/
/apps/ai-game-creator-shell/logs/
/apps/ai-game-creator-shell/.llm-drafts/
+16
View File
@@ -172,6 +172,20 @@ _Avoid_: 多步骤向导、完整规则编辑器、拖拽编辑器
Bark Battle 平台作品闭环按契约与领域规则、后端存储/API、最小前端纵切、投影体验、收口验证的顺序推进。
_Avoid_: mock 先行堆积、前后端各自发散、先做排行榜 UI
## 项目开发对话(DirectProject
**项目对话历史**:
AGC 本地项目内 Codex 原始对话条目的持久集合,是聊天展示、工具卡片和线程恢复注入的唯一持久事实源。
_Avoid_: 会话缓存、展示态历史、按 UI 需要另存的对话副本
**运行态事件**:
Thread Manager 向订阅者推送的当前回合原始事件流,只服务运行期间与短期断线恢复,不替代项目对话历史。
_Avoid_: 进度通知、快照轮询、第二套历史
**聊天投影**:
把项目对话历史条目与运行态事件转换成消息气泡和工具卡片的读取期转换;不持久化,也不构成事实源。
_Avoid_: 投影缓存文件、已脱敏卡片库、第二套 reducer
## Relationships
- 一个 **汪汪声浪大作战** 单局包含多个 **有效声浪触发**
@@ -206,3 +220,5 @@ _Avoid_: mock 先行堆积、前后端各自发散、先做排行榜 UI
- “入口闭环”曾可能只指内部 demo 或单个详情 CTA;已解析为 **正式作品入口闭环**,不新增独立专区或活动页。
- “创作编辑”曾可能指多步骤向导或完整编辑器;已解析为 **轻配置编辑流程**,使用单页表单 + 预览卡片完成保存草稿、发布和发布后跳转作品详情。
- “实施顺序”曾可能按 UI 或功能并行发散;已解析为契约/领域规则先行,再做后端存储/API,随后打通最小前端纵切,最后补投影体验与收口验证。
- “回合进度事件”曾同时指 Direct turn update 与 Thread Manager 运行态事件;已解析为 AGC 项目开发对话只保留 **运行态事件**
- “哪些消息可显示”曾可能由后端历史分页判断;已解析为可见性判断属于 **聊天投影**,后端只按原始条目分页,前端负责跳过不可显示条目并推进分页锚点。
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@genarrative/ai-game-creator-shell",
"private": true,
"version": "0.1.47",
"version": "0.1.67",
"type": "module",
"scripts": {
"dev": "node scripts/start-tauri-dev.mjs",
@@ -957,9 +957,6 @@ async function runInteractiveCargo(cliArguments, setActiveChild) {
return result;
}
// 立项策划跑 standard 档,`agent.delegate` 这类动作按项目权限策略必须逐个确认,
// 而确认和问询都只从 CLI 的 stdin 读。自主构建档没有这一步,所以只有 --plan 需要
// 一个把「人坐在终端前敲 approve」自动化掉的应答器;判据本身仍然走后端确认命令。
const swarmConfirmationPromptPattern = /输入 approve 或 reject$/u;
const swarmUserInputPromptPattern = /请选择 1-\d+,或直接输入其他答案:$/u;
@@ -14,16 +14,71 @@ const appRoot = fileURLToPath(new URL('..', import.meta.url));
// 提交摘要里的 pathspec 与 `git log` 都以仓库根为基准,不能在应用目录里执行。
const repoRoot = path.resolve(appRoot, '..', '..');
const defaultReleaseTarget = 'x86_64-pc-windows-msvc';
const releaseTarget =
process.env.AGC_BUILD_TARGET?.trim() || defaultReleaseTarget;
const bundleRoot = path.join(
appRoot,
'src-tauri',
'target',
releaseTarget,
'release',
'bundle',
);
function defaultTarget() {
return process.env.AGC_BUILD_TARGET?.trim() || defaultReleaseTarget;
}
function explicitBuildTarget(args) {
let target;
const separator = args.indexOf('--');
const options = separator < 0 ? args : args.slice(0, separator);
for (let index = 0; index < options.length; index += 1) {
const argument = options[index];
let value;
if (argument === '--target' || argument === '-t') {
value = options[++index];
} else if (argument.startsWith('--target=')) {
value = argument.slice('--target='.length);
} else {
continue;
}
if (!value?.trim() || value.startsWith('-')) {
throw new Error('--target 缺少有效目标');
}
if (target !== undefined) throw new Error('不能重复指定 --target');
target = value.trim();
}
return target;
}
function validateReleaseTarget(target) {
if (target === 'universal-apple-darwin') {
throw new Error(
'内置 Codex 资源仅支持 macOS 单架构构建,请使用 aarch64-apple-darwin 或 x86_64-apple-darwin',
);
}
if (
![
'x86_64-pc-windows-msvc',
'aarch64-apple-darwin',
'x86_64-apple-darwin',
].includes(target)
) {
throw new Error(`不支持的发布目标:${target}`);
}
return target;
}
/** 在入口冻结目标;所有发布步骤共享同一上下文,不再各自读取默认目标。 */
export function resolveReleaseContext(args = [], env = process.env) {
const target = validateReleaseTarget(
explicitBuildTarget(args) ||
env.AGC_BUILD_TARGET?.trim() ||
defaultReleaseTarget,
);
return Object.freeze({
target,
channel: resolveReleaseChannel(env, target),
bundleRoot: path.join(
appRoot,
'src-tauri',
'target',
target,
'release',
'bundle',
),
});
}
const packageJsonPath = path.join(appRoot, 'package.json');
const rootPackageLockPath = path.resolve(appRoot, '../..', 'package-lock.json');
const tauriConfigPath = path.join(appRoot, 'src-tauri', 'tauri.conf.json');
@@ -99,7 +154,7 @@ export function nextPatchVersion(localVersion, remoteVersion) {
return `${major}.${minor}.${patch + 1}`;
}
export function resolveReleasePlatform(target = releaseTarget) {
export function resolveReleasePlatform(target = defaultTarget()) {
if (target.includes('windows')) return 'windows';
if (target.includes('apple-darwin')) return 'darwin';
if (target.includes('linux')) return 'linux';
@@ -108,7 +163,7 @@ export function resolveReleasePlatform(target = releaseTarget) {
export function resolveReleaseChannel(
env = process.env,
target = releaseTarget,
target = defaultTarget(),
) {
const platform = resolveReleasePlatform(target);
const requested = env.AGC_UPDATE_CHANNEL?.trim();
@@ -142,13 +197,10 @@ export function updateManifestUrl(channel = resolveReleaseChannel()) {
}
/**
* 更新插件按运行时平台键查找清单条目:universal macOS 包同时挂
* `darwin-aarch64` 与 `darwin-x86_64`,单架构目标只挂对应键。
* 单架构产物只登记实际目标,不能把同一原生资源映射为另一架构。
*/
export function resolveManifestPlatformKeys(target = releaseTarget) {
if (target === 'universal-apple-darwin') {
return ['darwin-aarch64', 'darwin-x86_64'];
}
export function resolveManifestPlatformKeys(target = defaultTarget()) {
validateReleaseTarget(target);
if (target === 'aarch64-apple-darwin') return ['darwin-aarch64'];
if (target === 'x86_64-apple-darwin') return ['darwin-x86_64'];
if (target.includes('windows')) {
@@ -256,8 +308,8 @@ function replaceVersionLine(source, version, pattern, label) {
return source.replace(pattern, `$1${version}$3`);
}
export async function prepareReleaseVersion() {
const channel = resolveReleaseChannel();
export async function prepareReleaseVersion(context = resolveReleaseContext()) {
const { channel } = context;
const localVersion = parseVersion(readPackageJson().version, '本地版本');
const remoteVersion = await resolveRemoteHighWaterVersion(channel);
const requestedVersion = process.env.AGC_RELEASE_VERSION?.trim();
@@ -330,18 +382,14 @@ export async function prepareReleaseVersion() {
export function buildTauriBuildArguments(
args = [],
target = releaseTarget,
target = defaultTarget(),
platform = process.platform,
) {
const noBundle = args.includes('--no-bundle');
const targetIndex = args.indexOf('--target');
const explicitTarget =
targetIndex >= 0
? args[targetIndex + 1]
: args
.find((value) => value.startsWith('--target='))
?.slice('--target='.length);
const explicitTarget = explicitBuildTarget(args);
const targetArgs = noBundle || explicitTarget ? [] : ['--target', target];
if (!noBundle || explicitTarget)
validateReleaseTarget(explicitTarget || target);
const features = defaultEditorFeatures(
explicitTarget || (noBundle ? platform : target),
);
@@ -374,18 +422,33 @@ function writeChannelConfigFile(channel) {
return configPath;
}
export function runTauriBuild(args = []) {
const tauriArguments = buildTauriBuildArguments(args);
if (!tauriArguments.includes('--config') && !tauriArguments.includes('-c')) {
const channel = resolveReleaseChannel();
const configPath = writeChannelConfigFile(channel);
console.log(
`[ai-game-creator-shell] 渠道 ${channel} 端点配置:${configPath}`,
);
tauriArguments.push('--config', configPath);
export function runTauriBuild(
args = [],
context = resolveReleaseContext(args),
{ spawn = spawnSync } = {},
) {
if (
explicitBuildTarget(args) &&
explicitBuildTarget(args) !== context.target
) {
throw new Error('构建参数与发布上下文目标不一致');
}
const tauriArguments = buildTauriBuildArguments(args, context.target);
const { channel } = context;
const configPath = writeChannelConfigFile(channel);
console.log(
`[ai-game-creator-shell] 渠道 ${channel} 端点配置:${configPath}`,
);
// 最后合并渠道配置,防止用户配置中的端点与实际发布目标分叉。
const separator = tauriArguments.indexOf('--');
tauriArguments.splice(
separator < 0 ? tauriArguments.length : separator,
0,
'--config',
configPath,
);
const npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm';
const result = spawnSync(
const result = spawn(
npmCommand,
['--prefix', '../..', 'exec', 'tauri', '--', ...tauriArguments],
{ cwd: appRoot, stdio: 'inherit', shell: process.platform === 'win32' },
@@ -402,11 +465,11 @@ function listFiles(root) {
});
}
function artifactPriority(filePath) {
function artifactPriority(filePath, target) {
const name = path.basename(filePath).toLowerCase();
if (releaseTarget.includes('windows')) return name.endsWith('.exe') ? 0 : 99;
if (target.includes('windows')) return name.endsWith('.exe') ? 0 : 99;
// 更新链路要的是 updater 产物(macOS 为 .app.tar.gz),dmg 只作人工分发。
if (releaseTarget.includes('apple-darwin')) {
if (target.includes('apple-darwin')) {
return name.endsWith('.app.tar.gz') ? 0 : 99;
}
if (name.endsWith('.appimage.tar.gz')) return 0;
@@ -416,7 +479,8 @@ function artifactPriority(filePath) {
return 99;
}
export function selectReleaseArtifact(files) {
export function selectReleaseArtifact(files, target = defaultTarget()) {
validateReleaseTarget(target);
const explicit = process.env.AGC_UPDATE_ARTIFACT?.trim();
if (explicit) {
const resolved = path.resolve(explicit);
@@ -427,9 +491,10 @@ export function selectReleaseArtifact(files) {
}
return (
[...files]
.filter((filePath) => artifactPriority(filePath) < 99)
.filter((filePath) => artifactPriority(filePath, target) < 99)
.sort((left, right) => {
const priority = artifactPriority(left) - artifactPriority(right);
const priority =
artifactPriority(left, target) - artifactPriority(right, target);
return priority || left.localeCompare(right);
})[0] ?? null
);
@@ -450,13 +515,15 @@ function readUpdaterSignature(artifactPath) {
export function createUpdateManifest(
artifactPath,
{
channel = resolveReleaseChannel(),
target = releaseTarget,
target = defaultTarget(),
channel = resolveReleaseChannel(process.env, target),
publishedAt = new Date().toISOString(),
notes = readReleaseNotes(),
commit = readHeadCommit(),
} = {},
) {
validateReleaseTarget(target);
resolveReleaseChannel({ AGC_UPDATE_CHANNEL: channel }, target);
const signature = readUpdaterSignature(artifactPath);
const version = readPackageJson().version;
const fileName = path.basename(artifactPath);
@@ -604,9 +671,11 @@ export function createLegacyUpdateManifest(
};
}
export async function generateUpdateManifest() {
const channel = resolveReleaseChannel();
const artifact = selectReleaseArtifact(listFiles(bundleRoot));
export async function generateUpdateManifest(
context = resolveReleaseContext(),
) {
const { channel, target, bundleRoot } = context;
const artifact = selectReleaseArtifact(listFiles(bundleRoot), target);
if (!artifact) {
throw new Error(`未找到可发布的 AGC 安装包:${bundleRoot}`);
}
@@ -623,7 +692,7 @@ export async function generateUpdateManifest() {
`[ai-game-creator-shell] 未生成自动更新摘要(上一发布 commit=${previousCommit ?? '未知'},客户端相关提交=${commits ? commits.length : '不可判定'},最近提交=${recentCommits ? recentCommits.length : '不可判定'}`,
);
}
const manifest = createUpdateManifest(artifact, { channel, notes });
const manifest = createUpdateManifest(artifact, { channel, target, notes });
const manifestPath = path.join(bundleRoot, 'latest.json');
fs.writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
const notesPath = path.join(bundleRoot, 'release-notes.txt');
@@ -675,12 +744,24 @@ export async function generateUpdateManifest() {
};
}
export async function buildRelease(
args = [],
{
prepareVersion = prepareReleaseVersion,
build = runTauriBuild,
generateManifest = generateUpdateManifest,
} = {},
) {
const context = resolveReleaseContext(args);
if (!args.includes('--no-bundle')) await prepareVersion(context);
build(args, context);
if (!args.includes('--no-bundle')) return generateManifest(context);
}
if (
process.argv[1] &&
path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)
) {
const args = process.argv.slice(2);
if (!args.includes('--no-bundle')) await prepareReleaseVersion();
runTauriBuild(args);
if (!args.includes('--no-bundle')) await generateUpdateManifest();
await buildRelease(args);
}
@@ -14,6 +14,8 @@ import { fileURLToPath } from 'node:url';
import {
agcReleasePathPatterns,
buildRelease,
buildTauriBuildArguments,
collectRecentReleaseCommits,
collectReleaseCommits,
compareVersions,
@@ -22,11 +24,14 @@ import {
createUpdateManifest,
formatRecentReleaseNotes,
formatReleaseNotes,
generateUpdateManifest,
nextPatchVersion,
resolveManifestPlatformKeys,
resolvePreviousReleaseCommit,
resolveReleaseChannel,
resolveReleaseContext,
resolveRemoteHighWaterVersion,
runTauriBuild,
selectReleaseArtifact,
updateManifestUrl,
} from './build-release.mjs';
@@ -34,6 +39,21 @@ import {
const windowsTarget = 'x86_64-pc-windows-msvc';
const universalTarget = 'universal-apple-darwin';
test('native sidecar builds reject universal targets and accept each macOS architecture', () => {
assert.throws(() => buildTauriBuildArguments([], universalTarget), /单架构/);
assert.throws(
() => buildTauriBuildArguments(['--target=universal-apple-darwin']),
/单架构/,
);
for (const target of ['aarch64-apple-darwin', 'x86_64-apple-darwin']) {
assert.deepEqual(buildTauriBuildArguments([], target), [
'build',
'--target',
target,
]);
}
});
function withEnv(overrides, run) {
const previous = new Map();
for (const [key, value] of Object.entries(overrides)) {
@@ -132,9 +152,12 @@ test('channel manifest URL and build-time endpoint follow the channel', () => {
});
});
test('universal macOS builds publish one artifact under both platform keys', () => {
assert.deepEqual(resolveManifestPlatformKeys(universalTarget), [
test('macOS manifests only advertise the architecture actually built', () => {
assert.throws(() => resolveManifestPlatformKeys(universalTarget), /单架构/);
assert.deepEqual(resolveManifestPlatformKeys('aarch64-apple-darwin'), [
'darwin-aarch64',
]);
assert.deepEqual(resolveManifestPlatformKeys('x86_64-apple-darwin'), [
'darwin-x86_64',
]);
assert.deepEqual(resolveManifestPlatformKeys(windowsTarget), [
@@ -142,6 +165,218 @@ test('universal macOS builds publish one artifact under both platform keys', ()
]);
});
test('release context resolves explicit targets before environment/default and fails closed', () => {
for (const args of [
['--target', 'aarch64-apple-darwin'],
['--target=aarch64-apple-darwin'],
['-t', 'aarch64-apple-darwin'],
]) {
for (const env of [{}, { AGC_BUILD_TARGET: windowsTarget }]) {
const context = resolveReleaseContext(args, env);
assert.equal(context.target, 'aarch64-apple-darwin');
assert.equal(context.channel, 'dev-mac');
assert.match(
context.bundleRoot.replaceAll('\\', '/'),
/target\/aarch64-apple-darwin\/release\/bundle$/,
);
assert.ok(Object.isFrozen(context));
}
assert.throws(
() => resolveReleaseContext(args, { AGC_UPDATE_CHANNEL: 'dev-win' }),
/只能用于 windows/,
);
}
assert.equal(resolveReleaseContext([], {}).target, windowsTarget);
assert.equal(
resolveReleaseContext([], { AGC_BUILD_TARGET: 'x86_64-apple-darwin' })
.channel,
'dev-mac',
);
for (const args of [
['--target'],
['--target='],
['--target', '--no-bundle'],
['--target', windowsTarget, '--target=aarch64-apple-darwin'],
['--target', universalTarget],
['--target', 'unknown'],
])
assert.throws(() => resolveReleaseContext(args, {}));
});
test('explicit macOS target drives version lookup, Tauri endpoint, artifact and manifest together', async () => {
const calls = [];
const seenContexts = [];
await withStubbedFetch(
(url) => {
calls.push(url);
assert.match(url, /\/dev-mac\/latest\.json$/);
return jsonResponse({ version: '0.1.67' });
},
() =>
withEnv(
{ AGC_BUILD_TARGET: undefined, AGC_UPDATE_CHANNEL: undefined },
() =>
buildRelease(['--target', 'aarch64-apple-darwin'], {
prepareVersion: async (context) => {
seenContexts.push(context);
assert.equal(
await resolveRemoteHighWaterVersion(context.channel),
'0.1.67',
);
},
build: (args, context) => {
seenContexts.push(context);
runTauriBuild(args, context, {
spawn: (_binary, command) => {
const configIndex = command.lastIndexOf('--config');
const config = JSON.parse(
readFileSync(command[configIndex + 1], 'utf8'),
);
assert.match(
config.plugins.updater.endpoints[0],
/\/dev-mac\/latest\.json$/,
);
assert.ok(command.includes('aarch64-apple-darwin'));
assert.ok(
!command.includes('--features=cocos-editor-execute'),
);
return { status: 0 };
},
});
},
generateManifest: (context) => {
seenContexts.push(context);
withSignedArtifact('陶泥儿.app.tar.gz', (artifact) => {
assert.equal(
selectReleaseArtifact(
['/tmp/win.exe', artifact, '/tmp/mac.dmg'],
context.target,
),
artifact,
);
const manifest = createUpdateManifest(artifact, context);
assert.deepEqual(Object.keys(manifest.platforms), [
'darwin-aarch64',
]);
assert.match(
manifest.platforms['darwin-aarch64'].url,
/\/dev-mac\//,
);
});
},
}),
),
);
assert.equal(calls.length, 1, 'Mac 不应读取 Windows 迁移指针');
assert.equal(seenContexts.length, 3);
assert.ok(seenContexts.every((context) => context === seenContexts[0]));
});
test('real manifest writer uses the resolved bundle root and does not emit Windows artifacts', async () => {
const root = mkdtempSync(path.join(os.tmpdir(), 'agc-mac-manifest-'));
try {
const artifact = path.join(root, '陶泥儿.app.tar.gz');
writeFileSync(artifact, 'mac package');
writeFileSync(`${artifact}.sig`, 'mac signature');
writeFileSync(path.join(root, 'windows.exe'), 'wrong platform');
const context = {
...resolveReleaseContext(['--target=x86_64-apple-darwin'], {}),
bundleRoot: root,
};
const result = await withStubbedFetch(
(url) => {
assert.match(url, /\/dev-mac\/latest\.json$/);
return jsonResponse({}, 404);
},
() => generateUpdateManifest(context),
);
assert.equal(result.artifact, artifact);
assert.equal(result.manifestPath, path.join(root, 'latest.json'));
assert.equal(result.legacyManifestPath, null);
assert.deepEqual(Object.keys(result.manifest.platforms), ['darwin-x86_64']);
assert.match(result.manifest.platforms['darwin-x86_64'].url, /\/dev-mac\//);
} finally {
rmSync(root, { recursive: true, force: true });
}
});
test('invalid target or mismatched channel fails before any release side effect', async () => {
let touched = false;
const sideEffects = {
prepareVersion: () => {
touched = true;
},
build: () => {
touched = true;
},
generateManifest: () => {
touched = true;
},
};
await assert.rejects(
() => buildRelease(['--target', universalTarget], sideEffects),
/单架构/,
);
await withEnv({ AGC_UPDATE_CHANNEL: 'dev-win' }, () =>
assert.rejects(
() => buildRelease(['--target=aarch64-apple-darwin'], sideEffects),
/只能用于 windows/,
),
);
assert.equal(touched, false);
});
test('Windows remains the default and explicit Windows overrides macOS environment', () => {
const files = ['/tmp/mac.app.tar.gz', '/tmp/windows.exe', '/tmp/mac.dmg'];
for (const context of [
resolveReleaseContext([], {}),
resolveReleaseContext(['--target', windowsTarget], {
AGC_BUILD_TARGET: 'aarch64-apple-darwin',
}),
]) {
assert.equal(context.channel, 'dev-win');
assert.equal(
selectReleaseArtifact(files, context.target),
'/tmp/windows.exe',
);
runTauriBuild(
['--target', windowsTarget, '--config', 'user-config.json'],
context,
{
spawn: (_binary, command) => {
assert.ok(command.includes('--features=cocos-editor-execute'));
assert.ok(command.includes('user-config.json'));
const configIndex = command.lastIndexOf('--config');
const config = JSON.parse(
readFileSync(command[configIndex + 1], 'utf8'),
);
assert.match(
config.plugins.updater.endpoints[0],
/\/dev-win\/latest\.json$/,
);
return { status: 0 };
},
},
);
}
});
test('no-bundle smoke skips version writes and manifest generation', async () => {
const steps = [];
await buildRelease(['--no-bundle', '--target=aarch64-apple-darwin'], {
prepareVersion: () => {
steps.push('version');
},
build: (_args, context) => {
steps.push(context.channel);
},
generateManifest: () => {
steps.push('manifest');
},
});
assert.deepEqual(steps, ['dev-mac']);
});
test('channel manifest carries version, platform keys and signature', () => {
withSignedArtifact('陶泥儿_0.1.48_x64-setup.exe', (artifact) => {
withEnv({ AGC_UPDATE_RELEASE_NOTES: '修复与改进' }, () => {
@@ -345,6 +580,7 @@ test('release upload forces overwrite for artifact, signature and channel pointe
);
assert.match(source, /agc\/\$\{channel\}\/latest\.json/u);
assert.match(source, /agc\/latest\.json/u);
assert.match(source, /await buildRelease\(process\.argv\.slice\(2\)\)/u);
});
test('release notes list client commits with short sha and bound their size', () => {
@@ -35,6 +35,12 @@ const windowsTauriConfig = JSON.parse(
'utf8',
),
);
const macosTauriConfig = JSON.parse(
fs.readFileSync(
new URL('../src-tauri/tauri.macos.conf.json', import.meta.url),
'utf8',
),
);
const cargoManifestSource = fs.readFileSync(
new URL('../src-tauri/Cargo.toml', import.meta.url),
'utf8',
@@ -1358,6 +1364,37 @@ if (windowsTauriConfig.bundle?.useLocalToolsDir !== true) {
'AI game creator shell Windows Tauri config must cache bundling tools in the project target directory',
);
}
assert.deepEqual(
macosTauriConfig.bundle?.resources,
Object.fromEntries([
...[
'bin/codex',
'bin/codex-code-mode-host',
'codex-path/rg',
'codex-resources/zsh/bin/zsh',
'codex-package.json',
'NOTICE.md',
'manifest.json',
].map((file) => [
`resources/codex/mac-native/${file}`,
`coding-agent/mac-native/${file}`,
]),
['resources/plugins', 'plugins'],
]),
'macOS must bundle the complete native Codex layout and plugin workspace',
);
assert.deepEqual(
macosTauriConfig.plugins?.updater?.endpoints,
[
'https://agc-dev.oss-rg-china-mainland.aliyuncs.com/agc/dev-mac/latest.json',
],
'macOS local builds must not use the Windows update channel',
);
assert.equal(
macosTauriConfig.bundle?.macOS?.minimumSystemVersion,
'15.0',
'macOS deployment baseline must cover the bundled native zsh requirement',
);
if (tauriConfig.app?.withGlobalTauri !== true) {
throw new Error(
@@ -1553,13 +1590,11 @@ if (!viteConfigSource.includes('allow: [repoRoot]')) {
);
}
if (
!(
tauriConfig.build?.beforeDevCommand?.includes(
'run ai-game-creator-shell:dev-server',
) || tauriConfig.build?.beforeDevCommand?.includes('run agc:serve')
)
) {
if (!(
tauriConfig.build?.beforeDevCommand?.includes(
'run ai-game-creator-shell:dev-server',
) || tauriConfig.build?.beforeDevCommand?.includes('run agc:serve')
)) {
throw new Error(
'AI game creator shell beforeDevCommand must start the selected Vite dev server',
);
@@ -1722,7 +1757,7 @@ for (const snippet of [
'fn append_local_permission_log_at(',
'"command.auto"',
'GameCreationAppPermission::Auto',
'GAME_CREATOR_BUNDLED_CODEX_CLI_RELATIVE_PATH',
'fn game_creator_bundled_codex_cli_path',
'validate_game_creator_bundled_codex_cli',
'内置 Codex CLI 完整性校验失败',
]) {
@@ -0,0 +1,222 @@
import assert from 'node:assert/strict';
import { spawn, spawnSync } from 'node:child_process';
import { createHash } from 'node:crypto';
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
// 只操作临时复制品;不启动 GUI、不读取开发机凭据、不访问 Provider。
assert.equal(process.platform, 'darwin', '此验证必须在 macOS 执行');
const source = path.resolve(process.argv[2] || '');
assert.ok(
source.endsWith('.app') && fs.statSync(source).isDirectory(),
'请传入 .app 绝对路径',
);
const root = fs.realpathSync(
fs.mkdtempSync(path.join(os.tmpdir(), 'agc-macos-bundle-')),
);
const app = path.join(root, '陶泥儿 隔离测试.app');
const home = path.join(root, 'home');
const config = path.join(root, 'config');
const tmp = path.join(root, 'tmp');
const codexHome = path.join(root, 'codex-home');
for (const directory of [home, config, tmp, codexHome]) {
fs.mkdirSync(directory, { mode: 0o700 });
}
const env = {
HOME: home,
PATH: '/usr/bin:/bin',
TMPDIR: tmp,
CODEX_HOME: codexHome,
};
function run(command, args) {
const result = spawnSync(command, args, {
cwd: root,
env,
encoding: 'utf8',
timeout: 30_000,
maxBuffer: 1024 * 1024,
});
assert.ifError(result.error);
return result;
}
async function hashFile(file) {
const hash = createHash('sha256');
for await (const chunk of fs.createReadStream(file)) hash.update(chunk);
return hash.digest('hex');
}
async function handshake(executable) {
const child = spawn(executable, ['app-server'], {
cwd: root,
env,
stdio: ['pipe', 'pipe', 'pipe'],
});
let buffered = '';
let stderrBytes = 0;
try {
await new Promise((resolve, reject) => {
const timer = setTimeout(
() => reject(new Error('app-server 初始化超时')),
15_000,
);
const finish = (error) => {
clearTimeout(timer);
if (error) reject(error);
else resolve();
};
child.on('error', finish);
child.on('exit', (code) =>
finish(new Error(`app-server 提前退出 ${code}`)),
);
child.stderr.on('data', (chunk) => {
stderrBytes += chunk.length;
if (stderrBytes > 1024 * 1024)
finish(new Error('app-server stderr 超限'));
});
child.stdout.on('data', (chunk) => {
buffered += chunk.toString('utf8');
if (buffered.length > 1024 * 1024)
return finish(new Error('app-server stdout 超限'));
let end;
while ((end = buffered.indexOf('\n')) >= 0) {
const line = buffered.slice(0, end);
buffered = buffered.slice(end + 1);
try {
const message = JSON.parse(line);
if (message.id !== 1) continue;
assert.ok(message.result?.userAgent, '初始化必须返回真实服务身份');
assert.equal(message.error, undefined);
child.stdin.write(`${JSON.stringify({ method: 'initialized' })}\n`);
finish();
} catch (error) {
finish(error);
}
}
});
child.stdin.on('error', finish);
child.stdin.write(
`${JSON.stringify({
id: 1,
method: 'initialize',
params: {
clientInfo: {
name: 'agc_bundle_smoke',
title: 'AGC bundle smoke',
version: '1',
},
capabilities: { experimentalApi: true },
},
})}\n`,
);
});
} finally {
if (child.exitCode === null && child.signalCode === null) {
await new Promise((resolve) => {
const timer = setTimeout(() => child.kill('SIGKILL'), 3000);
child.once('exit', () => {
clearTimeout(timer);
resolve();
});
child.kill('SIGTERM');
});
}
}
}
try {
fs.cpSync(source, app, { recursive: true });
const resources = path.join(app, 'Contents/Resources');
const bundle = path.join(resources, 'coding-agent/mac-native');
const executable = path.join(bundle, 'bin/codex');
const main = path.join(
app,
'Contents/MacOS/genarrative-ai-game-creator-shell',
);
const manifest = JSON.parse(
fs.readFileSync(path.join(bundle, 'manifest.json'), 'utf8'),
);
assert.equal(manifest.schemaVersion, 'genarrative-codex-sidecar.v2');
assert.equal(
manifest.platform,
process.arch === 'arm64' ? 'darwin-arm64' : 'darwin-x64',
);
assert.equal(manifest.version, 'codex-cli 0.147.0');
const components = [
'bin/codex',
'bin/codex-code-mode-host',
'codex-path/rg',
'codex-resources/zsh/bin/zsh',
'codex-package.json',
];
assert.deepEqual(Object.keys(manifest.files).sort(), [...components].sort());
for (const component of components) {
const file = path.join(bundle, component);
assert.equal(await hashFile(file), manifest.files[component], component);
if (component !== 'codex-package.json') {
fs.accessSync(file, fs.constants.X_OK);
const arch = run('/usr/bin/lipo', ['-archs', file]);
assert.equal(arch.status, 0, component);
assert.equal(
arch.stdout.trim(),
process.arch === 'arm64' ? 'arm64' : 'x86_64',
component,
);
}
}
assert.ok(fs.existsSync(path.join(bundle, 'NOTICE.md')));
const plugin = path.join(resources, 'plugins/agc-cocos-editor');
for (const file of [
'plugin.json',
'src/entry.mjs',
'panels/cocos-editor.html',
]) {
assert.ok(fs.existsSync(path.join(plugin, file)), file);
}
const packageFiles = fs.readdirSync(resources, { recursive: true });
assert.ok(
!packageFiles.some((file) =>
/(^|\/)(\.env[^/]*|auth\.json|node_modules|target|\.git)(\/|$)|\.(exe|dll)$/.test(
file,
),
),
);
assert.equal(run(executable, ['--version']).stdout.trim(), manifest.version);
assert.equal(
run(path.join(bundle, 'codex-path/rg'), ['--version']).status,
0,
);
assert.equal(
run(path.join(bundle, 'codex-resources/zsh/bin/zsh'), ['--version']).status,
0,
);
// 使用正式 AGC 查找/校验入口,而非只证明 sidecar 可以独立执行。
const status = run(main, ['--config-dir', config, '--llm-status']);
const statusText = `${status.stdout}\n${status.stderr}`;
assert.ok(!statusText.includes('Codex CLI 未安装'), statusText);
assert.ok(
statusText.includes('authentication-required'),
'隔离账号应仅被登录门禁拒绝',
);
await handshake(executable);
// 临时复制品缺少辅助程序时,正式入口必须拒绝内置程序;PATH 无全局 Codex 可兜底。
fs.renameSync(
path.join(bundle, 'bin/codex-code-mode-host'),
path.join(root, 'saved-code-mode-host'),
);
const broken = run(main, ['--config-dir', config, '--llm-status']);
assert.notEqual(broken.status, 0);
assert.match(`${broken.stdout}\n${broken.stderr}`, /Codex CLI 未安装/);
console.log(
'PASS: 隔离安装包资源、架构、摘要、权限、正式 Codex 查找、app-server 握手及缺组件拒绝',
);
console.log(
'未验证:GUI、真实登录/Provider 对话、Cocos macOS 原生桥接;插件 Node 仍为外部前提',
);
} finally {
fs.rmSync(root, { recursive: true, force: true });
}
@@ -12,8 +12,7 @@ if (!/^[a-z0-9][a-z0-9.-]{1,62}$/u.test(bucket) || /[\r\n\0]/u.test(endpoint)) {
process.env.AGC_UPDATE_OSS_BASE_URL ||= `https://${bucket}.${endpoint}/agc`;
const dryRun = readReleaseDryRun();
const { generateUpdateManifest, prepareReleaseVersion, runTauriBuild } =
await import('./build-release.mjs');
const { buildRelease } = await import('./build-release.mjs');
function runOssutil(args) {
const binary = process.env.OSSUTIL_BIN?.trim() || 'ossutil';
@@ -51,10 +50,8 @@ function runOssutil(args) {
if (result.status !== 0) process.exit(result.status ?? 1);
}
await prepareReleaseVersion();
runTauriBuild([]);
const { artifact, channel, legacyManifestPath, manifest, manifestPath } =
await generateUpdateManifest();
await buildRelease(process.argv.slice(2));
const artifactKey = `agc/${channel}/${manifest.version}/${path.basename(artifact)}`;
// Jenkins/ossutil 默认会在目标对象已存在时交互询问并按默认值跳过;
// 发布清单是固定的 latest 指针,必须显式覆盖,否则流水线会误报成功但远端仍保留旧版本。
@@ -1192,7 +1192,7 @@ async function main() {
function isDirectModuleExecution() {
return Boolean(
process.argv[1] &&
resolve(process.argv[1]) === fileURLToPath(import.meta.url),
resolve(process.argv[1]) === fileURLToPath(import.meta.url),
);
}
+1 -1
View File
@@ -1745,7 +1745,7 @@ dependencies = [
[[package]]
name = "genarrative-ai-game-creator-shell"
version = "0.1.47"
version = "0.1.67"
dependencies = [
"agent-runtime-core",
"axum",
@@ -1,6 +1,6 @@
[package]
name = "genarrative-ai-game-creator-shell"
version = "0.1.47"
version = "0.1.67"
edition = "2021"
publish = false
+82 -48
View File
@@ -1,31 +1,18 @@
#[path = "build_support/codex_bundle.rs"]
mod codex_bundle;
#[path = "build_support/frontend_dist_guard.rs"]
mod frontend_dist_guard;
#[path = "build_support/runtime_prompt_bundle.rs"]
mod runtime_prompt_bundle;
#[cfg(windows)]
use sha2::{Digest, Sha256};
use std::collections::BTreeSet;
use std::env;
use std::fs;
use std::path::PathBuf;
#[cfg(windows)]
use std::io::{BufReader, Read};
const BUNDLED_CODEX_CLI_VERSION: &str = "codex-cli 0.147.0";
#[cfg(windows)]
const BUNDLED_CODEX_FILES: [&str; 6] = [
"bin/codex.exe",
"bin/codex-code-mode-host.exe",
"codex-path/rg.exe",
"codex-resources/codex-command-runner.exe",
"codex-resources/codex-windows-sandbox-setup.exe",
"codex-package.json",
];
#[cfg(windows)]
fn sha256_file(path: &std::path::Path) -> Result<String, std::io::Error> {
let file = fs::File::open(path)?;
let mut reader = BufReader::new(file);
@@ -42,7 +29,15 @@ fn sha256_file(path: &std::path::Path) -> Result<String, std::io::Error> {
}
fn stage_bundled_codex_cli(manifest_dir: &std::path::Path) {
#[cfg(windows)]
let target = env::var("TARGET").expect("Cargo TARGET");
println!("cargo:rustc-env=AGC_BUILD_TARGET={target}");
let Some(layout) = codex_bundle::for_target(&target) else {
assert!(
!target.contains("windows") && !target.contains("apple-darwin"),
"不支持的 Codex 随包目标:{target}"
);
return;
};
{
let app_root = manifest_dir
.parent()
@@ -51,24 +46,23 @@ fn stage_bundled_codex_cli(manifest_dir: &std::path::Path) {
.parent()
.and_then(|apps_dir| apps_dir.parent())
.expect("AI 游戏创作应用必须位于仓库 apps 目录下");
let source_candidates = [
app_root.join(
"node_modules/@openai/codex-win32-x64/vendor/x86_64-pc-windows-msvc",
),
app_root.join(
"node_modules/@openai/codex/node_modules/@openai/codex-win32-x64/vendor/x86_64-pc-windows-msvc",
),
repo_root.join(
"node_modules/@openai/codex-win32-x64/vendor/x86_64-pc-windows-msvc",
),
repo_root.join(
"node_modules/@openai/codex/node_modules/@openai/codex-win32-x64/vendor/x86_64-pc-windows-msvc",
),
];
let package = layout.npm_package;
let source_candidates = [app_root, repo_root]
.into_iter()
.flat_map(|root| {
[
root.join(format!("node_modules/@openai/{package}/vendor/{target}")),
root.join(format!(
"node_modules/@openai/codex/node_modules/@openai/{package}/vendor/{target}"
)),
]
})
.collect::<Vec<_>>();
let source = source_candidates
.iter()
.find(|path| {
BUNDLED_CODEX_FILES
layout
.files
.iter()
.all(|relative| path.join(relative).is_file())
})
@@ -83,14 +77,26 @@ fn stage_bundled_codex_cli(manifest_dir: &std::path::Path) {
.join("")
)
});
let target_dir = manifest_dir.join("resources/codex/win-x64");
let metadata: serde_json::Value = serde_json::from_slice(
&fs::read(source.join("codex-package.json")).expect("读取 Codex 原生包元数据失败"),
)
.expect("Codex 原生包元数据无效");
codex_bundle::validate_package_metadata(&metadata, &target, layout)
.unwrap_or_else(|error| panic!("{error}"));
let target_dir = manifest_dir.join("resources/codex").join(layout.directory);
let notice = target_dir.join("NOTICE.md");
if target.contains("apple-darwin") {
let source_notice =
manifest_dir.join("resources/codex/【声明】Mac内置Codex组件-2026-09-18.md");
stage_plugin_file(&source_notice, &notice);
println!("cargo:rerun-if-changed={}", source_notice.display());
}
if !notice.is_file() {
panic!("内置 Codex CLI 第三方声明缺失:{}", notice.display());
}
fs::create_dir_all(&target_dir).expect("创建内置 Codex CLI 资源目录失败");
let mut file_hashes = serde_json::Map::new();
for relative in BUNDLED_CODEX_FILES {
for relative in layout.files {
let source_path = source.join(relative);
let target_path = target_dir.join(relative);
if let Some(parent) = target_path.parent() {
@@ -104,15 +110,23 @@ fn stage_bundled_codex_cli(manifest_dir: &std::path::Path) {
if !target_matches_source {
fs::copy(&source_path, &target_path).expect("复制内置 Codex CLI 资源失败");
}
// 内容相同但曾被错误 chmod 的 staging 文件也必须恢复执行权限。
fs::set_permissions(
&target_path,
fs::metadata(&source_path)
.expect("读取组件权限失败")
.permissions(),
)
.expect("保留内置 Codex CLI 组件权限失败");
file_hashes.insert(
relative.to_string(),
serde_json::Value::String(source_sha256),
);
}
let manifest = serde_json::json!({
"schemaVersion": "genarrative-codex-sidecar.v2",
"platform": "win32-x64",
"version": BUNDLED_CODEX_CLI_VERSION,
"schemaVersion": codex_bundle::SCHEMA,
"platform": layout.platform,
"version": codex_bundle::CLI_VERSION,
"files": file_hashes,
});
let manifest_path = target_dir.join("manifest.json");
@@ -126,7 +140,7 @@ fn stage_bundled_codex_cli(manifest_dir: &std::path::Path) {
{
fs::write(&manifest_path, manifest_payload).expect("写入内置 Codex CLI 清单失败");
}
for relative in BUNDLED_CODEX_FILES {
for relative in layout.files {
println!("cargo:rerun-if-changed={}", source.join(relative).display());
}
println!("cargo:rerun-if-changed={}", notice.display());
@@ -256,8 +270,11 @@ fn stage_cocos_editor_payload(_manifest_dir: &std::path::Path) {}
///
/// 只复制插件运行需要的清单、入口、面板和 native payload,不复制 native 源码、
/// Cargo target 目录或 node_modules。
#[cfg(windows)]
fn stage_plugin_workspace(manifest_dir: &std::path::Path) {
let target = env::var("TARGET").expect("Cargo TARGET");
if !target.contains("windows") && !target.contains("apple-darwin") {
return;
}
let repo_root = manifest_dir
.parent()
.and_then(|app_root| app_root.parent())
@@ -266,6 +283,10 @@ fn stage_plugin_workspace(manifest_dir: &std::path::Path) {
.to_path_buf();
let workspace = repo_root.join("plugins");
let destination_root = manifest_dir.join("resources/plugins");
// staging 是专用生成目录;重建清除跨目标 payload 与已删除插件的残留。
if destination_root.exists() {
std::fs::remove_dir_all(&destination_root).expect("清理插件 staging 失败");
}
std::fs::create_dir_all(&destination_root).expect("创建插件资源目录失败");
let entries = match std::fs::read_dir(&workspace) {
Ok(entries) => entries,
@@ -273,6 +294,13 @@ fn stage_plugin_workspace(manifest_dir: &std::path::Path) {
};
for entry in entries.flatten() {
let plugin_root = entry.path();
assert!(
!entry
.file_type()
.expect("读取插件目录类型失败")
.is_symlink(),
"插件工作区不允许符号链接"
);
if !plugin_root.is_dir() || !plugin_root.join("plugin.json").is_file() {
continue;
}
@@ -287,17 +315,18 @@ fn stage_plugin_workspace(manifest_dir: &std::path::Path) {
std::path::PathBuf::from("panels"),
std::path::PathBuf::from("native/payload"),
] {
if relative == std::path::Path::new("native/payload") && !target.contains("windows") {
continue;
}
copy_plugin_tree(&plugin_root.join(&relative), &destination.join(&relative));
}
println!("cargo:rerun-if-changed={}", plugin_root.display());
}
}
#[cfg(windows)]
fn stage_plugin_file(source: &std::path::Path, destination: &std::path::Path) {
let Ok(bytes) = std::fs::read(source) else {
return;
};
let bytes = std::fs::read(source)
.unwrap_or_else(|error| panic!("读取随包资源失败 {}{error}", source.display()));
if std::fs::read(destination).is_ok_and(|existing| existing == bytes) {
return;
}
@@ -307,7 +336,6 @@ fn stage_plugin_file(source: &std::path::Path, destination: &std::path::Path) {
std::fs::write(destination, bytes).expect("复制插件资源失败");
}
#[cfg(windows)]
fn copy_plugin_tree(source: &std::path::Path, destination: &std::path::Path) {
let entries = match std::fs::read_dir(source) {
Ok(entries) => entries,
@@ -316,10 +344,17 @@ fn copy_plugin_tree(source: &std::path::Path, destination: &std::path::Path) {
for entry in entries.flatten() {
let target = destination.join(entry.file_name());
let path = entry.path();
assert!(
!entry
.file_type()
.expect("读取插件文件类型失败")
.is_symlink(),
"插件资源不允许符号链接"
);
if path.is_dir() {
let name = entry.file_name();
let name = name.to_string_lossy();
if matches!(name.as_ref(), "target" | "node_modules" | ".git") {
if name.starts_with('.') || matches!(name.as_ref(), "target" | "node_modules") {
continue;
}
std::fs::create_dir_all(&target).expect("创建插件资源目录失败");
@@ -331,12 +366,14 @@ fn copy_plugin_tree(source: &std::path::Path, destination: &std::path::Path) {
if name.contains(".test.") {
continue;
}
if name.starts_with('.') {
continue;
}
stage_plugin_file(&path, &target);
}
}
}
#[cfg(windows)]
fn copy_plugin_file(source: &std::path::Path, destination: &std::path::Path) {
if !source.is_file() {
return;
@@ -345,6 +382,3 @@ fn copy_plugin_file(source: &std::path::Path, destination: &std::path::Path) {
.expect("创建插件资源目录失败");
std::fs::copy(source, destination).expect("复制插件资源失败");
}
#[cfg(not(windows))]
fn stage_plugin_workspace(_manifest_dir: &std::path::Path) {}
@@ -0,0 +1,133 @@
//! 构建与运行共用的平台布局;只允许分发锁定原生包里的明确组件。
pub const VERSION: &str = "0.147.0";
pub const CLI_VERSION: &str = "codex-cli 0.147.0";
pub const SCHEMA: &str = "genarrative-codex-sidecar.v2";
#[derive(Clone, Copy, Debug)]
pub struct Layout {
pub platform: &'static str,
pub npm_package: &'static str,
pub directory: &'static str,
pub executable: &'static str,
pub files: &'static [&'static str],
}
const WINDOWS_FILES: &[&str] = &[
"bin/codex.exe",
"bin/codex-code-mode-host.exe",
"codex-path/rg.exe",
"codex-resources/codex-command-runner.exe",
"codex-resources/codex-windows-sandbox-setup.exe",
"codex-package.json",
];
const MAC_FILES: &[&str] = &[
"bin/codex",
"bin/codex-code-mode-host",
"codex-path/rg",
"codex-resources/zsh/bin/zsh",
"codex-package.json",
];
pub fn for_target(target: &str) -> Option<Layout> {
match target {
"x86_64-pc-windows-msvc" => Some(Layout {
platform: "win32-x64",
npm_package: "codex-win32-x64",
directory: "win-x64",
executable: "bin/codex.exe",
files: WINDOWS_FILES,
}),
"aarch64-apple-darwin" | "x86_64-apple-darwin" => Some(Layout {
platform: if target.starts_with("aarch64") {
"darwin-arm64"
} else {
"darwin-x64"
},
npm_package: if target.starts_with("aarch64") {
"codex-darwin-arm64"
} else {
"codex-darwin-x64"
},
directory: "mac-native",
executable: "bin/codex",
files: MAC_FILES,
}),
_ => None,
}
}
pub fn validate_package_metadata(
metadata: &serde_json::Value,
target: &str,
layout: Layout,
) -> Result<(), String> {
if metadata["layoutVersion"] == 1
&& metadata["version"] == VERSION
&& metadata["target"] == target
&& metadata["entrypoint"] == layout.executable
&& metadata["resourcesDir"] == "codex-resources"
&& metadata["pathDir"] == "codex-path"
{
Ok(())
} else {
Err(format!("Codex 原生包版本、布局或架构不匹配目标 {target}"))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn platform_layouts_are_explicit_and_preserve_upstream_components() {
let mac = for_target("aarch64-apple-darwin").unwrap();
assert_eq!(mac.platform, "darwin-arm64");
assert_eq!(mac.npm_package, "codex-darwin-arm64");
assert!(mac.files.contains(&"codex-resources/zsh/bin/zsh"));
assert!(mac.files.contains(&"bin/codex-code-mode-host"));
assert!(!mac.files.iter().any(|file| file.ends_with(".exe")));
let intel = for_target("x86_64-apple-darwin").unwrap();
assert_eq!(intel.platform, "darwin-x64");
assert_eq!(intel.npm_package, "codex-darwin-x64");
let windows = for_target("x86_64-pc-windows-msvc").unwrap();
assert_eq!(windows.directory, "win-x64");
assert_eq!(windows.files.len(), 6);
assert!(windows
.files
.contains(&"codex-resources/codex-windows-sandbox-setup.exe"));
assert!(for_target("universal-apple-darwin").is_none());
assert!(for_target("aarch64-pc-windows-msvc").is_none());
assert!(for_target("x86_64-unknown-linux-gnu").is_none());
}
#[test]
fn metadata_rejects_version_architecture_and_layout_drift() {
let target = "aarch64-apple-darwin";
let layout = for_target(target).unwrap();
let valid = serde_json::json!({
"layoutVersion": 1,
"version": VERSION,
"target": target,
"entrypoint": "bin/codex",
"resourcesDir": "codex-resources",
"pathDir": "codex-path",
});
assert!(validate_package_metadata(&valid, target, layout).is_ok());
for (key, value) in [
("layoutVersion", serde_json::json!(2)),
("version", serde_json::json!("0.0.0")),
("target", serde_json::json!("x86_64-apple-darwin")),
("entrypoint", serde_json::json!("bin/codex.exe")),
("resourcesDir", serde_json::json!("../private")),
("pathDir", serde_json::json!(null)),
] {
let mut invalid = valid.clone();
invalid[key] = value;
assert!(
validate_package_metadata(&invalid, target, layout).is_err(),
"{key}"
);
}
}
}
File diff suppressed because one or more lines are too long
@@ -2,8 +2,4 @@
需要等待专业 Agent 时不得调用 respond_to_userRuntime 会通过 delegate/all-join 完成屏障保持同一父 run,取得 readyDelegateReceipts 或 readyIsolatedJoins 后直接整合结果。readyDelegateReceipts 中 contractStatus=evidence-ready 只说明终态、产物和验证等客观证据齐全,你仍须按 acceptanceCriteria 判断语义是否满足;needs-repair 不得当作成功。contractStatus=needs-user-input 时,Runtime 会按原 delivery 逐一发起 user.input_request;每个请求答案收齐后,为对应原 delivery 仅创建一次 continuation 委派,repairOfDelegationId 与 continuationOfDelegationId 都指向该原 delivery,并提交 observation 给出的 questionsSha256、answersSha256Runtime 自动派生稳定 continuation identity,禁止跨 delivery 混用指纹。客观或语义不满足时可以发起一次新 agent.delegate,并把 repairOfDelegationId 指向已认领原 delivery;不得对返工再返工或为同一原 delivery 创建第二个返工。专业结果冲突且无法依据用户目标裁决时,合并问题后用一次 user.input_request 询问用户。只有实现路径、产品取舍或缺失事实会实质改变结果时才调用 user.input_request;项目内可读取事实、权限确认和工具失败不得伪装成用户问题。
委派 `project-planning` 时,acceptanceCriteria 只写产物形状、覆盖范围与红线(例如必须交付 `game/fast_gdd.md`、必须原创、必须只定义一个 MVP 闭环),**不得替用户预先裁定产品取舍**。用户没有指定的玩法规则、数值、关卡量级、美术方向和目标人群,一律留给策划子 Agent 按其 3 轮问询预算决定是提问还是按默认建议填写;不要写“未指定的标注为立项假设”“自行假设后继续”这类指令,那会把问询预算作废。平台事实(自包含 Web、desktop/mobile 双视口、keyboard/touch 双输入、本地 HTTP 预览)由 Runtime 固定注入,属于已定事实,不得要求标为待定、建议或开放项。
`project-planning` 的澄清 continuation,必须按 A/B/“需要原型验证”三项合同原样转述;B 是用户确认的 `confirmed/user_option`,不能转成默认建议。若用户后续自由填写推翻已确认决定,保留用户答案原文逐字不改写、不拆分、不搬轮次,并在被推翻决定后注明“已被第 N 轮回答推翻,以后者为准”,在新决定 topic 中写明推翻关系。
只在所有必要回执已认领、manifest 正式任务图已经完成、所有必要返工也已认领、项目副作用已验证且没有待确认动作或待回答请求时给用户最终回复。不要向用户暴露内部 task/event、工具计划、动态 child ID 或调试状态。
@@ -14,7 +14,7 @@ Let the client derive projections from real disk changes and trusted tool result
3. Keep read scopes separate: `asset.list` is the current project manifest, `asset.library.list` is the signed-in account library, and the web project's canvas resource read model is the authoritative canvas list. The account library is not the complete canvas list.
4. Use `canvas.asset_import` for safe account/canvas asset IDs or project-relative local paths. The client rechecks ownership and validates bytes; host absolute paths require native UI file-picker authorization.
5. When the user explicitly asks to create or derive video, character animation, sound effect, or background music, call `agc_create_or_derive_resource`. Use `create` only for video/audio without a source and `derive` with a registered `sourceLocalAssetId`; character animation is always derived from an image. Keep `prompt` inside the per-kind limit that the client really enforces: background music at most 140 characters, sound effect at most 1900, video and character animation at most 4000. A longer prompt is rejected before submission, so write the short version first instead of retrying the same text.
6. When the user explicitly asks to remove an image background, call `agc_remove_background` with a registered image `sourceLocalAssetId` and `assetName`. Optional `backgroundMode` is `complex` (semantic foreground segmentation; default) or `flat` (solid-colour background removal). Prefer `flat` when the background is known to be solid. Only `flat` accepts optional `screenColor`: `auto`, `#RRGGBB`, or omitted for automatic detection by the service. Do not select a colour on behalf of `auto`. The client requires the signed-in account, owns canvas/folder context and task identity, and returns only bounded queue state.
6. When the user explicitly asks to remove an image background, call `agc_remove_background` with a registered image `sourceLocalAssetId` and `assetName`. Optional `backgroundMode` is `complex` (semantic foreground segmentation; default) or `flat` (solid-colour background removal). Prefer `flat` when the background is known to be solid. Only `flat` accepts optional `screenColor`: `auto`, `#RRGGBB`, or omitted for automatic detection by the service. Do not select a colour on behalf of `auto`. The client requires the signed-in account, owns canvas/folder context and task identity, waits for the accepted operation, downloads and registers the completed local asset, and preserves the operation for recovery when the remote result is not yet known.
7. Preserve existing relative paths when a small edit is sufficient so client resource identities remain stable.
8. Do not edit `.agent/manifest.json`, revision counters, version records, resource IDs, canvas identities, source provenance, generation ledgers, or browser receipts by hand.
9. Do not create a version when no game file changed. The client compares content fingerprints and advances revision only after an actual source change.
@@ -16,4 +16,6 @@ Read scopes remain separate: `asset.list` is the current project's local manifes
`prompt` limits are per kind and are enforced before any paid submission: background music accepts 1-140 characters, sound effect 1-1900, video and character animation 1-4000, and image editing (`agc_edit_image`) 1-32000. The client composes the submitted request from a fixed prefix plus your prompt, so an over-limit prompt fails locally with the exact limit; shorten the text rather than resubmitting the same value. `agc_edit_image` remains the image path; this tool never generates or edits still images.
`agc_remove_background` accepts a registered image `sourceLocalAssetId`, `assetName`, and optional `backgroundMode` and `screenColor`. `complex` uses semantic segmentation to identify the foreground; `flat` removes a solid-colour background. Prefer `flat` when the background is known to be solid; omitting the mode selects `complex`. Only `flat` accepts a colour: `auto`, `#RRGGBB`, or omitted for automatic service detection. Never infer a concrete colour for `auto`. Empty or invalid values and colour without `flat` are rejected. The client resolves the formal source resource, canvas/folder context, stable operation identity, idempotency key, and authenticated External v1 `/api/external/v1/editor/images/background-removals` call. Mode and colour are part of request identity. Its result is bounded queue state; Codex must not poll internal workers, construct source URLs, or retry with a new identity after an uncertain response.
`agc_remove_background` accepts a registered image `sourceLocalAssetId`, `assetName`, and optional `backgroundMode` and `screenColor`. `complex` uses semantic segmentation to identify the foreground; `flat` removes a solid-colour background. Prefer `flat` when the background is known to be solid; omitting the mode selects `complex`. Only `flat` accepts a colour: `auto`, `#RRGGBB`, or omitted for automatic service detection. Never infer a concrete colour for `auto`. Empty or invalid values and colour without `flat` are rejected. The client resolves the formal source resource, canvas/folder context, stable operation identity, idempotency key, and authenticated request. Ordinary account mode maps the External v1 shaped route to `/api/editor/images/background-removals`; ExternalDeveloper mode uses `/api/external/v1/editor/images/background-removals`. Mode and colour are part of request identity. After acceptance, the client polls the authenticated generation status route, downloads the completed media, and commits it to the local manifest. If completion is unknown, it retains the same local operation for recovery; it never retries with a new identity or exposes internal worker details.
After an interrupted call, inspect `agc_list_registered_assets.pendingOperations`. Calling `agc_remove_background` again with the same source, name, mode, and colour resumes the matching pending operation. A submission marked `reconciliation-required` needs client-side reconciliation and cannot be automatically resumed. Do not change parameters to bypass a pending task. A queued receipt, fixed progress value, or absent local file does not establish that the background-removal provider is waiting in a queue; report only the observed state.
@@ -14,6 +14,9 @@ Implement the user's actual game request in the current project as an npm-manage
3. Build with the project's npm script before previewing. The playable entry is the package directory's `dist/index.html`; never report an unbuilt bare-module page as playable. Import assets or configure public assets so all runtime media is included in dist; preview and exports cannot read outside it.
4. Build a complete playable loop: visible objective, responsive input, meaningful state changes, success or failure feedback, and a reliable restart path where the game needs one.
5. Fit the active game scene to desktop and mobile viewports without accidental page scrollbars. Reserve deliberate safe space for HUD elements instead of covering interactive content.
- **画布居中只能由一处负责。** 使用 `Phaser.Scale.FIT``autoCenter: Phaser.Scale.CENTER_BOTH` 时,canvas 的直接父容器应使用尺寸明确的普通块布局,不再对同一 canvas 叠加 Grid/Flex 居中、`place-items: center`、自动外边距或居中 transform。Phaser 自动计算的 margin 与 CSS 居中叠加会使竖屏画面向右偏移。
- 若决定由 CSS 居中,则显式使用 `autoCenter: Phaser.Scale.NO_CENTER`,由 CSS 独立完成定位;外围页面可以继续使用 Grid/Flex,限制只针对同一 canvas 的重复定位。
- 出现偏移先检查游戏自身的 CSS 与 Phaser scale 配置,不添加 AGC 预览容器固定偏移补偿。修改布局后重新构建 dist,在桌面、移动及窗口 resize 后检查 canvas 相对游戏父容器居中(误差不超过 1 CSS px)、画面完整且无意外滚动条;不能仅凭 build 成功宣称布局通过。
6. Invoke `taonier-art-assets` for every new game brief that needs visual assets. First reuse suitable registered Taonier art; when the brief's required visual elements are missing or unsuitable, call the reviewed `agc_tools` generation/edit workflow in the same task. After the tool returns, wire its relative paths into the game and verify the rendered result. A game with unused generated assets or placeholder emoji/CSS where requested art should appear is not complete. Load media defensively only for genuinely optional effects, and never relabel a local placeholder as platform art.
7. Let Phaser own the render loop and input dispatch. Avoid duplicate scenes, stale event listeners, and state that survives restart unintentionally.
8. After a meaningful game change, use the browser playtest Skill and fix issues shown by real evidence before reporting completion.
@@ -7,5 +7,7 @@
- Score, steps, health, timer, or other core state updates consistently.
- Restart restores all state and does not duplicate timers, animation loops, or event listeners.
- Desktop and mobile layouts keep the core scene visible without accidental document scrolling.
- 画布的缩放与居中由 Phaser 或 CSS 中的一方独立负责。`FIT + CENTER_BOTH` 不与同一 canvas 父容器的 Grid/Flex 居中、自动外边距或居中 transform 叠加;使用 CSS 居中时关闭 Phaser 自动居中(`NO_CENTER`)。
- 在构建后的实际页面检查桌面、移动和 resize:比较 canvas 与游戏父容器的中心,预期居中时水平/垂直误差不超过 1 CSS px,并检查画面没有溢出或意外滚动条。偏移先修游戏 CSS/scale 配置,不用修改 AGC 预览位置掩盖。
- HUD and overlays reserve space and do not cover essential interactive content.
- Requested Taonier art is visibly integrated into the core experience when available.
@@ -1,6 +1,6 @@
{
"schemaVersion": "agc-skill-pack.v1",
"version": "2026-08-26.20",
"version": "2026-08-26.25",
"skills": [
{
"name": "agc-game-production-workflow",
@@ -63,7 +63,7 @@
"agents/openai.yaml",
"references/platform-art-contract.md"
],
"sha256": "c6329c6a3cbd17a237d042349d7fd8adcf240287ef56d23b49329923e976d534"
"sha256": "47ac742d9b88e5d6cd9833484ab212152578e58ae27f7add312fd1d78183385c"
},
{
"name": "agc-web-game-development",
@@ -80,7 +80,7 @@
"agents/openai.yaml",
"references/game-quality-checklist.md"
],
"sha256": "05b5cfbf7a40fd303717491f5cea84ff339a73359c9678b283fd54d2b5c45efd"
"sha256": "e122d8f3a6d986b594b95c971754d68197bf7896912fa8267d44a7aa129a57ba"
},
{
"name": "agc-browser-playtest",
@@ -123,7 +123,7 @@
"agents/openai.yaml",
"references/projection-contract.md"
],
"sha256": "93210c0eeb73b279d35aa85c201c226139b0bdf041f3300ac2c6e2c1bdd63afe"
"sha256": "247787975944ce8b21d7c879c39c60ec13608056cff9426ac374c9299937d475"
}
]
}
@@ -19,6 +19,12 @@ image, UI design image, or publication material; use `agc_edit_image` for an
edit of an existing registered image; use `taonier_prepare_game_art` only for
the complete game-art package and its canonical slices.
With `agc_generate_image`, `kind="character"` and `kind="art-spritesheet"`
generate the subject on a solid-colour background and automatically matte it
away afterwards, producing transparent-background results; write the prompt
for the subject only, never for a scene. `kind="image"` keeps the rendered
frame without extra processing.
When `agc_generate_image` is used with `kind="art-spritesheet"`, `sliceMode` is
required and has no default, so decide it explicitly:
@@ -0,0 +1,14 @@
# 内置 Codex CLI
本安装包包含锁定版本 Codex CLI 0.147.0 的 macOS 原生组件。
Codex CLI 按 Apache License 2.0 分发,源码与许可证见
https://github.com/openai/codex。
组件来自项目锁定的 `@openai/codex` 原生 npm 依赖,保留上游的
`bin/codex``bin/codex-code-mode-host``codex-path/rg`
`codex-resources/zsh/bin/zsh``codex-package.json` 相对布局。
原生依赖中的 ripgrep 与 zsh 按各自上游许可证分发:
https://github.com/BurntSushi/ripgrep 和 https://www.zsh.org/。
安装包不包含 API Key、登录状态、用户配置或项目数据。
@@ -21,6 +21,7 @@ mod direct_project_history;
mod direct_project_turn_history;
mod direct_runtime;
mod direct_thread_manager;
mod direct_thread_wire;
mod direct_tool_bridge;
mod direct_tool_calls;
mod direct_tools_mcp;
@@ -40,7 +41,8 @@ use codex_app_server::*;
pub(crate) use codex_app_server::{
cancel_direct_codex_turn_at,
direct_codex_canonical_project_identity_for_commands as direct_codex_canonical_project_identity,
direct_game_creator_codex_chat_at, direct_game_creator_home_codex_chat, DirectTurnCancelView,
direct_game_creator_codex_chat_at, direct_game_creator_home_codex_chat,
direct_thread_id_for_project, DirectTurnCancelView,
};
use codex_cli::*;
pub(crate) use codex_cli::{
@@ -55,6 +57,7 @@ pub(crate) use direct_project_history::*;
pub(crate) use direct_project_turn_history::*;
pub(crate) use direct_runtime::*;
pub(crate) use direct_thread_manager::*;
pub(crate) use direct_thread_wire::*;
pub(crate) use direct_tool_bridge::*;
pub(crate) use direct_tool_calls::*;
pub(crate) use direct_tools_mcp::*;
@@ -20,6 +20,29 @@ pub(crate) fn direct_codex_canonical_project_identity(
))
}
/// 项目根目录在 Thread Manager 里的线程身份。
///
/// 订阅入口、回合事件写入和"回合被兜底释放"三处必须算出同一个字符串,否则前端会订阅到
/// 一个永不产生事件的空线程。这个字符串**只取决于路径**:能归一就用 canonical 路径,只有
/// 归一本身失败(路径不存在 / 不是目录 / 无法安全解析)才退回调用方给的字符串。
///
/// 这里刻意不读 `.agent/manifest.json`:那次读取是"项目权威身份"(连接池摘要,见
/// `direct_codex_canonical_project_identity`)的要求,而线程 id 只是一个路径 key。把
/// manifest 的瞬时抖动混进线程 id,会让同一项目在"订阅那一刻"与"跑回合那一刻"算出两个
/// 字符串(例如调用方给的是符号链接路径),订阅就绑到一条永远不会有事件的空线程上。
pub(crate) fn direct_thread_id_for_project(root: &std::path::Path) -> String {
let Ok((canonical_root, _)) = resolve_direct_codex_project_authority(root) else {
return root.to_string_lossy().into_owned();
};
canonical_root
.to_str()
.and_then(|value| value.strip_prefix(r"\\?\"))
.map(std::path::Path::new)
.unwrap_or(canonical_root.as_path())
.to_string_lossy()
.into_owned()
}
pub(super) fn direct_codex_os_path_identity_bytes(path: &std::path::Path) -> Vec<u8> {
#[cfg(unix)]
{

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