Compare commits

..

525 Commits

Author SHA1 Message Date
menghao 6dca066a87 Merge branch 'master' into codex/game-agent-run
Project CI / Repository checks (pull_request) Successful in 1m6s
Project CI / Frontend tests (pull_request) Successful in 3m15s
Project CI / Backend tests (pull_request) Successful in 4m11s
Project CI / Native shell tests (pull_request) Successful in 16m43s
2026-08-07 19:53:30 +08:00
menghao 02ae3d3cad 合并最新主线并解决共享记忆冲突
Project CI / Backend tests (pull_request) Failing after 8s
Project CI / Repository checks (pull_request) Failing after 7s
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Successful in 3m0s
同步 origin/master 的 CI 与生成结果原子提交改动

保留双方 pitfalls 排障记录
2026-08-07 19:50:14 +08:00
kdletters 1bc8ccd077 合并外部 MCP 项目选择修复
Project CI / Frontend tests (push) Successful in 3m2s
Project CI / Backend tests (push) Successful in 3m29s
Project CI / Repository checks (push) Successful in 1m3s
Project CI / Native shell tests (push) Failing after 9m33s
合并紧凑项目列表与封面稳定引用
合并 MCP 请求体参数提示与回归测试
同步 External v1 契约、Skill 与项目记忆
2026-08-07 19:41:27 +08:00
kdletters f113326973 修复 CI 契约检查与原生依赖锁
Project CI / Repository checks (push) Successful in 1m30s
Project CI / Frontend tests (push) Successful in 2m55s
Project CI / Backend tests (push) Successful in 4m1s
Project CI / Native shell tests (push) Successful in 12m55s
改用量词表达工作流缩进正则以通过 ESLint。

补齐 AGC shared-contracts 的 sha2 锁依赖。
2026-08-07 19:26:44 +08:00
kdletters 9c2f02db25 增强 Gitea CI 网络稳定性
Project CI / Repository checks (push) Failing after 51s
Project CI / Native shell tests (push) Failing after 52s
Project CI / Frontend tests (push) Successful in 3m13s
Project CI / Backend tests (push) Successful in 3m46s
为所有 npm ci 增加整命令级有界重试。

补齐 AI 游戏创作 npm 与 Cargo 依赖缓存闭合验证。

更新可信 CI 镜像、缓存漂移告警和 Runner 运维文档。

记录 Actions Gateway CONNECT 断连崩溃的处理与验证边界。
2026-08-07 19:22:46 +08:00
kdletters e099a519ba 修复外部 MCP 项目选择与参数提示
项目列表新增紧凑摘要和最新封面稳定引用
MCP 固定摘要视图并前置校验必填请求体
同步 External v1 OpenAPI、Skill 与项目记忆
补充十九项目超限和四个 415 工具回归测试
2026-08-07 19:21:34 +08:00
kdletters 6c53eda71c 修复编辑器生成结果原子提交
Project CI / Repository checks (push) Successful in 1m23s
Project CI / Native shell tests (push) Failing after 56s
Project CI / Frontend tests (push) Successful in 3m44s
Project CI / Backend tests (push) Successful in 4m33s
新增九类编辑器生成 durable receipt 与稳定提交指纹
统一资源、素材、binding、画布和队列终态的 SpacetimeDB 原子事务
补齐未知结果有界重放、CAS 刷新、lease fencing 与原子失败退款
收紧 owner、project、object、跨记录语义和 replay 一致性校验
保持 Agent 与 External compact 结果契约及 512 KiB 上限
延迟 inline 计费完成边界并区分 procedure dispatch 前后取消
同步 schema、迁移、生成绑定、架构文档和故障回归测试
2026-08-07 18:03:30 +08:00
menghao d04339ad7f 修复自主完成合同测试竞态
Project CI / Repository checks (pull_request) Successful in 1m23s
Project CI / Native shell tests (pull_request) Successful in 12m15s
Project CI / Frontend tests (pull_request) Successful in 3m45s
Project CI / Backend tests (pull_request) Successful in 4m12s
隔离 readiness 状态投影,避免测试重复调度 preview-playtest child
补充 Runtime 终态投影测试的竞态避坑说明
2026-08-07 13:46:16 +08:00
menghao 6fe52a92bb 修复合并后的仓库检查失败
Project CI / Repository checks (pull_request) Successful in 1m8s
Project CI / Frontend tests (pull_request) Successful in 3m2s
Project CI / Backend tests (pull_request) Successful in 3m42s
Project CI / Native shell tests (pull_request) Failing after 9m28s
删除重复维护页原子替换函数并恢复符号链接防护
清理开发栈未使用变量与资源投影正则告警
统一相关测试导入与开发栈导出顺序
2026-08-07 12:44:29 +08:00
menghao 75e3f1d041 合并远端主线并解决游戏创作冲突
Project CI / Repository checks (pull_request) Failing after 33s
Project CI / Backend tests (pull_request) Successful in 3m45s
Project CI / Native shell tests (pull_request) Successful in 13m59s
Project CI / Frontend tests (pull_request) Successful in 3m1s
融合主线 Runtime、安全修复与提示词资源
保留可运行版本、资源替换和数值微调能力
修复资源画布布局、焦点与依赖关系融合
补齐 manifest 并发保护与 Tetris 场景兼容
同步前端测试、Rust 回归测试与权威文档
2026-08-07 12:15:12 +08:00
menghao 8a4b71bf8e 修复资源画布溢出与模板资源投影
Project CI / Backend tests (pull_request) Failing after 10s
Project CI / Repository checks (pull_request) Failing after 10s
Project CI / Frontend tests (pull_request) Successful in 3m3s
Project CI / Native shell tests (pull_request) Successful in 10m23s
闭合资源画布横向收缩链并增加内部滚动条

过滤任务产物通配模板避免生成无效资源卡

补充布局与资源投影回归测试

同步工作台文档与共享排障记忆
2026-08-07 10:53:41 +08:00
menghao 53e37ea361 支持App Run并行开发并修复资源画布
Project CI / Repository checks (pull_request) Failing after 10s
Project CI / Backend tests (pull_request) Failing after 10s
Project CI / Frontend tests (pull_request) Successful in 3m28s
Project CI / Native shell tests (pull_request) Failing after 9m27s
新增App Run独立开发profile并隔离端口、数据库、Tauri身份与AppData
常驻资源排列切换并避免布局状态挤压操作入口
显式扩展资源画布横向滚动范围并收敛依赖图可见连线
补充启动器、资源布局、界面回归测试与项目文档
2026-08-07 10:13:25 +08:00
kdletters 9dab1f53b9 修复Chat生成预算字段兼容
Project CI / Native shell tests (pull_request) Successful in 15m7s
Project CI / Repository checks (push) Successful in 1m14s
Project CI / Frontend tests (push) Successful in 3m57s
Project CI / Backend tests (push) Successful in 4m13s
Project CI / Native shell tests (push) Successful in 12m28s
Project CI / Repository checks (pull_request) Failing after 10s
Project CI / Backend tests (pull_request) Failing after 10s
Project CI / Frontend tests (pull_request) Successful in 3m23s
新增Chat生成预算字段能力并兼容新旧网关
VectorEngine编辑器客户端改用max_completion_tokens
补充BGM请求体回归与协议文档约束
2026-08-06 20:39:19 +08:00
lhk229 281c84b7bf BGM生成路径优化 (#142)
Project CI / Frontend tests (push) Failing after 2m11s
Project CI / Backend tests (push) Successful in 3m33s
Project CI / Native shell tests (push) Successful in 13m57s
Project CI / Repository checks (push) Successful in 1m15s
Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/142
Co-authored-by: Linghong <ink29535@proton.me>
Co-committed-by: Linghong <ink29535@proton.me>
2026-08-06 17:54:40 +08:00
k88936 a03f13d0a5 Fix/动作 前端展示下载+后端数据结构+精选 的问题 (#117)
Project CI / Repository checks (push) Successful in 1m28s
Project CI / Frontend tests (push) Successful in 3m19s
Project CI / Backend tests (push) Successful in 4m3s
Project CI / Native shell tests (push) Successful in 13m58s
原问题

```
历史角色动作是一个兼容例外:
后端允许它没有 editor_project_resource 资源行,只要布局自身保存了完整图片序列帧。
```

- 把生成动作的原视频asstetkind改为 video, 只把图片序列作为action
- db asset新增字段image_sequence_frames_json image_seq_duration_ms等, (原来动作的这些数据存在generation-input中,并不合适)
修改了externaljob,把这部分数据正确填写到数据库中。
- 为避免到处fallback,做了数据库迁移, 脚本: `scripts/spacetime-normalize-editor-character-actions.mjs`   手动进行过画布+素材库中动作序列帧+原始视频 迁移的测试

- 移除preview_video_path字段,  reason:
>preview video
    → separate resource/asset with assetKind="video"
  final transparent action
    → assetKind="character-animation"
    → source_resource_id points to the preview-video resource
    → image_sequence_frames_json contains the actual playable result
>
> So preview_video_path on the final action duplicates the source video resource’s image_src.
- 移除每个frame的index字段 原因: 这个只用于后端内部处理时有一个并发请求, 每个赋一个index方便收集, 后续没有再用到,且与数组本身重复

- 清除副产品preview video的generation_input_json,  因为会影响改造功能, 迁移后预览视频不提供改造(参数), 只有序列帧动作有改造

仍存在的共性问题: #134

- 导出:
下载改为完整序列帧, 封面不再作为fallback, 部分帧读取失败时行为:仍生成 ZIP,并记录失败帧, 不变

画布放置:
before:
![shotmd-1785207959-compressed.webp](/attachments/e56454f0-49a3-4a8a-951f-c21960975f99)
after:
![shotmd-1785231365-compressed.webp](/attachments/886f07df-c25b-4ecc-acc9-160e1795a991)
精选模块: 主页展示, 审核部分UI:
![shotmd-1785500046-compressed.webp](/attachments/9ec3b679-0045-494a-9f20-134f7e73fecf)
![shotmd-1785499780-compressed.webp](/attachments/42396e63-5f26-4853-a367-0f3c15111add)
这两处序列帧们的加载设计为惰式的, 只有hover和单独preview才会全部加载

Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/117
Reviewed-by: 段舒康 <kdletters@qq.com>
Co-authored-by: 王德宇 <kvtodev@outlook.com>
Co-committed-by: 王德宇 <kvtodev@outlook.com>
2026-08-06 16:57:38 +08:00
kdletters b63923eb04 修复智能体根任务可观测性
Project CI / Repository checks (push) Successful in 1m29s
Project CI / Frontend tests (push) Successful in 3m36s
Project CI / Backend tests (push) Successful in 3m31s
Project CI / Native shell tests (push) Successful in 17m40s
根任务先持久化启动确认并在审计异常时保持可执行队列连续性
严格校验根子任务与会话绑定并收束消息身份冲突
幂等恢复公开终态消息并消除回执和隔离汇合重复输出
统一同一运行关联消息的排序与前端状态展示
隔离运行时公开状态与智能体提示词及压缩上下文
补充运行时回归测试、前端测试和工程文档
2026-08-06 15:14:23 +08:00
kdletters 2c57edd59d 修复画布素材导出分片读取
Project CI / Repository checks (push) Successful in 1m2s
Project CI / Frontend tests (push) Successful in 3m6s
Project CI / Backend tests (push) Successful in 3m40s
Project CI / Native shell tests (push) Successful in 14m47s
补齐 OSS 响应体失败与局部 206 的同源字节兜底
保留角色动作逐帧 objectKey 与 assetObjectId
补充导出、Abort、契约回归与文档
2026-08-06 12:56:30 +08:00
kdletters ef6281e135 修复游戏创作条件任务图路由
Project CI / Repository checks (push) Successful in 1m19s
Project CI / Frontend tests (push) Successful in 4m4s
Project CI / Backend tests (push) Successful in 4m5s
Project CI / Native shell tests (push) Successful in 14m55s
固定规则降级为 Supervisor advisory 上下文并持久化工作流决策
加入 code-director 资产审计、精确缺口路由与幂等恢复
避免完整资产、仅缺清单和无效旧资产场景重复或错误生成美术
补齐 Prompt Bundle、共享契约、回归测试和协作文档
2026-08-06 11:53:00 +08:00
kdletters 7b075df398 合并远端主线并保留游戏创作修复
Project CI / Frontend tests (push) Failing after 24s
Project CI / Repository checks (push) Successful in 56s
Project CI / Backend tests (push) Successful in 3m48s
Project CI / Native shell tests (push) Successful in 12m5s
合入 origin/master 的六个最新提交
保留双方 AI 游戏创作 Runtime、资源图与工作台改动
按时间顺序合并三份项目文档记录
通过完整 Rust、App Surface、类型与编码门禁
2026-08-05 23:56:34 +08:00
kdletters bc1fe7d8fd 修复游戏创作编排恢复与进度可观测性
提取并固化 Supervisor 工作流与任务图约束
修复 game-chat 计划收敛、当前 Run 写入归属和素材完成门
补强 parent wake 持久恢复、幂等投影与 deferred 竞态
改进 Agent 进度消息时间戳、等待态和滚动可见性
补齐 Rust、App Surface 回归及项目文档
2026-08-05 23:47:46 +08:00
kdletters 6f181b36a1 修复编辑器生成幂等与参考图契约
Project CI / Frontend tests (push) Failing after 22s
Project CI / Repository checks (push) Successful in 58s
Project CI / Backend tests (push) Successful in 3m30s
Project CI / Native shell tests (push) Successful in 12m34s
生成队列按稳定请求标识去重并保持外部幂等哈希兼容
统一拒绝参考图超限并同步前端、后端、Provider 与 OpenAPI 契约
按真实归属重建生成引用并阻止直接持久化伪造来源
锁定参考图在途上传上下文并保留批量部分成功结果
关闭内部生成 POST 自动重试并补齐回归测试与项目文档
修正最新主线开发者密钥弹窗的导入排序门禁
2026-08-05 23:31:16 +08:00
kdletters e5ebdf0a8e 修复开发者密钥时间显示
Project CI / Repository checks (push) Failing after 40s
Project CI / Backend tests (push) Successful in 3m55s
Project CI / Frontend tests (push) Successful in 3m8s
Project CI / Native shell tests (push) Successful in 14m3s
复用个人中心时间解析逻辑格式化秒级小数时间戳
统一展示密钥创建时间和最近使用时间
补充弹窗回归测试与接入文档约束
2026-08-05 21:48:30 +08:00
lhk229 8f19964e3f 加入手动完美像素入口;像素艺术勾选时自动补提示词约束 (#124)
Project CI / Repository checks (push) Successful in 1m0s
Project CI / Backend tests (push) Successful in 3m52s
Project CI / Native shell tests (push) Successful in 13m8s
Project CI / Frontend tests (push) Successful in 2m43s
Co-authored-by: 段舒康 <kdletters@qq.com>
Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/124
Reviewed-by: 段舒康 <kdletters@qq.com>
Co-authored-by: Linghong <ink29535@proton.me>
Co-committed-by: Linghong <ink29535@proton.me>
2026-08-05 21:28:40 +08:00
menghao 62e0fe94ef 资源卡依赖关系及类型分类预览 (#129)
Project CI / Repository checks (push) Successful in 1m2s
Project CI / Frontend tests (push) Successful in 3m5s
Project CI / Backend tests (push) Successful in 3m41s
Project CI / Native shell tests (push) Successful in 13m7s
完成资源卡按类型和按依赖分类展现的功能

Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/129
Co-authored-by: menghao <mh18530625731@163.com>
Co-committed-by: menghao <mh18530625731@163.com>
2026-08-05 19:15:46 +08:00
kdletters 0cc257ce6d 允许开发环境访问托管MCP
Project CI / Repository checks (push) Successful in 1m13s
Project CI / Frontend tests (push) Successful in 3m35s
Project CI / Backend tests (push) Successful in 4m30s
Project CI / Native shell tests (push) Successful in 12m50s
将dev公开域名加入MCP Host与Origin白名单
新增正负例锁定DNS rebinding防护
同步外部API文档和项目排障经验
2026-08-05 15:23:26 +08:00
kdletters 427fbca100 修复 Runner GUI owner 跨重启登记
Project CI / Repository checks (push) Successful in 1m16s
Project CI / Frontend tests (push) Successful in 3m15s
Project CI / Backend tests (push) Successful in 3m49s
Project CI / Native shell tests (push) Successful in 12m42s
保存 GUI owner attach 参数并按 AppData 与 bootId 重放
在 Runner endpoint 返回前失败关闭未完成的 owner 登记
补充幂等、重试、配置隔离测试和生命周期文档
2026-08-05 15:14:40 +08:00
kdletters 17f8f4b48b 修正游戏创作硬截止恢复测试
Project CI / Repository checks (push) Successful in 1m1s
Project CI / Native shell tests (push) Successful in 11m27s
Project CI / Frontend tests (push) Successful in 3m12s
Project CI / Backend tests (push) Successful in 3m36s
删除与同动作生成恢复语义冲突的过期重启断言
保留硬截止对账现场与生成账本脱敏验证
2026-08-05 10:44:39 +08:00
menghao dc7c7dc6cc 完成P7验收修复与CI稳定性加固
Project CI / Repository checks (pull_request) Failing after 10s
Project CI / Backend tests (pull_request) Failing after 11s
Project CI / Frontend tests (pull_request) Failing after 18s
Project CI / Native shell tests (pull_request) Failing after 7m24s
修正工作台前端 lint 与正式测试切片初始化依赖
补齐可调参数完成态测试夹具并稳定生成恢复 HTTP 读取
修正 macOS Mach-O release 产物识别与原生壳门禁
同步阶段七验收文档与长期排障记忆
2026-08-05 10:00:09 +08:00
kdletters 2ca674b5d8 修正运行态测试来源默认值
Project CI / Repository checks (push) Successful in 57s
Project CI / Frontend tests (push) Successful in 3m20s
Project CI / Backend tests (push) Successful in 3m51s
Project CI / Native shell tests (push) Failing after 8m45s
无 source 提交保留原有 Supervisor 来源

移除测试夹具中的无关格式变化
2026-08-04 22:06:37 +08:00
kdletters 838feaeae9 修复游戏聊天续写来源匹配
Project CI / Frontend tests (push) Successful in 3m45s
Project CI / Backend tests (push) Successful in 4m41s
Project CI / Native shell tests (push) Failing after 9m45s
Project CI / Repository checks (push) Successful in 1m56s
Steer 目标增加 Runtime source 精确匹配

游戏聊天仅续写同来源 Run 并保留跨入口任务隔离

补充模型与 AppSurface 回归夹具和项目记忆
2026-08-04 22:02:32 +08:00
kdletters cd96db3fb6 恢复游戏创作生成任务并完善运行进度
Project CI / Repository checks (push) Successful in 1m14s
Project CI / Frontend tests (push) Failing after 23s
Project CI / Backend tests (push) Successful in 3m51s
Project CI / Native shell tests (push) Failing after 9m52s
持久化并原样恢复 External v1 生成请求、operation 和同一 pending action
允许画布生成对账回执校验后收敛到最终终态
兼容受控换签素材在透明代理 fake-IP 环境下安全下载
保持对账步骤与 context bundle 一致以支持同一任务续跑
压缩运行状态卡片、增加详情弹层和消息时间戳
补齐恢复链、Agent DB、界面回归及项目文档
2026-08-04 21:42:12 +08:00
kdletters 3f47b2df87 修复master现有CI基线失败
Project CI / Native shell tests (push) Successful in 12m30s
Project CI / Repository checks (push) Successful in 1m3s
Project CI / Backend tests (push) Successful in 3m40s
Project CI / Frontend tests (push) Successful in 2m58s
整理六处前端导入顺序并移除未使用类型导入

同步Project Supervisor测试断言到权威Prompt Bundle文案
2026-08-04 21:37:12 +08:00
kdletters 04251f42a7 禁止协作Prompt跨语义复用
Project CI / Frontend tests (push) Successful in 3m18s
Project CI / Backend tests (push) Successful in 4m11s
Project CI / Repository checks (push) Failing after 44s
Project CI / Native shell tests (push) Failing after 11m33s
为runtime supervisor chat variant overlay与Provider fragment建立单一section所有权
仅允许Supervisor planning与chat显式复用同一identity section
阻断动态variant与静态composition的重复注入
补齐跨域alias负例并同步架构文档
2026-08-04 18:58:51 +08:00
kdletters 22edb1dfb1 收紧Supervisor Prompt所有权
从planning visual与chat组合推导完整Supervisor专属section集合
拒绝专属section流入公共runtime平台变体专业overlay或Provider fragment
将公共Runtime header改为身份中立并消除Supervisor双重system身份
保留普通专业Agent规划与最终回复身份约束
补齐跨层逃逸负例并同步架构文档
2026-08-04 18:58:51 +08:00
kdletters 68d202f4a4 隔离Supervisor专属Prompt段
限制identity section仅用于Supervisor planning与chat
限制final-reply section仅用于Supervisor chat
拒绝公共runtime变体overlay与Provider fragment复用专属段
补齐五类失败关闭回归并同步架构文档
2026-08-04 18:58:51 +08:00
kdletters 9c978f00cb 补全协作Prompt增量构建监听
递归登记Prompt Bundle各级目录为构建依赖
确保嵌套目录新增孤立Markdown触发失败关闭
补充深层目录依赖回归并同步架构文档
2026-08-04 18:58:51 +08:00
kdletters 07a18d516b 强类型化协作Prompt选择器
将role overlay source改为构建期强类型语义selector
消除Supervisor身份合同的第二个配置入口
强制Supervisor规划与最终回复复用同一身份section
移除user context中的Supervisor重复身份注入
收窄background context builder接口并补齐失败关闭回归
同步协作graph配置化边界文档
2026-08-04 18:58:51 +08:00
kdletters b8e3eb4c7f 保留专业Agent回复身份约束
仅对Supervisor final-reply移除重复核心身份
保留普通专业Agent在tool-plan与final-reply上下文中的身份约束
增加普通Agent两条请求路径的回归断言
2026-08-04 18:58:50 +08:00
kdletters 15a0924d4b 拆分Supervisor身份与回复合同
将Supervisor共享核心身份与最终回复规则拆成独立Prompt section
由manifest组合interaction和final-reply system prompt
让background planning只注入核心身份并移除final-reply user context重复合同
补齐请求级单次注入断言、构建期组合校验和边界文档
2026-08-04 18:58:50 +08:00
kdletters d02b4afeae 收紧协作Prompt单一来源
复用Bundle内Supervisor身份合同覆盖后台规划上下文
将首批协作协议错误收敛为结构化事实并由外置fragment给出动作指令
监听Prompt Bundle根目录以阻断增量构建中的孤立section
补齐源码回流门禁、依赖断言和边界文档
2026-08-04 18:58:50 +08:00
kdletters ab08ac0ac3 外置Supervisor交互协作提示
将Supervisor交互与最终回复身份合同迁入版本化Prompt Bundle
将isolated模板目录静态说明纳入manifest组合并仅在Rust注入动态节点ID
补齐构建期注册、源码回流门禁和运行期回归覆盖
同步协作graph配置化边界文档
2026-08-04 18:58:50 +08:00
kdletters 82f5455972 外置Provider协作图提示片段
把 isolated 与 all-join 合同移入 Prompt Bundle
把 autonomous 首轮与 Supervisor manifest 指令移入 Prompt Bundle
把首批协作、回执收敛、DAG 等待和试玩返工指令移入 Prompt Bundle
保留 Rust 对工具收窄、状态判断和正式 DAG 的强制执行
补充 fragment 注册校验、生产源码门禁和请求级回归
2026-08-04 18:58:50 +08:00
kdletters 84926ee0cd 外置智能体协作编排与节点目录
Project CI / Repository checks (push) Failing after 4m58s
Project CI / Frontend tests (push) Successful in 3m18s
Project CI / Backend tests (push) Successful in 4m9s
Project CI / Native shell tests (push) Successful in 14m3s
由 Prompt Bundle manifest 统一驱动 section、composition、变体和 role overlay
由构建脚本生成 Supervisor 与六组专业 Agent 的静态节点目录
构建期失败关闭校验路径、引用、selector、alias 与 seed DAG 一致性
补充平台、Editor、Provider 请求、节点快照和非法 manifest 回归
同步 Runtime 技术方案与项目决策记录
2026-08-04 18:58:50 +08:00
kdletters e14130f234 修复静态视觉状态与可见证据
Canvas、context 与图片整体赋值进入状态流并失效旧绑定
无条件 return、throw 与 ESM 依赖失败阻断后续视觉证据
telemetry 仅接受可见 DOM 与可达 JavaScript 状态字段
CSS 资产路径保持大小写并要求命中可见元素
新增视觉反例正例并更新共享决策日志
2026-08-04 18:58:50 +08:00
kdletters a00b0af348 修复脚本复合调用与Promise回调图
限定复合赋值与字面量短路的可调用结果
保留序列表达式函数对象覆盖与删除身份
补齐原生Promise变量回调与直接绑定构造边
新增控制流回归并同步技术方案和决策记录
2026-08-04 18:58:50 +08:00
kdletters 3a70b0ed87 修复静态视觉证据与脚本语义
按 Script Record 边界组合 classic 脚本并保持 ASI 与 defer 顺序

以 AST 和 semantic binding 关联可见 Canvas、绘制调用与资源赋值时序

保持动态 namespace 只读写入语义并排除不可达投影证据

过滤 inert 与非 JavaScript 玩法诱饵并保持资产路径大小写

补充视觉回归、完成合同预期与长期技术文档
2026-08-04 18:58:50 +08:00
kdletters 3212955c08 修复ESM解构投影与模块完成性
按源码顺序投影副作用依赖声明并按声明身份去重重命名
支持对象和数组解构写入导出绑定及最终可调用根传播
按可达绑定使用建立动态导入解构需求
扩展顶层 Promise await 的静态不完成识别与回归
同步技术方案与共享决策记录
2026-08-04 18:58:50 +08:00
kdletters eb83634fb0 修复脚本短路构造与Promise链调用图
按JavaScript短路语义建模sequence、logical与逻辑赋值callee

补齐assignment、conditional与未覆盖bind的构造目标解析

穿透delete括号并恢复函数对象原型内建调用

沿动态导入Promise链传播精确callback参数槽

补充控制流回归及技术方案与共享决策记录
2026-08-04 18:58:50 +08:00
kdletters fbd99278fa 修复ESM初始化与动态成员投影
live binding 仅以模块初始化结束时的最终 callable 建立外部需求。

直接 awaited namespace 成员按 occurrence 支持赋值、回调、构造与深层成员替换。

side-effect import 按依赖顺序投影全局效果并对静态不完成顶层 await 失败关闭。

投影保持依赖和声明源码顺序,循环去重同步移除重复初始化写入。

assignment class expression 分离 static 与 instance member demand。

补充正例、反例、视觉回归并更新技术方案与共享决策。
2026-08-04 18:58:50 +08:00
kdletters 02b80c048c 修复脚本延迟状态与复合调用边
异步回调沿完整闭包调用链读取同步收尾状态

函数对象内建覆盖支持普通成员来源与删除恢复

复合callee与普通函数构造器建立正确调用边

补充控制流回归测试与权威文档约束
2026-08-04 18:58:50 +08:00
kdletters 566567973c 修复视觉门 HTML 与 classic 脚本时序
隔离惰性与原始文本容器中的 Canvas 和样式诱饵
按解析阻塞与 defer 阶段组合 classic 脚本并拒绝 async 不确定顺序
补充视觉回归、权威技术方案与长期决策记录
2026-08-04 18:58:50 +08:00
kdletters d4f5d9ce6d 修复动态模块赋值根与直接成员需求
将导出 live binding、对象成员与 prototype 安装的 callable 纳入精确投影可达根

记录直接 await import namespace 成员的 occurrence 级 export demand

补充静态实例隔离、恒假边界与传递动态依赖回归

同步 AI 游戏创作技术方案与共享决策
2026-08-04 18:58:50 +08:00
kdletters ac002098f7 修复视觉脚本与模块求值顺序
Project CI / Repository checks (push) Failing after 31s
Project CI / Frontend tests (push) Failing after 4m14s
Project CI / Backend tests (push) Successful in 4m59s
Project CI / Native shell tests (push) Successful in 18m23s
保留 raw-text JavaScript 原文并屏蔽 HTML 注释诱饵
按 HTML 标签顺序组合 classic inline 与 external 脚本
按依赖先于 importer 的顺序组合 ESM 投影
补充视觉、脚本顺序与模块初始化回归
同步静态视觉门技术方案与项目决策
2026-08-04 18:58:50 +08:00
kdletters 9250fb7b1f 修复异步回调状态与函数别名覆盖
区分异步回调的可达注册点与闭包外层状态执行点
按函数对象身份共享 call、apply、bind 自有成员覆盖
补充异步时序、函数别名和独立 bind 对象回归
同步技术方案与项目决策记录
2026-08-04 18:58:50 +08:00
kdletters 88d3de2398 修复脚本回调与函数内建调用图
区分异步回调可达根与同步回调副作用传播时点

跟踪函数对象自有 call apply bind 覆盖并保留条件分支

保留 new class expression 赋值后的实例 owner

补充调用图回归测试与技术决策文档
2026-08-04 18:58:49 +08:00
kdletters debc9cb5c0 修复模块脚本视觉资产门
复用有界模块投影检查 inline 与 external module 的可达 drawImage
拒绝未链接、恒假与纯 HTML 路径视觉诱饵
补充完成合同回归和视觉门文档
2026-08-04 18:58:49 +08:00
kdletters 1923e8e314 修复ESM导出绑定初始化投影
将导出根的直接顶层赋值与原声明共同投影。

按语义根符号纳入对象成员与原型安装的RHS依赖。

新增live binding回归并同步技术方案与决策记录。
2026-08-04 18:58:49 +08:00
kdletters 4f9df30dba 修复脚本分支与回调参数快照
在条件测试完成后分别冻结两侧 callable identity。

按回调参数自身起点解析身份,保留前置参数副作用。

新增两类求值顺序回归并同步技术方案与决策记录。
2026-08-04 18:58:49 +08:00
kdletters 4bed4a149a 修复脚本调用与终止求值顺序
冻结 identifier callee 与 new constructor 的参数前身份,并将调用副作用保留在参数之后。

将 callable assignment 延后到 RHS 完成,保留自调用赋值的旧 callable。

按 Oxc AST 函数体与语句边界处理 return、throw、guard 和 catch 的 alias 副作用。

新增六类求值顺序回归并同步技术方案与项目决策记录。
2026-08-04 18:58:49 +08:00
kdletters e37945e306 修复可调用回调与视觉脚本可达性
合并条件表达式两端可调用身份并保留成员 bind 赋值结果

穿透回调调用括号并校正 Promise 回调参数槽

使用原始大小写脚本计算视觉资产语义可达性

补充回归测试与 Runtime 技术决策文档
2026-08-04 18:58:49 +08:00
kdletters d574732156 修复循环模块回接与内联源码限额
循环投影声明去重后继续把 import 引用回接到既有 canonical,并补足稳定确认轮次。

内联模块先按原文累计 2 MiB 源码预算,再执行语法和语义失败关闭。

新增 self-cycle、无效超限与无效小型内联模块回归,并同步技术方案与共享决策。
2026-08-04 18:58:49 +08:00
kdletters 3863d95456 修复游戏脚本构造继承与可调用身份
补齐显式和隐式派生构造、直接类表达式与继承成员查找。

区分普通函数和箭头函数的 this 词法所有者。

支持赋值函数、本地别名与 bind 结果的调用边。

区分业务 call apply bind 方法与 Function.prototype 调用。

新增六组失败回归并同步技术方案与项目决策。
2026-08-04 18:58:49 +08:00
kdletters 149b21622d 修复脚本别名求值顺序与分支状态
Project CI / Repository checks (push) Failing after 45s
Project CI / Frontend tests (push) Successful in 3m7s
Project CI / Backend tests (push) Successful in 3m40s
Project CI / Native shell tests (push) Failing after 17m14s
冻结 receiver 赋值时的 source owner,阻止后续重赋值倒灌

按 JavaScript 参数与 RHS 求值顺序传播嵌套调用副作用

补齐 switch 条件赋值、无条件退出截断与条件关键字作用域语义

新增回归测试并同步技术方案与项目决策记录
2026-08-04 18:58:49 +08:00
kdletters f47a30cff2 修复脚本回调槽位与恒假区间索引
受控 callback API 按大小写敏感名称和真实参数位传播调用
函数可达性 analysis 预计算并借用合并后的恒假区间索引
补充本地及跨模块回归并同步技术方案和共享决策
2026-08-04 18:58:49 +08:00
kdletters 5ea2dee663 修复循环模块投影身份与内联体积门禁
按来源模块和原始根绑定传播投影声明身份
回流去重前把引用改接到既有 canonical 并拒绝未收敛固定点
将 inline module 纳入累计二 MiB JavaScript 预算
新增双端命名捕获循环与内联超限回归
同步技术方案与共享决策记录
2026-08-04 18:58:49 +08:00
kdletters 865ff7e7d8 修复被调用函数条件赋值状态合并
保留被调用函数内条件赋值前的既有 alias 状态
新增条件副作用同时可达真实与候选接收者的回归测试
2026-08-04 18:58:49 +08:00
kdletters 141726e0f1 修复脚本可达性与事务目录竞态
完善构造器、函数表达式、call/apply 与受控回调的调用图
按条件分支、函数副作用和类定义时机解析 alias 与 super owner
避免动态导出同名污染、嵌套绑定捕获、shorthand 改键和循环投影膨胀
在 committed 发布后复核目录身份并原子隔离 retired 事务叶子
新增十四项 ESM 可达性、投影闭包和 Unix 目录竞态回归
同步 AI 游戏创作技术方案与共享决策记录
2026-08-04 18:58:49 +08:00
kdletters 267171a1d0 修复游戏脚本投影与图集事务身份校验
完善 ESM 声明、导入成员与动态依赖的 AST 投影
按真实调用时序解析 alias、receiver owner 与 dynamic import occurrence
补齐匿名默认导出、构造调用、回调与静态实例成员边界
提交图集事务前校验 retained directory handle 的 pathname identity
增加投影、时序、动态依赖与 live commit 回归测试
同步 AI 游戏创作技术方案与共享决策记录
2026-08-04 18:58:49 +08:00
kdletters ac736ca72c 修复图集恢复竞态与模块绑定冲突
冻结九路径恢复前态并让可信事务句柄贯穿提交与回滚
将无日志的旧图集残留收口为只读识别和人工对账
按符号大小写保留导入别名并为投影根绑定分配无冲突名称
补齐普通文件竞态、目录替换和模块命名冲突回归
同步图集事务与 ESM 投影技术约束
2026-08-04 18:58:49 +08:00
kdletters 7118b03f1a 修复 ESM 重复别名投影
保留同一导出的多个别名并合并同源导入声明
按最终模块源去重投影并统一匿名默认导出的规范别名
增加重复别名与跨桥接回归并同步技术约束
2026-08-04 18:58:49 +08:00
kdletters 4bb9f77f20 收紧图集恢复与模块投影一致性
拆分 Windows 祖先固定与事务叶子句柄权限,避免重复捕获共享冲突
为 Unix 恢复前态增加非阻塞稳定双读、元数据与叶子身份复核
保持缺失合同父目录无副作用并补齐 CAS 与残留清理回归
按 Oxc symbol span 投影 import alias、namespace、shorthand 与 bridge
同步图集事务和 Tetris ESM 权威技术约束
2026-08-04 18:58:49 +08:00
kdletters bf8eff53e3 加固游戏静态门与图集事务一致性
使用 Oxc AST 与语义符号验证 JavaScript 模块、作用域和控制流
锚定图集事务目录并保证九文件快照与错误回滚一致
修复早注册捕获监听器下的可信点击因果验收
补齐默认与命名空间模块投影、回归测试和长期技术文档
2026-08-04 18:58:48 +08:00
kdletters c804b1e564 修复浏览器点击因果收口时序
Project CI / Repository checks (push) Failing after 35s
Project CI / Frontend tests (push) Failing after 2m21s
Project CI / Backend tests (push) Successful in 4m9s
Project CI / Native shell tests (push) Successful in 20m17s
冻结可信输入监听器同步产生的最后状态

点击返回后在隔离世界收口并排除定时任务污染

补齐后注册点击监听器真实Chrome回归与指纹文档
2026-08-04 18:58:48 +08:00
kdletters e12586b0b8 加固图集恢复与方块模块语义
锚定事务目录并以CAS保护恢复安装和逆序回滚

创建与读取图集快照统一使用跨平台可信有界双读

按显式模块绑定和可达控制流验收俄罗斯方块语义

补齐目录替换、并发冲突及脚本解析回归与文档
2026-08-04 18:58:48 +08:00
kdletters d1e3cc319d 修复游戏验收竞态与静态门边界
图集事务使用跨平台可信有界双读并在恢复失败时逆序回滚

浏览器试玩在同一任务冻结输入尾部状态并绑定完整探针指纹

俄罗斯方块静态门按真实模块图和可达语义拒绝脚本诱饵

补齐事务、浏览器与俄罗斯方块回归测试及技术文档
2026-08-04 18:58:48 +08:00
kdletters 2b41a9a1ac 修复游戏完成门与事务恢复原子性
完整校验九路径事务快照后再执行 Canvas 恢复。

排除 HTML 非执行容器、src 正文与非棋盘消行诱饵。

递归读取受限本地模块依赖并覆盖内联模块入口。

兼容 capture-phase 点击处理并更新试玩场景指纹。

补齐真实浏览器、静态合同、事务恢复测试与架构文档。
2026-08-04 18:58:48 +08:00
kdletters 38afa8ae21 修复多智能体游戏验收边界
完善 Canvas 提交恢复顺序与快照读取预算。

收紧俄罗斯方块静态验收、可信交互与外部脚本边界。

补齐旧合同迁移、原生工具 schema 与动作审计白名单。

同步技术方案、共享决策记录与回归测试。
2026-08-04 18:58:48 +08:00
kdletters e424c5539e 修复游戏图集事务与俄罗斯方块验收
为九个固定图集合同路径补齐持久事务、原子标记、锁守卫和崩溃恢复。

统一校验主图与切片的资源、资产和任务身份,避免远端请求期间占用项目写锁。

收紧俄罗斯方块静态语义、浏览器动作因果和固定场景合同,拒绝注释与伪 telemetry 绕过。

迁移旧 Generic 俄罗斯方块根合同和试玩子任务合同,并失效旧场景回执。

补齐事务故障、恶意脚本、真实 Chrome、game-chat 修复和合同迁移回归测试。

同步 AI 游戏创作技术方案与共享决策记录。
2026-08-04 18:58:48 +08:00
kdletters 3ac0a6fafc 冻结游戏图集私有完成合同
持久化主图与四切片的私有摘要回执
绑定切片清单与当前Canvas资源身份
完成门拒绝素材与公开清单的协同篡改
将私有回执纳入原子回滚与崩溃恢复
补齐图集合同回归测试与技术文档
2026-08-04 18:58:48 +08:00
kdletters 602723ea0d 修复游戏续跑与图集完成门
保持失败续跑的原始任务身份并向 Provider 传递有效目标
收紧俄罗斯方块玩法连续性和浏览器动作因果验证
将图集主图、四切片、清单与登记纳入可恢复原子提交
校验切片来源、规范像素唯一性、可见性与有界解码
保留 External 生成结果的稳定来源资源字段
补齐调度子 Agent 展示和事件流测试
同步 Runtime 技术方案与项目决策记录
2026-08-04 18:58:48 +08:00
kdletters c2ef8631f8 明确泥点不足的游戏生成中断原因
统一余额不足分类与稳定原因码
阻止泥点不足进入重试和对账状态
在游戏聊天与阶段记录展示固定安全说明
补齐 API、Runtime 与前端回归测试
同步技术方案与项目决策记录
2026-08-04 18:58:48 +08:00
kdletters ef128dd8da 修复游戏续跑与美术资产工作流
统一纯继续意图、原任务合同继承与同源边界
要求既有游戏由当前代码任务真实修改后再验证
为俄罗斯方块提供完整玩法与移动端触控 fallback
生成并原子持久化四类透明图集切片
强制游戏 Canvas 实际使用生成素材
同步 Runtime prompt、Skill、前端进度与项目文档
补齐续跑、素材门禁、fallback 与提交回滚回归测试
2026-08-04 18:58:48 +08:00
kdletters e8aad0b739 修复MCP旧协议错误文本泄漏
Project CI / Repository checks (push) Failing after 48s
Project CI / Frontend tests (push) Failing after 20s
Project CI / Backend tests (push) Successful in 4m17s
Project CI / Native shell tests (push) Successful in 15m48s
将 legacy MCP 结构与目录绑定错误收敛为稳定类别
避免 serde 原始错误回显模型提交的私密字符串
补充结构错误和未知目录绑定的不泄密测试与踩坑说明
2026-08-04 18:58:48 +08:00
kdletters 48504e02aa 修复原生工具合同与MCP参数边界
使用安全 JSON Schema 校验动态 MCP 参数并在实际调用前重验历史 pending
将 legacy MCP schema 错误接回 arguments-schema repair 链
统一 Native Prompt、required-nullable 输入与 project.patchset 三类严格合同
按 Editor Key 拆分 Supervisor 视觉产物并清理旧 envelope 术语
补齐执行边界、repair、Prompt 分支与全量回归测试
同步更新 Runtime 决策与踩坑文档
2026-08-04 18:58:48 +08:00
kdletters ed413618eb 修正Provider原生工具调用合同
区分动态 MCP 原生函数与 legacy mcp.call 包装器

要求 strict schema 的 nullable 字段显式传值

增加非空 MCP 目录和必填字段回归测试
2026-08-04 18:57:26 +08:00
kdletters 0c44293341 统一画布素材类型合同
补齐 Provider Prompt 的 icon-spec 类型

统一 Prompt、原生 schema 与执行校验的素材类型目录

增加权威集合、schema、执行校验和最终请求回归测试
2026-08-04 18:57:25 +08:00
kdletters f725e15382 补全Linux持久命令沙箱说明
恢复 command.start 的 workspace-write 与 network-disabled 合同
增加 Linux 平台持久命令沙箱回归断言
2026-08-04 18:57:25 +08:00
kdletters d367ded584 补全画布生成提示词语义
恢复 canvas.asset_generate 同步写入画布、素材库和本地 assets 的说明
增加最终 Provider 请求的三端写入回归断言
2026-08-04 18:57:25 +08:00
kdletters 749c384417 消除Provider提示词合同冲突
把原生工具输入合同直接写入唯一提示词 section
按目标平台单次选择 command.exec 与 command.start 合同
增加旧合同缺失和合同唯一性的最终请求断言
2026-08-04 18:57:25 +08:00
kdletters 53a0c71772 修复最终Provider提示词拼接
移除最终 Provider 请求中的自然语言精确替换链
按原生工具合同和平台条件显式组合最终提示词
增加最终请求合同与源码回归测试
修正原生工具目录数据流和维护文档
2026-08-04 18:57:25 +08:00
kdletters e2b5056af5 提取智能体协作编排提示词
将 Runtime 公共提示词与 Supervisor 协作编排拆分为版本化 Prompt Bundle
统一原生工具目录并将 MCP 工具留给动态目录
补充 Bundle 组合、工具目录和 Provider 契约测试
更新 Runtime 技术方案与项目记忆
2026-08-04 18:57:25 +08:00
kdletters 732c6ee3f4 修复 game-chat 续跑目标漂移与产物覆盖
继承同一会话失败根任务的原始目标与完成基线
保护非占位游戏入口并拒绝重复整文件覆盖
纠正规范图运行时语义与状态序列推进规则
补充续跑继承、图集门禁和事故文档回归
2026-08-04 18:57:25 +08:00
menghao 3ec3a09380 完成游戏工作台资源替换与数值微调
实现可信资源规格校验与不可变资源替换子版本
新增登记参数读取、暂停态写入和会话失效链路
补齐前后端合同、生成产物约束与回归测试
同步工作台 PRD、技术方案和共享决策记录
2026-08-04 18:38:41 +08:00
kdletters 7f18f7ce04 修复画布副本持久化与素材类型覆盖
Project CI / Frontend tests (push) Failing after 21s
Project CI / Repository checks (push) Failing after 43s
Project CI / Backend tests (push) Successful in 3m44s
Project CI / Native shell tests (push) Successful in 10m42s
复制布局复用项目资源并区分资源登记状态
新增图层素材类型覆盖并保持资源默认类型
补齐结构化存储迁移、绑定与权威类型校验
同步前后端回归测试和画布持久化文档
2026-08-04 18:06:15 +08:00
k88936 99d239c8bf style: 画布编辑器多行输入框样式调整 (#130)
Project CI / Repository checks (push) Successful in 50s
Project CI / Backend tests (push) Successful in 3m30s
Project CI / Frontend tests (push) Successful in 3m42s
Project CI / Native shell tests (push) Successful in 11m34s
复用了画布agent的输入框:

* 高度自适应
* 滑动条样式变为浅色和位置不再出界

before
![shotmd-1785745933-compressed.webp](/attachments/95727f6d-63e1-48f7-b806-8203cd73d1eb)
after
![shotmd-1785745957-compressed.webp](/attachments/b5af077d-d3b9-4572-9135-39e288291e24)

Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/130
Co-authored-by: 王德宇 <kvtodev@outlook.com>
Co-committed-by: 王德宇 <kvtodev@outlook.com>
2026-08-04 17:07:30 +08:00
menghao 752505547d 实现运行工作台正式测试切片与悬停信息
Project CI / Frontend tests (pull_request) Failing after 23s
Project CI / Repository checks (pull_request) Failing after 1m4s
Project CI / Backend tests (pull_request) Successful in 4m59s
Project CI / Native shell tests (pull_request) Successful in 13m17s
新增正式测试切片合同、状态机与上一项/播放暂停/下一项控制
新增可信悬停资源解析与资源管理画布定位
扩展 Tauri 版本登记、运行 Bridge 和 Agent 生成合同
补齐 TypeScript、Rust 与 AppSurface 回归测试
同步工作台 PRD、技术方案与共享决策记录
保持 P2 资源替换、参数写入和下一版本能力未接线
2026-08-04 17:06:24 +08:00
menghao 203ce5b9e7 实现游戏运行会话与桥接协议
Project CI / Backend tests (pull_request) Successful in 3m49s
Project CI / Native shell tests (pull_request) Failing after 8m26s
Project CI / Frontend tests (pull_request) Failing after 25s
Project CI / Repository checks (pull_request) Failing after 54s
冻结 Host/Game Bridge 双向消息合同与安全校验
为 PreviewRegistry 增加预览身份并注入宿主 bootstrap
接入 iframe 一次性会话、状态投影和暂停继续控制
补充协议、AppSurface、Rust 生命周期与共享合同测试
同步更新工作台 PRD、技术方案和共享决策记录
2026-08-04 16:16:04 +08:00
menghao d1a47c0fe7 实现游戏工作台P0/P1可运行版本能力
Project CI / Frontend tests (pull_request) Successful in 3m43s
Project CI / Repository checks (pull_request) Failing after 1m27s
Project CI / Backend tests (pull_request) Successful in 4m26s
Project CI / Native shell tests (pull_request) Failing after 7m40s
冻结工作台运行版本、会话、参数、资源与消息跨端合同
新增可信 Runtime 验证后的不可变可运行版本登记与快照校验
支持 Tauri 客户端选择、切换并运行历史版本快照
收紧普通预览授权边界并同步资源高亮与明确错误展示
补充前后端测试、PRD、技术方案和项目决策记录
2026-08-04 15:21:55 +08:00
menghao 2e0ef02fda 修复CI依赖准备顺序
Project CI / Repository checks (pull_request) Successful in 1m1s
Project CI / Frontend tests (pull_request) Successful in 3m7s
Project CI / Backend tests (pull_request) Successful in 3m48s
Project CI / Native shell tests (pull_request) Successful in 10m55s
修复依赖图测试import排序门禁

在后端构建门禁前预取锁定Cargo依赖

新增Backend-CI执行顺序回归测试

同步更新Gitea-CI开发运维约定
2026-08-04 12:00:04 +08:00
menghao ab16c87c5d 调整资源依赖视图连线规则
Project CI / Repository checks (pull_request) Failing after 48s
Project CI / Backend tests (pull_request) Failing after 29s
Project CI / Frontend tests (pull_request) Successful in 2m54s
Project CI / Native shell tests (pull_request) Successful in 10m33s
限制任务虚线仅在同资源类型分区内渲染
调亮精确资源引用橙线并保持持续展示
取消资源点击后的依赖高亮与无关连线弱化
补充依赖图单元测试与工作台集成测试
同步更新项目开发工作台 PRD
2026-08-04 11:20:58 +08:00
menghao 6d8c7ae496 修复前端异步读取卸载竞态
Project CI / Repository checks (pull_request) Successful in 55s
Project CI / Backend tests (pull_request) Successful in 4m13s
Project CI / Native shell tests (pull_request) Successful in 11m16s
Project CI / Frontend tests (pull_request) Successful in 2m29s
未登录画布不再触发受保护的钱包刷新
充值中心读取在换代与卸载时中止并失效
补充卸载取消回归测试与共享排障经验
2026-08-04 10:38:28 +08:00
menghao 80bcb4ba0e 完成资源管理阶段七验收
Project CI / Repository checks (pull_request) Successful in 1m1s
Project CI / Backend tests (pull_request) Successful in 3m43s
Project CI / Native shell tests (pull_request) Successful in 10m47s
Project CI / Frontend tests (pull_request) Failing after 1m41s
补齐视频与资源读取失败空态测试
完成全量前后端和 Rust CI 验收
修复 macOS/BSD 跨平台门禁与测试隔离
更新阶段七验收与共享项目记忆
2026-08-04 10:06:12 +08:00
menghao df4e61a208 合并最新主分支
同步 Runtime、外部 API 与统一弹窗等主分支更新

解决开发栈进程探活、Runtime continuation 与启动测试冲突

保留资源依赖图排障记忆并验证冲突路径
2026-08-03 19:21:12 +08:00
menghao fef53b634e 完成正式项目版本阶段六
Project CI / Repository checks (pull_request) Failing after 43s
Project CI / Frontend tests (pull_request) Failing after 2m6s
Project CI / Backend tests (pull_request) Successful in 3m37s
Project CI / Native shell tests (pull_request) Successful in 11m49s
扩展 manifest 正式迭代版本合同并强制历史记录追加不可变
接入版本卡、父子关系与绑定资源高亮
补齐共享契约、Tauri 存储与工作台回归测试
同步工作台 PRD、技术方案与项目记忆
2026-08-03 19:04:01 +08:00
k88936 e6b3199490 Fix/统一修复modal样式失效 (#122)
Project CI / Repository checks (push) Successful in 48s
Project CI / Backend tests (push) Successful in 3m53s
Project CI / Frontend tests (push) Successful in 3m21s
Project CI / Native shell tests (push) Successful in 11m16s
之前遇到几次弹窗的样式不生效,bug 现在在画布agent的删除对话弹窗又出现了,
这个pr把类似的修改集中到最下层的UnifiedModal,适用于所有的modal,
一些特殊的modal有特殊处理.

画布agent的删除对话弹窗
![shotmd-1785399342.jpg](/attachments/d63d7dc6-bf7e-4f13-bfe8-bc4716cd798f)

---------

Co-authored-by: 段舒康 <kdletters@qq.com>
Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/122
Reviewed-by: 段舒康 <kdletters@qq.com>
Co-authored-by: 王德宇 <kvtodev@outlook.com>
Co-committed-by: 王德宇 <kvtodev@outlook.com>
2026-08-03 17:55:47 +08:00
menghao ba996aad80 完成资源依赖排列阶段五
Project CI / Frontend tests (pull_request) Failing after 21s
Project CI / Repository checks (pull_request) Successful in 1m1s
Project CI / Backend tests (pull_request) Successful in 3m54s
Project CI / Native shell tests (pull_request) Successful in 11m49s
计算资源引用 SCC 与任务深度下限
拆分 producer assignment 和布局深度合同
补齐依赖布局回归测试
同步工作台 PRD、技术方案与项目记忆
2026-08-03 17:51:59 +08:00
kdletters 3c58e76a71 加固game-chat平台生成恢复与单轮收束
Project CI / Repository checks (push) Successful in 1m1s
Project CI / Backend tests (push) Successful in 4m2s
Project CI / Native shell tests (push) Successful in 10m55s
Project CI / Frontend tests (push) Successful in 3m27s
新增External Editor私有生成账本并实现GET-only恢复
保留未知生成结果、截止现场与人工对账身份
加固pending continuation取消所有权和异常持久化
补齐平台美术、默认栈、game-chat及配置隔离回归测试
同步AI游戏创作技术方案与共享项目记忆
2026-08-03 17:30:27 +08:00
menghao d374f3292a 完成资源聚焦阶段四
Project CI / Repository checks (pull_request) Successful in 1m16s
Project CI / Frontend tests (pull_request) Failing after 2m37s
Project CI / Backend tests (pull_request) Successful in 3m29s
Project CI / Native shell tests (pull_request) Successful in 11m21s
新增项目文档与媒体资源安全读取命令
补齐Markdown、扩展美术媒体与音频聚焦展示
增加安全边界与工作台回归测试
同步PRD、技术方案与共享决策
2026-08-03 17:20:14 +08:00
menghao 2c65878b60 完成资源分类投影与中央聚焦
Project CI / Repository checks (pull_request) Failing after 49s
Project CI / Frontend tests (pull_request) Failing after 2m16s
Project CI / Backend tests (pull_request) Successful in 3m55s
Project CI / Native shell tests (pull_request) Successful in 11m17s
收口文档、版本、美术和音频资源分类
将资源详情改为中央主视窗聚焦并恢复列表上下文
补充资源身份、聚焦状态和依赖图回归测试
同步工作台PRD、技术方案和项目决策记录
2026-08-03 16:39:43 +08:00
kdletters 205c47eb60 修复Runtime默认栈与任务图门禁
Project CI / Repository checks (push) Successful in 1m0s
Project CI / Backend tests (push) Successful in 4m14s
Project CI / Native shell tests (push) Successful in 11m44s
Project CI / Frontend tests (push) Successful in 3m5s
为pending恢复和后续队列建立装箱的Tokio任务边界
同步三Director首波任务图的测试夹具
补齐Linux容器进程与Runtime栈边界文档
恢复Native shell完整默认栈测试门禁
2026-08-03 16:16:59 +08:00
menghao 7339bb5da1 暂缓资源卡拖动并统一资源管理合同
Project CI / Repository checks (pull_request) Failing after 10s
Project CI / Backend tests (pull_request) Failing after 10s
Project CI / Frontend tests (pull_request) Failing after 2m18s
Project CI / Native shell tests (pull_request) Successful in 11m37s
移除资源卡 Pointer 拖动入口并保留点击详情
改写交互与布局测试,覆盖指针不改坐标且不提交 CAS
同步工作台 PRD、技术方案和项目决策记录
2026-08-03 15:35:54 +08:00
kdletters 9450377693 修正容器进程组清理断言
Project CI / Repository checks (push) Successful in 1m10s
Project CI / Native shell tests (push) Failing after 6m32s
Project CI / Backend tests (push) Successful in 4m20s
Project CI / Frontend tests (push) Successful in 3m29s
使用可执行成员语义校验Linux进程组已停止
避免容器孤儿僵尸让signal探活断言误报失败
2026-08-03 15:35:47 +08:00
kdletters 04a6be5c3d 修复容器进程组清理误判
Project CI / Repository checks (push) Successful in 1m5s
Project CI / Frontend tests (push) Failing after 2m11s
Project CI / Native shell tests (push) Failing after 3m4s
Project CI / Backend tests (push) Successful in 3m41s
区分Linux进程组中的可执行成员与僵尸进程
补齐容器PID 1不回收孤儿进程的回归测试
同步记录Tauri进程树清理的容器边界
2026-08-03 15:31:40 +08:00
kdletters 53f06055a4 修复画布权威快照合并回归
Project CI / Frontend tests (push) Failing after 2m10s
Project CI / Repository checks (push) Successful in 1m19s
Project CI / Native shell tests (push) Failing after 3m27s
Project CI / Backend tests (push) Successful in 3m53s
统一生成完成态与本地布局的生命周期合并
保留同项目权威刷新中的有效画布选择
同步生成集成夹具与真实后端完成契约
补齐画布持久化回归测试和项目记忆
2026-08-03 15:20:44 +08:00
kdletters cf0864c956 合并远端master更新
Project CI / Frontend tests (push) Failing after 24s
Project CI / Repository checks (push) Successful in 1m13s
Project CI / Native shell tests (push) Failing after 3m39s
Project CI / Backend tests (push) Successful in 3m56s
合并远端Issue 115、118、127和128修复
保留移动端创作工具门禁与本地既有提交

# Conflicts:
#	docs/project-memory/shared-memory/pitfalls.md
2026-08-03 15:14:31 +08:00
kdletters d3eeaf979d 恢复移动端创作工具门禁
移动端底部导航仅保留我的入口
移动端创作、项目与画布直达统一展示桌面端提示
补充移动端入口与画布阻断回归测试
纠正旧模板退役时越权扩大的移动端产品口径
2026-08-03 15:13:26 +08:00
menghao c24e3010f8 Merge remote-tracking branch 'origin/master' into codex/dependency-graph
Project CI / Repository checks (pull_request) Successful in 1m3s
Project CI / Frontend tests (pull_request) Failing after 2m7s
Project CI / Backend tests (pull_request) Successful in 3m25s
Project CI / Native shell tests (pull_request) Successful in 10m41s
2026-08-03 14:24:46 +08:00
menghao d8064eff49 同步自主首批任务图测试夹具
Project CI / Repository checks (pull_request) Failing after 11s
Project CI / Backend tests (pull_request) Failing after 11s
Project CI / Frontend tests (pull_request) Successful in 2m46s
Project CI / Native shell tests (pull_request) Successful in 10m54s
补齐可信 Supervisor 根任务与三 Leader 首批合同测试数据

更新视觉失败和 Ready 任务调度断言以匹配最新任务图

修复 Provider 重试恢复响应仍使用旧底层 Agent 合同的问题
2026-08-03 14:21:30 +08:00
kdletters 6fe646ba2b 修复开放Issue 115、118、127和128
Project CI / Frontend tests (push) Failing after 21s
Project CI / Repository checks (push) Successful in 58s
Project CI / Native shell tests (push) Failing after 3m7s
Project CI / Backend tests (push) Successful in 3m33s
补齐Anthropic strict能力门控、传输schema、缓存usage和真实端点验收
隔离可选MCP服务目录失败并安全重定位局部schema引用
修复PowerShell 7环境下Windows私有ACL检查
统一角色与图标素材落库的用户prompt语义
合并权威画布快照与本地待保存或在途布局并补齐回归
同步更新技术文档、项目记忆和验证门禁
2026-08-03 14:03:20 +08:00
menghao bda0d0d398 修复Linux进程树探活与Runtime默认栈溢出
Project CI / Repository checks (pull_request) Successful in 1m7s
Project CI / Frontend tests (pull_request) Successful in 3m0s
Project CI / Backend tests (pull_request) Successful in 3m32s
Project CI / Native shell tests (pull_request) Failing after 7m38s
Linux进程组探活忽略已终止但未回收的zombie成员

pending恢复与后续队列统一跨越装箱的Tokio任务边界

补充Tauri生命周期和Runtime默认栈回归测试与文档
2026-08-03 13:34:25 +08:00
kdletters d1a657b5d2 为未鉴权MCP返回接入引导
保持401与Bearer挑战并提供机器可读的Key配置步骤

统一缺失格式错误和无效Key响应以避免凭据枚举

保留请求元信息并同步OpenAPI集成清单与架构文档

补充鉴权脱敏契约测试并完成本地dev栈验证
2026-08-03 12:03:50 +08:00
menghao b95da30721 Merge branch 'master' into codex/dependency-graph
Project CI / Repository checks (pull_request) Successful in 54s
Project CI / Frontend tests (pull_request) Failing after 2m9s
Project CI / Backend tests (pull_request) Successful in 3m46s
Project CI / Native shell tests (pull_request) Failing after 3m4s
2026-08-03 11:55:21 +08:00
menghao 7f038490f1 修复运行时恢复路径栈溢出
Project CI / Repository checks (pull_request) Failing after 7s
Project CI / Backend tests (pull_request) Failing after 10s
Project CI / Frontend tests (pull_request) Successful in 2m51s
Project CI / Native shell tests (pull_request) Failing after 7m51s
为 pending continuation 与后台主循环增加可取消的 Tokio 任务边界
保留 durable batch 恢复防重和父任务取消语义
补充运行时技术约束与共享排障记录
2026-08-03 11:53:59 +08:00
kdletters 6a02c7fb38 合并外部API MCP与异步生成能力
基于最新master接入托管式Streamable HTTP MCP并复用External API Key鉴权

统一External v1生成任务的幂等异步提交与状态查询

同步完整Skill资源、OpenAPI契约、AI游戏客户端与Worker适配

保留game-chat生命周期与首轮调度约定并完成重基验证
2026-08-03 11:47:20 +08:00
kdletters 38c43b708a 优化游戏聊天生命周期与首轮调度
Project CI / Repository checks (push) Successful in 1m8s
Project CI / Frontend tests (push) Failing after 2m8s
Project CI / Native shell tests (push) Failing after 3m28s
Project CI / Backend tests (push) Successful in 3m42s
新增受控 Tauri 开发启动器并在启动失败或终端退出时收束客户端进程树
修复 game-chat source hydration 与专业 Agent 已提交回复的持久可见性
统一正式任务图和 game-chat 首轮只激活策划美术程序三个 Director
限制显式首批协作合同提前激活底层 Agent 或 isolated child
同步六任务进度投影、共享契约、回归测试与项目文档
2026-08-03 11:41:59 +08:00
menghao 05c608214e 修复资源依赖图布局初始化与拖动性能
Project CI / Repository checks (pull_request) Successful in 1m0s
Project CI / Frontend tests (pull_request) Successful in 3m4s
Project CI / Backend tests (pull_request) Successful in 3m29s
Project CI / Native shell tests (pull_request) Failing after 5m34s
将任务依赖深度迁移到 Rust SCC 压缩图并返回稳定结果

为 dependency 模式增加图加载屏障并重派生自动布局

通过 DOM 热路径和局部 SVG 缓存避免拖动全量 React 重渲染

补充 4096 资源、异步初始化及布局保持回归测试

同步工作台 PRD、技术方案与共享项目记忆
2026-08-03 11:16:02 +08:00
menghao 37f4a63112 合并最新master并解决工作台冲突
Project CI / Repository checks (pull_request) Successful in 1m17s
Project CI / Frontend tests (pull_request) Successful in 3m13s
Project CI / Backend tests (pull_request) Successful in 3m45s
Project CI / Native shell tests (pull_request) Failing after 5m39s
合并 master 最新游戏聊天前端 Lint 修复。

保留依赖图分支的 Hook 稳定化逻辑并统一注释格式。
2026-08-03 10:35:49 +08:00
menghao fe34eee052 合并最新master并解决工作台冲突
合并game-chat五分钟首版与平台美术硬门更新
解决App响应流Hook的等价内容冲突
稳定新增消息追加回调并整理合并后的导入顺序
通过前端完整测试、Lint、类型检查和Rust tests编译
2026-08-03 10:30:48 +08:00
kdletters 7309adb4f0 修复游戏聊天前端Lint门禁
Project CI / Frontend tests (push) Failing after 24s
Project CI / Repository checks (push) Successful in 2m21s
Project CI / Backend tests (push) Successful in 3m36s
Project CI / Native shell tests (push) Failing after 5m35s
整理游戏聊天相关导入顺序
稳定专业Agent最终回复回调并补齐Effect依赖
2026-08-03 10:27:04 +08:00
kdletters c00dd099e3 扩展MCP的完整Skill资源
拆分外部编辑器Skill为四篇渐进式参考文档
MCP资源列表支持逐篇发现和读取Skill内容
Skill归档和manifest同步七文件清单及SHA校验
同步OpenAPI、架构文档和项目决策记录
2026-08-03 09:59:00 +08:00
kdletters 964b883466 强化game-chat五分钟首版与平台美术硬门
Project CI / Frontend tests (push) Failing after 23s
Project CI / Backend tests (push) Successful in 3m18s
Project CI / Repository checks (push) Failing after 55s
Project CI / Native shell tests (push) Failing after 5m21s
将game-chat首版固定为美术、代码、静态检查和试玩四阶段并单轮收束。

由平台生成并登记art-spec图片,强制用于主要背景、玩家和目标的可达Canvas绘制。

为全部在途动作增加从根Run计时的300秒绝对截止和确定性失败清理。

修复代码revision归属判断,防止美术变更跳过唯一Provider写入。

将四阶段公开输出和final-reply逐条固化到聊天并更新进度投影。

补齐图片解码、路径、隐藏与不可达绕过、超时竞态及前端回归测试和文档。
2026-08-01 22:45:16 +08:00
kdletters b7f8b31b36 优化game-chat首版生成与聊天输出
Project CI / Repository checks (push) Failing after 51s
Project CI / Frontend tests (push) Successful in 3m12s
Project CI / Backend tests (push) Successful in 3m29s
Project CI / Native shell tests (push) Failing after 7m50s
将 game-chat 收束为三阶段五分钟首版快车道并补齐累计预算、恢复和完成门禁
将 Runtime 安全公开事件与专业 Agent 最终回复逐条幂等写入项目聊天
修复预览 revision 绑定、自动启动刷新、Runner 退出和 Windows 后台窗口收口
补充前后端回归测试、配置门禁和项目技术文档
2026-08-01 18:33:10 +08:00
kdletters fe496f531d 修复AI游戏创作前端lint
Project CI / Frontend tests (push) Failing after 24s
Project CI / Repository checks (push) Successful in 1m35s
Project CI / Backend tests (push) Successful in 3m49s
Project CI / Native shell tests (push) Successful in 11m36s
固定response-stream更新回调并补齐Effect依赖\n调整Runtime模型测试的import顺序
2026-07-31 20:04:11 +08:00
kdletters e1d031b86f 增加外部API的MCP与异步生成模式
新增托管式Streamable HTTP MCP端点并复用外部API Key鉴权
统一图片视频音频等生成请求为幂等异步提交和状态查询
提供可发现的使用说明、OpenAPI资源及完整Skill下载包
同步更新OpenAPI契约并规定接口变更必须连带维护
适配AI游戏创作Shell的异步提交轮询与安全重试
补齐MCP方法映射、异步Worker和客户端回归测试
2026-07-31 19:48:28 +08:00
menghao cced839da5 修复合并后的前端Lint门禁
Project CI / Repository checks (pull_request) Successful in 55s
Project CI / Frontend tests (pull_request) Successful in 2m55s
Project CI / Native shell tests (pull_request) Successful in 11m45s
Project CI / Backend tests (pull_request) Successful in 3m54s
稳定项目总控响应流更新回调并补齐Effect依赖
调整Agent Runtime模型测试的导入顺序
通过完整ESLint、类型检查和AppSurface回归测试
2026-07-31 19:31:24 +08:00
menghao e77d187497 合并最新master并解决资源图冲突
Project CI / Repository checks (pull_request) Failing after 47s
Project CI / Frontend tests (pull_request) Successful in 3m21s
Project CI / Backend tests (pull_request) Successful in 3m49s
Project CI / Native shell tests (pull_request) Successful in 11m42s
合并远端master的运行收口、聊天输出与画布交互更新
保留资源依赖图只读命令注册和Rust测试隔离配置
解决main.rs入口附近的内容冲突
完成依赖图、退出保护及完整前端回归验证
2026-07-31 19:19:05 +08:00
menghao 29dce59b35 将资源依赖图计算迁移到Rust
Project CI / Repository checks (pull_request) Failing after 10s
Project CI / Backend tests (pull_request) Failing after 7s
Project CI / Frontend tests (pull_request) Successful in 2m50s
Project CI / Native shell tests (pull_request) Successful in 11m33s
新增只读资源依赖图模型,完成过滤、去重、环检测和任务流聚合
前端SVG仅负责几何渲染、搜索联动、选中高亮和拖动预览
补充资源图、覆盖层和工作台回归测试
同步更新工作台PRD、技术方案与项目记忆
2026-07-31 19:09:57 +08:00
menghao f582ecf032 优化资源依赖图连线外观
Project CI / Repository checks (pull_request) Failing after 11s
Project CI / Backend tests (pull_request) Failing after 10s
Project CI / Frontend tests (pull_request) Successful in 3m5s
Project CI / Native shell tests (pull_request) Successful in 10m26s
将任务流分支改为平滑贝塞尔曲线
调整两类连线的线宽、虚线和箭头样式
补充连线几何测试与相关文档
2026-07-31 18:36:21 +08:00
kdletters 33ec7b2861 修复AI游戏创作长耗时与运行收口
Project CI / Repository checks (push) Failing after 2m19s
Project CI / Frontend tests (push) Failing after 2m50s
Project CI / Backend tests (push) Successful in 4m20s
Project CI / Native shell tests (push) Successful in 12m0s
自主构建只执行正式清单任务图并移除重复静态委派
预览基础设施失败立即收口并绑定当前版本验证凭证
客户端退出前检查Runner持久任务状态并阻止忙碌关闭
修复上下文检查点恢复边界并补齐恢复测试
为全部Agent配置默认推理强度与实际重试状态展示
补齐配置、协作、预览、Runner及全量回归测试
同步技术方案、开发流程与长期决策记录
2026-07-31 18:26:35 +08:00
kdletters 831181faec 优化 game-chat 单轮生成与聊天输出
Project CI / Repository checks (push) Failing after 59s
Project CI / Frontend tests (push) Successful in 3m11s
Project CI / Backend tests (push) Successful in 3m33s
Project CI / Native shell tests (push) Successful in 10m30s
每条 Supervisor ready 输出按稳定身份固化到 game-chat 聊天框并修复 hydration 竞态。

新增 game-chat source 白名单,试玩完成后跳过发布任务并收紧完成门。

配置 External Editor API 时强制使用并引用 Canvas 美术图集,补齐前端、Rust、AppSurface 测试与协作文档。
2026-07-31 17:35:00 +08:00
k88936 386534a415 Feat/artagent 点击/右键功能 聚焦到画布上的素材 (#123)
Project CI / Frontend tests (push) Failing after 22s
Project CI / Repository checks (push) Successful in 1m10s
Project CI / Backend tests (push) Successful in 3m40s
Project CI / Native shell tests (push) Successful in 10m56s
- 为避免prop drilling把原有的刷新画布集中到一个useContext中,
   在此基础上实现画布聚焦, 并在画布agent中使用

![shotmd-1785482938-compressed.webp](/attachments/59d71873-79fc-40e8-a9dc-7830a5ad7f3c)

Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/123
Co-authored-by: 王德宇 <kvtodev@outlook.com>
Co-committed-by: 王德宇 <kvtodev@outlook.com>
2026-07-31 17:25:35 +08:00
menghao a431ab47cd 合并最新 master 并解决依赖图文档冲突
Project CI / Frontend tests (pull_request) Successful in 3m7s
Project CI / Backend tests (pull_request) Successful in 3m37s
Project CI / Native shell tests (pull_request) Successful in 12m20s
Project CI / Repository checks (pull_request) Successful in 59s
保留资源依赖图的纯前端 SVG 决策记录
保留主分支新增的抠图元数据与 OpenAPI 决策记录
同步 master 最新代码并保持依赖图与后端测试修复
2026-07-31 16:50:59 +08:00
lhk229 72acd0ec05 停止向用户泄露抠图模型 (#120)
Project CI / Frontend tests (push) Successful in 3m40s
Project CI / Backend tests (push) Successful in 4m11s
Project CI / Repository checks (push) Successful in 1m19s
Project CI / Native shell tests (push) Successful in 12m36s
Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/120
Co-authored-by: Linghong <ink29535@proton.me>
Co-committed-by: Linghong <ink29535@proton.me>
2026-07-31 16:40:43 +08:00
menghao 11140b9fb6 修复后端源码约束测试
Project CI / Native shell tests (pull_request) Successful in 11m56s
Project CI / Repository checks (pull_request) Successful in 59s
Project CI / Frontend tests (pull_request) Successful in 3m35s
Project CI / Backend tests (pull_request) Successful in 3m49s
同步 UI 素材切片持久化失败断言至现有 warning 映射函数
保持生产逻辑和持久层不变
2026-07-31 16:31:09 +08:00
menghao 246fd1d9d6 同步最新 master 修复 CI 基线
Project CI / Repository checks (pull_request) Successful in 1m15s
Project CI / Frontend tests (pull_request) Successful in 3m23s
Project CI / Native shell tests (pull_request) Successful in 11m51s
Project CI / Backend tests (pull_request) Failing after 2m47s
合并画板素材上传后的私有图片预览修复。

确保 PR 分支包含当前 master 基础提交。
2026-07-31 16:05:05 +08:00
menghao 68ea9bdff3 合并最新 master 并解决资源依赖图冲突
Project CI / Repository checks (pull_request) Failing after 7s
Project CI / Frontend tests (pull_request) Failing after 2m19s
Project CI / Backend tests (pull_request) Failing after 8s
Project CI / Native shell tests (pull_request) Successful in 12m34s
同步 mentor 已合入 master 的最新工程改动。

保留资源依赖图决策记录并整合 master 的新增决策。

# Conflicts:
#	docs/project-memory/shared-memory/decision-log.md
2026-07-31 15:54:40 +08:00
kdletters 48f9c8e690 修复画板素材上传后的私有图片预览
Project CI / Repository checks (push) Successful in 48s
Project CI / Frontend tests (push) Failing after 27s
Project CI / Backend tests (push) Failing after 2m51s
Project CI / Native shell tests (push) Successful in 12m58s
分离上传后的签名预览地址与稳定持久化地址
保留素材落库回填后的即时签名预览
补充裸 generated 路径不得用于即时预览的回归测试
同步图片画布上传与持久化技术约束
2026-07-31 15:46:08 +08:00
menghao 0b6be155dd 合并最新 AI 游戏创作 App 分支
Project CI / Frontend tests (pull_request) Successful in 3m18s
Project CI / Repository checks (pull_request) Failing after 22s
Project CI / Backend tests (pull_request) Failing after 22s
Project CI / Native shell tests (pull_request) Failing after 22s
2026-07-31 15:34:36 +08:00
kdletters 9eae1a28c5 Merge remote-tracking branch 'origin/codex/ai-game-creator-app' into HEAD
Project CI / Backend tests (push) Failing after 2m47s
Project CI / Frontend tests (push) Successful in 3m11s
Project CI / Repository checks (push) Successful in 53s
Project CI / Native shell tests (push) Successful in 12m48s
2026-07-31 15:33:05 +08:00
menghao 26cfd85d25 修复AGC的macOS临时路径兼容 (#125)
Project CI / Frontend tests (push) Failing after 21s
Project CI / Repository checks (push) Successful in 1m1s
Project CI / Backend tests (push) Successful in 3m0s
Project CI / Native shell tests (push) Successful in 11m36s
规范化配置回归测试的临时根路径
补充跨平台路径比较技术说明与踩坑记录

Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/125
Co-authored-by: menghao <mh18530625731@163.com>
Co-committed-by: menghao <mh18530625731@163.com>
2026-07-31 15:28:05 +08:00
menghao 8531a9af3e 实现资源依赖关系图层
Project CI / Frontend tests (pull_request) Successful in 2m40s
Project CI / Native shell tests (pull_request) Successful in 10m40s
Project CI / Repository checks (pull_request) Failing after 7s
Project CI / Backend tests (pull_request) Failing after 7s
新增资源依赖图模型、去重、环检测与上下游查询。

使用原生 SVG 渲染资源引用和聚合任务流,并接入搜索、高亮、拖动及生命周期清理。

修复资源自引用连线被卡片遮挡的问题。

补充前端回归测试并同步工作台 PRD、技术方案和决策记录。
2026-07-31 15:13:18 +08:00
kdletters 842d99697a 合并游戏聊天0.1.1到master
Project CI / Repository checks (push) Successful in 1m11s
Project CI / Frontend tests (push) Failing after 2m6s
Project CI / Backend tests (push) Failing after 2m44s
Project CI / Native shell tests (push) Failing after 3m14s
合入独立game-chat release构建、内置Runner与退出收束。
合入自动预览刷新、结构化进度展示及强化试玩验收。
保留master资源画布、共享预览和原生壳严格门禁。
修复Windows Runner单实例锁与GUI owner锁固定路径兼容。
2026-07-31 14:27:36 +08:00
kdletters 66341fe7a5 修复Windows Runner固定锁路径校验
Project CI / Frontend tests (push) Failing after 16s
Project CI / Repository checks (push) Failing after 49s
Project CI / Backend tests (push) Successful in 2m58s
Project CI / Native shell tests (push) Failing after 2m46s
允许私有AppData中的单实例锁与GUI owner锁。
继续拒绝其他任意锁文件名并补齐回归测试。
让Runner测试使用经过私有DACL初始化的AppData夹具。
2026-07-31 13:58:39 +08:00
kdletters dcd8901246 发布独立游戏聊天0.1.1并强化试玩验收
新增只能打开游戏聊天页的0.1.1独立release构建配置。
内置Runner启动、诊断日志、Windows后台进程与退出收束。
修复自动预览启动、同页版本刷新和结构化验收状态展示。
强化试玩协议、窗口末端采样与固定失败识别,允许正常输赢但拒绝无法推进。
完善旧验收回执自愈和当前场景指纹完成门。
补齐Rust、前端、真实Chrome回归测试及项目文档。
2026-07-31 13:44:13 +08:00
kdletters cf1a023125 收紧图集切片内存并批量持久化
Project CI / Repository checks (push) Successful in 1m0s
Project CI / Backend tests (push) Failing after 2m42s
Project CI / Frontend tests (push) Successful in 2m45s
Project CI / Native shell tests (push) Successful in 11m42s
按需编码并限制图集上传并发、超时与累计裁剪像素
批量确认切片对象、项目资源、账号素材和完成批次
稳定派生切片记录标识并收紧重放与来源资源校验
复用已鉴权项目资源避免手动拆分全账号扫描
补充图集资源边界文档与回归测试
2026-07-31 13:40:28 +08:00
kdletters 63e90ec779 Merge pull request 'Fix/画布agent优化' (#121) from fix/artagent-rerefine-prompt into master
Project CI / Repository checks (push) Successful in 58s
Project CI / Frontend tests (push) Successful in 3m9s
Project CI / Backend tests (push) Successful in 3m50s
Project CI / Native shell tests (push) Successful in 11m9s
Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/121
Reviewed-by: 段舒康 <kdletters@qq.com>
2026-07-31 13:36:11 +08:00
kdletters 9951bc573b Merge branch 'master' into fix/artagent-rerefine-prompt
Project CI / Repository checks (pull_request) Successful in 1m0s
Project CI / Native shell tests (pull_request) Successful in 11m35s
Project CI / Frontend tests (pull_request) Successful in 2m54s
Project CI / Backend tests (pull_request) Successful in 3m33s
2026-07-31 13:20:12 +08:00
kdletters 93ed7f2c57 将每日免费泥点纳入后台配置
Project CI / Repository checks (push) Successful in 1m0s
Project CI / Backend tests (push) Successful in 3m30s
Project CI / Frontend tests (push) Successful in 2m57s
Project CI / Native shell tests (push) Successful in 12m11s
在账号配置页一次维护初始泥点和每日免费额度
将每日额度贯穿钱包配置、日切重置与充值中心投影
补齐迁移兼容、生成绑定、测试和文档
2026-07-31 13:04:27 +08:00
k88936 81911ffbee Merge remote-tracking branch 'origin/master' into fix/artagent-rerefine-prompt
Project CI / Frontend tests (pull_request) Successful in 2m43s
Project CI / Repository checks (pull_request) Successful in 1m7s
Project CI / Backend tests (pull_request) Successful in 3m30s
Project CI / Native shell tests (pull_request) Successful in 11m32s
2026-07-31 12:12:47 +08:00
k88936 3ca96c4cca 记录画布Agent待确认提示词边界
Project CI / Repository checks (pull_request) Failing after 10s
Project CI / Backend tests (pull_request) Failing after 7s
Project CI / Frontend tests (pull_request) Failing after 2m2s
Project CI / Native shell tests (pull_request) Successful in 12m10s
专题文档明确匹配pending卡片时使用正向条件化引导

决策记录固化避免全局禁止重发话术的模型实测结论

踩坑记录补充过度泛化的原因、处理与验证方式
2026-07-31 12:09:38 +08:00
kdletters 0386a5df7c 修复数据库备份异步上传收尾
Project CI / Frontend tests (push) Successful in 2m41s
Project CI / Native shell tests (push) Failing after 19s
Project CI / Backend tests (push) Successful in 3m43s
Project CI / Repository checks (push) Successful in 44s
使用独立systemd服务承接Jenkins退出后的OSS上传
串行补偿延期归档并仅在完整验真后清理
补充备份回归门禁与生产运维约定
2026-07-31 12:08:45 +08:00
menghao 216407d93e 实现资源画布布局持久化 (#116)
Project CI / Frontend tests (push) Failing after 20s
Project CI / Repository checks (push) Successful in 1m2s
Project CI / Backend tests (push) Successful in 2m59s
Project CI / Native shell tests (push) Successful in 11m58s
冻结资源画布布局数据与 CAS 合同
实现双模式本地 sidecar 安全读写
接入二维拖动、默认排版和跨重启恢复
补齐并发冲突、安全边界和界面测试
同步技术文档与共享决策

Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/116
Reviewed-by: 段舒康 <kdletters@qq.com>
Co-authored-by: menghao <mh18530625731@163.com>
Co-committed-by: menghao <mh18530625731@163.com>
2026-07-31 12:00:48 +08:00
k88936 ce47df4c3d 补齐画布Agent业务提示词契约测试
覆盖确认取消、取消后新调用与无依赖批量串行策略

覆盖消息窗口截断、窗口外重新引用与工具路由矩阵
2026-07-31 11:53:48 +08:00
k88936 2b785423ed 同步画布代理对话约束文档
更新后端契约与前端接入文档中的消息输入规则。
记录图片引用、提示词上下文和异常响应处理决策。
补充相关排障经验并移除过期说明。
2026-07-31 11:30:48 +08:00
k88936 2fa05cd605 统一画布代理文本与附件输入约束
要求用户消息包含非空文本,附件仅作为消息上下文。
同步后端领域校验、接口错误和请求测试。
禁用前端纯附件发送并更新交互回归测试。
保留发送失败时的草稿与附件恢复行为。
2026-07-31 11:30:48 +08:00
k88936 b09a98db48 重构画布代理提示词与工具调用循环
统一系统消息、工具结果与异常响应的消息构造。
补充无效响应纠正、批量工具调用和待确认状态处理。
精简图片上下文提示并完善越界引用回退规则。
补齐运行循环和提示词行为测试。
2026-07-31 11:30:48 +08:00
AIGameCreator App a36290b2e5 合并AI游戏创作智能体与通用Runtime基座
Project CI / Frontend tests (push) Failing after 27s
Project CI / Repository checks (push) Successful in 3m20s
Project CI / Backend tests (push) Successful in 3m52s
Project CI / Native shell tests (push) Successful in 13m19s
合并 codex/ai-game-creator-app 的独立客户端、多智能体 Runtime、Runner 与可扩展 LLM Provider 能力
保留 master 最新画布、钱包、后端和原生壳约束并完成四处语义化冲突合并
补齐根 Vitest 对独立 Tauri guest 模块的隔离测试别名并保持 HostBridge 依赖边界
统一正式工作台与 game-chat 的安全本地预览组件及 native-shell 静态门禁
修复合并态 Rust 格式、前端 lint 与共享文档验证口径
2026-07-30 18:01:19 +08:00
AIGameCreator App d4075c3423 抽取通用多智能体运行时与可扩展Provider
Project CI / Frontend tests (push) Failing after 3m43s
Project CI / Native shell tests (push) Failing after 3m36s
Project CI / Repository checks (push) Failing after 4m36s
Project CI / Backend tests (push) Successful in 8m36s
新增纯 Rust agent-runtime-core,提供运行时契约、能力注册、Agent 目录、Profile、完成策略与零重放恢复
抽取中立 LLM Provider 协议与可扩展 Registry,并适配 OpenAI Responses、OpenAI Chat 和 Anthropic
将 AGC interaction、Provider 控制、Runner 生命周期、steering 与 tool-plan handoff 接入统一运行时边界
补充非游戏消费者、Provider 网络闭环、Runtime 恢复及 GUI Runner owner 测试
同步 Cargo/npm 门禁、Runtime 技术方案和项目共享记忆
2026-07-30 16:15:51 +08:00
kdletters b512430e53 收紧图集切片资源边界
Project CI / Repository checks (push) Successful in 1m4s
Project CI / Frontend tests (push) Successful in 2m5s
Project CI / Native shell tests (push) Successful in 2m32s
Project CI / Backend tests (push) Successful in 3m37s
前置限制原始连通域、局部候选和输出切片数量
统一图集切片的有界阻塞线程执行
统一角色图标和UI的原图安全降级
补齐异常输入回归测试与工程文档
2026-07-30 13:44:17 +08:00
kdletters 2cb40f246a Merge pull request 'Feat/pixel art' (#119) from feat/pixel_art into master
Project CI / Repository checks (push) Successful in 1m3s
Project CI / Frontend tests (push) Successful in 2m2s
Project CI / Native shell tests (push) Successful in 2m24s
Project CI / Backend tests (push) Successful in 3m31s
Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/119
Reviewed-by: 段舒康 <kdletters@qq.com>
2026-07-29 21:38:11 +08:00
lhk229 5ec7182d65 修复画布图层查询在重渲染窗口下的测试竞态
Project CI / Repository checks (pull_request) Successful in 1m0s
Project CI / Frontend tests (pull_request) Successful in 2m1s
Project CI / Native shell tests (pull_request) Successful in 2m31s
Project CI / Backend tests (pull_request) Successful in 3m41s
only exposes character animation generation 用例先 await findByAltText 取到
第一个图层,再用同步 getByAltText 取第二个。合并 web master 带入的项目封面
快照改动会在图层落位后触发一次重渲染,同步查询正好落进该窗口就取不到元素,
CI 962 因此失败。

该写法在 master 上逐字相同,属既有竞态,非本分支引入;但它挡住本 PR 的 CI,
故改为异步查询容忍这次重渲染,不改变断言语义与产品代码。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 13:23:07 +00:00
lhk229 bc28f00c2d 修复 inline 路径修复性回读缺少绝对 deadline
Project CI / Repository checks (pull_request) Successful in 1m6s
Project CI / Native shell tests (pull_request) Successful in 2m28s
Project CI / Backend tests (pull_request) Successful in 3m30s
Project CI / Frontend tests (pull_request) Successful in 1m14s
上一轮把修复性回读绑到外层 request_deadline,但 with_external_call_deadline
只在队列 worker 与 openai_image_generation 两处调用,inline HTTP 请求的
RequestContext 默认 external_call_deadline=None,于是 download_deadline 传下去
仍是 None,走无界 download.await——该修复实际只对队列模式生效。

守卫改为在 request_deadline 缺失时自行以 Instant::now() +
EDITOR_PIXEL_ART_MAX_PROCESSING_DURATION 重新计时派生上界,两种模式下都不再
出现无界 GET。结构断言同时要求出现 unwrap_or_else 兜底与该常量。

同时修正决策记录里「最多增加一次 OSS GET」的措辞:约束是不重复读取已成功
取得的对象,而非整个请求至多一次 GET;第一次回读失败或被像素预算掐断时
允许第二次也是最后一次尝试,不视为违规。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 13:12:21 +00:00
lhk229 9a37deeaf0 收窄像素规整尺寸守卫的生效范围表述
Project CI / Repository checks (pull_request) Successful in 1m16s
Project CI / Frontend tests (pull_request) Successful in 2m4s
Project CI / Native shell tests (pull_request) Successful in 2m29s
Project CI / Backend tests (pull_request) Successful in 3m31s
决策记录原文写「修复失败返回尺寸错误交由调用方降级」,读起来像是角色和
图标两条链路都会降级。实际上守卫只保证像素路径不再谎报「尺寸无误」,
拿到尺寸错误之后如何处置仍由各调用方既有语义决定,本次未改动任何调用方。

改为显式写明生效范围:角色据此走原图安全降级、链路闭环;图标沿用 master
既有的非致命语义,只记录告警后继续持久化并拆分,因此 BgFilter 尺寸漂移且
回贴修复失败时仍可能持久化尺寸异常的透明图集,该残留属 master 既有行为,
不在本次范围内解决。守卫断言的注释同步收窄。

仅调整表述,不改代码行为,不新增承诺。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 12:56:37 +00:00
lhk229 fefea643aa 修正图标像素规整专题执行顺序
Project CI / Frontend tests (pull_request) Successful in 1m53s
Project CI / Repository checks (pull_request) Successful in 45s
Project CI / Native shell tests (pull_request) Successful in 2m20s
Project CI / Backend tests (pull_request) Successful in 3m32s
明确图标图集以 provider 原图实际尺寸完成 Alpha 回贴与像素规整
删除规整后仍有独立最终尺寸处理的旧描述
说明 snapper 内部 nearest 与角色前置 Lanczos 的边界
2026-07-29 12:42:05 +00:00
lhk229 bc486aaff5 修正文档中的像素规整与外部 API 契约
Project CI / Repository checks (pull_request) Successful in 1m2s
Project CI / Frontend tests (pull_request) Successful in 2m2s
Project CI / Native shell tests (pull_request) Successful in 2m30s
Project CI / Backend tests (pull_request) Successful in 4m2s
同步角色与图片画布文档的 Lanczos、去背和像素规整执行顺序
补全外部 OpenAPI 四个稳定 warning code 的语义
为外部编辑器 skill 补充顶层 style 参数、兼容规则和请求示例
2026-07-29 12:39:51 +00:00
lhk229 937378ab91 消除像素规整降级路径的重复与无界 OSS 回读
Project CI / Repository checks (pull_request) Successful in 1m0s
Project CI / Frontend tests (pull_request) Successful in 2m1s
Project CI / Native shell tests (pull_request) Successful in 2m26s
Project CI / Backend tests (pull_request) Successful in 3m28s
尺寸守卫此前一律走会回读 provider 原图的包装函数,带来两个问题:permit
获取失败、worker 内 deadline、join 异常和 worker 超时这四条分支其实已经
持有原图,却又对同一 object key 发起第二次 GET,把"最多增加一次 OSS GET"
放大成两次;而第一次回读超时后的那次 GET 完全没有绝对 deadline,突破
30 秒像素预算。

拆成两类:已持有原图的四条分支改走纯内存守卫 degrade_editor_pixel_art_
with_provider_source,零额外 GET;尚未取得原图的三条分支仍走回读守卫,
但该次 GET 改以外层请求 deadline 为绝对上界——用已耗尽的像素预算绑会让
修复必然失败,不绑则突破预算。

apply_editor_postprocessed_alpha_from_persisted_provider_source_or_original
新增可选 download_deadline,非像素路径传 None 保持既有语义;尺寸比对抽为
editor_postprocessed_alpha_matches_delivery_dimensions 供两类守卫共用。
计数断言固定"回读守卫 3 处、内存守卫 4 处",该断言在编写时即抓出一处
分支数误判。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 12:29:42 +00:00
lhk229 414735efde 同步剩余文档的双告警并存规则
Project CI / Repository checks (pull_request) Successful in 1m0s
Project CI / Frontend tests (pull_request) Successful in 2m7s
Project CI / Native shell tests (pull_request) Successful in 2m36s
Project CI / Backend tests (pull_request) Successful in 3m42s
外部编辑器 API 技能文档、外部生成 Worker 化方案和图片画布编辑器 MVP
接入方案仍写着通用 warning 与 sliceWarning 互斥、并以通用告警优先,与
已放开并存的 openapi 契约和 8ed85e17f 的队列 / inline 归一实现不一致。

四处统一改为:仅 postprocess-failed-source-preserved 与 sliceWarning 互斥
(该失败不进入拆分),风格归一化与像素规整产生的通用 warning 可与
sliceWarning 并存且两条都必须展示;同步补充队列侧的拼接与 code 收敛规则。

UI 设计图素材提取不接受 style 参数也不走像素规整,其文档中的互斥表述
仍然成立,未改动。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 12:01:50 +00:00
lhk229 8ed85e17f4 修复队列与 Web 吞掉并存的 sliceWarning
Project CI / Repository checks (pull_request) Successful in 1m3s
Project CI / Frontend tests (pull_request) Successful in 1m59s
Project CI / Native shell tests (pull_request) Successful in 2m25s
Project CI / Backend tests (pull_request) Successful in 3m28s
风格归一化与像素规整新增的通用 warning 可以与 sliceWarning 并存,openapi
已放开该组合,但两个消费端仍是二选一:队列 extract_editor_generation_warning
在 warning 存在时根本不读 sliceWarning,Web inline
resolveEditorGenerationWarningMessage 同样直接返回通用告警。

两侧改为与 inline 响应相同的归一策略:只有一条时原样保留,两条并存时按
"通用在前、拆分在后"拼接,队列侧 code 收敛为 multiple-generation-warnings
并复用既有长度上界收敛。同步修正三处仍声明二者互斥的文档。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 11:44:27 +00:00
lhk229 49965ddd7e 修复角色尺寸恢复降级覆盖已累积生成告警
Project CI / Repository checks (pull_request) Successful in 50s
Project CI / Frontend tests (pull_request) Successful in 2m6s
Project CI / Native shell tests (pull_request) Successful in 2m35s
Project CI / Backend tests (pull_request) Successful in 3m35s
generate_editor_image_for_owner 的角色透明图尺寸恢复失败分支直接返回
warning: Some(...),没有合并 generation_warning,导致 style 为未知值时
契约承诺的 unsupported-image-style 告警在该降级路径上消失。

改为经 merge_editor_generation_warnings 合并,与该函数另外两个返回点一致。
新增结构断言固定"普通图片与图标生成的所有返回点都不得出现裸 warning: Some(",
并同步角色降级断言到合并后的形状。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 11:27:11 +00:00
lhk229 a7d8bccec9 修复像素规整降级绕过交付尺寸守卫
Project CI / Repository checks (pull_request) Successful in 1m4s
Project CI / Frontend tests (pull_request) Successful in 2m1s
Project CI / Native shell tests (pull_request) Successful in 2m26s
Project CI / Backend tests (pull_request) Successful in 3m28s
像素路径的 best-effort 降级分支(预算耗尽、回读 provider 原图失败或超时、
CPU permit 获取失败、worker 内 deadline、join 异常、worker 超时)此前都直接
返回 BgFilter 原始输出并把尺寸错误置为 None,跳过非像素路径已有的尺寸比对
与 alpha 回贴。BgFilter 回图尺寸漂移叠加并发上限 2 的 permit 超时后,角色会
绕过原图安全降级,角色和图标都可能持久化尺寸漂移的低分辨率透明图。

新增 degrade_editor_pixel_art_to_postprocessed_with_dimension_guard 收口所有
降级分支,复用非像素路径的守卫:尺寸一致原样返回且不产生额外 OSS GET,漂移
才回读原图重贴 alpha,修复失败返回尺寸错误交调用方降级。由 provider 原图合成
的 rgba_source fallback 尺寸天然正确,不经守卫。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 11:19:01 +00:00
kdletters 5479559c86 修复游戏聊天启动白屏
Project CI / Repository checks (push) Failing after 52s
Project CI / Backend tests (push) Successful in 3m10s
Project CI / Frontend tests (push) Successful in 3m19s
Project CI / Native shell tests (push) Failing after 10m3s
在创建 WebView 前写入 game-chat 初始 URL

增加启动顺序与禁止二次导航门禁

补齐跨平台回归测试和项目文档
2026-07-29 17:59:10 +08:00
lhk229 9655324dea 补齐生成 payload 新增 style 字段的测试断言
Project CI / Repository checks (pull_request) Successful in 3m32s
Project CI / Frontend tests (pull_request) Successful in 5m6s
Project CI / Native shell tests (pull_request) Successful in 6m32s
Project CI / Backend tests (pull_request) Successful in 7m50s
useImageCanvasGenerationWorkflow.test.tsx 用 toHaveBeenCalledWith 精确匹配
普通图片生成 payload,本分支为该 payload 增加 style 字段后未同步该文件,
CI 前端测试报 "+ style: none"。

该文件不在本分支改动清单内,故此前未被发现。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 09:47:17 +00:00
lhk229 717b94aad8 合并 web master 角色交付尺寸统一
Project CI / Frontend tests (pull_request) Failing after 5m43s
Project CI / Repository checks (pull_request) Successful in 5m48s
Project CI / Native shell tests (pull_request) Successful in 7m49s
Project CI / Backend tests (pull_request) Successful in 8m50s
接受 master 的角色带背景原图与透明图统一交付尺寸方案,像素模式不再
豁免提前归一:逻辑像素规整改在按业务像素矩阵 resize_to_fill(Lanczos
重采样 + 居中裁切)后的交付尺寸图上进行,snapper 自行还原回输入尺寸,
删除原先后置的 nearest 二次恢复及其 pixel_art_applied 开关。

后处理降级告警合并两侧机制:postprocess 失败路径改用 master 的
_with_dimension 重载并继续经 merge_editor_generation_warnings 汇总;
成功路径补回 master 的 dimension_warning,避免自动合并将其丢弃。

结构断言改为只固定 editor_postprocess_fallback_warning 共同前缀。
decision-log 保留双方新决策条目,并修订像素艺术条目中已过时的
"provider 原尺寸分析网格"表述。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 09:33:36 +00:00
lhk229 a97b12d73a 清理像素规整重构残留的死代码
restore_editor_generated_image_output_dimensions 在本分支把
restore_editor_generated_image_output_dimensions_or_original 改为转发到
_with_filter 之后失去全部生产调用者,仅剩单测在用,非测试构建报 dead_code。

删除该包装函数,改由测试直接调用 _with_filter 并显式传 Lanczos3。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 08:22:41 +00:00
lhk229 ac9797b5c3 修复图标描述回退与移动端重复样式
修正图标生成恢复时空提示词对旧描述的阻断。

删除移动端生成按钮重复的宽度声明。
2026-07-29 08:15:43 +00:00
kdletters 3a64411e8c 统一角色原图与透明图交付尺寸
Project CI / Repository checks (push) Successful in 51s
Project CI / Frontend tests (push) Successful in 1m44s
Project CI / Native shell tests (push) Successful in 2m7s
Project CI / Backend tests (push) Successful in 3m16s
角色原图持久化前归一到业务交付尺寸
拒绝错比例透明蒙版并降级保留原图
合并尺寸降级与后处理失败告警
补齐全模型全尺寸真实像素回归
同步角色图片尺寸边界文档
2026-07-29 16:10:54 +08:00
k88936 6ee33dc561 fix: 首页「最近项目」缩略图与退出前视角不一致,出现偏移或裁切 (#111)
Project CI / Repository checks (push) Successful in 1m4s
Project CI / Frontend tests (push) Successful in 2m9s
Project CI / Native shell tests (push) Successful in 2m38s
Project CI / Backend tests (push) Successful in 3m23s
- 封面使用真实画布尺寸及最终 viewport.x/y/scale。
- 320×240 封面改为居中 cover 裁切,不再从左上角取景。
- 正确绘制画布背景色。

in canva:
![shotmd-1784874081.jpg](/attachments/4ac128cc-64c8-4a78-9e75-c35902049d3e)
![shotmd-1784876202.jpg](/attachments/6197259b-887e-4fd6-95b5-b722ec670a02)

in home:
![shotmd-1784874090.jpg](/attachments/241c7cd3-1eee-4f7b-96f2-4ca0268d2bee)
![shotmd-1784876211.jpg](/attachments/aa4200b6-bef0-4122-a797-ebc082b27a17)

因为原本的布局持久化可能有一些bug,改动不相关,所以我回退到最开始的一版:
- 不额外监听画布尺寸变化,给最小尺寸兜底,(大了比小了好)
- 封面不要求强一致性,生成/上传时机仍然按照原来随布局持久化

优化了封面生成:
- 改用webp格式
- 尽量利用图片缓存

最终生成封面从700ms加速到150ms以内, 加上必须的上传和确认150ms 和 布局持久化的时间相差不多,不是特别离谱的手速都能保证两者一致

---------

Co-authored-by: kdletters <kdletters@qq.com>
Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/111
Co-authored-by: 王德宇 <kvtodev@outlook.com>
Co-committed-by: 王德宇 <kvtodev@outlook.com>
2026-07-29 16:09:30 +08:00
lhk229 fae6f00c9f 合并 web master 最新更新
Project CI / Frontend tests (pull_request) Failing after 52s
Project CI / Repository checks (pull_request) Successful in 1m2s
Project CI / Native shell tests (pull_request) Successful in 2m10s
Project CI / Backend tests (pull_request) Successful in 3m28s
将 web/master 的画布快照、图集标签和 Agent 框架更新合入像素艺术功能分支。

# Conflicts:
#	docs/project-memory/shared-memory/decision-log.md
#	server-rs/crates/api-server/src/external_editor_api.rs
2026-07-29 07:02:56 +00:00
lhk229 a6a6be23c9 开启图标图集BgFilter交叉校验
将生成图标素材的 flat 请求固定切换为 cross_check=on。

同步调整现有结构断言与编辑器、后端和共享决策文档。
2026-07-29 06:43:59 +00:00
kdletters edc99e55e4 修复跨设备画布旧快照覆盖
Project CI / Frontend tests (push) Failing after 43s
Project CI / Repository checks (push) Successful in 47s
Project CI / Native shell tests (push) Successful in 2m47s
Project CI / Backend tests (push) Successful in 3m13s
按用户隔离画布缓存并等待权威 revision 后开放保存
固化保存重试版本并安全处理认证重载与冲突恢复
合并迟到资源图层且隔离跨账号异步请求
强制 Web 与 External 画布写入使用 expectedRevision CAS
补充竞态回归测试并同步 OpenAPI、Skill 与技术文档
2026-07-29 13:51:49 +08:00
lhk229 8848a68fb0 调整像素网格步长估算分位数
将相邻边缘峰间距由中位数改为线性插值 P30。

同步更新像素规整技术方案和共享决策记录。
2026-07-29 05:42:08 +00:00
lhk229 1ed8064d2f 统一图标图集全连通域拆分
移除前端从提示词解析素材数量的逻辑,完整提示词作为单个请求元素提交。

删除后端按描述数量截断切片的路径,自动拆分与手动拆分复用全连通域算法。

统一切片命名和尺寸、像素、数量限制,保留手动拆分按钮与接口。

更新既有测试、OpenAPI、编辑器文档和共享决策记录。
2026-07-29 04:52:29 +00:00
AIGameCreator App 349be22800 合并开发态游戏聊天创作页
Project CI / Frontend tests (push) Failing after 23s
Project CI / Repository checks (push) Failing after 32s
Project CI / Backend tests (push) Successful in 2m53s
Project CI / Native shell tests (push) Failing after 9m50s
合并 codex/agc-game-chat 的开发态游戏聊天入口
保留当前分支 Runtime 恢复与视觉产物门禁
整合前端回归测试与 AI 游戏创作技术方案
2026-07-29 12:11:28 +08:00
AIGameCreator App dae59992b1 新增开发态游戏聊天创作页
新增仅开发态游戏聊天入口与本地安全预览布局
将Supervisor进度、返工、测试、迭代和图片证据写入聊天
完善自动预览授权持久化、锁竞争重试与Runtime收尾恢复
规范视觉产物走规范图、UI设计和透明图集专用接口
补齐共享契约、回归测试、技术方案和项目记忆
2026-07-29 11:54:06 +08:00
lhk229 732fcf0b45 新增图片生成像素艺术后处理
新增确定性像素网格规整模块并保留第三方 MIT 许可证。

为普通图片、角色和图标图集接入像素艺术选项、并发预算和失败降级。

同步前端交互、请求契约、OpenAPI、项目文档与测试。
2026-07-29 03:46:03 +00:00
kdletters 44f47e5db1 修复图集素材标签持久化与拆分校验
Project CI / Native shell tests (push) Successful in 2m40s
Project CI / Backend tests (push) Successful in 3m16s
Project CI / Repository checks (push) Successful in 1m0s
Project CI / Frontend tests (push) Successful in 2m5s
项目资源复用增加素材类型匹配,避免同源旧类型资源回流
标签保存期间禁用拆分并在服务端确认后回写资源引用
补齐乱序请求、快照刷新、失败回滚和撤销历史保护
新增前后端回归测试并同步图集入口设计文档
2026-07-29 11:06:56 +08:00
kdletters d7f0c45164 抽取画布 Agent 公共执行框架
Project CI / Repository checks (push) Successful in 1m3s
Project CI / Frontend tests (push) Successful in 1m59s
Project CI / Native shell tests (push) Successful in 2m27s
Project CI / Backend tests (push) Successful in 3m5s
新增业务中立的 function-calling harness 与公共提示词协议

统一画布 Agent 工具路由约束和待确认控制语义

保留失败前输出并事务化收口 memory、deadline 与取消状态

迁移画布 Agent 和 API 编排并同步架构文档与项目记忆
2026-07-28 21:34:34 +08:00
kdletters b1db88c114 修复AGC总控恢复与工具计划交接
Project CI / Repository checks (push) Successful in 1m3s
Project CI / Frontend tests (push) Successful in 2m50s
Project CI / Backend tests (push) Successful in 3m5s
Project CI / Native shell tests (push) Successful in 9m33s
修复Windows下tool-plan账本按句柄原子安装失败。

补齐项目总控空态、持久Runtime水合与核对后重试交互。

修正Responses多角色内容映射与steer审计幂等身份。

修复首批协作repair累积、缺失Agent约束和isolated单槽替换。

收紧API Key安全持久化检测并覆盖装饰赋值与自然语言边界。

修复Provider retry恢复扫描与无画布密钥时的视觉产物降级。

补充定向回归测试和项目技术文档。
2026-07-28 19:59:43 +08:00
kdletters 271d5d7bd3 持久化用户历史消费泥点投影
Project CI / Native shell tests (push) Successful in 2m28s
Project CI / Repository checks (push) Successful in 59s
Project CI / Frontend tests (push) Successful in 1m58s
Project CI / Backend tests (push) Successful in 3m5s
后台用户详情展示历史花费并保留手动对账
消费落账原子更新投影并提供存量初始化
为手动对账增加独立管理员操作权限
更新SpacetimeDB绑定、文档和测试
2026-07-28 16:20:43 +08:00
k88936 66a8b7f597 画布agent 完善上下文 (#101)
Project CI / Repository checks (push) Successful in 53s
Project CI / Frontend tests (push) Successful in 2m34s
Project CI / Native shell tests (push) Successful in 2m42s
Project CI / Backend tests (push) Successful in 3m28s
* 补全完整的工具参数
* 调整提示词应对一些bad case
* 把attachment的名称/描述纳入上下文

Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/101
Co-authored-by: 王德宇 <kvtodev@outlook.com>
Co-committed-by: 王德宇 <kvtodev@outlook.com>
2026-07-28 15:44:05 +08:00
k88936 78e6959ca4 画布agent交互优化 (#105)
Project CI / Repository checks (push) Successful in 1m10s
Project CI / Frontend tests (push) Successful in 1m27s
Project CI / Native shell tests (push) Successful in 2m45s
Project CI / Backend tests (push) Successful in 3m47s
输入框尺寸根据输入内容调整高度,达到最大高度后再出现翻页条。
before:
![shotmd-1784699696.jpg](/attachments/20491333-efe9-44f3-ba6c-1d84579473b2)
after:
![shotmd-1784699381.jpg](/attachments/6018e4e1-6ccc-4de7-92de-5d3f5fb43846)
![shotmd-1784699431.jpg](/attachments/8e91351e-29a5-4220-a7e2-e09554b00935)

调整对话切换角标样式
before:
![shotmd-1784699673.jpg](/attachments/7c3470ab-6f7d-4aa8-9660-4db8e942bd28)
after:
![shotmd-1784699465.jpg](/attachments/e8342741-c1a4-4669-9ad4-c8b34cfeaf30)

新建对话按钮禁用 当已在一个新对话中

Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/105
Co-authored-by: 王德宇 <kvtodev@outlook.com>
Co-committed-by: 王德宇 <kvtodev@outlook.com>
2026-07-28 15:22:49 +08:00
lhk229 d29240b954 补齐 Anthropic 原生工具与三协议流式工具调用 (#112)
Project CI / Repository checks (push) Successful in 46s
Project CI / Backend tests (push) Successful in 2m55s
Project CI / Native shell tests (push) Successful in 9m53s
Project CI / Frontend tests (push) Successful in 2m28s
Anthropic 请求发送 tools 与对象形态 tool_choice 并解析 tool_use block,解除本地对 function tools 的拦截
Chat / Responses / Anthropic 三种协议的流式工具增量按槽位聚合,收尾校验参数为完整 JSON,截断流不返回半截参数
解除 App 侧 Anthropic 降级为文本 JSON 协议的两处守卫与对应提示词分支
新增依赖真实凭据的流式工具验收用例,默认 ignore

Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/112
Co-authored-by: 孔令弘 <ink29535@proton.me>
Co-committed-by: 孔令弘 <ink29535@proton.me>
2026-07-28 13:33:49 +08:00
AIGameCreator App 26ef00f7b9 修复游戏创作脚本剩余ESLint错误
Project CI / Repository checks (push) Successful in 1m7s
Project CI / Frontend tests (push) Successful in 2m52s
Project CI / Backend tests (push) Successful in 3m3s
Project CI / Native shell tests (push) Failing after 6m25s
整理配置检查与测试文件导入顺序
调整配置向导无限循环写法通过Lint门禁
2026-07-28 12:49:48 +08:00
AIGameCreator App d155873454 修复自主构建脚本ESLint错误
Project CI / Frontend tests (push) Failing after 22s
Project CI / Repository checks (push) Failing after 47s
Project CI / Backend tests (push) Successful in 3m4s
Project CI / Native shell tests (push) Failing after 7m33s
删除未使用的任务计数解析函数
移除未消费的响应参数与调用字段
2026-07-28 12:46:50 +08:00
AIGameCreator App 26555e66af 修复AI游戏客户端手机号登录契约
密码登录、验证码发送和验证码登录改用国家码与纯手机号字段
非 JSON 认证错误回退为中文操作提示
补充登录契约、错误回退测试和决策记录
2026-07-27 21:31:58 +08:00
AIGameCreator App 97dc708576 修复AI游戏客户端手机号登录契约
Project CI / Repository checks (push) Failing after 55s
Project CI / Frontend tests (push) Successful in 2m49s
Project CI / Backend tests (push) Successful in 3m7s
Project CI / Native shell tests (push) Failing after 6m57s
密码登录、验证码发送和验证码登录改用国家码与纯手机号字段
非 JSON 认证错误回退为中文操作提示
补充登录契约、错误回退测试和决策记录
2026-07-27 21:31:35 +08:00
AIGameCreator App 6bcd176bdf 合并 master 最新更新
Project CI / Frontend tests (push) Failing after 24s
Project CI / Repository checks (push) Failing after 43s
Project CI / Backend tests (push) Successful in 3m5s
Project CI / Native shell tests (push) Failing after 6m49s
合入 master 的 BgFilter、CI、运维与现役平台改造。

保留 AI 游戏创作 Runtime、独立锁文件与原生壳验证链路。

修复共享充值账单组件、LLM 网关与退役 Agent 兼容边界。

同步冲突文档、锁文件和开发脚本。
2026-07-27 18:28:26 +08:00
kdletters 0ef5c2bb79 修复AGC在Windows上的启动失败
Project CI / Frontend tests (push) Failing after 25s
Project CI / Repository checks (push) Failing after 54s
Project CI / Backend tests (push) Successful in 4m54s
Project CI / Native shell tests (push) Failing after 7m35s
通过子进程私有环境变量传递DACL目标路径,避免PowerShell命令参数解析失败。
同步补充AI游戏创作实施方案和项目踩坑记录。
2026-07-27 17:45:16 +08:00
AIGameCreator App b18b367382 修复运行续作与工具路径交接
Project CI / Repository checks (push) Failing after 52s
Project CI / Frontend tests (push) Successful in 2m22s
Project CI / Backend tests (push) Successful in 4m55s
Project CI / Native shell tests (push) Failing after 8m37s
无活动 Runtime 时将自然语言继续转换为新执行并保留显式恢复语义
成功响应落账前按工具契约规范化项目内绝对路径
拒绝重复键隐藏路径、动态 MCP 和项目外路径的交接放宽
补齐续作分流、路径重放和失败关闭回归测试
同步更新 Runtime 技术方案与共享踩坑记录
2026-07-27 17:01:11 +08:00
AIGameCreator App 4522f9dca1 修复工具计划响应交接误判
Project CI / Repository checks (push) Failing after 1m31s
Project CI / Frontend tests (push) Successful in 3m12s
Project CI / Backend tests (push) Successful in 5m44s
Project CI / Native shell tests (push) Failing after 8m33s
区分计划叙述、源码内容与结构化敏感输入,避免安全字面量误触 reconciliation
为成功响应交接失败持久化受控分类、错误摘要与字符数
补充工具计划回归测试及 Runtime 技术和排障文档
2026-07-27 14:24:07 +08:00
AIGameCreator App ab89776307 修复项目总控上下文预加载说明
Project CI / Frontend tests (push) Failing after 26s
Project CI / Repository checks (push) Failing after 52s
Project CI / Native shell tests (push) Failing after 33s
Project CI / Backend tests (push) Successful in 5m14s
按 Agent 身份在 prompt 格式化阶段选择上下文预加载文案
删除依赖上游完整字符串的静默替换链路
补充普通 Agent 与 Supervisor 最终请求回归测试
同步 Runtime 上下文压缩技术约束
2026-07-27 12:04:14 +08:00
AIGameCreator App 427a8c151a 完善自主构建正式产物与终端测试
Project CI / Frontend tests (push) Failing after 24s
Project CI / Repository checks (push) Failing after 46s
Project CI / Backend tests (push) Successful in 4m14s
Project CI / Native shell tests (push) Failing after 7m17s
新增终端 AppData 配置向导并强化跨平台密钥与进程树安全

升级自主构建为十六任务产物 DAG 并接入两类真实画布素材

完善完成基线、并发补验、验证证据与受限画布返工合同

强化确定性与真实 Swarm E2E 的 exactly-once 和正式产物校验

修复确定性 Provider 终态修复后的复验交付状态

同步更新客户端实现计划、决策记录和踩坑说明
2026-07-27 04:04:06 +08:00
AIGameCreator App 655aa0e2f6 测试纯静态美术产物验证合同
新增无 package.json 的 art-asset-plan 回归场景

约束自主验证仅走静态 smoke 与浏览器验收链路

记录当前错误暴露 project.verify 的失败证据
2026-07-25 20:08:21 +08:00
AIGameCreator App 006846e667 修复Swarm连续任务恢复与终态归属
Project CI / Repository checks (push) Successful in 2m43s
Project CI / Backend tests (push) Successful in 7m41s
Project CI / Native shell tests (push) Failing after 12m2s
Project CI / Frontend tests (push) Failing after 1m10s
以启动 mutation 返回的 acceptedRunId 建立不可变 turn baseline

拆分队列忙碌与 Runtime 可追加状态并恢复 cancelled canonical 后的 pending 任务

按 finalization message ID 和完整 task journal 隔离连续 B/C 对话、失败扫描与报告计数

以 agentId 和 runId 聚合专业 Agent 终态并保持 journal 失败优先

补齐重复投递、恢复幂等、连续轮次和历史 repair 回归及项目文档
2026-07-25 14:07:54 +08:00
AIGameCreator App 3237ad140a 完善智能体交互与画布美术生成
为 Supervisor 与部门 Director 接入统一 Interaction Loop 和持久 Runtime 调度
在配置画布 API Key 时强制委派美术 Agent 并复用规范素材
收紧画布生成角色权限、图片内容校验和项目锁并发边界
完善专业 Agent revision 验证、任务恢复与 Provider 兼容处理
补充自主协作、真实画布生成、运行时收束测试及技术文档
2026-07-24 21:44:07 +08:00
AIGameCreator App ddbca15e30 修复Agent Swarm聊天测试Runner冲突
Project CI / Frontend tests (push) Failing after 50s
Project CI / Backend tests (push) Successful in 6m58s
Project CI / Repository checks (push) Successful in 2m42s
Project CI / Native shell tests (push) Failing after 11m11s
为人工聊天测试复制隔离 AppData,避免复用正式 Runner
新增空闲 Runner 安全收束与临时目录清理
补齐初始化占位页校验、回归测试和开发文档
2026-07-23 13:52:06 +08:00
AIGameCreator App 52d47d5470 合并远端AI游戏创作分支更新
Project CI / Frontend tests (push) Failing after 20s
Project CI / Repository checks (push) Successful in 2m21s
Project CI / Backend tests (push) Successful in 5m16s
Project CI / Native shell tests (push) Failing after 9m35s
保留 Agent Runtime、Runner、项目与测试的模块化拆分
吸收跨平台启动与本地开发栈稳定性修复
补齐 Gitea CI 门禁与异步测试稳定性改进
统一前端 Runtime 水合、策略读取与状态重置语义
2026-07-23 12:40:28 +08:00
AIGameCreator App 917fcd5726 添加Agent Swarm一键测试入口
新增 agc:test 确定性自动验收短命令。
新增 agc:test:chat 自动发现 AppData、创建测试项目并启动自主 Swarm。
复用正式预览服务完成浏览器打开、信号停止和安全清理。
补充命令契约、跨平台目录、项目哨兵和预览地址测试。
同步客户端技术方案与团队复验流程。
2026-07-23 12:15:26 +08:00
menghao ff84b5a308 修复AI游戏创作壳跨平台启动 (#107)
Project CI / Frontend tests (push) Failing after 20s
Project CI / Repository checks (push) Successful in 1m33s
Project CI / Backend tests (push) Successful in 4m7s
Project CI / Native shell tests (push) Successful in 11m20s
修复 macOS 下 Unix 文件身份比较和临时目录测试兼容
隔离 AI 游戏创作本地数据库与发布身份并阻止旧 schema 降级启动
完善 Tauri 开发栈错误传播和 POSIX 子进程树清理
跳过 macOS 不支持的进程指标回调以消除周期告警
补充开发调度测试、技术方案和团队排障记忆

Reviewed-on: https://git.genarrative.world/git/GenarrativeAI/Genarrative/pulls/107
Co-authored-by: menghao <mh18530625731@163.com>
Co-committed-by: menghao <mh18530625731@163.com>
2026-07-23 10:50:02 +08:00
AIGameCreator App 167b11d52e 完善自主 Swarm 无干预可玩交付
固定首批程序实现与质量只读职责,并在计划执行前阻断质量 Agent 项目写入
要求非只读专业 Agent 完成本人修改和对应 revision 验证后再交付
补齐 Provider 瞬态重试、最终回复和 Swarm CLI 终态收敛
升级 Provider action batch v3 并兼容 v2/v1 持久恢复
扩展确定性与真实外部 Provider 塔防验收、前端状态和项目文档
2026-07-23 01:06:54 +08:00
AIGameCreator App 7b145b3067 修复自主构建等待确认导致的循环中断
将自主模式剩余确认策略统一失败关闭并保持标准模式语义
迁移旧自主确认批次并在同一 Session 和 run 重新规划
补齐零执行审计、恢复回归和真实可玩验收记录
2026-07-22 20:57:37 +08:00
AIGameCreator App 64ca2f99b2 修复多 Agent 并行写入导致的自主构建中断
将执行前 project revision 漂移改为 blocked observation 并在同一 run 自动重新规划
为 file.write 和 file.patch 增加项目锁内 pending 与 revision 二次校验
补充 stale action 回归、真实外部模型与确定性可玩塔防验收记录
2026-07-22 19:49:12 +08:00
AIGameCreator App 9371cc537a 并行拆分客户端生成与验收大型模块
拆分 tool-plan 持久交接的模型、校验、发现和跨平台存储模块。

拆分旧生成链的提示、画布、产物、生命周期和追踪模块。

拆分 Swarm CLI 的输入、观察、终态判定、报告与测试模块。

拆分浏览器发现、CDP、网络策略、试玩、证据与测试模块。

补充兼容可见性、集成验证和第三轮拆分文档。
2026-07-22 18:28:19 +08:00
AIGameCreator App e142ef5eac 修复自主构建收束回复与公共失败审计
为已通过完成门禁的自主构建总控补充确定性最终回复兜底。

保留 Provider 失败生命周期并沿用回复流与 finalization 幂等提交。

将公共失败事件和 Agent DB 审计改为哈希、长度与稳定分类。

补充私有诊断隔离回归、真实外部 E2E 证据与项目文档。
2026-07-22 17:48:00 +08:00
kdletters 27f66bf0b1 稳定AI原生壳终态审计测试
Project CI / Repository checks (push) Successful in 1m39s
Project CI / Frontend tests (push) Successful in 2m0s
Project CI / Backend tests (push) Successful in 6m18s
Project CI / Native shell tests (push) Successful in 13m6s
让最终回复失败测试等待 Runtime 终态与 Agent lane 完整释放
让并行后台任务测试在读取对话和审计前等待两个 Agent lane 释放
补充异步终态测试的具体回归用例说明
2026-07-22 16:42:20 +08:00
AIGameCreator App 759951ab12 继续拆分客户端工作区与 Agent 运行时模块
拆出项目工作区视图、命令策略、摘要命令与开发面板模块。

拆出 Runtime action、driver 与 protocol 的职责模块并保留稳定 facade。

保留测试模块、兼容重导出与原有可见性边界。

补充结构拆分决策、踩坑记录与实施计划验收结果。
2026-07-22 16:03:34 +08:00
kdletters f92c1a6f43 稳定AI分支Cargo依赖准备
Project CI / Repository checks (push) Successful in 2m4s
Project CI / Frontend tests (push) Successful in 2m36s
Project CI / Backend tests (push) Successful in 4m23s
Project CI / Native shell tests (push) Failing after 8m52s
在后端测试前有界重试server-rs依赖fetch
在原生门禁前分别准备桌面壳和AI壳Rust依赖
保持测试与编译命令单次执行并继续暴露真实失败
2026-07-22 16:01:12 +08:00
kdletters 084543621b 优化AI游戏创作分支CI依赖准备
Project CI / Repository checks (push) Successful in 1m48s
Project CI / Frontend tests (push) Successful in 2m16s
Project CI / Backend tests (push) Failing after 47s
Project CI / Native shell tests (push) Failing after 10m15s
四个CI任务复用预构建工具链与下载缓存
直接从Gitea checkout并增加npm和Git网络重试
保留AI壳独立依赖安装测试与双Cargo锁门禁
2026-07-22 15:57:22 +08:00
AIGameCreator App 0aaa191f8d 并行拆分客户端运行时与项目摘要模块
将 runtime_tools 拆为十五个职责模块并保留 Agent 可见性

将 Runner 拆为协议端点分发客户端与所有权模块

将进程会话拆为模型持久化生命周期 IO 恢复与测试模块

将项目摘要拆为十四个无环模块并保留一百一十二个导出

记录并行拆分边界与稳定树验收规则
2026-07-22 14:45:36 +08:00
AIGameCreator App 2ec05ba85d 修复自主构建验证收敛与浏览器取证
限制旧试玩失败下的重复委派并强制当前 revision 复验

收紧固定试玩控件唯一可见启用合同

为 Chrome 使用短临时目录并支持当前 run 截图别名

补齐确定性门禁与运行时决策记录
2026-07-22 14:43:55 +08:00
kdletters 017e956724 补齐AI原生CI浏览器依赖
Project CI / Frontend tests (push) Successful in 2m38s
Project CI / Repository checks (push) Successful in 2m56s
Project CI / Backend tests (push) Successful in 9m4s
Project CI / Native shell tests (push) Successful in 15m6s
通过 Google 官方签名 APT 源安装 headless Chrome
保持真实 DOM 与 Canvas smoke 不降级
同步 Gitea CI 运维要求和共享踩坑记录
2026-07-21 23:15:10 +08:00
kdletters b6c85a5216 稳定AI原生壳异步终态测试
Project CI / Frontend tests (push) Successful in 2m52s
Project CI / Repository checks (push) Successful in 3m12s
Project CI / Backend tests (push) Successful in 9m11s
Project CI / Native shell tests (push) Failing after 12m37s
等待 Agent 终态和执行通道释放后再断言持久化副作用
使用一次性测试注入覆盖 CI root 环境下的对话写失败
补充异步 Runtime 与 CI 写失败的共享踩坑记录
2026-07-21 22:56:17 +08:00
AIGameCreator App be89296492 拆分 AI 游戏创作客户端大型模块
拆分 App 认证、壳层、运行配置与项目摘要模块
拆分 Tauri 项目能力与 Rust 测试领域模块
拆分界面测试与 Agent Runtime 真实 E2E 套件
补充源码扫描和客户端模块化文档约定
2026-07-21 22:53:29 +08:00
kdletters a273377b17 稳定AI原生壳全量测试
Project CI / Frontend tests (push) Successful in 2m47s
Project CI / Repository checks (push) Successful in 3m6s
Project CI / Backend tests (push) Successful in 10m25s
Project CI / Native shell tests (push) Failing after 15m34s
为 command.exec 沙箱测试安装受信任的 ripgrep
将共享后台锁的 Tauri suite 固定为单线程
同步 CI 调度与排障文档
2026-07-21 22:23:17 +08:00
kdletters 94ee363d84 补齐原生CI的merged-usr预检
Project CI / Frontend tests (push) Successful in 2m49s
Project CI / Repository checks (push) Successful in 3m24s
Project CI / Backend tests (push) Successful in 8m21s
Project CI / Native shell tests (push) Failing after 10m21s
按运行时代码动态复现 merged-usr 符号链接
避免 bubblewrap canary 因动态加载器路径误报失败
2026-07-21 22:03:01 +08:00
kdletters 5d045d532f 修复隔离CI的原生沙箱环境
Project CI / Native shell tests (push) Failing after 2m18s
Project CI / Frontend tests (push) Successful in 3m17s
Project CI / Repository checks (push) Successful in 3m56s
Project CI / Backend tests (push) Successful in 9m25s
为 rustup 引导和工具链安装增加有界重试
显式安装并预检 bubblewrap 沙箱能力
将 Node 与 Rust 工具暴露到受信任系统路径
记录 Runner systempaths 空切片修补与验收口径
2026-07-21 21:56:23 +08:00
kdletters bf349a38a3 稳定隔离CI的Cargo依赖下载
Project CI / Frontend tests (push) Successful in 2m50s
Project CI / Backend tests (push) Failing after 3m1s
Project CI / Repository checks (push) Successful in 3m16s
Project CI / Native shell tests (push) Failing after 11m25s
关闭 Cargo HTTP multiplexing,降低代理链瞬时 TLS EOF 影响
将 Cargo 网络重试次数提高到 10 次
同步开发运维与共享工作流说明
2026-07-21 21:38:03 +08:00
kdletters 79b9404983 修正隔离CI的代理与提权流程
Project CI / Frontend tests (push) Successful in 3m2s
Project CI / Repository checks (push) Successful in 3m21s
Project CI / Backend tests (push) Failing after 3m36s
Project CI / Native shell tests (push) Failing after 11m16s
保留root任务的代理环境并为非root sudo透传受控代理
记录Gitea 1.26.4与rootless runner隔离部署
沉淀Docker socket和Compose路径排障经验
2026-07-21 21:28:14 +08:00
AIGameCreator App 9fad853440 拆分 Agent 运行时模块 2026-07-21 20:48:11 +08:00
kdletters 1f29ea6d8c 稳定AI前端异步测试
Project CI / Native shell tests (push) Failing after 59s
Project CI / Backend tests (push) Failing after 59s
Project CI / Repository checks (push) Failing after 1m58s
Project CI / Frontend tests (push) Failing after 2m46s
等待项目Agent运行态水合完成后再断言提交方式
避免干净runner较慢时同步查询抢跑
2026-07-21 20:19:13 +08:00
kdletters 5611b60d7f 修复原生CI命令路径
Project CI / Frontend tests (push) Failing after 3m0s
Project CI / Repository checks (push) Successful in 3m3s
Project CI / Backend tests (push) Successful in 7m22s
Project CI / Native shell tests (push) Failing after 10m18s
将setup-node的Node与npm映射到受信任系统目录
保持command.exec生产安全白名单不变
同步更新CI开发运维文档
2026-07-21 20:12:20 +08:00
kdletters 676c4beb60 补齐Gitea测试门禁
Project CI / Backend tests (push) Successful in 5m35s
Project CI / Native shell tests (push) Failing after 11m9s
Project CI / Repository checks (push) Successful in 2m23s
Project CI / Frontend tests (push) Successful in 2m16s
拆分前端、后端与原生壳测试任务
接入server-rs workspace正式全量测试
将AI游戏创作分支及独立依赖纳入CI
修复既有测试断言、格式与异步稳定性问题
稳定AI Tauri并发回执测试
更新开发运维和共享流程文档
2026-07-21 19:40:38 +08:00
AIGameCreator App a983597f13 修复 Agent 原生工具严格 Schema 兼容 2026-07-21 19:24:18 +08:00
AIGameCreator App d8a070f8f8 补齐自主可玩项目确定性门禁
- 新增确定性 OpenAI Chat Provider 与安全 E2E wrapper
- 修复成功试玩后历史失败 observation 仍阻断收束的问题
- 覆盖塔防专业返工、双视口和 37 条试玩断言并同步文档
2026-07-21 18:24:52 +08:00
AIGameCreator App 1fce5460f9 修复总控试玩失败后的专业返工收口
总控进入协作后将试玩失败收窄为 code-prototype 后续委派,避免越权直接修改项目
保留无协作兼容路径和新 revision 先复验再试玩的完成门禁
补齐协作分支回归测试并修正自主完成合同测试夹具
同步 Runtime 技术方案、踩坑记录和 Rust 格式
2026-07-21 17:26:16 +08:00
AIGameCreator App 81d9252b6b 修复自主构建交付与试玩收敛
修复截断 scaffold 强制小范围补丁并提高修复输出预算
修复验证后并行读取批次快照不一致
收窄已验证交付并支持总控验收专业产物 revision
补充自主构建、Provider 批次和试玩验证门回归测试
2026-07-21 16:18:35 +08:00
AIGameCreator App ecff991330 修复自主试玩失败状态持久化
持久化当前 revision 的试玩失败标记并驱动总控进入源码修复

在试玩通过后安全清除失败凭证并补充上下文压缩回归测试
2026-07-21 13:30:16 +08:00
AIGameCreator App 9bb048c11b 完善自主构建运行时并提高 Runner 启动容错
完善 Agent Swarm 自主游戏构建、委派协作、验证门和试玩闭环

补齐浏览器验证、CLI 入口、项目状态与运行时测试覆盖

将外部 Agent Runner 冷启动超时提高到 30 秒并增加回归测试

同步真实 E2E 自测脚本、配置检查和项目决策记录
2026-07-21 12:53:27 +08:00
AIGameCreator App 1d4aad2600 合并远端 AI 游戏创作分支改动
同步首页侧栏与富文本输入改造
保留当前 GameAgent 工作台和自主 Runtime 改动
2026-07-21 11:46:38 +08:00
AIGameCreator App 67ed73d857 合并 GameAgent V1 UI 分支
引入游戏创作工作台与资源预览界面
同步 UI 原型生成和视觉验收约束

# Conflicts:
#	apps/ai-game-creator-shell/src/App.tsx
#	docs/README.md
#	docs/project-memory/shared-memory/decision-log.md
#	server-rs/crates/api-server/src/editor_project.rs
2026-07-21 11:20:56 +08:00
AIGameCreator App cd97427f26 收紧UI原型生成与视觉验收
强化UI原型专用2K横屏提示词与画板Art Spec
要求当前图片通过结构化视觉语义验收后才能完成
将未验收图片明确标记为候选界面图
修正UI设计负面词并补齐Runtime、界面与文档回归
2026-07-20 21:46:48 +08:00
AIGameCreator App a7323572a0 完善总控纯聊天交互边界
在独立聊天窗口复用工具确认与结构化追问控件

按项目保留未发送草稿并展示Runtime恢复确认

补齐草稿、恢复、确认和追问的界面回归测试
2026-07-20 21:31:31 +08:00
AIGameCreator App a3769978a7 补齐总控聊天窗口事件权限
允许 supervisor-chat 窗口监听和取消监听 Runtime 事件

保证独立聊天窗口实时接收总控 Agent 状态与回复更新
2026-07-20 21:18:22 +08:00
AIGameCreator App b783d5d7c7 补齐项目图片资源预览
在工作台资源浮层中直接按比例展示已登记图片

新增受控 Tauri 图片读取以及权限、路径、格式和尺寸校验

补齐加载失败状态、布局回归、Rust 测试和技术文档
2026-07-20 20:18:04 +08:00
AIGameCreator App 3a8dff1404 完善游戏创作工作台与智能体恢复闭环
实现横屏项目开发工作台、资源画布、Supervisor 对话与专业 Agent 状态展示

修复总控和专业 Agent 重试、Runner 接管、历史成果跨 Run 持久展示及确认流程

补齐画板图片产物合同、客户端内预览、共享契约与安全边界

新增完整回归测试、工作台 PRD、技术方案与待解决事项
2026-07-20 19:48:05 +08:00
AIGameCreator App 36734e158e 新增总控Agent纯聊天开发窗口
新增开发态独立窗口路由与专业Agent开发页入口
固定复用project-supervisor活动会话、Runtime和持久对话
提供纯消息区、流式等待状态、输入框与运行时设置
补齐窗口编码、前端交互、开发态门禁和原生壳验证
同步AI游戏创作实施计划与项目决策记录
2026-07-20 17:25:58 +08:00
AIGameCreator App a3337f4493 合并最新master分支
合入 origin/master 最新画布、外部接口与后端模块化改动。

按新队列语义解决画布测试和原生壳检查冲突。

把编辑器 Agent 迁移到模块化实现并适配 LlmRunRequest。

删除已废弃的旧编辑器 Agent 单文件与个人 Claude 本地配置。
2026-07-20 16:08:24 +08:00
AIGameCreator App 0fbb76fb94 补齐Agent Runtime工具计划强杀恢复门禁
新增真实 Provider 工具计划交接 checkpoint、Runner 强杀恢复与零重放验收。

收紧 Supervisor 首波协作、返工 runId 和持久 delivery 合同。

扩展敏感正文扫描、跨平台安全回归和 E2E 自测。

注册两级 npm 命令并同步 Runtime 验收文档与当前证据。
2026-07-20 15:48:07 +08:00
k88936 125927e0e8 Ai game creator app home sidebar (#86)
![shotmd-1784186268.jpg](/attachments/c828773c-4f1a-4654-b76d-c944b82ec023)
![shotmd-1784186877.jpg](/attachments/f1782ba3-245a-40c1-8caa-cbd7e4cce74b)
![shotmd-1784186948-compressed.webp](/attachments/f3d02ac3-db7a-439b-9a84-7aceefad9048)
TODO: 补充说明书链接

Reviewed-on: https://git.genarrative.world/git/GenarrativeAI/Genarrative/pulls/86
Co-authored-by: 王德宇 <kvtodev@outlook.com>
Co-committed-by: 王德宇 <kvtodev@outlook.com>
2026-07-20 15:03:23 +08:00
AIGameCreator App 791a50ffe8 完善Agent Runtime工具计划持久交接
新增 tool-plan 成功响应私有账本并支持 base 与 repair 零网络恢复
补齐 Provider 生命周期闭合、终态清理和 Runner 空闲门禁
收紧 Agent DB 审计白名单并拒绝原始 Provider 与调用标识
加固 Unix exchange/quarantine 与 Windows 句柄枚举存储路径
扩展 E2E 自测、跨平台回归和 V1.43 工程文档
2026-07-20 11:05:11 +08:00
AIGameCreator App 58dad6e96d 补齐Swarm最终回复重试真实门禁
新增Supervisor最终回复瞬时故障、持久退避与Runner强杀真实验收入口
强化故障代理异步选择器、停止竞态和请求隐私回归
修复并行Agent文件写改删的短等待写锁与绝对路径脱敏
补充终态sidecar等待、并发写锁测试和六轮真实Provider证据
同步Runtime方案、实施计划与项目共享记忆文档
2026-07-20 05:50:24 +08:00
AIGameCreator App c321aef489 完善 Agent Runtime 成功交接与终态恢复
新增 Provider 成功响应 handoff,绑定真实 requestId 并支持原子恢复
补齐 compaction 与 finalization v4 的 stream committed 提交事务
让 Runner 在 handoff 存在时保持 busy,并覆盖冲突与崩溃窗口
同步 V1.41 技术方案、实施计划和项目共享记忆
2026-07-20 02:31:11 +08:00
AIGameCreator App 50e33dd469 完善最终回复 Provider 持久重试恢复
将 final-reply 与前置上下文压缩接入持久重试 sidecar
恢复原请求和流式输出,避免重新规划与重复助手消息
补齐 Agent DB requestKind 契约与重启时序回归
同步 V1.40 文档、验证证据和未完成崩溃窗口
2026-07-20 01:00:06 +08:00
AIGameCreator App 160fe3a8b4 完善 Agent Provider 持久重试真实验收
将瞬态故障注入迁移到 Project Supervisor 首次工具规划并验证持久退避恢复
为故障代理补充仅含序号和时间的元数据请求审计与对应测试
强化真实 E2E 对并行委派、重启恢复、重试时序、分账和终局清理的验收
修正瞬态重试目标的 maxRetries 配置门禁并同步 Runtime 文档与项目记忆
2026-07-19 23:24:51 +08:00
AIGameCreator App 21abd45f86 完善Agent Provider持久重试与恢复
新增按Agent和run隔离的Provider重试sidecar与原子恢复扫描
接入首次工具规划和自动上下文压缩的持久等待与到期续跑
补齐Goal暂停恢复、取消、steer、FIFO、finalization和Runner idle门禁
移除请求指纹中的刷新时间并覆盖跨秒恢复与物理请求一致性
补充sidecar、Runner、并行调度回归及V1.39技术文档
2026-07-19 21:18:53 +08:00
AIGameCreator App 0ee8e664fa 完善父 run 协作策略快照与恢复
固化父 run 协作策略快照与独立绑定记录
统一危险 Agent/run ID 的路径键与锁身份
补齐 legacy claim、aborted batch 和非协作 v1 恢复边界
增强真实 E2E 的确认链与 source endpoint 隔离门禁
扩展协作回归至 52 项并同步 V1.38 文档验收状态
2026-07-19 18:52:33 +08:00
AIGameCreator App 29228afb9e 强化隔离智能体分阶段认领门禁
新增 minIsolatedGroupsBeforeClaim 协作策略并保持旧指纹兼容
首次 claim 前校验已建立与 ready group 数且保留既有恢复优先级
补齐只读 scope 边界、全量回归和真实 Provider 验收记录
2026-07-18 17:09:33 +08:00
AIGameCreator App 9bdfad2822 补齐多组隔离智能体真实验收
将混合 Swarm 验收拆分为先行和后续两个 all-join 分组
校验单次 observed claim 汇总两组、跨组写入范围与创建时序
补充分阶段 Supervisor 提示、协作策略回归和真实 Provider 验收记录
2026-07-18 15:37:33 +08:00
AIGameCreator App 27a35c2e2c 保证混合协作回执完整观察
为静态回执和隔离 join 分配独立预算,拒绝静默截断

按精确 delegationId 集合推进 claim 观察并收紧恢复锁边界

补充 V1.36 回归测试与技术决策文档
2026-07-18 13:10:53 +08:00
AIGameCreator App 6299faa81e 原子化隔离 Agent 结果认领
为多 ready all-join 增加持久 claim journal 和全锁预取
补齐旧 partial claim、跨 action 重放与未观察完成门禁
修复 Agent DB 撕裂尾行后的幂等认领审计
保证 readyIsolatedJoins 完整输出并封堵多 owner 冲突
补充锁竞争、迁移恢复和全量回归验证
同步 Runtime V1.35 技术方案与共享决策
2026-07-18 04:59:08 +08:00
AIGameCreator App edfeeff701 封堵隔离子 Agent 命令越界
禁止动态隔离子 Agent 通过项目级命令绕过 writeScopes
在工具策略和 Provider 批次预检中统一执行隔离门禁
补充恶意 sibling 写入、旧 pending 与混合协作回归
同步 Runtime V1.34 技术方案和共享决策
2026-07-18 03:16:36 +08:00
AIGameCreator App 1b045a5f46 收敛 Agent 工具计划格式修复
过滤 Provider 推理内容并受限归一化非最终工具旁白
为原生工具协议增加递归重复键校验和稳定错误分类
补充 repair 统计、失败证据与零泄漏真实验收门禁
同步 Agent Runtime 技术方案和项目决策记录
2026-07-18 02:04:08 +08:00
AIGameCreator App 0ca15a2645 强化项目总控协作合同与崩溃恢复
新增 Supervisor 协作策略控制面和 mixed 首批原子预检。\n升级 Provider action batch v2 并补齐 isolated spawn 幂等恢复与旧协议失败关闭。\n限制委派后总控项目变更、进程 stdin 和破坏性 MCP,同时保留进程治理能力。\n加固委派、隔离 Agent、持久进程和 Provider 日志的持久化与并发边界。\n扩充确定性回归、真实 Provider 验收器、自测和项目文档。
2026-07-17 23:36:43 +08:00
AIGameCreator App c607451edd 补齐总控静态与隔离混合协作验收
新增同一 Supervisor Session/run 下 static delegate 与 isolated all-join 的真实 Provider 门禁。
补齐首批确认、并行重叠、强杀恢复、持久化身份和零泄漏审计。
增加双向完成屏障回归、命令入口及 Runtime/开发文档记录。
修正原生计划元调用与业务 action 数量的验收边界。
2026-07-17 16:37:26 +08:00
AIGameCreator App 4474fb9eab 补齐智能体消息活锁回归与验收记录
新增重复 agent.message 的有界活锁回归并验证持久化幂等
收紧 isolated all-join 与 PTY 测试的异步竞态断言
同步自主 Swarm 真实验收结果、工作流和长期踩坑记录
2026-07-17 12:21:34 +08:00
AIGameCreator App 5263efdfc1 补齐自主Swarm终端验收与恢复门禁
新增Project Supervisor自主终端协作真实E2E与隔离AppData安全检查
为Swarm Chat输出脱敏单行turn report并补齐终端收束断言
强化Supervisor多专业并行委派与语义验收提示
修复静态委派和隔离all-join混合等待及认领恢复
为agent.message增加语义幂等持久化并避免重复消息伪造进展
补充消息幂等、混合恢复和turn report定向回归测试
增加根级与应用级自主验收命令并更新Runtime技术文档
2026-07-17 11:48:07 +08:00
AIGameCreator App 5a0e647662 补齐Swarm瞬态重试真实门禁
新增受控回环故障代理及代理环境绕过保护
扩展Supervisor Swarm真实E2E的重试零副作用与恢复断言
补充代理测试、命令入口和Runtime协作文档
2026-07-17 09:28:41 +08:00
AIGameCreator App 570d346db2 修复本地回环端口池耗尽
让Agent Runner与本地预览复用Linux非临时端口回退
让MCP HTTP测试夹具预留可用端口并有限重试
补充端口池耗尽排障与验证约束
2026-07-17 07:12:08 +08:00
AIGameCreator App 0e1b158579 完成Agent Runtime总控群协作验收
补齐Provider瞬态重试、原生动作批次与持久恢复门禁
完善总控委派合同、返工认领和专业Agent私有消息审计
新增supervisor-swarm真实E2E验收与定向回归
同步Runtime V1.28技术方案、决策记录和排障经验
2026-07-17 07:06:25 +08:00
AIGameCreator App f24e0dcf30 完善Agent多动作批次持久化
新增Provider多动作整批预检、确认聚合和稳定cursor恢复
修复修改后验证门禁、Agent DB落盘顺序和Goal恢复cursor回退
补齐批次恢复、拒绝、并行、故障与最终收束回归测试
同步Runtime V1.28技术方案和项目决策记录
2026-07-16 20:02:29 +08:00
AIGameCreator App 3fd799b723 合并远端 AI 游戏创作分支改动
接入首页组件拆分与草稿状态持久化
保留项目总控 Supervisor 会话和运行时入口
合并 Tailwind 首页样式与 Agent 移动端布局
同步客户端 API、测试及实施计划
2026-07-16 17:42:58 +08:00
AIGameCreator App d575b6887f 合并 master 最新改动
同步 origin/master 至 b303605bf
保留项目总控 Runtime 决策并合入后台账号与画布更新
沿用当前 platform-llm LlmRunRequest 接口解决背景决策冲突
2026-07-16 17:07:13 +08:00
AIGameCreator App 13629c60cb 接入正式项目总控对话入口
登录后项目开发页接入 project-supervisor active Session 与 same-run steer
为全新项目自动创建 Supervisor Session 并隔离 legacy 项目对话写入
展示总控运行状态、确认问答与专业 Agent 只读协作状态
补充桌面窄屏样式、界面回归测试和 V1.28 文档
2026-07-16 16:29:45 +08:00
AIGameCreator App 84328de5ad 强化项目总控合同委派与返工门禁
为 agent.delegate 增加验收合同、预期产物和返工身份
持久化结构化证据并收紧 Supervisor 唯一回复门禁
补齐并发返工、恢复、脱敏和原生协议行为回归
同步 V1.28 实现与真实 Provider 验收状态
2026-07-16 14:47:14 +08:00
k88936 ee0b4b5d8a Game creator extract home view (#80)
抽取homeview方便后续修改

---------

Co-authored-by: kdletters <kdletters@qq.com>
Reviewed-on: https://git.genarrative.world/git/GenarrativeAI/Genarrative/pulls/80
Co-authored-by: kvtodev <kvtodev@outlook.com>
Co-committed-by: kvtodev <kvtodev@outlook.com>
2026-07-16 14:33:57 +08:00
AIGameCreator App e1cb5b699e 补齐单 Agent 持久只读并行批次
实现严格只读动作的持久并行执行与线性化恢复
补齐崩溃窗口、控制漂移和串行屏障回归
新增真实 Provider parallel-read suite 并记录 PASS 证据
同步 Runtime 技术方案、实施计划与项目决策
2026-07-16 12:38:34 +08:00
AIGameCreator App 6ff4556201 修复单 Agent 指令中断恢复轮次
修正 Provider 返回后消费 steer 时的下一轮 context 索引
新增 Runner 强杀恢复的正式 Provider 隔离验收入口与证据门禁
补充同 run steer 回归和 V1.17 PASS 事实源
2026-07-16 11:10:03 +08:00
AIGameCreator App 0b608edd01 加强Goal原生协议真实验收
强制 Goal 成功计划与格式修复全程使用原生工具目录。
为 Goal 阶段等待增加 Runtime 终态快速失败。
补充正式 Provider 复验证据并关闭过期计划状态。
2026-07-16 09:06:13 +08:00
AIGameCreator App 69159b2b39 接入单Agent原生工具目录
为 OpenAI Chat 与 Responses 广告独立 Runtime 和 MCP 函数。
支持持久计划 checkpoint、多动作顺序与严格协议拒绝。
补齐真实 Provider 协议门禁、确定性回归和 Runtime 文档。
2026-07-16 08:15:39 +08:00
AIGameCreator App 9d29631b01 补齐项目Skill渐进加载
发现并校验项目内 Codex 与 Agents Skill 元数据
按需加载命中正文并绑定仓库上下文指纹
补充确定性测试和真实 Provider 隔离验收
同步 Runtime 方案、实施计划与项目决策记录
2026-07-16 07:07:53 +08:00
AIGameCreator App daa5704759 完成仓库指令真实验收
新增scoped-agents正式Provider行为验收套件
使用仅含哈希的双兄弟目录fixture验证根到叶规则
收紧项目变更路径、配置隔离和公共泄漏门禁
记录openai_chat与gpt-5.5真实验收通过证据
2026-07-16 06:28:08 +08:00
AIGameCreator App e99cfa4185 补齐仓库指令作用域
升级仓库启动上下文并按目录作用域加载AGENTS指令
区分仓库指令与不可信参考资料并固定权限安全边界
阻止旧版上下文指纹恢复后直接执行项目写入
补充作用域、请求载荷和迁移阻断回归测试
同步Runtime方案、App实施计划与项目决策记录
2026-07-16 05:59:26 +08:00
AIGameCreator App fa15655a75 完成持久目标真实验收
修复文件写入正文被清洗和末尾换行被截断的问题
收紧运行事件与审计投影并兼容旧脱敏记录恢复
升级真实Goal验收到context v5和Provider lifecycle v2
记录正式gpt-5.5全链路验收证据并同步实施文档
2026-07-16 05:41:14 +08:00
AIGameCreator App e399eaf5de 补齐智能体持久化用户输入流程
新增 user.input_request 状态机与私有 sidecar,支持重启恢复、取消和同一 Run 续跑
接入终端聊天、开发 Agent 聊天、项目 Agent 对话和 Project Supervisor 问题卡
扩展任务队列、能力清单与前后端共享契约
补齐单元测试、界面回归、真实 Runtime E2E 和技术文档
2026-07-16 03:44:31 +08:00
AIGameCreator App 0425afd5cf 实现Runner托管的MCP动态工具
接入STDIO与Streamable HTTP MCP连接、动态工具目录和Runner协议
将mcp.call纳入持久动作、工具审批、私有结果和强杀恢复
增加AppData配置、开发配置界面及聊天CLI的MCP状态入口
补齐真实Provider E2E、全量回归、安全扫描和技术文档
2026-07-16 01:07:58 +08:00
AIGameCreator App 543a5469f8 实现Agent持久上下文压缩
新增全局与单 Agent token 预算、持久摘要 sidecar、自动及手动压缩恢复链路
接入 Runner、CLI /compact、开发 UI 状态和共享能力契约
补齐幂等、漂移、生命周期、恢复、隐私及真实三十轮端到端验收
同步 Runtime 技术方案、App 实施计划和长期决策记录
2026-07-15 22:08:17 +08:00
AIGameCreator App 26decf24da 接入单Agent原生联网检索
新增全局与单Agent联网检索配置、状态和开发界面
将直聊与后台planning接入Provider原生搜索并限制repair与final reply
升级Provider lifecycle v2并兼容历史v1记录
增加隔离真实E2E与公共审计泄漏门禁
记录当前gpt-5.5网关真实检索不可用结论
2026-07-15 18:05:10 +08:00
AIGameCreator App 3f5424a0b1 实现后台Agent真流式回复
接入身份绑定的后台最终回复流并保持唯一finalization提交
完善Project Supervisor与Swarm CLI增量展示、恢复和竞态处理
禁止Runtime Provider重定向重放并加固生命周期与公共审计脱敏
增加真实Provider隔离验收、定向回归和技术文档
2026-07-15 15:58:02 +08:00
AIGameCreator App fda565f40b 加固Goal Provider请求与最终化恢复
绑定Provider请求快照与稳定requestId并禁止歧义错误自动重放
新增Goal真实E2E控制序列、Runner归属清理和失败验证门禁
修复finalization取消竞态、严格七槽容量预留和精确审计恢复
收紧任务委派验证错误等公共审计与敏感信息脱敏
补齐Goal CLI初始化、orphan reconciliation和异常恢复回归
同步Runtime技术方案与长期决策记录
2026-07-15 12:59:28 +08:00
AIGameCreator App b0be078d6c 补齐单Agent持久目标模式
新增Agent会话级Goal的创建编辑暂停恢复清理与CLI/Tauri入口
升级Runtime context v4、pending action v5和finalization v3的Goal绑定
修复恢复半提交、缺失Goal投影及暂停过渡态的失败关闭
补齐开发窗口目标模式、故障注入测试和项目文档
2026-07-15 06:46:48 +08:00
AIGameCreator App 5f317e79f8 补齐项目总控纯聊天入口
新增agc:chat短命令并默认进入project-supervisor
保留agc:swarm显式父Agent调试兼容
补充CLI默认路由与参数回归测试
同步Runtime方案、App计划和长期决策记录
完成真实终端入口启动退出验证
2026-07-15 04:20:29 +08:00
AIGameCreator App f5d2b3786a 完善单Agent持久计划与恢复验收
新增结构化计划更新、单调修订、完成门禁和失败进度保留
升级上下文与最终回复恢复协议并绑定规划仓库指纹
收紧模型正文公共审计和CLI本地存储路径输出
补齐开发界面计划展示、Supervisor紧凑摘要与乱序竞态合并
强化真实Provider验收器并记录TLS外部门禁未通过
补充Rust前端回归及长期技术文档
2026-07-15 04:03:16 +08:00
AIGameCreator App 5ab664b22e 实现项目总控Agent与并行协作闭环
将普通主聊天接入独立project-supervisor Session和持久Runtime
新增静态委派delivery、claim、等待唤醒与唯一最终回复协议
支持同轮多专业Agent并行、回执汇总和同Session多轮对话
修复Session锁序、Agent DB旁路、恢复拒绝和迟到回执竞态
收紧Runner定向唤醒、重启恢复和父任务终态收束语义
更新客户端状态展示、共享契约、定向测试与项目文档
完成真实Provider双Agent并行和多轮聊天验收
2026-07-15 00:21:14 +08:00
AIGameCreator App 21e0877dfa 新增Agent Swarm纯聊天验证入口
新增无GUI终端REPL并接入真实External Runner与持久会话

支持全Agent状态事件、运行中steer、确认拒绝和恢复收束

新增agc:swarm短命令、配置门禁和Rust测试

记录真实Provider验证结果与现存父回执汇总缺口
2026-07-14 19:36:03 +08:00
AIGameCreator App 55463e7b2b 补齐Agent会话分叉能力
新增 Session 分叉命令与开发窗口交互
统一 Session 变更和 Runtime 入队线性化锁
补齐持久化、失败回滚、并发边界与前端隔离测试
同步 Runtime 技术方案和项目决策记录
2026-07-14 18:26:29 +08:00
AIGameCreator App fdbaf1be80 合并 master 到 AI 游戏创作分支
同步共享主题样式与对应测试
同步项目约束与决策记录
2026-07-14 17:50:32 +08:00
AIGameCreator App 840811c56b 合并 master 到 AI 游戏创作分支
同步最新退款复核与发布安全边界改动
同步角色动作素材入库与微信支付退款闭环
保留当前分支单 Agent Runtime V1.13 实现
合并保留双方共享决策与踩坑记录
2026-07-14 17:11:39 +08:00
AIGameCreator App 56f02cc46b 补齐单Agent运行中追加指令
新增同一 Run 持久化追加指令、Provider 中断与安全重规划链路
补齐开发窗口、项目 Agent 面板和 CLI 的 steer 入口与状态交互
升级 Runner 协议并支持旧 Runner 空闲退出后平滑替换
增加真实 Provider steer 验收脚本并修复 finalization 与 Git 提交回归
同步 Runtime 技术方案、实施计划和共享决策记录
2026-07-14 17:08:04 +08:00
AIGameCreator App 1b971ac792 补齐单Agent真实Git提交验收
将 project.git_commit 纳入真实 Provider 完整交付链路
核对原始提交对象、精确 tree、双 reflog、审计与回执
验证提交后保留预存改动并保持副作用零重放
同步 Runtime 技术方案、实施计划与项目决策记录
2026-07-14 15:20:57 +08:00
AIGameCreator App 86bbd046ec 补齐单Agent受控本地Git提交
新增 project.git_commit 强制确认命令并同步前后端共享契约
绑定 git.inspect 安全快照、当前 revision 与 passed verification gate
使用临时 index、原子 update-ref、双 reflog 和跨平台 index 安装创建精确提交
限制动态隔离 child 提交并保护 Git objects、refs、reflog 与控制文件
补齐安全审计、fallback receipt、needs-reconciliation 和执行中恢复不重放
新增故障矩阵测试并同步 Runtime 技术方案、实施计划与项目决策记录
2026-07-14 14:39:56 +08:00
AIGameCreator App 4ef3dbd677 合并主分支最新改动
同步 master 的最新功能与修复
保留 AI 游戏创作客户端分支现有实现

# Conflicts:
#	docs/project-memory/shared-memory/decision-log.md
#	docs/project-memory/shared-memory/pitfalls.md
#	scripts/dev.mjs
#	server-rs/crates/api-server/src/editor_screen_background_decision.rs
#	server-rs/crates/api-server/src/modules/admin.rs
#	src/components/rpg-entry/RpgEntryHomeView.tsx
2026-07-14 13:05:45 +08:00
AIGameCreator App f2b26010bd 完善Agent Runner恢复与真实进程验收
增加Linux临时端口耗尽时的高位loopback安全回退
修复Runner重启恢复的逐投影幂等与完整身份失败关闭
为Runtime JSONL尾部和进程恢复审计增加修复与冲突校验
强化Runner强杀E2E的分层证据与非ENOENT错误处理
阻止模型最终回复复述私有PTY输出及短值
补齐恢复回归测试、真实Provider验收与技术文档
2026-07-14 12:48:45 +08:00
AIGameCreator App 689082901f 为持久进程增加可信启动握手
新增 PTY 外私有 bridge 与 sandbox ready/commit/exec 协议
升级 process record v3 并收紧恢复、幂等与 final/idle 门禁
完善 target 前台进程组、graceful 后代收束和审计失败处理
补齐跨平台回归测试及 Runtime 文档
2026-07-14 09:41:18 +08:00
AIGameCreator App d5cb2f3719 为一次性命令增加可信启动握手
新增 Linux trampoline 私有控制协议和 sandbox-ready/exec-established 状态机
让 command.exec 与 project.verify 在 durable commit 后才启动真实目标
补齐 launch unknown reconciliation、target exec failure 和 revision/gate 审计语义
覆盖 bwrap 分隔符、FD 映射、协议失败和真实命令回归测试
同步 Runtime 技术方案、决策记录和已知陷阱
2026-07-14 07:49:04 +08:00
AIGameCreator App 580e4dd87f 修正持久进程真实验收协议
将 process-session fixture 改为不依赖控制面和 namespace 身份的纯 PTY 协议
使用 durable start、readiness、cursor、stdin 哈希和 cwd 进程归零校验交互链
新增真实 Node 子进程 smoke 覆盖 readiness、精确回显与停止状态
记录 Provider 瞬态失败和可信 exec-ready 两阶段协议
同步长期决策、技术方案与沙箱验收踩坑
2026-07-14 06:35:43 +08:00
AIGameCreator App 143684011b 完善Linux工作区命令沙箱
新增 bubblewrap 工作区写入、控制目录保护和默认断网沙箱
统一 command.exec、command.start 与 project.verify 的启动和审计边界
开放 Linux 通用项目命令并保留非 Linux 固定命令兼容边界
补齐持久进程元数据、真实进程测试、共享契约和发布依赖
同步真实 Provider 结论、已知竞态与项目长期文档
2026-07-14 05:54:02 +08:00
AIGameCreator App a9f7bda805 完善Agent持久进程会话能力
新增Runner托管的PTY持久进程会话与安全输出游标
接入start、poll、stdin、terminate的权限、审计和完成门禁
强化Linux进程组看护、Windows Job回收与崩溃核对语义
补齐Runtime确定性测试和真实Provider双套件验收
同步共享契约、实施方案与长期项目记忆
2026-07-14 03:26:44 +08:00
AIGameCreator App 7f8b5da22a 完善Agent命令回查与收束能力
让 durable command.exec observation 直接返回 sourceActionId,命令分页不再依赖动作历史
持久化 all-join 认领摘要与 reviewer 里程碑,保护最新动作历史观察
放宽无业务依赖的验证顺序并加强真实 Provider E2E 顺序门禁
补齐确定性测试、Runtime 文档和共享决策记录
2026-07-14 01:16:29 +08:00
AIGameCreator App 648170b224 新增命令输出分页回查能力
新增 command.output_read 并按当前 Agent 的持久动作身份分页读取命令输出
为 command.exec 写入受限 transcript sidecar 并保持审计与回执零正文
完善隔离 Agent 模板提示、失败结果收束和重复 spawn 去重
将真实 Provider E2E 改为无固定配方的结果导向验收
同步共享命令与能力契约并补齐 Rust 和 TypeScript 测试
更新 Runtime 技术方案、实施计划和共享决策记录
2026-07-14 00:22:02 +08:00
AIGameCreator App 74dd45ef13 补齐Agent模型视觉检查闭环
新增 image.inspect 安全图片读取、多模态 Provider 调用与只读恢复语义
补齐共享契约、视觉动作回执和多模态失败日志脱敏
扩展确定性测试与真实 Provider 双视口 E2E 验收
同步 Runtime 技术方案和项目共享决策记录
2026-07-13 21:30:13 +08:00
AIGameCreator App 0d643ddbbb 完善Agent持久动作与隔离任务恢复
收紧Agent DB容量、句柄锁、终态回执和动作历史身份校验
补齐pending动作、task、event、observation与receipt崩溃恢复幂等
扩展跨平台路径清洗、仓库上下文门禁和瞬时LLM重试
让隔离父run持久等待并通过parent-wake恢复同一run
修复确认动作阶段投影与最近工具状态推进
扩充Rust安全回归和真实Provider E2E验收
同步Runtime技术方案、实施计划与项目决策记录
2026-07-13 20:09:26 +08:00
AIGameCreator App e714c8c2b6 完善Agent长任务上下文与Git真实验收 2026-07-13 12:13:04 +08:00
AIGameCreator App 5e1d4ddeee 补齐Agent Git工作树审阅与聊天状态交互 2026-07-13 11:21:29 +08:00
AIGameCreator App 5c3b8ec267 完善Agent多文件变更集能力
新增受确认的 project.patchset 事务式多文件修改与回滚机制

补充 checkpoint 内容差异和文件内容哈希约束

加强隔离 Agent 路径范围与仓库指纹复核

扩展共享命令契约、真实 LLM E2E 与 Runtime 文档
2026-07-13 01:08:36 +08:00
AIGameCreator App 49ea9eec67 完善Agent受控命令与推理配置
新增受控 command.exec 固定程序、参数策略、隔离环境和有界审计
接入项目 revision、验证资格、确认动作复核与失败核对门禁
支持全局及每 Agent 独立推理档位并提供发布默认配置
补齐前端配置、共享契约、Runtime 回归和真实 Provider 验收
同步开发流程、技术方案与项目共享决策记录
2026-07-12 23:22:11 +08:00
AIGameCreator App 5e627a4677 完善通用开发 Agent Runtime V1.1
新增仓库上下文指纹复核与 durable action 漂移保护
拆分 App CLI 与独立 Runner 的投递执行边界并补齐恢复诊断
加入桌面和移动端浏览器验证及跨源网络阻断
实现隔离子 Agent 私有记忆与终止状态传播
补齐 Provider 协议确认副作用重放与 join 真实端到端验证
同步共享契约实施计划决策记录与开发流程文档
2026-07-12 20:58:42 +08:00
AIGameCreator App 028e6b872d 实现仓库启动上下文构建
新增有界仓库扫描、规范正文与多语言入口摘要
实现固定 Git 状态降级、SHA-256 指纹和 Prompt 限额渲染
补充嵌套规范、敏感路径、符号链接、预算和 Manifest 单元测试
2026-07-12 16:11:42 +08:00
AIGameCreator App b022bb456a 补齐单Agent删除与聊天恢复闭环
修复事件监听失败后的真实非流式降级与空 choices SSE 兼容
接入受策略保护的 file.delete 并加固确认、revision 和核对门禁
让客户端项目写入统一推进 revision,补齐锁内策略复核
为 manifest 增加跨平台替换与恢复副本
补齐 Runtime、契约和恢复回归测试并同步文档
2026-07-12 14:59:34 +08:00
AIGameCreator App 82fec317a3 完善Agent最终回复崩溃恢复
新增三阶段 finalization journal,恢复时不重放 LLM、工具或回执
为会话消息增加兼容 messageId 与审计幂等自愈
补齐取消、revision 漂移、状态丢失、损坏文件和跨平台替换恢复
增加并发锁短等待、长回复容量与故障注入回归
同步 AI 游戏创作 App 技术方案和项目决策记录
2026-07-12 11:51:22 +08:00
AIGameCreator App de2335dbfe 完善Agent最终回复过期自愈
区分最终完成、过期凭证和致命错误,保持同一运行重新规划
为最终回复绑定项目版本并覆盖只读任务的并发漂移
持久化上下文停滞状态并过滤动态验证输出
补充并发、重启和停滞回归测试及长期文档
2026-07-12 10:35:43 +08:00
AIGameCreator App 7af1297df3 完善Agent项目修改验证门禁
新增项目级 revision 与 per-run 验证凭证持久化
接入修改和验证工具并在最终回复前锁内复核
升级 context bundle 与 pending action v2 恢复语义
补充并发、故障、旧版本恢复测试和技术文档
2026-07-12 09:30:07 +08:00
AIGameCreator App 427820089d 修复Agent聊天流式响应与滚动反馈
兼容OpenAI-compatible SSE中choices为null的元数据帧

固定开发Agent聊天消息区高度并保留内部滚动

补齐流式协议、回退路径、界面约束测试和文档
2026-07-12 08:11:36 +08:00
AIGameCreator App 8493bb39cd 增强单Agent上下文续跑与聊天可靠性
将六轮预算改为可压缩续跑窗口并持久化绑定 run 的上下文包
补齐上下文恢复、凭据清洗、项目验证脚本和跨窗口回归
修复流式尾包兼容、上游错误重复请求和聊天内部滚动等待状态
同步单 Agent Runtime 技术方案和长期决策记录
2026-07-12 05:54:27 +08:00
AIGameCreator App bd647a2aff 修复Agent聊天滚动与等待状态
固定空Runtime场景的消息区和输入区网格行位
让长聊天记录仅在消息面板内部滚动
为等待LLM回复状态补充aria-busy并强化回归测试
同步更新实施方案和决策记录
2026-07-12 04:19:11 +08:00
AIGameCreator App b137b63e3d 完善单Agent默认执行与聊天状态反馈
开发窗口默认使用可执行 Runtime 并保留显式聊天模式
固定消息区内部滚动并持续展示运行状态
终态前先持久化 assistant 回复并自动同步当前 Session
补充会话隔离、落盘顺序和布局回归测试
同步实施方案与项目决策记录
2026-07-12 03:29:10 +08:00
AIGameCreator App 65f2632198 完善单Agent流式聊天与原生工具规划
修复 OpenAI SSE 空 choices、异常尾包和读取中断导致完整回复丢失
固定聊天记录区域并增加持续等待状态与内部滚动
接入原生 function tool 计划协议并补齐严格校验和回归测试
更新 AI 游戏创作技术方案与决策记录
2026-07-12 02:32:22 +08:00
AIGameCreator App 44ac45cd5b 补齐单Agent代码验证闭环
新增受控 project.verify 与 headless agent-task 入口
补强工具计划协议修复、瞬时重试和验证后收束门禁
完善进程清理、写锁恢复、审计关联及覆盖测试
同步共享契约、开发文档和验证脚本
2026-07-12 00:59:05 +08:00
AIGameCreator App ffbc990f5d 修复Agent聊天流式错误与等待反馈
完善OpenAI Chat SSE尾包、错误与结束事件处理
事件监听不可用时降级普通回复并继续持久化
补充等待状态、监听拒绝与协议回归测试
将平台LLM测试纳入客户端完整检查
2026-07-11 23:46:18 +08:00
AIGameCreator App 637b91778e 补齐单Agent代码导航与局部编辑能力
新增项目字面搜索、分段文件读取和精确局部补丁工具

提升后台循环与任务上下文预算并增加空响应重试

支持Chat Completions推理强度配置并补齐回归测试

同步技术方案和项目决策记录
2026-07-11 22:12:07 +08:00
AIGameCreator App 83c2ddb8bb 修复Agent流式回复与等待状态
兼容OpenAI Chat SSE用量尾包并保留异常空响应校验
流式监听或首包前失败时自动降级普通回复
固定聊天消息区高度并启用内部滚动与可靠滚底
在等待LLM期间显示动态连接和接收状态
补充SSE协议与客户端降级回归测试
同步Agent聊天技术方案与项目决策记录
2026-07-11 18:34:10 +08:00
AIGameCreator App 47ad28623a 修正Agent聊天滚动与折叠布局
恢复开发聊天页整页纵向滚动
为Runtime恢复确认区保留独立布局行
修复展开折叠后Runtime与聊天内容重叠
补充确认区结构回归测试并修正文档
2026-07-11 18:00:36 +08:00
AIGameCreator App 50004d579c 优化Agent聊天滚动与状态折叠
固定开发聊天页视口高度并拆分局部滚动区域
为Runtime状态面板增加可折叠详情且保留任务控制
合并流式delta更新并跳过重复Runtime状态提交
补充折叠回归测试与Runtime界面文档
2026-07-11 16:39:02 +08:00
AIGameCreator App 197e1e26c6 补齐Agent Runtime统一错误事件
失败和预算耗尽路径追加error语义事件并保留旧生命周期事件

Runtime状态面板支持展开全部最近事件并展示六类事件

补充前后端回归测试、可视验收截图和技术决策文档
2026-07-11 00:23:40 +08:00
AIGameCreator App b65541ce4c 补齐Agent委派结果回执闭环
持久化父子任务关联并将各类终态结果幂等回执给父Agent

补齐并发锁、取消抑制、恢复补漏和对话落盘失败门禁

展示委派来源并完善Runtime回归测试与技术文档
2026-07-10 23:40:33 +08:00
AIGameCreator App f9e61beb54 完善游戏创作 Agent Runtime 执行闭环
收紧后台规划与回复上下文,项目事实只经权限工具进入 observation
统一前台聊天与后台任务的 Agent 锁并保留多 Agent 并行
补齐独立开发聊天和主工作区的重启恢复确认及跨项目隔离
修正工具预算耗尽、超额动作提示和完成后队列 drain 语义
补充 Runtime、恢复、并发、流式与项目切换回归测试和技术决策文档
2026-07-10 22:00:31 +08:00
AIGameCreator App 7842d5bab3 修复Tauri事件订阅与开发白屏
为客户端与开发窗口补齐只读事件监听 capability
允许 Vite 开发服务器加载仓库共享契约
增加 capability 与共享源码配置门禁
同步更新实施计划和项目决策记录
2026-07-10 19:33:14 +08:00
AIGameCreator App 1ea6671583 完善 Agent 多会话运行时
为开发者 Agent 聊天新增会话创建、切换、归档和历史只读界面
按会话隔离对话、运行状态、任务事件、提示上下文和后台回复
保持单 Agent FIFO 与 OS 锁并让重试恢复沿用原会话
补齐 Tauri 命令、持久化目录、旧会话兼容与回归测试
同步实施方案和项目决策记录
2026-07-10 18:22:01 +08:00
AIGameCreator App aea75ef701 补齐Agent自动工具动作恢复屏障
自动工具动作使用耐久账本记录 approved、executing 与 observed 状态,按崩溃点恢复精确动作或观察
将 needs-reconciliation 提升为 Agent 队列屏障,并在系统锁内按 FIFO 启动 pending 任务
补充自动动作恢复、策略收紧、审计配对、核对队列与并发配置回归测试
同步 Agent Runtime 决策和实施计划,修正项目策略确认文案断言
2026-07-10 15:51:14 +08:00
AIGameCreator App c88c94b98c 支持Agent待确认动作可靠恢复
持久化精确待确认工具动作并绑定run、输入指纹与发生序号

使用OS级Agent锁串行确认、拒绝、取消、恢复与队列续跑

增加取消中状态、开发确认拒绝控件和私有Runtime文件边界

补齐并发恢复、重启核对、取消失败与前端交互回归测试

同步Agent Runtime技术方案与项目决策记录
2026-07-10 12:24:54 +08:00
AIGameCreator App a5c85c912b 绑定Agent工具确认到精确动作
Runtime 为工具输入生成 SHA-256 指纹和安全摘要

确认票据仅放行同一 Agent、run、command 和输入

开发窗口接通待确认动作的确认继续入口

补充动作变更阻断和界面确认回归测试

同步 Runtime V1 技术方案和项目记忆
2026-07-10 09:01:32 +08:00
AIGameCreator App d150f77301 允许Agent恢复项目快照
后台 Runtime 工具箱新增 project.restore

Agent 可按权限策略请求恢复到指定 checkpoint

补充恢复成功和确认阻断测试

同步 Runtime V1 文档和项目记忆
2026-07-10 08:33:05 +08:00
AIGameCreator App bdf3ae87da 允许Agent创建项目快照
后台 Runtime 工具箱新增 project.checkpoint

Agent 可在写入前按权限策略创建本地 checkpoint

补充 checkpoint 成功和确认阻断测试

同步 Runtime V1 文档和项目记忆
2026-07-10 07:29:06 +08:00
AIGameCreator App 739e89ea38 允许Agent调度Ready任务
后台 Runtime 工具箱新增 agent.schedule_ready

Agent 可按权限策略把 manifest ready task 投递到对应队列

补充自动调度和确认阻断的 Rust 测试

同步 Runtime V1 文档和项目记忆
2026-07-10 07:15:27 +08:00
AIGameCreator App 436d67ae24 补齐Ready任务调度入口
开发模式 Agent 状态栏新增调度 Ready 控制

调度前复用项目权限确认并合并返回 Runtime 状态

补充前端测试覆盖开发入口和普通用户隐藏

更新 Runtime V1 文档并移除已调用命令白名单例外
2026-07-10 07:06:58 +08:00
AIGameCreator App 2c5635a35a 支持调度Ready任务给Agent
新增 agent.schedule_ready 命令,将 manifest ready task 投递到对应 Agent 后台队列。

为调度入口接入默认确认权限、Tauri handler 和 native-only 门禁。

补充 Runtime 测试覆盖 ready 任务调度和默认策略拦截。

同步 Agent Runtime 技术方案和项目决策记录。
2026-07-10 06:58:46 +08:00
AIGameCreator App 1ccda076dc 允许Agent创建项目任务
新增 task.create 工具,让后台 Agent 可把拆解结果追加到 manifest 任务图。

接入 task.create 权限策略、工具 prompt、审计记录和共享命令契约。

补充后台 Runtime 测试覆盖任务创建成功路径和确认策略拦截。

同步 Agent Runtime 技术方案和项目决策记录。
2026-07-10 06:45:02 +08:00
AIGameCreator App 8c9693a907 支持Agent工具确认后继续
新增一次性工具确认票据并在Runtime权限gate中按run消费。

提供确认待确认后台任务的Tauri命令和开发面板按钮。

确认后把原waiting run标记为confirmed并投递新run继续执行。

补充确认续跑测试并同步Agent Runtime文档。
2026-07-10 06:26:29 +08:00
AIGameCreator App b30ca890bb 串行化Agent本地JSONL追加
新增按目标文件路径串行的本地追加写入helper。

让agent.db、对话、Runtime事件任务和Agent运行日志统一写完整JSON行。

补充并发追加测试覆盖JSONL逐行可解析。

同步Agent Runtime技术方案和决策记录。
2026-07-10 06:16:17 +08:00
AIGameCreator App 1a764af20c 收紧Agent私有记忆边界
禁止Agent通过memory.write写入其他Agent私有记忆。

跨Agent共享改由blackboard.write或agent.message承接。

补充后台Runtime测试覆盖跨Agent私有记忆阻断。

同步Agent Runtime技术方案和决策记录。
2026-07-10 06:09:15 +08:00
AIGameCreator App 0aa34cad79 保证Agent后台任务Run唯一
后台任务入队时检测同一Agent历史runId并自动生成去重后缀。

agent.delegate审计和观察结果使用实际委派runId。

补充重复runId队列测试,确认两个任务不会被快照折叠。

同步Agent Runtime技术方案和决策记录。
2026-07-10 05:57:05 +08:00
AIGameCreator App ecd57918fc 补齐Agent后台任务取消重试
新增Agent Runtime后台任务按runId取消和重试命令。

取消任务写入cancelled状态、事件流和审计记录,并阻止被取消任务继续落回复。

前端Runtime状态面板展示取消和重试操作及cancelled队列计数。

补充Rust生命周期测试、前端断言和技术文档。
2026-07-10 05:48:54 +08:00
AIGameCreator App 912234e6de 保留Agent工具确认等待态
后台Runtime命中工具确认策略时停在waiting-for-confirmation。

任务队列和前端状态面板展示等待确认计数。

补充Rust和前端测试覆盖工具确认等待态。

同步AI游戏创作App技术方案和决策记录。
2026-07-10 05:27:19 +08:00
AIGameCreator App d09febc7cd 支持Agent独立工具策略
扩展项目权限策略,按Agent保存独立拒绝和确认命令。

后台Runtime按项目级与Agent级策略叠加生成工具快照并拦截执行。

主聊天新增agent-policy命令并保留既有策略确认流程。

补充前端和Rust测试覆盖独立Agent策略读写与执行拦截。

同步AI游戏创作App技术方案和项目决策记录。
2026-07-10 05:04:56 +08:00
AIGameCreator App 5058b42ca9 实时同步Agent后台状态
新增 Agent Runtime Tauri 实时更新事件

前端开发窗口和主窗口监听并合并 Runtime 状态

补充后台任务实时更新测试和 Runtime 文档
2026-07-10 04:46:58 +08:00
AIGameCreator App 0f9cfb0451 恢复Agent后台任务队列
- 新增 Agent Runtime 恢复命令,按 agent.resume 自动策略重接任务

- 恢复时优先处理遗留 running,再串行 drain pending

- 补充前端 runtime refresh 和 Rust/React 回归测试

- 更新 AI 游戏创作 App 实施计划与决策记录
2026-07-10 04:28:18 +08:00
AIGameCreator App b98f34a727 补齐Agent结构化计划进度
新增 Agent Runtime 结构化计划步骤与当前步骤索引。

在工具、观察、回复和失败生命周期中更新计划步骤状态。

在开发面板、主窗口状态卡和聊天摘要展示当前计划步骤。

补充后台 loop 成功与最终回复失败的计划步骤测试。

同步 AI 游戏创作 App 实施计划和项目决策记录。
2026-07-10 04:07:06 +08:00
AIGameCreator App 20c760bf45 展示Agent循环轮次进度
新增 Agent Runtime loopIteration、maxLoopIterations 和 toolActionBudget 观测字段

在 Runtime 面板、主 Agent 卡片、agent.run_status 和连续上下文展示 loop 进度

补充前端状态展示测试、Rust JSON 与 prompt 上下文断言

同步 AI 游戏创作 App 技术方案和项目决策记录
2026-07-10 03:45:32 +08:00
AIGameCreator App f72deb9477 补齐Agent任务队列观测
新增 Agent Runtime taskQueue 汇总 pending/running/completed/failed 队列状态

在 Runtime 面板、主 Agent 卡片、agent.run_status 和下一轮 prompt 展示队列摘要

补充最近动作与任务队列前端测试、Rust JSON 与连续上下文测试

同步 AI 游戏创作 App 技术方案和项目决策记录
2026-07-10 03:36:46 +08:00
AIGameCreator App 4e19f68bf8 展示Agent Runtime事件流
Runtime 状态面板接入 recentEvents,展示 thinking/action/observation 等事件。

流式 Agent 状态归一化保留最近事件和任务,避免 payload 覆盖历史可见性。

补充事件流 UI 测试,同步 Runtime V1 文档。
2026-07-10 03:21:41 +08:00
AIGameCreator App 113d80f305 补齐Agent Runtime目标等待状态
Agent Runtime state 新增 currentGoal 和 waitingOn,写入后台任务生命周期。

状态面板、Agent 状态卡和 agent.run_status 展示当前目标与等待对象。

补充 Runtime 状态测试和 wire JSON 断言,同步 Runtime V1 文档。
2026-07-10 03:11:05 +08:00
AIGameCreator App 0326cc819c 补齐Agent Runtime任务委派工具
后台 Agent 工具箱新增 agent.delegate,可把任务投递到目标 Agent 独立队列。

agent.delegate 复用项目权限策略,确认策略下不启动目标 Agent。

补充委派协作测试,同步 Runtime V1 文档和命令契约。
2026-07-10 02:51:30 +08:00
AIGameCreator App 7571654274 补齐Agent Runtime状态观察工具
后台 Agent 工具箱新增 agent.run_status,可读取自己或目标 Agent 的 Runtime 状态摘要。

agent.run_status 复用项目权限策略,策略确认时不读取或泄露状态细节。

补充同伴状态观察测试,同步 Runtime V1 文档。
2026-07-10 02:34:05 +08:00
AIGameCreator App d0dfced8ed 补齐Agent Runtime项目差异工具
后台 Agent 工具箱新增 project.diff,可按 checkpoint 查看本地项目差异。

project.diff 复用项目权限策略,策略确认时不泄露差异细节。

补充 Runtime 差异工具测试,同步 Runtime V1 文档。
2026-07-10 02:25:32 +08:00
AIGameCreator App e91b7f3294 补齐Agent Runtime文件列表工具
后台 Agent 工具箱新增 file.list,可按相对路径列出项目文件摘要。

file.list 复用项目权限策略,策略确认时不枚举文件。

补充 Runtime 文件列表工具测试,同步 Runtime V1 文档。
2026-07-10 02:15:03 +08:00
AIGameCreator App 48cdf33c2c 补齐Agent Runtime连续上下文
后台 Agent 规划上下文加入本 Agent 最近状态、任务和工具动作。

新后台 run 继承同 Agent 最近回复和工具动作,避免多轮任务断档。

补充同 Agent 连续性与跨 Agent 隔离测试,同步 Runtime V1 文档。
2026-07-10 02:05:01 +08:00
AIGameCreator App eee974fb9e 补齐Agent Runtime工具策略快照
Runtime state 新增 toolPolicy,派生工具级 auto、confirm 和 deny 策略。

后台规划 prompt 注入当前工具策略,Agent 可在决策前感知权限边界。

状态面板展示工具策略摘要,补充策略映射和 prompt 注入测试。
2026-07-10 01:52:41 +08:00
AIGameCreator App 28116b054f 补齐Agent Runtime最近动作状态
Runtime state 新增 recentToolCalls,记录最近工具动作、状态、原因和观察摘要。

Agent 状态面板展示最近动作,减少从 observation 文本推断执行过程。

补充后台工具 loop 结构化动作记录测试,同步 Runtime V1 文档。
2026-07-10 01:44:46 +08:00
AIGameCreator App d38bd34c47 补齐Agent Runtime任务图读取工具
后台 Agent 工具箱新增 task.list,可读取 manifest 任务图和 readyTaskIds。

任务图读取复用 task.list 权限策略,并在策略拦截时不暴露任务细节。

补充任务图读取成功与策略拦截测试,同步 Runtime V1 文档。
2026-07-10 01:39:03 +08:00
AIGameCreator App ac4448a2ef 补齐Agent Runtime任务状态工具
后台 Agent 工具箱新增 task.update,可由 Agent 更新 manifest 任务状态。

任务状态更新复用 task.update 权限策略、项目写锁和 manifest 任务真相源。

补充任务状态更新成功与策略拦截测试,同步 Runtime V1 文档。
2026-07-10 01:32:00 +08:00
AIGameCreator App 31ec13c52c 补齐Agent Runtime素材生成工具
后台 Agent 工具箱新增 canvas.asset_generate,可由 Agent 自主生成首版美术素材。

素材生成复用 External Editor API、项目权限策略、项目写锁和本地 manifest 资产登记。

补充生成成功与策略拦截测试,同步 Runtime V1 文档。
2026-07-10 01:20:11 +08:00
AIGameCreator App 4a9a2e692f 补齐Agent Runtime预览启动工具
后台 Agent 工具箱新增 preview.start,可由 Agent 自主启动本地预览。

预览启动复用共享 PreviewRegistry、权限策略、项目写锁、manifest、preview log 和 trace。

补充预览启动成功与策略拦截测试,并同步 Runtime V1 文档。
2026-07-10 01:08:49 +08:00
AIGameCreator App 67c9958bac 补齐Agent Runtime受限自检工具
后台 Agent 工具箱新增 command.run_limited,仅允许 game.static_smoke。

受限自检复用 command.run_limited 权限策略、本地项目锁和静态自检安全边界。

补充自检成功与策略拦截测试,同步 Runtime V1 文档。
2026-07-10 01:01:05 +08:00
AIGameCreator App d24fd7071d 补齐Agent Runtime写入工具
后台 Agent 工具箱新增 memory.write 和 file.write。

写入工具复用项目权限策略、本地项目锁和路径保护,并写入 agent.db 审计。

补充写入成功与策略拦截测试,同步 Runtime V1 文档。
2026-07-10 00:46:27 +08:00
AIGameCreator App 59219a97d6 补齐Agent Runtime多轮观察循环
后台 Agent 任务改为最多三轮 plan/action/observation/replan 循环。

Runtime state 新增 nextStep,并在状态面板和主 Agent 卡片展示下一步。

补充多轮重规划测试、前端状态展示断言,并同步实施计划和决策记录。
2026-07-10 00:38:39 +08:00
AIGameCreator App abb174965b 补齐Agent Runtime协作工具
Agent 后台任务工具箱新增项目黑板写入和 Agent 定向留言。

协作写工具复用 memory.write 和 conversation.write 项目策略。

补充 Runtime 写入成功与策略拦截测试,更新实施计划和决策记录。
2026-07-10 00:23:37 +08:00
AIGameCreator App e38ad19efa 补齐Agent运行态状态列表
主窗口 Agent 状态列表批量读取并展示 Runtime 状态和最近任务。

单 Agent 对话与 Runtime 使用任务 ID 作为规范 Agent ID。

兼容旧 group-role Agent 别名并映射到规范任务 ID。

补充 Rust 与前端测试,更新 Runtime 文档和共享决策记录。
2026-07-10 00:07:46 +08:00
AIGameCreator App 7a6fda2513 补齐Agent后台任务排队执行
同一 Agent 后台任务忙时改为写入 pending 队列。

后台 drain 持有 Agent 锁并串行执行 pending 任务。

开发窗口提示后台任务已加入队列并展示 pending 状态。

补充 Rust 与前端测试,更新 Runtime 文档和共享决策记录。
2026-07-09 23:38:19 +08:00
AIGameCreator App 7c17ce6811 补齐Agent任务历史可视化
Agent Runtime 增加每个 Agent 的任务历史 JSONL 和最近任务读取。

任务记录状态改为 running、completed、failed 的任务视角。

开发窗口和项目 Agent 弹窗的 Runtime 面板展示最近任务。

补充 Rust 与前端测试,并更新实施计划和共享决策记录。
2026-07-09 23:22:06 +08:00
AIGameCreator App 8c077d8eb8 补齐Agent计划工具观察循环
后台Agent任务增加计划、工具动作、观察和最终回复循环。

只读工具调用接入项目权限策略和runtime事件。

前端测试覆盖工具动作状态展示并修正Agent卡片点击定位。

更新AI游戏创作App实施计划和共享决策记录。
2026-07-09 23:09:29 +08:00
AIGameCreator App 83901d5e78 补齐Agent后台并行任务
新增单Agent后台任务命令,按Agent独立runtime锁并行运行。

开发单聊和项目Agent对话弹窗增加后台运行入口。

后台任务结果写回Agent对话、runtime事件和agent.db审计记录。

补充并行后台任务测试和实施计划决策文档。
2026-07-09 22:53:08 +08:00
AIGameCreator App 2a64aa8fe3 补齐Agent Runtime状态观测
新增每个 Agent 的 runtime state 和 event JSONL 持久化

单 Agent 聊天和角色 brief 生成写入 task、session、run 状态

开发聊天页和项目 Agent 对话展示 runtime 状态与读取失败

排除 runtime 目录对 checkpoint、index 和 restore 的干扰

补充 Runtime V1 文档和回归测试
2026-07-09 22:36:18 +08:00
AIGameCreator App 3200e3b48c 支持Agent聊天流式状态
单 Agent 聊天新增 Tauri 流式事件并按 runId 过滤增量

开发窗口和项目 Agent 对话发送时显示保存、连接、接收和落盘状态

流式草稿先在界面增量显示,完成后再保存 assistant 消息

补充前端流式状态回归和 Rust SSE 回调测试
2026-07-09 16:09:59 +08:00
AIGameCreator App a2bbeb79ee 补齐Agent聊天失败回执
Agent 聊天在用户消息已保存后将回复失败原因落盘为 assistant 消息

新增 --agent-chat 开发诊断入口验证单 Agent LLM 调用链

补充开发 Agent 聊天失败回执和 CLI 解析测试
2026-07-09 15:41:12 +08:00
AIGameCreator App 57cb1fa391 提示Agent聊天LLM配置缺口
开发 Agent 聊天入口主动检查并展示当前 Agent LLM 配置状态

单 Agent 对话在 LLM 未就绪时显示配置提示并阻止发送

补充开发入口和项目对话入口的 LLM 缺口回归测试
2026-07-09 15:00:35 +08:00
AIGameCreator App 9bcd6d928c 修正Agent聊天验证口径
前端测试不再用回显用户输入冒充真实回复

Rust LLM provider 测试断言回复不是用户原文
2026-07-09 01:14:44 +08:00
AIGameCreator App 46fbcdf78a 修复Agent对话真实回复可见性
主窗口单 Agent 对话改为调用真实 Agent 回复

开发聊天入口在回复失败时把错误显示到对话区

更新单 Agent 对话回归测试
2026-07-08 22:58:49 +08:00
AIGameCreator App c0ff9edf97 支持单Agent真实对话与并行执行
新增单 Agent 真实 LLM 对话命令并按 agentLlm.<agentId> 路由

开发聊天窗口切换 Agent 时自动读取历史并持久化真实回复

Agent loop 按 dependencyWaves 并行执行同一 wave 内角色 brief

补充并行执行、单 Agent 对话和界面回归测试

更新 AI 游戏创作 App 技术方案文档
2026-07-08 20:54:05 +08:00
AIGameCreator App 788c085684 补齐侧栏菜单失焦关闭
我的和帮助菜单点击外部或焦点离开后自动收起

保留菜单内部点击交互不被提前关闭

补充侧栏菜单关闭行为测试
2026-07-08 20:31:22 +08:00
AIGameCreator App 1c88b924d5 清理首页菜单与泥点弹层细节
移除泥点弹层账户读取状态文案

使用详情改为统一占位通知

修复帮助按钮展开态灰色背景

补充泥点弹层交互断言
2026-07-08 20:26:19 +08:00
AIGameCreator App 06e79ab2bc 修复首页账户帮助菜单交互
统一我的和帮助菜单为点击触发

菜单项接入占位通知弹窗并提升弹层层级

调整泥点与升级入口为分段胶囊样式

补充首页菜单交互边界测试
2026-07-08 20:15:07 +08:00
AIGameCreator App d8dc11592c 添加开发专用Agent聊天窗口
新增debug专用developer窗口并路由到agent-chat入口

实现单Agent选择、历史读取和对话持久化

收紧发布入口不暴露开发聊天并补充测试

同步更新AI游戏创作App开发窗口文档口径
2026-07-08 17:52:09 +08:00
AIGameCreator App d251525f77 重做GameAgent单窗口首页
登录后直接进入单窗口客户端首页并保留兼容命令

首页支持做游戏做素材做方案切换、附件队列和目录创建流程

项目组和项目开发占位改为同窗口切换并保存首条需求

顶部泥点充值合并展示,账户帮助配置回到底部侧栏

补充账户泥点精选素材读取与首页项目视觉测试

同步AI游戏创作实施文档、决策记录和上下文术语
2026-07-08 17:35:45 +08:00
AIGameCreator App 6cb0b5d6a7 修复客户端认证异常处理
登录态探活遇到服务不可达时保留本地 access token。

退出登录重试时 refresh 失败仍继续调用服务端 logout。

补充客户端认证异常处理回归测试。
2026-07-08 14:24:06 +08:00
AIGameCreator App 67a6cbb8d5 合并 master 分支
合并 origin/master 到 AI 游戏创作客户端功能分支。

解决画布文档、决策记录和本地工具配置冲突。

适配背景色决策与编辑器 Agent 测试到现行 LLM API。
2026-07-08 11:51:30 +08:00
AIGameCreator App b1cbda97b0 收起首页项目操作
首页最近项目卡片改为只读展示。

刷新、清空、显示和移除操作保留在项目页。

更新启动器项目操作回归测试。
2026-07-08 11:21:56 +08:00
AIGameCreator App 18b834af36 收起空公告栏占位
无公告时启动器主区域不再启用公告布局。

调整账户条和首页输入区域的无公告顶部间距。

补充启动器无公告布局回归测试。
2026-07-08 11:02:32 +08:00
AIGameCreator App 7afc0da5c4 补齐客户端验证码登录
新增独立客户端手机号验证码发送和登录流程。

登录请求在网络层失败时展示登录服务不可达提示。

补充验证码登录、Load failed 文案和登录页基线测试。

同步 AI 游戏创作 App 登录口径文档。
2026-07-08 10:39:40 +08:00
AIGameCreator App ada9bc9553 隐藏空通知条
启动器通知列表为空时不渲染顶部通知条

移除登录页顶部通知占位背景

补充默认无通知条的启动器测试
2026-07-08 10:26:48 +08:00
AIGameCreator App f9d8142068 接入客户端登录和配套后端启动
启动客户端时先检查平台登录态,未登录展示登录页,登录后进入启动器首页

独立客户端登录使用平台 auth 接口并对 refresh 做并发去重

Tauri 开发启动改为短命令 agc:serve,并先拉起配套 SpacetimeDB 与 api-server

AGC Vite 代理读取 dev-stack 状态并暴露本地 marker,复用时校验 API target

恢复启动器项目目录输入、最近项目刷新移除和非空文件夹提醒交互

补充启动器和登录 gate 测试,并更新 AI 游戏创作 App 开发文档
2026-07-08 02:25:31 +08:00
AIGameCreator App 3b3d9dcf8e 替换客户端首页左侧导航
按 GameAgent 需求落地首页、项目、帮助三类左侧入口

项目页复用本地最近工作区记录并提供打开和显示目录操作

帮助入口改为浮层菜单并接入使用指南、联系我们、最新动态页面

为独立客户端声明 lucide-react 图标依赖
2026-07-07 22:37:03 +08:00
AIGameCreator App 40213b839c 重做客户端静态首页
按参考图替换启动器首页为纯静态展示

补齐左侧导航、顶部优惠条、主输入区和最近项目卡片

调整响应式布局并保留配置弹窗入口
2026-07-07 22:18:20 +08:00
AIGameCreator App 21938815f1 改造主聊天为正常Agent交互
普通聊天改为调用主聊天 Agent 并读取项目上下文
新增 /generate 和 /draft 显式生成入口
补齐主聊天 agentLlm.chat 路由、测试和文档记忆
2026-07-06 21:05:36 +08:00
AIGameCreator App d2ddb932b3 合并 master 更新到 AI 游戏创作分支
合入 master 的画布 Agent、精选素材审核、外部编辑器 API 与认证投影更新
保留当前分支的 AI 游戏创作壳、配置项和 LLM 运行接口改造
解决图片编辑器、LLM、去背景完成、外部生成排序和文档冲突
沿用 master 的 SpacetimeDB auth_store_projection 迁移与生成绑定
2026-07-06 11:47:19 +08:00
AIGameCreator App 7afec12958 拆分游戏创作壳 Tauri 入口
拆出 CLI、命令、配置、Agent、素材、项目、预览和窗口模块
拆出 Rust 单测并保留 main.rs 作为 Tauri 薄入口
扩展壳配置与原生壳门禁的 Rust 源码扫描范围
同步 AI 游戏创作 App 技术方案和决策记录
2026-07-04 16:25:45 +08:00
AIGameCreator App 3340b307d6 补充项目进度聊天入口
新增 /progress 项目进度摘要

补充 /next 与 /help 的进度入口覆盖

验证 /progress 不触发文件读取、运行、预览、导出或写入

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-04 15:01:38 +08:00
AIGameCreator App 5649316217 补充普通用户操作导引入口
新增 /guide 纯聊天操作导引

补充 /next 与 /help 的导引入口覆盖

验证 /guide 不触发文件读取、运行、预览、导出或写入

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-04 14:48:10 +08:00
AIGameCreator App 7fc7f930c6 补充下一轮分工计划聊天入口
新增 /plan 下一轮分工计划摘要

补充 /next 与 /help 的计划入口覆盖

验证 /plan 不触发文件读取、运行、预览、导出或写入

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-04 14:36:13 +08:00
AIGameCreator App d6571d3ccd 补充验证证据台账聊天入口
新增 /evidence 当前验证证据台账摘要

补充 /next 与 /help 的证据入口覆盖

验证 /evidence 不触发文件读取、运行、预览、导出或写入

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-04 14:25:34 +08:00
AIGameCreator App 7f210c5028 补充 Agent LLM 路由清单
新增 /llm-routes 只读聊天入口

展示全局默认路由、单独 agent 路由和配置缺口

补充 /help 与 /next 的路由清单覆盖

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-04 14:16:24 +08:00
AIGameCreator App 608764d974 补充复玩观察聊天入口
新增 /retention 首轮复玩和留存观察摘要

补充 /next 与 /help 的复玩观察入口覆盖

验证 /retention 不触发文件读取、运行、预览、导出或写入

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-04 14:05:08 +08:00
AIGameCreator App 14e92e477f 补充本地化文案聊天入口
新增 /localization 本地化与文案检查摘要

补充 /next 与 /help 的本地化入口覆盖

验证 /localization 不触发文件读取、运行、预览、导出或写入

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-04 13:55:52 +08:00
AIGameCreator App 6d2e1ffb3a 补充兼容性说明聊天入口
新增 /compatibility 兼容性说明摘要

补充 /next 与 /help 的兼容性入口覆盖

验证 /compatibility 不触发文件读取、运行、预览或导出

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-04 13:47:53 +08:00
AIGameCreator App 345591e3c6 补充已知问题聊天入口
新增 /known-issues 已知问题清单摘要

补充 /next 与 /help 的已知问题入口覆盖

验证 /known-issues 不触发文件读取、运行、预览、导出或 agent 控制

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-04 13:32:33 +08:00
AIGameCreator App f6ad06eb1a 补充封面缩略图聊天入口
新增 /cover 封面与缩略图检查摘要

补充 /next 与 /help 的封面入口覆盖

验证 /cover 不触发文件读取、运行、预览、导出或 agent 控制

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-04 13:25:36 +08:00
AIGameCreator App 2d526b4ea1 补充试玩更新说明聊天入口
新增 /release-notes 试玩更新说明摘要

补充 /next 与 /help 的更新说明入口覆盖

验证 /release-notes 不触发文件读取、运行、预览、导出或 agent 控制

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-04 13:17:41 +08:00
AIGameCreator App 18b40149cd 补充媒体资料包聊天入口
新增 /media-kit 媒体资料包摘要

补充 /next 与 /help 的媒体资料包入口覆盖

验证 /media-kit 不触发文件读取、运行、预览、导出或 agent 控制

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-04 13:10:54 +08:00
AIGameCreator App 65893fba53 补充社区发布聊天入口
新增 /post 社区发布文案摘要

补充 /next 与 /help 的社区发布入口覆盖

验证 /post 不触发文件读取、运行、预览、导出或 agent 控制

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-04 13:01:13 +08:00
AIGameCreator App 74bd134b55 补充试玩问答聊天入口
新增 /faq 试玩常见问答摘要

补充 /next 与 /help 的 FAQ 入口覆盖

验证 /faq 不触发文件读取、运行、预览、导出或 agent 控制

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-04 12:55:31 +08:00
AIGameCreator App 3c55ba3694 补充试玩短视频聊天入口
新增 /trailer 试玩短视频脚本摘要

补充 /next 与 /help 的短视频入口覆盖

验证 /trailer 不触发文件读取、运行、预览、导出或 agent 控制

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-04 12:49:52 +08:00
AIGameCreator App 6c3615f5d9 补充上架资料聊天入口
新增 /store 上架资料清单摘要

补充 /next 与 /help 的上架资料入口覆盖

验证 /store 不触发文件读取、运行、预览、导出或 agent 控制

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-04 12:44:28 +08:00
AIGameCreator App fd86fd98ee 补充宣传截图聊天入口
新增 /screenshots 宣传截图清单摘要

补充 /next 与 /help 的宣传截图入口覆盖

验证 /screenshots 不触发文件读取、运行、预览、导出或 agent 控制

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-04 12:37:23 +08:00
AIGameCreator App 1a873ee88f 补充试玩问卷聊天入口
新增 /survey 试玩问卷问题摘要

补充 /next 与 /help 的试玩问卷入口覆盖

验证 /survey 不触发文件读取、运行、预览、导出或 agent 控制

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-04 12:31:01 +08:00
AIGameCreator App a8a233095e 补充缺陷复现聊天入口
新增 /bug-report 缺陷复现记录摘要

补充 /next 与 /help 的缺陷记录入口覆盖

验证 /bug-report 不触发文件读取、运行、预览、导出或 agent 控制

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-04 12:24:09 +08:00
AIGameCreator App c4462d68ab 补充试玩邀请聊天入口
新增 /invite 试玩邀请文案摘要

补充 /next 与 /help 的试玩邀请入口覆盖

验证 /invite 不触发文件读取、运行、预览、导出或 agent 控制

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-04 12:19:27 +08:00
AIGameCreator App f07b9b4343 补充首批试玩对象聊天入口
新增 /audience 首批试玩对象摘要

补充 /next 与 /help 的试玩对象入口覆盖

验证 /audience 不触发文件读取、运行、预览、导出或 agent 控制

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-04 12:10:04 +08:00
AIGameCreator App 94344098a9 补充隐私导出边界入口
新增 /privacy 隐私与导出边界摘要

补充 /next 与 /help 的隐私入口覆盖

验证 /privacy 不触发文件读取、预览、导出或 agent 控制

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-04 11:57:45 +08:00
AIGameCreator App 48f6a8af3d 补充改版说明草稿入口
新增 /revise 下一轮改版说明草稿

补充 /next 与 /help 的改版入口覆盖

验证 /revise 不触发文件读取、运行、预览、导出或 agent 控制

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-04 11:51:45 +08:00
AIGameCreator App 34f2ab7b3b 补充任务依赖链聊天入口
新增 /deps 任务依赖链摘要

补充 /next 与 /help 的依赖入口覆盖

验证 /deps 不触发文件读取、运行、预览、导出或 agent 控制

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-04 11:44:18 +08:00
AIGameCreator App 0e8b6b98e9 补充试玩就绪度聊天入口
新增 /ready 试玩就绪度摘要

补充 /next 与 /help 的就绪度入口覆盖

验证 /ready 不触发文件读取、运行、预览、导出或 agent 控制

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-04 11:38:13 +08:00
AIGameCreator App 5021f3fa5f 补充当前阻塞项聊天入口
新增 /blockers 当前阻塞项摘要

补充 /next 与 /help 的阻塞入口覆盖

验证 /blockers 不触发文件读取、运行、预览、导出或 agent 控制

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-04 11:31:45 +08:00
AIGameCreator App 29110a3907 补充试玩前打磨聊天入口
新增 /polish 试玩前打磨清单摘要

补充 /next 与 /help 的打磨入口覆盖

验证 /polish 不触发文件读取、运行、预览、导出或 agent 控制

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-04 11:19:37 +08:00
AIGameCreator App 3a96f0c7ae 补充创作规格包聊天入口
新增 /spec 创作规格包摘要

补充 /next 与 /help 的规格入口覆盖

验证 /spec 不触发文件读取、运行、预览或导出命令

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-04 11:08:46 +08:00
AIGameCreator App 160598d8f9 补充下一轮小步清单聊天入口
新增 /todo 下一轮小步清单摘要

补充 /next 与 /help 的小步清单入口覆盖

验证 /todo 不触发文件读取、运行、预览或导出命令
2026-07-04 10:52:07 +08:00
AIGameCreator App acd6715589 补充试玩讲解稿聊天入口
新增 /demo 30 秒试玩讲解稿摘要

补充 /next 与 /help 的讲解稿入口覆盖

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-04 10:44:05 +08:00
AIGameCreator App 6555984d73 补充手动测试计划聊天入口
新增 /test-plan 手动测试计划摘要

补充 /next 与 /help 的测试计划入口覆盖

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-04 10:36:35 +08:00
AIGameCreator App f2789a9b20 补充性能加载聊天入口
新增 /performance 性能与加载检查摘要

补充 /next 与 /help 的性能入口覆盖

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-04 10:26:56 +08:00
AIGameCreator App 4d9e054200 补充无障碍聊天入口
新增 /accessibility 可读性与无障碍检查摘要

补充 /next 与 /help 的入口覆盖

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-04 10:18:03 +08:00
AIGameCreator App 92adeb77fa 补充素材署名聊天入口
新增 /credits 素材署名与来源摘要

补充 /next 与 /help 的署名入口覆盖

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-03 19:08:20 +08:00
AIGameCreator App 5b5624021a 补充移动试玩聊天入口
新增 /mobile 移动试玩检查摘要

补充 /next 与 /help 的移动入口覆盖

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-03 18:59:54 +08:00
AIGameCreator App ddd6b70f52 补充新手引导聊天入口
新增 /tutorial 新手引导检查摘要

补充 /next 与 /help 的引导入口覆盖

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-03 18:52:55 +08:00
AIGameCreator App c796dac003 补充试玩定位聊天入口
新增 /pitch 试玩定位与卖点摘要

补充 /next 与 /help 的定位入口覆盖

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-03 18:45:44 +08:00
AIGameCreator App 44f810ba01 补充作品页文案聊天入口
新增 /listing 作品页草稿摘要

补充 /next 与 /help 的文案入口覆盖

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-03 18:37:55 +08:00
AIGameCreator App 6ce4a68ece 补充试玩交付聊天入口
新增 /share 试玩交付清单摘要

补充 /next 与 /help 的交付入口覆盖

同步 AI 游戏创作 App 技术方案和决策记录

校准项目权限确认提示测试
2026-07-03 18:28:44 +08:00
AIGameCreator App 5896350075 补充玩法规则聊天入口
新增 /rules 玩法操作与规则摘要

补充 /next 与 /help 的规则入口覆盖

同步 AI 游戏创作 App 技术方案和决策记录
2026-07-03 18:18:47 +08:00
AIGameCreator App fde0a3ae80 补充试玩反馈与数值聊天入口
新增 /feedback 试玩反馈摘要和修改说明草稿

新增 /balance 数值与难度口径摘要

补充 /next 与 /help 的入口覆盖

同步技术方案和项目决策记录
2026-07-03 18:09:11 +08:00
AIGameCreator App c192e01b89 补充 MVP 范围聊天入口
新增 /mvp 最小可玩范围摘要和后续草稿

补充 /next 与 /help 的 MVP 入口覆盖

同步技术方案和项目决策记录
2026-07-03 17:56:43 +08:00
AIGameCreator App 86799a4da9 补充创作目标聊天入口
新增 /goal 创作目标来源摘要和细化草稿

补充 /next 与 /help 的目标入口覆盖

同步技术方案和项目决策记录
2026-07-03 17:45:56 +08:00
AIGameCreator App 92c9592e46 补充生成变更聊天入口
新增 /changes 最近生成变更摘要和读取草稿

补充 /next 与 /help 的变更入口覆盖

同步技术方案和项目决策记录
2026-07-03 17:39:18 +08:00
AIGameCreator App 03a2e9fa03 补充质量检查聊天入口
新增 /qa 质量检查清单和后续草稿

补充 /next 与 /help 的 QA 入口覆盖

同步技术方案和项目决策记录
2026-07-03 17:33:28 +08:00
AIGameCreator App a05e8e0365 补充运行预算聊天入口
新增 /budget 运行预算摘要和后续草稿

补充 /next 与 /help 的预算入口覆盖

同步技术方案和项目决策记录
2026-07-03 17:24:42 +08:00
AIGameCreator App bb7ce9a1c8 补充专业组进度聊天入口
新增 /groups 专业组进度摘要和任务草稿

补充 /next 与 /help 的专业组入口覆盖

同步技术方案和项目决策记录
2026-07-03 17:18:13 +08:00
AIGameCreator App 3353ea37ef 补充任务验收标准聊天入口
新增 /criteria 当前任务验收摘要和任务草稿

补充 /next 与 /help 的验收入口覆盖

同步技术方案和项目决策记录
2026-07-03 17:13:07 +08:00
AIGameCreator App 3a4504a04f 补充项目时间线聊天入口
新增 /timeline 项目活动摘要和日志草稿

补充 /next 与 /help 的时间线入口覆盖

同步技术方案和项目决策记录
2026-07-03 17:05:40 +08:00
AIGameCreator App 25868e099a 补充生成上下文聊天入口
新增 /context 上下文来源摘要和草稿

补充 /next 与 /help 的上下文入口覆盖

同步技术方案和项目决策记录
2026-07-03 16:57:35 +08:00
AIGameCreator App cb1ab51b58 补充美术素材聊天入口
新增 /art 美术素材摘要和草稿

补充 /next 与 /help 的美术入口覆盖

同步技术方案和项目决策记录
2026-07-03 16:48:08 +08:00
AIGameCreator App bc057b7ef7 补充试玩状态聊天入口
新增 /playtest 试玩摘要和下一步草稿

补充 /next 与 /help 的试玩入口覆盖

同步技术方案和项目决策记录
2026-07-03 16:34:45 +08:00
AIGameCreator App 7250ecf0cc 补充评审状态聊天入口
新增 /review 评审摘要和读取草稿

补充 /next 与 /help 的评审入口覆盖

同步技术方案和项目决策记录
2026-07-03 16:25:16 +08:00
AIGameCreator App 169f74b3c8 补充轮次产物聊天入口
新增 /passes 轮次产物读取草稿

补充 /next 和 /help 的轮次入口覆盖

同步技术方案和项目决策记录
2026-07-03 16:14:23 +08:00
AIGameCreator App b97ebb9a8b 补充内部真相源聊天入口
新增 /internals 内部真相源读取草稿

补充内部入口界面测试和帮助覆盖

同步技术方案和项目决策记录
2026-07-03 16:07:33 +08:00
AIGameCreator App 8e458ab08e 补充发布准备聊天入口
新增 /publish 发布准备清单和安全草稿

补充发布准备入口界面测试和帮助覆盖

同步技术方案和项目决策记录
2026-07-03 16:00:04 +08:00
AIGameCreator App c63e87e5f2 补充音频素材聊天入口
新增 /audio 音频素材盘点和安全草稿

补充音频入口界面测试和帮助覆盖

同步技术方案和项目决策记录
2026-07-03 15:51:55 +08:00
AIGameCreator App 88279cea3d 补充本地试玩包列表入口
新增 /exports 聊天命令和试玩包列表摘要

新增 Tauri 试玩包列表命令和安全过滤测试

同步共享命令契约、技术方案和决策记录
2026-07-03 15:40:07 +08:00
AIGameCreator App f3d9ae38d0 补充本地试玩包导出入口
新增 /export 聊天命令和主窗口导出确认入口

新增本地试玩 ZIP 白名单打包和安全记录

同步共享命令契约、技术方案和决策记录
2026-07-03 15:27:37 +08:00
AIGameCreator App 1c7532ea99 补充运行辅助文件入口
新增聊天侧run-files命令列出Agent运行辅助文件读取草稿

补充主窗口命令帮助和下一步建议测试

同步AI游戏创作App技术方案和共享决策记录
2026-07-03 04:45:37 +08:00
AIGameCreator App e47f346561 补充项目交接聊天入口
新增聊天侧handoff命令基于当前状态生成项目交接摘要

补充主窗口交接入口和帮助命令测试

同步AI游戏创作App技术方案和共享决策记录
2026-07-03 04:37:08 +08:00
AIGameCreator App 4a6a9d4a2f 补充Run历史聊天入口
新增聊天侧runs命令基于已加载状态生成Run读取草稿

补充主窗口Run历史入口和帮助命令测试

同步AI游戏创作App技术方案和共享决策记录
2026-07-03 04:27:46 +08:00
AIGameCreator App f8af8ca507 补充项目风险命令入口
新增聊天侧risks命令基于当前状态生成风险摘要

补充主窗口风险入口和帮助命令测试

同步AI游戏创作App技术方案和共享决策记录
2026-07-03 04:19:38 +08:00
AIGameCreator App d046866c07 补充项目简报命令入口
新增聊天侧brief命令基于当前状态生成项目简报

补充帮助命令和主窗口简报入口测试

同步AI游戏创作App技术方案和共享决策记录
2026-07-03 04:12:49 +08:00
AIGameCreator App 6992dede5b 补充下一步建议命令
新增聊天侧next命令基于当前状态给出安全草稿建议

补充主窗口下一步建议测试和帮助命令覆盖

同步AI游戏创作App技术方案和共享决策记录
2026-07-03 04:05:42 +08:00
AIGameCreator App b8cb088056 补充日志读取命令入口
新增聊天侧logs命令列出常用日志读取草稿

补充帮助命令和主窗口日志入口测试

同步AI游戏创作App技术方案和共享决策记录
2026-07-03 03:59:26 +08:00
AIGameCreator App 53d8acc2dc 补充Run产物读取入口
新增聊天侧run-artifacts命令列出最近Run产物读取草稿

补充帮助命令和主窗口Run产物入口测试

同步AI游戏创作App技术方案和共享决策记录
2026-07-03 03:50:28 +08:00
AIGameCreator App e1f00d8aca 补充Agent对话读取入口
新增聊天侧agent-conversations命令列出Agent对话读取草稿

补充帮助命令和主窗口对话入口测试

同步AI游戏创作App技术方案和共享决策记录
2026-07-03 03:46:11 +08:00
AIGameCreator App 37a6455059 补充Agent记忆读取入口
新增聊天侧agent-memories命令列出私有记忆读取草稿

补充帮助命令和主窗口记忆入口测试

同步AI游戏创作App技术方案和共享决策记录
2026-07-03 03:42:47 +08:00
AIGameCreator App f0ba3c0327 补充Agent状态聊天汇总
新增聊天侧agents命令汇总每个Agent当前状态

补充帮助命令和主窗口状态汇总测试

同步AI游戏创作App技术方案和共享决策记录
2026-07-03 03:38:49 +08:00
AIGameCreator App 6fbd1e044a 补充项目策略快捷入口
新增索引资产登记和记忆写入确认草稿入口

补充用户面策略快捷入口测试

同步AI游戏创作App技术方案和共享决策记录
2026-07-03 03:31:40 +08:00
AIGameCreator App 5369440e15 补充预览策略快捷入口
新增打开预览和停止预览确认草稿入口

补充用户面策略快捷入口测试

同步AI游戏创作App技术方案和共享决策记录
2026-07-03 03:24:37 +08:00
AIGameCreator App bd1dfe198b 补充产物读取命令入口
新增聊天侧常用生成产物命令列表

补充入口HTML读取草稿和用户面测试

同步AI游戏创作App技术方案和共享决策记录
2026-07-03 03:20:10 +08:00
AIGameCreator App c88678c28d 补充常用产物读取入口
新增主窗口常用生成产物读取草稿入口

补充用户面快捷入口测试

同步AI游戏创作App技术方案和共享决策记录
2026-07-03 03:12:21 +08:00
AIGameCreator App 980cae575e 补充音频资产快捷入口
新增主窗口音效登记和画板音频导入草稿入口

补充用户面快捷入口测试

同步AI游戏创作App技术方案和共享决策记录
2026-07-03 03:04:59 +08:00
AIGameCreator App ae245e11df 补充Agent私有记忆写入
新增单Agent对话面板私有记忆追加入口

补充Tauri本地Agent记忆写入命令和策略测试

同步AI游戏创作App技术方案和共享决策记录
2026-07-03 02:58:53 +08:00
AIGameCreator App 41b23add83 补充开发日志查看入口
新增开发窗口项目日志只读查看入口

补充命令预览和Agent日志的用户面测试

同步AI游戏创作App技术方案和共享决策记录
2026-07-03 02:45:23 +08:00
AIGameCreator App c503b15ab5 补充Agent LLM状态展示
回填LLM状态到Agent列表和单Agent对话
补充Agent级Provider状态的用户面测试
同步AI游戏创作App技术方案和共享决策记录
2026-07-03 02:36:08 +08:00
AIGameCreator App 875d9fd727 补充主窗口项目摘要
新增主窗口任务资产和最近命令摘要
补充项目摘要的用户面测试
同步AI游戏创作App技术方案和共享决策记录
2026-07-03 02:25:44 +08:00
AIGameCreator App 1ad51e30c6 补充Agent对话与继续草稿入口
新增对话读写策略确认草稿入口

新增Agent继续说明草稿入口

补充用户面快捷入口测试

同步AI游戏创作App技术方案和共享决策记录
2026-07-03 02:14:55 +08:00
AIGameCreator App 4a6540a5af 忽略外部API冒烟测试产物
新增外部 API 冒烟测试输出目录忽略规则
2026-07-03 02:06:15 +08:00
AIGameCreator App eb80a592c0 补充AI游戏创作草稿快捷入口
新增灵感草稿入口,仅填入创作需求不触发生成

新增预览和Agent状态权限确认草稿入口

补充主窗口草稿入口测试覆盖

同步AI游戏创作App文档和共享决策记录
2026-07-03 02:02:21 +08:00
AIGameCreator App 425743820a 补齐AI游戏创作轻量读取草稿入口
为Trace产物和checkpoint补充只填草稿的读取与回滚入口

补充Agent输出、活动和上下文包读取草稿入口

补充黑板覆盖与清空草稿入口

同步AI游戏创作App文档和共享决策记录
2026-07-03 01:56:01 +08:00
AIGameCreator App e3fd0d483d 拓宽AI游戏创作主窗口快捷入口
在主窗口头部显示当前预览状态

补充黑板、画板资产导入和资产读取草稿快捷入口

为Trace产物提供读取命令草稿

同步AI游戏创作App文档和共享决策记录
2026-07-03 01:43:35 +08:00
AIGameCreator App 998e33ca3d 完善AI游戏创作App本地工作区与Agent协作
补齐工作区启动器、非空目录确认和主窗口切换入口

改为运行时配置文件并支持全局与单Agent LLM Provider

接入平台 External API 生成和同步美术资产

补齐本地对话记录、Agent私有记忆和项目黑板

完善Agent状态、历史Run、快照、文件和资产快捷入口

同步AI游戏创作App实施计划和共享决策记录
2026-07-03 01:32:51 +08:00
AIGameCreator App 76b5718d77 落地游戏创作本地工程护栏
新增项目 checkpoint、diff、restore、本地索引、写锁和项目级权限策略。

接入聊天命令和共享命令契约,普通用户可确认恢复与策略写入。

补充上下文敏感信息过滤,避免密钥和本机配置进入 LLM prompt。

更新 AI 游戏创作 App 文档、共享记忆和相关测试。
2026-07-01 16:26:43 +08:00
AIGameCreator App 5ddf0cc325 合并远端创作应用分支
合并 origin/codex/ai-game-creator-app 的最新提交。

保留本地美术资源生成接口与素材库合并改动。
2026-07-01 14:40:27 +08:00
lhk229 65d1489bdd 新增 Anthropic 链路,LLM 请求收口为 LlmRunRequest/LlmApiKind,新增Agent流程图绘图脚本 (#70)
新增 Anthropic 链路,LLM 请求收口为 LlmRunRequest/LlmApiKind,为未来创建更多字段适配高级功能准备

Reviewed-on: https://git.genarrative.world/git/GenarrativeAI/Genarrative/pulls/70
Co-authored-by: Linghong <ink29535@proton.me>
Co-committed-by: Linghong <ink29535@proton.me>
2026-06-30 19:33:37 +08:00
AIGameCreator App e72e689f6a 接入平台美术生成接口
在 AI 游戏创作 Agent loop 中配置 editorApi.apiKey 时调用 External Editor 图片生成 API

将生成结果换签下载到 assets/canvas-generated/ 并登记为 canvas 来源资产

补充平台生图 mock 测试和相关方案决策文档
2026-06-30 15:47:10 +08:00
AIGameCreator App ff95dfa62f 合并编辑器素材库分支
合并 codex/editor-asset-library 到 AI 游戏创作 App 分支。

保留 AI 游戏创作客户端配置决策,并合入素材库分支新增文档。

排除素材库分支误带的 .env.local 本机密钥改动。
2026-06-30 15:23:41 +08:00
AIGameCreator App 588a529875 改用客户端运行时配置
移除 AI 游戏创作壳专属 .env 读取,改为默认配置模板与 Tauri 运行时配置。

新增主窗口配置面板,读写 LLM 与画板 API 配置。

更新 CLI smoke、门禁、测试和项目文档。
2026-06-30 15:13:51 +08:00
kdletters 54b18bf0e2 增强生成音频下载重试
为生成音频下载添加 identity 请求头和响应体读取失败重试。

补充音频下载响应体失败后重试成功的单元测试。
2026-06-30 13:46:08 +08:00
kdletters a8c19e132d 完善画布任务与标准绿幕抠除链路
统一编辑器标准绿幕提示词和本地绿幕透明化后处理

生成标准绿幕资产前保存源图到 OSS 并下沉字节级抠绿到 platform-image

将手动去背景接入外部生成队列与画布任务侧栏

修复任务侧栏分页、滚动、计时、焦点与完成信息展示

补充右键菜单关闭和素材复制下载交互

同步编辑器相关文档和项目记忆
2026-06-30 11:29:54 +08:00
AIGameCreator App 1fedd62c90 完善创作壳运行控制审计
记录自动状态命令到本地命令日志

限制 command.auto 只能记录 auto 权限命令

补齐 agent retry 和 resume 的界面与生命周期测试
2026-06-30 10:19:51 +08:00
kdletters 10b170e7a2 完善画布素材与抠图任务体验
素材库资产支持直接下载。

画布复制图片时同步写入系统剪贴板。

手动抠图请求直接进入画布任务列表并支持聚焦。
2026-06-29 19:53:05 +08:00
kdletters dbf38f3a8c 显示画板顶部用户头像
在画板顶部泥点右侧显示当前用户头像、昵称和用户码。

头像入口复用账号弹窗,未登录时打开登录入口。

补充画板顶部头像入口的组件和集成测试。
2026-06-29 18:07:44 +08:00
kdletters 7417370ae9 修复画布任务列表服务端任务显示
任务列表只使用服务端返回的生成任务。

保留生成任务水合后的开始和结束时间。

同步任务列表与画布阶段视图测试。
2026-06-29 17:22:42 +08:00
kdletters 73eb3f6dc8 隐藏精选部分素材分类
隐藏陶泥儿精选中的特效、场景和游戏分类入口

补充创作首页精选分类隐藏断言
2026-06-29 17:21:09 +08:00
kdletters 496bafbb7f 更新.env.local 2026-06-29 16:28:39 +08:00
kdletters a6e3aef5b2 修复任务侧栏空页签跳转
保留用户手动选择的空排队生成中页签。

补充任务侧栏空页签回归测试。
2026-06-29 16:26:30 +08:00
kdletters 12ef866b66 完善画布任务列表与远程抠图接入
新增图片画布任务侧栏页签、滚轮隔离、完成时间、后端计时和运行中状态展示。

限制外部生成任务只显示当前项目,并让任务点击聚焦画布内容和快速编辑源图。

接入外部生成任务列表查询状态过滤、提示词摘要和后端任务映射。

补充 BiRefNet 抠图请求日志、任务耗时提示和相关文档。

补充侧栏、画布聚焦、外部任务契约和 api-server 定向测试。
2026-06-29 16:19:28 +08:00
kdletters d2428b30f2 Merge remote-tracking branch 'origin/codex/editor-asset-library' into codex/remote-cutout-task-sidebar 2026-06-29 16:12:29 +08:00
kdletters 45e4b6e64a 修复画布快速编辑还原生成器
直接点击生成图时还原原生成器对话框

非生成图直接点击只选中不打开生成器

快速编辑按钮和右键入口按素材元数据打开对应生成器

补齐资源元数据回填和入口边界测试
2026-06-29 16:06:51 +08:00
kdletters 495fcc8801 切换图片画布抠图到 BiRefNet
新增图片画布去背景 BFF 配置与路由,服务端代理 BiRefNet 并持久化结果。

将手动去背景、角色图、图标 spritesheet、UI 素材提取和角色动作帧抠图切到 BiRefNet。

新增画布右上角任务侧栏并展示去背景任务耗时与状态。

同步图片画布技术文档和项目决策记录。
2026-06-29 15:02:14 +08:00
AIGameCreator App 9af13974db 支持平台入口初始页签
为平台入口透传 initialPlatformTab 参数

避免移动端隐藏页签覆盖显式创作页签

更新 RPG 入口交互测试的创作页签起点
2026-06-28 04:53:35 +08:00
AIGameCreator App e4395c77e0 默认使用 Responses 协议
将 platform-llm 文本请求默认协议改为 Responses

为旧 Chat Completions 网关保留显式兼容开关

同步 AI 游戏创作 App 协议配置与文档
2026-06-28 00:01:02 +08:00
lhk229 21b56ab611 Fix/llm parsing and null output (#69)
修复LLM解析错误(输出过长被截断)、LLM回复为空(Deepseek服务端问题)

---------

Co-authored-by: AIGameCreator App <dsk@genarrative.world>
Reviewed-on: https://git.genarrative.world/git/GenarrativeAI/Genarrative/pulls/69
Co-authored-by: lhk229 <ink29535@proton.me>
Co-committed-by: lhk229 <ink29535@proton.me>
2026-06-26 22:02:39 +08:00
AIGameCreator App afd699a060 补齐游戏创作智能体本地Run控制
新增 agent run 状态、停止、重试和恢复命令
把 run 生命周期写入 trace、activity、output 和 context bundle
补齐聊天入口、测试覆盖和实施计划文档
2026-06-26 21:55:31 +08:00
AIGameCreator App 5de4916956 增强游戏创作智能体生成过程可见性
在聊天中实时展示 Planner、Orchestrator、Generator 和 Evaluator 进度
将生成完成摘要切换为完整 run trace 和 LLM 对话证据
补齐质量评审任务、测试覆盖和实施计划文档
2026-06-26 19:36:21 +08:00
AIGameCreator App 1b4bca1ab3 修正 AI 游戏创作真实网关生成链路
调整 AI 游戏创作 App 的 LLM 默认超时和输出上限

将组内角色 brief 改为本地编排生成,保留 6 组多角色 trace,减少真实 provider 调用

允许画板资源占位引用通过自检,继续拒绝固定模板和未完成实现

更新本地 provider smoke 和 Agent trace 断言
2026-06-25 21:03:46 +08:00
AIGameCreator App 72a6d635da AI 游戏创作智能体 App v1 最小落地
新增独立 Tauri 壳 apps/ai-game-creator-shell,只保留聊天入口,正式用户窗口不承载游戏预览画面,开发模式通过独立窗口展示任务、文件、记忆、预览和日志

新增游戏创作专业组与种子任务图契约,覆盖策划/美术/程序/数值/音乐/运营 6 组下 15 个组内角色

新增共享契约本地项目 manifest、内置命令权限枚举、run trace schema 和 ready-task 选择器

扩展平台 LLM 支持流式请求,增加 GENARRATIVE_GAME_CREATOR_LLM_STREAM 开关

新增 AI 游戏创作 App 的聊天命令集:/help /capabilities /audit /project /llm-status /status /files /assets /read /tasks /trace /smoke /run /preview /preview-status /preview-open /preview-stop /memory /remember /forget-memory /canvas /sync-canvas-project /import-canvas-asset /import-canvas-export

新增本地项目初始化、权限 gate(pending/confirm/cancel)、文件上传、受限命令白名单 game.static_smoke 和本地 HTTP 预览

新增 Planner / 6 组角色 agent / Generator / Evaluator / ArtifactWriter / Playtest 文件驱动 loop,最多 3 轮返工,结构化 repairRoutes

新增实时 run trace 写入 .agent/run.latest.json 与 .agent/runs/,包含 taskGraph、passPlans 和步级 toolCalls

新增短期/长期记忆 memory/session.md 和 memory/project.md,支持聊天读取/追加/覆盖/删除

新增画板对接:canvas.project_open、canvas.project_sync、canvas.asset_import、canvas.export_import

新增 npm run ai-game-creator-shell:check 开发验收入口,覆盖 typecheck、单元测试、端到端 smoke

新增 check:native-shells 静态守门:release 只登记 main 聊天窗口,CSP 禁止内嵌预览,开发窗口只在 debug 下打开,用户侧预览命令必须调用 open_local_game_preview
2026-06-25 21:03:46 +08:00
959 changed files with 547904 additions and 10290 deletions
@@ -1,93 +1,70 @@
---
name: genarrative-external-editor-api
description: Guide use of Genarrative's external editor/canvas OpenAPI. Use when a user describes a canvas/editor integration need and Codex must infer the right `/api/external/v1` API automatically, prepare canvas and asset-library context, abstract reusable art specs before generating assets, upload references, draft curl/HTTP/SDK requests, or set up and safely handle a Genarrative developer API Key.
description: Guide use of Genarrative's hosted external editor/canvas MCP or asynchronous `/api/external/v1` OpenAPI. Use when an Agent needs to discover the hosted integration, choose a canvas or asset operation, upload local reference media, create or update projects and asset-library records, submit and poll image/video/audio generation, interpret generated artifacts and warnings, draft HTTP/Python calls, or securely handle a Genarrative developer API Key.
---
# Genarrative External Editor API
Use the live OpenAPI contract as the source of truth: `GET https://www.genarrative.world/api/external/v1/openapi.json`. In this repository, the same contract is `docs/openapi/genarrative-external-v1.openapi.json`. If exact fields or enums matter, read the contract before emitting final code.
Discover the live integration through `GET https://www.genarrative.world/api/external/v1/agent-integration.json`. Treat `GET https://www.genarrative.world/api/external/v1/openapi.json` as the field-level source of truth. In this repository, the same contract is `docs/openapi/genarrative-external-v1.openapi.json`.
Prefer the bundled Python helper for runnable examples: `scripts/genarrative_external_api.py`. It uses only Python stdlib, reads the local JSON API Key file, fixes the production base URL, and wraps upload/confirm/generation routes.
Prefer the hosted Streamable HTTP MCP at `https://www.genarrative.world/api/external/v1/mcp` when the Agent supports remote MCP with a custom Bearer token. It exposes the External v1 operations as tools and the Skill documentation as resources; it does not require a local MCP server. Use this complete Skill package when remote MCP is unavailable or local-file upload needs client-side orchestration.
Prefer `scripts/genarrative_external_api.py` for runnable REST calls. It uses only Python stdlib, reads the local private API Key file, keeps the production base URL fixed, uploads local references, and wraps asynchronous submission, polling, and result retrieval.
## Workflow
1. At the start of a new conversation, ask the user for the canvas name before the first generation call unless an existing session is already provided. Create or use a project with that name and an asset-library folder with the same name. Keep `canvasName`, `projectId`, `assetFolderId`, and the current art spec in conversation state.
2. Before any art asset generation, abstract the user's request into a reusable art spec. Ask only for missing spec fields required by the selected asset type. If a current spec already exists and the user does not request a new style/spec, reuse it automatically.
3. Classify the user's natural-language intent. Do not ask the user to choose an API:
- "生成/生图/做一张图" -> image generation
- "重绘/修改这张图" -> image edit
- "用这张参考图/基于本地图生成" -> upload local reference image, then generation or edit
- "上传本地素材" -> upload ticket, OSS form upload, object confirm
- "保存画板/更新布局" -> canvas save
- "读取私有素材" -> signed read URL
4. Ask only for missing inputs that affect the request body or an actually ambiguous route:
- credentials JSON path only if the user cannot use the default local path
- canvas name when no current canvas session exists; existing `projectId`, folder/resource IDs only when resuming a known project
- media type, prompt, references, dimensions, model, ratio, duration, and resolution
- whether referenced media is already uploaded as `objectKey` or still local
5. Every external generation must write to both the canvas and the asset library. Include `projectId`, `assetFolderId`, a display label, and `canvasCompletion` whenever the target endpoint supports them. For character animation, use the helper's two-step fallback: generate with `projectId` + `canvasCompletion`, then create a library asset from the first returned frame in the session folder.
6. If the user lacks an API Key, guide setup before request design.
7. Read `references/api-selection.md` before finalizing any request. Use the core table below for fast routing, then verify details in the reference.
8. Use `scripts/genarrative_external_api.py` when the user wants runnable Python, reference image upload, canvas/folder session setup, art-spec carrying, or a chain that should execute with fewer hand-written curl steps.
9. Keep to `/api/external/v1` unless the user explicitly asks for internal profile/admin APIs.
1. Discover the integration manifest. Choose hosted MCP when supported; otherwise use the helper or direct REST.
2. Before the first generation in a new conversation, obtain a canvas name unless an existing `projectId` and `assetFolderId` were supplied. Create or reuse a project and a same-name asset-library folder. Retain `canvasName`, `projectId`, `assetFolderId`, and the current art spec.
3. Normalize art requests into a reusable spec. Ask only for missing values that block the selected operation. Reuse the spec until the user changes its style, subject family, palette, format, or constraints.
4. Infer the operation from the user's intent. Do not ask the user to select an API unless two operations would produce materially different artifacts.
5. If a reference exists only as a local file, upload and confirm it first. Pass the stable returned `objectKey` to generation; never substitute a temporary signed URL.
6. For generation endpoints that support the fields, include `projectId`, `assetFolderId`, an asset label, and `canvasCompletion` so the result enters both the canvas and its same-name library folder.
7. Treat every generation POST as asynchronous. Send one stable `Idempotency-Key` per logical request, retain the returned `operationId`, and poll the returned `statusUrl` or `GET /api/external/v1/generations/{operationId}` according to `pollAfterMs`.
8. Consume `result` only after `status=completed`. On `failed`, surface the safe error. On a client timeout or lost response, retain the operation/key; do not create a replacement request.
9. Reload the normal project or asset-library read endpoint when the caller needs complete authoritative state. Generation results are intentionally compact.
10. Stay within `/api/external/v1`. Never call internal workers, queues, admin/profile APIs, or SpacetimeDB endpoints unless the user explicitly changes scope.
## Core Routes
## Essential Invariants
| Intent | Method and path | Required fields |
| --- | --- | --- |
| List/create projects | `GET/POST /api/external/v1/editor/projects` | create: optional `title` |
| Save canvas | `PATCH /api/external/v1/editor/projects/{projectId}/canvas` | `viewport`, `layers` |
| Upload local media | `POST /api/external/v1/assets/direct-upload-tickets` -> OSS form -> `POST /api/external/v1/assets/objects/confirm` | ticket: `legacyPrefix`, `fileName`; confirm: `objectKey`, `assetKind` |
| Read private media | `GET /api/external/v1/assets/read-url` | `objectKey` or `legacyPublicPath` |
| Image generation | `POST /api/external/v1/editor/images/generations` | `prompt` |
| Image edit/redraw | `POST /api/external/v1/editor/images/edits` | `prompt`, `sourceImageSrc` |
| Icon spritesheet | `POST /api/external/v1/editor/icon-spritesheets/generations` | `referenceImageSrc`, `iconDescriptions` |
| UI asset extraction | `POST /api/external/v1/editor/ui-designs/assets/extractions` | `sourceImageSrc`, `aspectRatio`, `imageSize`; use `assetFolderId` for library folder |
| Character animation | `POST /api/external/v1/editor/character-animations/generations` | `sourceLayerId`, `sourceImageSrc`, `sourceWidth`, `sourceHeight`, `promptText`, `resolution`, `ratio`, `frameCount`, `durationSeconds`, `model` |
| Video generation | `POST /api/external/v1/editor/videos/generations` | `prompt`, `model`, `aspectRatio`, `durationSeconds`, `resolution`, `mode`, `sound` |
| Sound effect | `POST /api/external/v1/editor/audios/sound-effects/generations` | `prompt`, `duration` |
| Background music | `POST /api/external/v1/editor/audios/background-music/generations` | `gptDescriptionPrompt`, `makeInstrumental` |
- Authenticate MCP and business API calls with `Authorization: Bearer <tnr_sk_...>`. Never ask the user to paste a key into chat or place one in repository files.
- All eight generation POST routes require `Idempotency-Key` and return HTTP `202`; `202` is durable acceptance, not a media result.
- Retry an uncertain submission only with the exact same body and the same idempotency key. A polling timeout is not permission to generate again.
- Use stable references such as `objectKey`, project resource ID, or asset ID in generation requests. Use `/assets/read-url` only for temporary preview/download access.
- Preserve both warning channels after completion. A general `warning` can coexist with `sliceWarning`; do not discard either.
- Do not invent missing derivatives. A source-preserved warning means the main source remains usable but requested post-processing failed. A slice warning means the complete transparent sheet is usable but individual slices are absent.
- Keep generated artifacts in the canvas and asset library together. Character animation accepts `assetFolderId` and `assetLabel`; its completed result directly returns the final `assetKind="character-animation"` resource and asset with formal sequence fields. Do not create a duplicate first-frame record.
## Art Spec Interface
## Documentation Navigation
Maintain one current art spec per conversation. A compact spec is enough:
Read only the references needed for the task, but always verify exact schemas and enums against live OpenAPI:
```json
{
"assetType": "character | background | prop | ui | icon | animation | video | audio",
"subject": "要生成的主体",
"style": "画风/材质/时代/参考风格",
"palette": "主色与禁用色",
"composition": "构图、镜头、姿态或布局",
"format": "比例、尺寸、分辨率、帧数、时长",
"constraints": "必须保留/禁止出现/透明或绿幕要求",
"references": ["objectKey 或本地路径说明"]
}
```
- `references/capability-routing.md`: read before selecting an MCP tool or REST operation, creating a canvas session, or working in the AI game creator visual DAG.
- `references/api-operations.md`: read when constructing project, canvas, asset-library, upload, generation, or generation-status calls.
- `references/authentication-and-safety.md`: read before handling credentials, local files, OSS form upload, retries, private media, or logs.
- `references/requests-and-outputs.md`: read before building generation payloads, polling, interpreting compact results, applying canvas completion, or handling post-processing warnings.
For a first spec, infer fields from the user's words and ask only for missing fields that block the selected API. Examples: character animation needs source image/layer, dimensions, motion, ratio, frame count, and duration; UI extraction needs source design image plus target density; icon spritesheet needs reference image and icon descriptions. After a spec exists, reuse it for later assets unless the user changes style, subject family, palette, format, or constraints.
The hosted MCP exposes the same documents through:
## API Key
- `genarrative://external-editor/skill`
- `genarrative://external-editor/skill/references/capability-routing.md`
- `genarrative://external-editor/skill/references/api-operations.md`
- `genarrative://external-editor/skill/references/authentication-and-safety.md`
- `genarrative://external-editor/skill/references/requests-and-outputs.md`
- `genarrative://external-editor/openapi`
The external OpenAPI uses:
## Hosted Integration Discovery
```text
Authorization: Bearer <tnr_sk_...>
```
- Manifest: `GET /api/external/v1/agent-integration.json`.
- Hosted MCP: `POST /api/external/v1/mcp`, Streamable HTTP, same Bearer API Key.
- OpenAPI: `GET /api/external/v1/openapi.json`.
- Raw Skill entry: `GET /api/external/v1/skill/SKILL.md`.
- Complete Skill archive: `GET /api/external/v1/skill.zip`.
The OpenAPI JSON endpoint is public; every other external endpoint requires the Bearer API Key.
The archive contains this main file, four one-level references, the Python helper, and `agents/openai.yaml`. Verify its SHA-256 against `agent-integration.json` before installing. Discovery, OpenAPI, and Skill downloads are public; MCP and business operations require authentication.
Use this fixed production base URL:
## Python Helper
```text
https://www.genarrative.world/
```
Guide the user to create a key from the logged-in product UI under `开发者 API Key`. The raw key is shown only once; never ask the user to paste it into chat. Tell them to store it in this local private JSON file, outside the repository:
```text
~/.config/genarrative/external-editor-api.json
```
Store the API Key outside the repository at `~/.config/genarrative/external-editor-api.json`:
```json
{
@@ -95,246 +72,47 @@ Guide the user to create a key from the logged-in product UI under `开发者 AP
}
```
Set the file readable only by the current user where possible: `chmod 600 ~/.config/genarrative/external-editor-api.json`. Do not use environment variables for this API.
Smoke test by reading the JSON file, without printing the key:
```bash
api_key="$(node -e 'const fs=require("fs"); const p=process.argv[1]; const c=JSON.parse(fs.readFileSync(p,"utf8")); process.stdout.write(c.apiKey || "");' "$HOME/.config/genarrative/external-editor-api.json")"
curl -fsS "https://www.genarrative.world/api/external/v1/editor/projects" \
-H "Authorization: Bearer $api_key"
```
For generated client code, read `apiKey` from the JSON file, fail with a clear missing-config error, and redact keys in logs.
Python smoke without printing the key:
Set restrictive permissions where possible, then smoke-test without printing the key:
```bash
chmod 600 ~/.config/genarrative/external-editor-api.json
python3 .codex/skills/genarrative-external-editor-api/scripts/genarrative_external_api.py list-projects
```
## Request Patterns
For Python callers, prefer:
For a canvas-backed generation:
```python
from genarrative_external_api import GenarrativeExternalClient
client = GenarrativeExternalClient()
session = client.prepare_canvas_session("新画板")
art_spec = {
"assetType": "background",
"subject": "幻想森林主视觉",
"style": "手绘游戏概念图",
"palette": "翡翠绿、金色光斑,避免低饱和灰",
"composition": "16:9 横版,中心留出角色站位",
"format": "16:9, 1K",
"constraints": "无文字、无 UI 按钮",
"references": [],
}
client.generate_image(
"生成幻想森林背景",
"生成一张 16:9 幻想森林游戏背景",
canvasSession=session,
assetLabel="森林背景",
aspectRatio="16:9",
imageSize="1K",
artSpec=art_spec,
artSpec={
"assetType": "background",
"subject": "幻想森林主视觉",
"style": "手绘游戏概念图",
"palette": "翡翠绿与金色光斑",
"composition": "横版,中心留出角色站位",
"format": "16:9, 1K",
"constraints": "无文字、无 UI 按钮",
"references": [],
},
)
```
Use the helper directly from this skill path, or copy it into the caller's project. Do not change the fixed base URL or move the API Key into environment variables.
Helper convenience methods wait locally, but the server still uses short asynchronous submit/status requests. For durable caller-controlled orchestration, call `submit_generation`, persist its `operationId` and idempotency key, then call `get_generation` or `wait_for_generation`.
Use this shared base:
```bash
api="https://www.genarrative.world"
credentials_file="$HOME/.config/genarrative/external-editor-api.json"
api_key="$(node -e 'const fs=require("fs"); const p=process.argv[1]; const c=JSON.parse(fs.readFileSync(p,"utf8")); process.stdout.write(c.apiKey || "");' "$credentials_file")"
auth=(-H "Authorization: Bearer $api_key")
json=(-H "Content-Type: application/json")
```
Create a project:
```bash
curl -fsS "$api/api/external/v1/editor/projects" \
"${auth[@]}" "${json[@]}" \
-d '{"title":"新画板"}'
```
Generate an image and save it into both the canvas and the asset-library folder:
```json
{
"prompt": "一张横版幻想森林背景,适合游戏主视觉",
"kind": "spec",
"aspectRatio": "16:9",
"imageSize": "1K",
"projectId": "<projectId>",
"assetFolderId": "<assetFolderId>",
"assetLabel": "森林背景",
"generationInputs": {
"artSpec": {
"assetType": "background",
"style": "手绘游戏概念图"
}
},
"canvasCompletion": {
"title": "森林背景",
"placeholder": {
"x": 0,
"y": 0,
"width": 1024,
"height": 576,
"originalWidth": 1024,
"originalHeight": 576
}
}
}
```
Then call `POST /api/external/v1/editor/images/generations`.
For direct HTTP/curl, create or find the folder first with `GET /api/external/v1/editor/assets/library` and `POST /api/external/v1/editor/assets/folders`. The folder label should match the canvas name.
## Reference Images
When the user provides a local reference image path/file, upload it first; do not ask the user to convert it to base64.
Python helper path:
```python
from genarrative_external_api import GenarrativeExternalClient
client = GenarrativeExternalClient()
session = client.prepare_canvas_session("新画板")
ref = client.upload_reference_image("/path/to/reference.png")
client.generate_image(
"基于参考图生成一张 16:9 游戏背景",
canvasSession=session,
assetLabel="参考图背景",
aspectRatio="16:9",
imageSize="1K",
referenceImageSrcs=[ref["objectKey"]],
)
```
Use the normal upload flow with:
```json
{
"legacyPrefix": "generated-character-drafts",
"pathSegments": ["editor", "external-editor-references"],
"fileName": "<original-file-name>",
"contentType": "image/png",
"access": "private"
}
```
After OSS form upload, confirm the object with `assetKind: "editor_reference_image"`. Put the returned `objectKey` into the generation request:
- image generation: `referenceImageSrcs`
- image edit/redraw: `sourceImageSrc`; extra references go in `referenceImageSrcs`
- icon spritesheet: `referenceImageSrc`
- UI asset extraction: `sourceImageSrc`; extra references go in `referenceImageSrcs`
- character animation: `sourceImageSrc`
- video generation image references: `referenceImageSrcs`
Use `signedUrl` only for display/download. For generation requests, use `objectKey`, project resource ID, asset ID, public URL, or Data URL as the endpoint allows; prefer uploaded `objectKey` for local/private reference images.
OSS form upload shape, using the ticket response saved as `ticket.json`. The default response has `upload`; if the caller explicitly requested the API response envelope, use `data.upload`:
```bash
node - <<'NODE' ticket.json /path/to/reference.png
const fs = require('fs');
const path = require('path');
(async () => {
const body = JSON.parse(fs.readFileSync(process.argv[2], 'utf8'));
const ticket = body.upload || body.data?.upload;
if (!ticket) throw new Error('Upload ticket response missing upload payload');
const filePath = process.argv[3];
const form = new FormData();
for (const [key, value] of Object.entries(ticket.formFields)) {
if (value != null) form.append(key, value);
}
const bytes = fs.readFileSync(filePath);
form.append(
'file',
new Blob([bytes], { type: ticket.contentType || 'application/octet-stream' }),
path.basename(filePath),
);
const response = await fetch(ticket.host, { method: 'POST', body: form });
if (!response.ok) {
throw new Error(`OSS upload failed: ${response.status} ${await response.text()}`);
}
})().catch((error) => {
console.error(error.message);
process.exit(1);
});
NODE
```
Then confirm with `contentLength`:
```json
{
"objectKey": "<ticket upload.objectKey>",
"contentType": "image/png",
"contentLength": 12345,
"assetKind": "editor_reference_image",
"accessPolicy": "private"
}
```
`contentLength` is a JSON number from the local file byte size, not a quoted string.
For character animation from an uploaded local image, set:
```json
{
"sourceLayerId": "external-reference-hero",
"sourceImageSrc": "<uploaded objectKey>",
"sourceWidth": 720,
"sourceHeight": 1280,
"promptText": "让角色自然呼吸并轻微转身",
"resolution": "720p",
"ratio": "9:16",
"frameCount": 40,
"durationSeconds": 5,
"model": "seedance2.0-fast"
}
```
Use an existing canvas layer ID when the image came from a project layer. If it came only from a local upload, derive a stable synthetic `sourceLayerId` from the file name, for example `external-reference-hero`. Read `sourceWidth` and `sourceHeight` from the actual image before upload; ask the user only if the dimensions cannot be determined.
The helper uses a 420 second timeout for generation calls, including character animation and video. Direct HTTP clients should not use a 70 second request timeout for animation.
Character animation currently returns canvas completion data but not a direct `asset` payload. To keep the "canvas + asset library" invariant, call `client.animate_character(..., canvasSession=session, canvasTitle="...")`; the helper creates a library asset from the first returned frame in the session folder after the animation call succeeds.
For video generation, always include `mode: "std"`. When using image/video/audio references, default to `model: "seedance2.0-fast"` unless the user asks for another listed model, because reference media support is limited to the Seedance 2.0 family.
For image edit/redraw that should replace an existing canvas layer, pass `projectId` and `targetLayerId`. If the user instead gives an explicit `canvasCompletion`, let that placement win.
For sound effects and BGM, `assetFolderId` and `assetLabel` can write the generated audio to the account asset library, same as image/video generation.
## Successful Responses with Warnings
Character image generation (including character redraw through `kind: "character"`), icon spritesheet generation, and UI asset extraction can return HTTP 2xx with an optional structured `warning`. A 2xx response means the task completed, but it does not guarantee that every requested post-processed derivative exists.
- Apply the returned `project` and media snapshots before interpreting optional derivatives: character responses use `resource` / `asset`, while icon spritesheet and UI extraction responses use `spritesheetResource` / `spritesheetAsset`. When `warning.code` is `postprocess-failed-source-preserved`, the saved provider source image is the authoritative main result. Character output has no transparent derivative; icon spritesheet and UI extraction output have neither a transparent spritesheet nor slices. Display `warning.reason` directly, and do not synthesize missing derivatives or restart generation.
- `sliceWarning` is a separate condition used only when transparent spritesheet post-processing succeeded but automatic slicing failed. Keep `sliceWarning.reason` as the original diagnostic and continue using the complete transparent spritesheet; a UI may add context when displaying it, but must not rewrite the stored reason.
- The service contract keeps `warning` and `sliceWarning` mutually exclusive. As defensive handling for a malformed response containing both, treat the general `warning` as authoritative and do not misclassify the source-preserved result as a slicing-only warning.
For character animation, pass the canvas session and asset label to `animate_character`. The helper submits asynchronously and returns the completed compact result containing the authoritative formal `resource` and `asset`; do not synthesize a library asset from the first frame.
## Guardrails
- Do not invent endpoints outside the OpenAPI, especially internal worker or runtime task-list routes.
- Do not omit canvas/library context for generation. New generated assets should enter both the canvas and the asset-library folder named after the canvas.
- Do not put API Keys in repository files, generated project files, command history snippets with literal secrets, logs, docs, commits, or screenshots. The only default storage is the user's local private JSON credentials file.
- Do not use account JWT endpoints as the default external integration path. The profile API can create/revoke keys for logged-in product users, but it is not part of the external editor OpenAPI.
- When an endpoint returns `project`, `resource`, or `asset`, treat those as the authoritative updated project/resource/asset snapshots.
## Resources
- `references/api-selection.md`: intent routing and required-field cheat sheet.
- `scripts/genarrative_external_api.py`: stdlib Python helper for OpenAPI fetch, API Key loading, local reference upload, object confirm, project/canvas calls, and generation requests.
- Do not change the fixed production base URL in generated examples.
- Do not move the API Key into environment variables, source files, generated projects, logs, docs, screenshots, or shell snippets containing literal secrets.
- Do not treat a Data URL, Blob URL, expiring signed URL, worker lease, or provider diagnostic as a durable result.
- Do not reconstruct authoritative canvas, resource, or library snapshots from a compact generation response.
- Do not replace icon-spritesheet generation with ordinary image generation when the deliverable requires a reusable transparent atlas.
@@ -1,6 +1,6 @@
interface:
display_name: "Genarrative External Editor API"
short_description: "Auto-route canvas API generation"
default_prompt: "Use $genarrative-external-editor-api to prepare a canvas session, infer the right API, and generate assets into the canvas and library."
short_description: "Route async canvas generation safely"
default_prompt: "Use $genarrative-external-editor-api to discover the hosted integration, prepare a canvas session, and submit and poll asset generation into the canvas and library."
policy:
allow_implicit_invocation: true
@@ -0,0 +1,107 @@
# API Operations
Use this reference after selecting a capability. Treat `GET /api/external/v1/openapi.json` as authoritative for exact request/response schemas, required fields, constraints, and operation IDs.
All paths below are relative to `https://www.genarrative.world`. Discovery and Skill download routes are public. Project, asset, upload, generation, and generation-query operations require the Bearer API Key.
## Project and Canvas Operations
| Operation | Method and path | Minimum input |
| --- | --- | --- |
| List projects | `GET /api/external/v1/editor/projects` | Authentication; optional `view=full\|summary` (default `full`) |
| Create project | `POST /api/external/v1/editor/projects` | Optional `title` |
| Load recent project | `GET /api/external/v1/editor/projects/recent` | Authentication |
| Get project | `GET /api/external/v1/editor/projects/{projectId}` | `projectId` |
| Delete project | `DELETE /api/external/v1/editor/projects/{projectId}` | `projectId` |
| Rename project | `PATCH /api/external/v1/editor/projects/{projectId}/metadata` | `title` |
| Save canvas | `PATCH /api/external/v1/editor/projects/{projectId}/canvas` | `viewport`, `layers`, `expectedRevision` |
| Add project resource | `POST /api/external/v1/editor/projects/{projectId}/resources` | `imageSrc`, `width`, `height`, `sourceType` |
Canvas save uses optimistic revision control. Pass the last authoritative `expectedRevision`; on conflict, reload instead of replaying a stale full layout.
Project listing supports two views:
- `view=full` is the REST default and returns the complete project, canvas, layers, and resources.
- `view=summary` returns only `projectId`, `title`, `updatedAt`, and nullable `cover`, so callers can display, search, disambiguate same-name projects, and select a safe target without loading every canvas snapshot.
- Hosted MCP `list_editor_projects` always uses `summary`; call `get_editor_project` after selecting a `projectId` when complete authoritative state is required.
- `cover` contains only `resourceId`, stable `objectKey`, dimensions, and `updatedAt`. It never embeds image bytes, a Data URL, or a signed URL. To display it, pass `cover.objectKey` to `get_external_asset_read_url`; signed URLs are temporary and must not be persisted or reused as generation references.
## Asset and Upload Operations
| Operation | Method and path | Minimum input |
| --- | --- | --- |
| Create direct-upload ticket | `POST /api/external/v1/assets/direct-upload-tickets` | `legacyPrefix`, `fileName` |
| Confirm uploaded object | `POST /api/external/v1/assets/objects/confirm` | `objectKey`, `assetKind` |
| Get signed read URL | `GET /api/external/v1/assets/read-url` | `objectKey` or `legacyPublicPath` |
| Read asset library | `GET /api/external/v1/editor/assets/library` | Authentication |
| Create folder | `POST /api/external/v1/editor/assets/folders` | `label` |
| Update folder | `PATCH /api/external/v1/editor/assets/folders/{folderId}` | `label` or `collapsed` |
| Delete folder | `DELETE /api/external/v1/editor/assets/folders/{folderId}` | `folderId` |
| Create asset record | `POST /api/external/v1/editor/assets` | `folderId`, `label`, `imageSrc`, `width`, `height`, `sourceType` |
| Update asset record | `PATCH /api/external/v1/editor/assets/{assetId}` | `label` or `folderId` |
| Delete asset record | `DELETE /api/external/v1/editor/assets/{assetId}` | `assetId` |
Upload is a three-step client flow: create a ticket, POST the file and returned fields directly to the OSS form endpoint, then confirm the returned `objectKey`. See `authentication-and-safety.md` before implementing this flow.
## Generation Operations
Every generation row requires a stable `Idempotency-Key` header and returns HTTP `202` with an asynchronous submission, not the generated media.
| Capability | POST path | Required body fields | Common optional body fields |
| --- | --- | --- | --- |
| Image generation | `/api/external/v1/editor/images/generations` | `prompt` | `kind`, `style`, `model`, `aspectRatio`, `imageSize`, `size`, `referenceImageSrcs`, `projectId`, `assetFolderId`, `assetLabel`, `canvasCompletion`, `generationInputs` |
| Image edit/redraw | `/api/external/v1/editor/images/edits` | `prompt`, `sourceImageSrc` | `referenceImageSrcs`, `model`, `size`, `projectId`, `assetFolderId`, `assetLabel`, `sourceResourceId`, `targetLayerId`, `canvasCompletion` |
| Icon spritesheet | `/api/external/v1/editor/icon-spritesheets/generations` | `referenceImageSrc`, `iconDescriptions` | `style`, `referenceImageSrcs`, `screenColor`, `model`, `aspectRatio`, `imageSize`, `projectId`, `assetFolderId`, `assetLabel`, `canvasCompletion` |
| UI asset extraction | `/api/external/v1/editor/ui-designs/assets/extractions` | `sourceImageSrc`, `aspectRatio`, `imageSize` | `screenColor`, `model`, `referenceImageSrcs`, `projectId`, `assetFolderId`, `spritesheetLabel`, `canvasCompletion` |
| Character animation | `/api/external/v1/editor/character-animations/generations` | `sourceLayerId`, `sourceImageSrc`, `sourceWidth`, `sourceHeight`, `promptText`, `resolution`, `ratio`, `frameCount`, `durationSeconds`, `model` | `projectId`, `sourceResourceId`, `assetFolderId`, `assetLabel`, `canvasCompletion` |
| Video generation | `/api/external/v1/editor/videos/generations` | `prompt`, `model`, `aspectRatio`, `durationSeconds`, `resolution`, `mode`, `sound` | `referenceImageSrcs`, `referenceVideoSrcs`, `referenceAudioSrcs`, `webSearchEnabled`, `projectId`, `assetFolderId`, `assetLabel`, `canvasCompletion` |
| Sound effect | `/api/external/v1/editor/audios/sound-effects/generations` | `prompt`, `duration` | `model`, `projectId`, `assetFolderId`, `assetLabel`, `canvasCompletion`, `generationInputs` |
| Background music | `/api/external/v1/editor/audios/background-music/generations` | `gptDescriptionPrompt`, `makeInstrumental` | `projectId`, `assetFolderId`, `assetLabel`, `canvasCompletion`, `generationInputs` |
Poll all eight through:
```text
GET /api/external/v1/generations/{operationId}
```
Supply the `operationId` returned by submission. Poll no faster than `pollAfterMs` and retain the ID after a caller-side timeout.
## Canvas and Library Field Rules
- Pass `projectId` and `canvasCompletion` to write generated output into the canvas.
- Pass `assetFolderId` plus `assetLabel` for image, edit, icon spritesheet, video, sound effect, and BGM operations when supported.
- UI extraction uses `assetFolderId` and `spritesheetLabel`.
- Character animation accepts `assetFolderId` and `assetLabel`. Its completed compact result directly returns the final `assetKind="character-animation"` resource and asset with `imageSequenceFrames` and `imageSequenceDurationMs`; never create a duplicate first-frame resource or asset.
- If a caller must manually create a `character-animation` resource or asset, put the authoritative frames and total sequence duration in `imageSequenceFrames` and `imageSequenceDurationMs`. Keep `generationInputs` replayable: it must not contain legacy runtime fields such as `characterAnimation`, `frames`, `previewVideoPath`, `frameCount`, `fps`, or `durationSeconds`.
- Reload project/library state after completion when full current state is required.
## Reference Field Mapping
After confirming a local upload, pass its stable `objectKey` into:
| Target capability | Field |
| --- | --- |
| Image generation | `referenceImageSrcs` |
| Image edit/redraw | `sourceImageSrc`; additional references in `referenceImageSrcs` |
| Icon spritesheet | `referenceImageSrc`; additional style references in `referenceImageSrcs` |
| UI design extraction | `sourceImageSrc`; additional references in `referenceImageSrcs` |
| Character animation | `sourceImageSrc` |
| Video with image references | `referenceImageSrcs` |
Use video/audio reference arrays only with models that support them. Do not pass an expiring signed read URL as a generation reference.
## Common Values
Use OpenAPI as the final authority; these common values are a routing aid:
- Image `kind`: `spec`, `character`, `quick-edit`, `ui-design`, `publication-material`; ordinary image generation may omit it.
- Image `model`: `gpt-image-2`, `gemini-3.1-flash-image-preview`, `nanobanana2`, `nano-banana`.
- Image `aspectRatio`: `1:1`, `2:3`, `3:2`, `9:16`, `16:9`.
- Image `imageSize`: `0.5K`, `1K`, `2K`.
- Video `model`: `seedance2.0`, `seedance2.0-fast`, `kling3.0`, `kling3.0-omni`, `veo3.1`, `veo3.1-fast`.
- Video `aspectRatio`: `16:9`, `9:16`, `1:1`, `4:3`, `3:4`, `21:9`.
- Video `resolution`: `480p`, `720p`, `1080p`; `mode`: `std`; `sound`: `on` or `off`.
- Character animation uses `model: "seedance2.0-fast"`; `resolution`: `480p` or `720p`; `frameCount`: `32`, `40`, or `48`; `durationSeconds`: `4`, `5`, or `6`; `ratio`: `same`, `1:1`, `4:3`, `16:9`, `9:16`, or `3:4`.
- UI extraction uses `aspectRatio: "1:1"`; use `imageSize: "1K"` for normal/small extraction and `2K` for dense designs.
Do not hard-code this list as a replacement client schema. In particular, the top-level image `style` field is intentionally extensible; see `requests-and-outputs.md` for its fallback behavior.
@@ -1,202 +0,0 @@
# External Editor API Routing
Source of truth: `docs/openapi/genarrative-external-v1.openapi.json`.
## Base
- Fixed base URL: `https://www.genarrative.world/`.
- Public contract: `GET /api/external/v1/openapi.json`.
- Authenticated calls: `Authorization: Bearer <tnr_sk_...>`.
- Default credentials file: `~/.config/genarrative/external-editor-api.json` with an `apiKey` string.
- Generation clients should allow long-running responses. Use at least 420 seconds for character animation and video; 70 seconds is too short for animation.
## Canvas Session and Art Spec
At the start of a new conversation, ask for a canvas name before the first generation call unless the user already supplied `projectId` and `assetFolderId`. Create or reuse:
1. `POST /api/external/v1/editor/projects` with `title` = canvas name.
2. `GET /api/external/v1/editor/assets/library`; if no folder has the same label, `POST /api/external/v1/editor/assets/folders` with `label` = canvas name.
3. Keep `canvasName`, `projectId`, `assetFolderId`, and the current art spec in conversation state.
Before generating art assets, normalize the user's request into a current art spec with `assetType`, `subject`, `style`, `palette`, `composition`, `format`, `constraints`, and `references`. Ask follow-up questions only for missing fields that block the selected endpoint. Reuse the current spec automatically when the user asks for another asset without changing style/spec requirements. Put the spec in `generationInputs.artSpec` and summarize it in the prompt when useful.
## Intent Routing
Infer the endpoint from the user's description. Do not present this as a menu unless the request is genuinely ambiguous.
| User says | Route |
| --- | --- |
| "生成图片", "生图", "做一张背景/角色/宣发图" | `POST /api/external/v1/editor/images/generations` |
| "重绘", "调整这张图", "基于这张图修改" | `POST /api/external/v1/editor/images/edits` |
| "用这张参考图", "参考本地图片生成", "基于本地图做图" | Upload local image first, then pass returned `objectKey` into the generation/edit reference field |
| "按规范图生成图标", "拆图标" | `POST /api/external/v1/editor/icon-spritesheets/generations` |
| "从 UI 设计图提取素材" | `POST /api/external/v1/editor/ui-designs/assets/extractions` |
| "让角色动起来", "生成角色动画帧" | `POST /api/external/v1/editor/character-animations/generations` |
| "生成视频" | `POST /api/external/v1/editor/videos/generations` |
| "生成音效" | `POST /api/external/v1/editor/audios/sound-effects/generations` |
| "生成背景音乐/BGM" | `POST /api/external/v1/editor/audios/background-music/generations` |
| "上传本地素材/图片/音频/视频" | Upload flow: direct upload ticket -> OSS form upload -> object confirm |
| "保存画板布局" | `PATCH /api/external/v1/editor/projects/{projectId}/canvas` |
| "创建/读取/删除画板项目" | Project endpoints |
| "素材库/文件夹/素材记录" | Asset library endpoints |
| "读取私有素材/拿可访问链接" | `GET /api/external/v1/assets/read-url` |
Ask a follow-up only when two routes could both be correct and produce different artifacts, for example "处理这张图" without saying edit, extract UI assets, or use it as a reference for new generation.
## Endpoint Map
| User intent | Endpoint | Minimum request |
| --- | --- | --- |
| Read contract | `GET /api/external/v1/openapi.json` | No auth required |
| List projects | `GET /api/external/v1/editor/projects` | API Key |
| Create project | `POST /api/external/v1/editor/projects` | Optional `title` |
| Load recent project | `GET /api/external/v1/editor/projects/recent` | API Key |
| Get/delete project | `GET` or `DELETE /api/external/v1/editor/projects/{projectId}` | `projectId` |
| Rename project | `PATCH /api/external/v1/editor/projects/{projectId}/metadata` | `title` |
| Save canvas layout | `PATCH /api/external/v1/editor/projects/{projectId}/canvas` | `viewport`, `layers` |
| Add project resource | `POST /api/external/v1/editor/projects/{projectId}/resources` | `imageSrc`, `width`, `height`, `sourceType` |
| Create upload ticket | `POST /api/external/v1/assets/direct-upload-tickets` | `legacyPrefix`, `fileName` |
| Confirm uploaded object | `POST /api/external/v1/assets/objects/confirm` | `objectKey`, `assetKind` |
| Get signed read URL | `GET /api/external/v1/assets/read-url` | `objectKey` or `legacyPublicPath` |
| Read asset library | `GET /api/external/v1/editor/assets/library` | API Key |
| Create/update/delete folder | `POST /api/external/v1/editor/assets/folders`, `PATCH`/`DELETE /api/external/v1/editor/assets/folders/{folderId}` | create: `label`; update: `label` or `collapsed` |
| Create asset record | `POST /api/external/v1/editor/assets` | `folderId`, `label`, `imageSrc`, `width`, `height`, `sourceType` |
| Update/delete asset | `PATCH`/`DELETE /api/external/v1/editor/assets/{assetId}` | update: `label` or `folderId` |
## Generation Endpoints
| User intent | Endpoint | Required fields | Common optional fields |
| --- | --- | --- | --- |
| Generate image/spec/character/UI/publication material | `POST /api/external/v1/editor/images/generations` | `prompt` | `kind`, `model`, `aspectRatio`, `imageSize`, `size`, `referenceImageSrcs`, `projectId`, `assetFolderId`, `assetLabel`, `canvasCompletion`, `generationInputs` |
| Edit/redraw image | `POST /api/external/v1/editor/images/edits` | `prompt`, `sourceImageSrc` | `referenceImageSrcs`, `model`, `size`, `projectId`, `assetFolderId`, `assetLabel`, `sourceResourceId`, `targetLayerId`, `canvasCompletion` |
| Generate icon spritesheet | `POST /api/external/v1/editor/icon-spritesheets/generations` | `referenceImageSrc`, `iconDescriptions` | `referenceImageSrcs`, `model`, `aspectRatio`, `imageSize`, `projectId`, `assetFolderId`, `canvasCompletion` |
| Extract assets from UI design | `POST /api/external/v1/editor/ui-designs/assets/extractions` | `sourceImageSrc`, `aspectRatio`, `imageSize` | `model`, `referenceImageSrcs`, `projectId`, `assetFolderId`, `spritesheetLabel`, `canvasCompletion` |
| Generate character animation | `POST /api/external/v1/editor/character-animations/generations` | `sourceLayerId`, `sourceImageSrc`, `sourceWidth`, `sourceHeight`, `promptText`, `resolution`, `ratio`, `frameCount`, `durationSeconds`, `model` | `projectId`, `sourceResourceId`, `canvasCompletion`; then create a library asset from the first returned frame |
| Generate video | `POST /api/external/v1/editor/videos/generations` | `prompt`, `model`, `aspectRatio`, `durationSeconds`, `resolution`, `mode`, `sound` | `referenceImageSrcs`, `referenceVideoSrcs`, `referenceAudioSrcs`, `webSearchEnabled`, `projectId`, `assetFolderId`, `assetLabel`, `canvasCompletion` |
| Generate sound effect | `POST /api/external/v1/editor/audios/sound-effects/generations` | `prompt`, `duration` | `model`, `projectId`, `assetFolderId`, `assetLabel`, `canvasCompletion`, `generationInputs` |
| Generate background music | `POST /api/external/v1/editor/audios/background-music/generations` | `gptDescriptionPrompt`, `makeInstrumental` | `projectId`, `assetFolderId`, `assetLabel`, `canvasCompletion`, `generationInputs` |
All generation requests should be placed into both the current canvas and its same-name asset-library folder. For endpoints that support `assetLabel`, pass it. For UI extraction, use `spritesheetLabel`. For icon spritesheet, the folder is enough. For character animation, the endpoint does not return `asset`; after success call `POST /api/external/v1/editor/assets` using the first returned frame as `imageSrc`, the session `assetFolderId`, and `assetKind: "character-animation"`.
## HTTP 2xx Warning Handling
Character image generation (including character redraw through `kind: "character"`), icon spritesheet generation, and UI asset extraction may return HTTP 2xx while carrying a structured `warning`; completion does not imply that all post-processed derivatives exist.
- Consume the returned `project` and media snapshots as authoritative: character responses use `resource` / `asset`, while icon spritesheet and UI extraction responses use `spritesheetResource` / `spritesheetAsset`. `warning.code: "postprocess-failed-source-preserved"` means the saved provider source is the main result. Character output has no transparent derivative, while icon spritesheet and UI extraction have no transparent spritesheet and no slices. Display `warning.reason` directly; do not construct missing assets or retry the provider generation from scratch.
- `sliceWarning` is only for a transparent spritesheet that was created successfully but could not be split automatically. Use the complete transparent spritesheet and preserve `sliceWarning.reason` as the original diagnostic; it is not a post-processing/source-preserved warning.
- The service contract keeps `warning` and `sliceWarning` mutually exclusive. If a malformed response contains both, prioritize the general `warning` over `sliceWarning` defensively.
## Reference Image Upload
If the user provides a local file as a reference image, run upload before the generation request:
1. `POST /api/external/v1/assets/direct-upload-tickets`.
Use `legacyPrefix: "generated-character-drafts"`, `pathSegments: ["editor", "external-editor-references"]`, original `fileName`, detected image `contentType`, and `access: "private"`.
2. Upload the file to the returned OSS form endpoint with all returned `formFields`.
3. `POST /api/external/v1/assets/objects/confirm` with returned `objectKey`, detected `contentType`, `contentLength` if known, `assetKind: "editor_reference_image"`, and `accessPolicy: "private"`.
4. Use the returned `objectKey` in the actual editor request.
OSS form upload uses `upload.host` and every non-null `upload.formFields` entry, then the file part named `file`. Default responses expose `upload`; envelope responses expose `data.upload`. Save the upload ticket response as `ticket.json`:
```bash
node - <<'NODE' ticket.json /path/to/reference.png
const fs = require('fs');
const path = require('path');
(async () => {
const body = JSON.parse(fs.readFileSync(process.argv[2], 'utf8'));
const ticket = body.upload || body.data?.upload;
if (!ticket) throw new Error('Upload ticket response missing upload payload');
const filePath = process.argv[3];
const form = new FormData();
for (const [key, value] of Object.entries(ticket.formFields)) {
if (value != null) form.append(key, value);
}
const bytes = fs.readFileSync(filePath);
form.append(
'file',
new Blob([bytes], { type: ticket.contentType || 'application/octet-stream' }),
path.basename(filePath),
);
const response = await fetch(ticket.host, { method: 'POST', body: form });
if (!response.ok) {
throw new Error(`OSS upload failed: ${response.status} ${await response.text()}`);
}
})().catch((error) => {
console.error(error.message);
process.exit(1);
});
NODE
```
Field mapping after upload:
| Target API | Put uploaded `objectKey` in |
| --- | --- |
| Image generation | `referenceImageSrcs` |
| Image edit/redraw | `sourceImageSrc`; additional references in `referenceImageSrcs` |
| Icon spritesheet | `referenceImageSrc`; additional style refs in `referenceImageSrcs` |
| UI design extraction | `sourceImageSrc`; additional refs in `referenceImageSrcs` |
| Character animation | `sourceImageSrc` |
| Video generation with image references | `referenceImageSrcs` |
Do not put the signed read URL into generation fields. Signed URLs are for user-visible preview/download; generation fields should use the stable `objectKey` for uploaded private references.
## Common Enums
- Image `kind`: `spec`, `character`, `quick-edit`, `ui-design`, `publication-material`.
- Image `model`: `gpt-image-2`, `gemini-3.1-flash-image-preview`, `nanobanana2`, `nano-banana`.
- Image `aspectRatio`: `1:1`, `2:3`, `3:2`, `9:16`, `16:9`.
- Image `imageSize`: `0.5K`, `1K`, `2K`.
- Video `model`: `seedance2.0`, `seedance2.0-fast`, `kling3.0`, `kling3.0-omni`, `veo3.1`, `veo3.1-fast`.
- Video `aspectRatio`: `16:9`, `9:16`, `1:1`, `4:3`, `3:4`, `21:9`.
- Video `resolution`: `480p`, `720p`, `1080p`.
- Video `mode`: always `std`.
- Video `sound`: `on`, `off`.
- Character animation `model`: always `seedance2.0-fast`.
- Character animation `resolution`: `480p`, `720p`; `frameCount`: `32`, `40`, `48`; `durationSeconds`: `4`, `5`, `6`; `ratio`: `same`, `1:1`, `4:3`, `16:9`, `9:16`, `3:4`.
## Local Reference Media Details
- `contentLength` in object confirm is a JSON number from local byte size, not a string.
- For character animation, use an existing project layer ID as `sourceLayerId` when available.
- If the source is only an uploaded local image, derive `sourceLayerId` from the file name, such as `external-reference-hero`, and keep it stable across retries.
- Read `sourceWidth` and `sourceHeight` from the local image. If dimensions cannot be read, ask instead of inventing dimensions.
- UI design extraction uses fixed `aspectRatio: "1:1"`; choose `imageSize: "1K"` for normal/small extractions and `2K` for dense designs.
- Video image/video/audio references are supported only by the Seedance 2.0 family; default referenced-media video requests to `model: "seedance2.0-fast"`, `mode: "std"`, and explicit `sound`.
- Image edit/redraw can pass `targetLayerId` with `projectId` to replace an existing canvas layer when no explicit `canvasCompletion` is supplied.
- Image, edit, video, sound effect, and BGM generation can pass `assetFolderId` and `assetLabel`; response `asset` is the created/updated library record.
- Icon spritesheet and UI extraction can pass `assetFolderId`; UI extraction can also pass `spritesheetLabel`.
## Canvas Completion
Use `canvasCompletion` for generation in this skill so the generated result is written back into the project canvas by the backend.
Required:
```json
{
"title": "素材名称",
"placeholder": {
"x": 0,
"y": 0,
"width": 512,
"height": 512,
"originalWidth": 512,
"originalHeight": 512
}
}
```
`dialogId` is optional. If the response includes `project`, `resource`, or `asset`, use those snapshots instead of reconstructing canvas/resource/library state locally.
## Upload Flow
For a local file that should become a project resource or library asset:
1. `POST /api/external/v1/assets/direct-upload-tickets` with `legacyPrefix`, `fileName`, and optional `contentType`, `access`, `maxSizeBytes`.
2. Submit the file to the returned OSS form endpoint with returned `formFields`.
3. `POST /api/external/v1/assets/objects/confirm` with returned `objectKey` and an `assetKind`.
4. Create a project resource or library asset with the confirmed `assetObjectId`/`objectKey`.
For reading private/generated assets, call `GET /api/external/v1/assets/read-url?objectKey=...` and use the returned `signedUrl`.
@@ -0,0 +1,146 @@
# Authentication and Safety
Read this reference before handling credentials, local files, private objects, uploads, retries, or logs.
## Contents
- [API Key Setup](#api-key-setup)
- [Idempotency and Unknown Outcomes](#idempotency-and-unknown-outcomes)
- [Local Reference Upload](#local-reference-upload)
- [Stable and Temporary Media References](#stable-and-temporary-media-references)
- [Logging and Command Safety](#logging-and-command-safety)
- [Scope and Retry Guardrails](#scope-and-retry-guardrails)
## API Key Setup
Authenticated calls use:
```text
Authorization: Bearer <tnr_sk_...>
```
Guide a logged-in user to create a key in the product UI under `开发者 API Key`. The raw key is shown only once. Never ask the user to paste it into chat.
Store it outside repositories in the user's private JSON file:
```text
~/.config/genarrative/external-editor-api.json
```
```json
{
"apiKey": "tnr_sk_..."
}
```
Set the file readable only by the current user where supported:
```bash
chmod 600 ~/.config/genarrative/external-editor-api.json
```
Use this fixed production base URL:
```text
https://www.genarrative.world/
```
Do not use environment variables as the default API Key storage for this integration. Generated clients must load the JSON file, fail clearly when it is absent or malformed, and redact credentials from errors and logs.
Smoke-test without printing the key:
```bash
api_key="$(node -e 'const fs=require("fs"); const p=process.argv[1]; const c=JSON.parse(fs.readFileSync(p,"utf8")); process.stdout.write(c.apiKey || "");' "$HOME/.config/genarrative/external-editor-api.json")"
curl -fsS "https://www.genarrative.world/api/external/v1/editor/projects" \
-H "Authorization: Bearer $api_key"
```
The OpenAPI document, integration manifest, raw Skill entry, and Skill archive are public. Hosted MCP and all project, asset, upload, generation, and generation-query operations require the Bearer API Key.
## Idempotency and Unknown Outcomes
For each logical generation:
1. Create one printable ASCII `Idempotency-Key` of 1-128 bytes.
2. Persist the key with the exact request body and returned `operationId`.
3. If submission transport fails or the response is lost, resend only the exact same body with the same key.
4. Never allocate a new key merely because the outcome is unknown.
5. On a polling timeout, retain `operationId` and query later. Do not submit another generation.
Treat a different body under the same key as invalid. Do not automatically replay a failed terminal generation unless the user intentionally requests a new logical generation.
## Local Reference Upload
Do not ask the user to convert local files to base64. Upload from the Agent/client machine:
1. Detect the original filename, MIME type, byte length, and image dimensions when relevant.
2. Create a ticket with `POST /api/external/v1/assets/direct-upload-tickets`.
3. POST all returned non-null `formFields` and the file part named `file` directly to `upload.host`.
4. Confirm the object with `POST /api/external/v1/assets/objects/confirm`.
5. Pass the confirmed stable `objectKey` to the selected editor operation.
For a private reference image, use a ticket body shaped like:
```json
{
"legacyPrefix": "generated-character-drafts",
"pathSegments": ["editor", "external-editor-references"],
"fileName": "<original-file-name>",
"contentType": "image/png",
"access": "private"
}
```
The default response exposes `upload`; an explicitly enveloped response exposes `data.upload`. Treat the returned host and form fields as opaque. Do not log the entire ticket or persist it longer than needed.
Confirm with the actual file metadata:
```json
{
"objectKey": "<upload.objectKey>",
"contentType": "image/png",
"contentLength": 12345,
"assetKind": "editor_reference_image",
"accessPolicy": "private"
}
```
`contentLength` is a JSON number in bytes, not a quoted string. Never invent `sourceWidth` or `sourceHeight`; read them from the local image or ask the user if they cannot be determined.
For character animation, reuse a real canvas layer ID when available. For a local-only source, derive a stable synthetic `sourceLayerId`, such as `external-reference-hero`, from the filename and keep it unchanged across retries.
The bundled helper implements ticket creation, a stdlib multipart upload, confirmation, dimension detection for common formats, and stable source-layer IDs:
```python
from genarrative_external_api import GenarrativeExternalClient
client = GenarrativeExternalClient()
reference = client.upload_reference_image("/path/to/reference.png")
print(reference["objectKey"])
```
Do not print the complete confirmation response if it may contain temporary access data. Prefer passing the returned `objectKey` directly to the next call.
## Stable and Temporary Media References
- Use `objectKey`, project resource ID, asset ID, or an allowed durable public URL for generation input.
- Use a Data URL only when the endpoint explicitly allows it and the caller has a deliberate reason; do not persist it as a durable output.
- Never use a Blob URL outside the browser process that created it.
- Use `GET /api/external/v1/assets/read-url` to obtain a short-lived `signedUrl` for display/download.
- Never store or feed an expiring signed URL back into generation when a stable `objectKey` exists.
## Logging and Command Safety
- Never place an API Key in repository files, generated projects, command arguments containing a literal key, docs, commits, screenshots, stack traces, test fixtures, or telemetry.
- Redact `Authorization`, API Key values, upload signatures, cookies, signed URL query strings, and private absolute paths from logs and user-visible errors.
- Do not print credentials while diagnosing JSON configuration. Report only presence/absence and safe validation errors.
- Do not commit the credentials file or copy it into the Skill archive.
- Do not expose provider diagnostics, worker leases, queue internals, or server filesystem paths returned by an unexpected error.
## Scope and Retry Guardrails
- Do not use account JWT/profile endpoints as the default external integration. Logged-in profile APIs may create/revoke developer keys, but they are outside this external editor contract.
- Do not call internal workers, queues, SpacetimeDB, or admin endpoints.
- Do not bypass upload confirmation or invent an object key.
- Do not retry post-processing locally by fabricating assets. Respect completed warning semantics from `requests-and-outputs.md`.
- Use bounded polling. A local wait budget ending does not cancel or fail the server operation.
@@ -0,0 +1,89 @@
# Capability Routing
Use this reference to translate user intent into a hosted MCP tool or its corresponding External v1 REST operation. Use `genarrative://external-editor/openapi` or `GET /api/external/v1/openapi.json` for exact schemas.
## Integration Surface
- Fixed production base URL: `https://www.genarrative.world/`.
- Discovery manifest: `GET /api/external/v1/agent-integration.json`.
- Hosted MCP: `/api/external/v1/mcp`, Streamable HTTP, authenticated with the same Bearer API Key as REST.
- Public contract: `GET /api/external/v1/openapi.json`.
- Skill fallback: `GET /api/external/v1/skill/SKILL.md` or `GET /api/external/v1/skill.zip`.
Prefer MCP when the Agent supports a remote endpoint plus a custom Bearer token. Prefer the complete Skill and Python helper when MCP is unavailable or a client-side local-file upload must be orchestrated. The MCP tool names are derived from OpenAPI `operationId` values in snake case; select by capability instead of memorizing the name.
## Canvas Session
Before the first generation in a new conversation, obtain a canvas name unless the user already supplied an existing `projectId` and `assetFolderId`.
1. List or create a project. When creating one, use the canvas name as `title`.
2. Read the asset library. Reuse a folder with the same label or create one with the canvas name.
3. Retain `canvasName`, `projectId`, `assetFolderId`, and the current art spec in conversation state.
Generated artifacts must enter both the current canvas and its same-name library folder whenever the endpoint supports that invariant. Pass `projectId`, `assetFolderId`, the endpoint's label field, and `canvasCompletion`. Character animation returns the final formal resource and asset directly; use those records and never create a duplicate from the first frame.
## Art Spec Routing
Before art generation, normalize the user's request into:
```json
{
"assetType": "character | background | prop | ui | icon | animation | video | audio",
"subject": "要生成的主体",
"style": "画风、材质、时代或参考风格",
"palette": "主色与禁用色",
"composition": "构图、镜头、姿态或布局",
"format": "比例、尺寸、分辨率、帧数或时长",
"constraints": "必须保留、禁止出现、透明或绿幕要求",
"references": ["objectKey、资源 ID 或本地文件说明"]
}
```
Infer what is already clear and ask only for missing fields that block the selected endpoint. Reuse the current spec unless the user changes style, subject family, palette, format, or constraints. Store structured context under `generationInputs.artSpec` where supported and summarize it in the prompt when useful.
## Intent Map
| User intent | MCP/REST capability |
| --- | --- |
| Generate a background, character, spec, UI mockup, or publication image | Image generation |
| Redraw, retouch, or replace an existing image | Image edit |
| Generate from a local reference | Upload and confirm the local file, then image generation or edit |
| Build a reusable transparent icon/game atlas from a visual spec | Icon spritesheet generation |
| Extract marked assets from an existing UI design | UI design asset extraction |
| Animate a character into frames | Character animation generation |
| Generate video | Video generation |
| Generate a sound effect | Sound-effect generation |
| Generate background music/BGM | Background-music generation |
| Upload a local image/audio/video asset | Upload ticket -> OSS form upload -> object confirm |
| Save viewport/layers | Canvas save |
| Create, load, rename, or delete a canvas | Project operations |
| Organize folders and asset records | Asset-library operations |
| Obtain temporary access to private media | Signed read URL |
| Check generation progress or retrieve its result | Generation query |
Do not present an API menu unless the request is genuinely ambiguous. Ask a follow-up when two routes create different artifacts, for example “处理这张图” could mean edit, extract marked UI assets, or use it as a reference for a new generation.
## Route-Specific Decisions
- Use image edit when the requested output replaces or modifies a source image. With `projectId`, pass `targetLayerId` to replace an existing layer when no explicit `canvasCompletion` is supplied.
- Use icon spritesheet generation for a transparent reusable atlas when a stable visual-spec reference and concrete `iconDescriptions` exist. Do not use ordinary image generation just because it can draw several objects.
- Use UI extraction only for an existing UI design image with red-box annotations. It is not UI generation.
- Use a project layer ID as character animation `sourceLayerId` when one exists. For a local-only source, derive a stable synthetic ID from the filename.
- For video with image/video/audio references, use a Seedance 2.0-family model; default to `seedance2.0-fast`, `mode: "std"`, and explicit `sound`.
- Use `signedUrl` only for preview/download. Feed stable `objectKey` or registered resource/asset identifiers into generation.
## AI Game Creator Canonical Visual DAG
Keep the existing autonomous-build task graph. Do not add a parallel task system or collapse these artifacts into one ordinary generation request:
1. `art-director` generates `assets/art-spec.png` with image generation, `kind: "spec"`, then registers it as `assetKind: "icon-spec"`. This image is the authoritative visual spec; `generationInputs.artSpec` is supporting structured context.
2. `design-foundation` generates `assets/ui-prototype.png` with `kind: "ui-design"`, using the registered art-spec resource ID in `referenceImageSrcs`.
3. `art-asset-plan` generates transparent `assets/art-spritesheet.png` through icon spritesheet generation, using the same registered art-spec resource ID as `referenceImageSrc` plus concrete `iconDescriptions`.
For a playable Canvas game, do not stop at generation. Make `code-prototype` depend on `art-asset-plan` and consume the persisted `iconImageSrcs` slices for core players, blocks or targets, scene obstacles, and feedback. For the four-category game-chat contract, require exactly four slices before registering the local runtime sheet; both fewer and extra components fail closed. Treat `art-spec.png` as reference-only. A full-sheet `<img>`, CSS background, path-only mention, guessed equal-grid crop, or code-drawn replacement for core entities is not runtime asset use. If slicing produces `sliceWarning`, keep the complete transparent sheet as a valid editor artifact, but fail the playable game asset gate until real slice files or verified atlas coordinates exist; never invent coordinates or replace the icon-spritesheet route with ordinary image generation.
Never use `assets/ui-prototype.png` as the spritesheet visual-spec reference. UI extraction is outside this canonical DAG.
## Scope Boundary
Stay within `/api/external/v1`. Do not invent worker, queue, runtime task-list, admin, profile, or SpacetimeDB calls. The only external generation query is `GET /api/external/v1/generations/{operationId}`.
@@ -0,0 +1,240 @@
# Requests and Outputs
Use this reference to build generation payloads, carry canvas/library context, poll asynchronous jobs, and interpret compact completed results. Verify exact schemas against `GET /api/external/v1/openapi.json`.
## Contents
- [Asynchronous Submission](#asynchronous-submission)
- [Polling State Machine](#polling-state-machine)
- [Canvas and Asset-Library Completion](#canvas-and-asset-library-completion)
- [Art Spec and Image Request](#art-spec-and-image-request)
- [Local Reference Requests](#local-reference-requests)
- [Compact Completed Result](#compact-completed-result)
- [Warning Semantics](#warning-semantics)
- [Output Handling Checklist](#output-handling-checklist)
## Asynchronous Submission
All eight generation POST routes require `Idempotency-Key` and return HTTP `202` with an `ExternalEditorGenerationSubmissionResponse` shaped like:
```json
{
"operationId": "task-...",
"kind": "editor_image_generation",
"status": "queued",
"statusUrl": "/api/external/v1/generations/task-...",
"pollAfterMs": 1500,
"updatedAtMicros": 1785456000000000
}
```
The response acknowledges durable submission only. It is never the completed media response.
Submit with one stable key per logical request:
```bash
api="https://www.genarrative.world"
credentials_file="$HOME/.config/genarrative/external-editor-api.json"
api_key="$(node -e 'const fs=require("fs"); const p=process.argv[1]; const c=JSON.parse(fs.readFileSync(p,"utf8")); process.stdout.write(c.apiKey || "");' "$credentials_file")"
idempotency_key="$(node -e 'process.stdout.write(require("node:crypto").randomUUID())')"
submission="$(curl -fsS "$api/api/external/v1/editor/images/generations" \
-H "Authorization: Bearer $api_key" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $idempotency_key" \
-d @request.json)"
operation_id="$(node -e 'const v=JSON.parse(process.argv[1]); process.stdout.write(v.operationId || v.data?.operationId || "")' "$submission")"
```
Persist the key, exact request body, and `operationId`. If submission outcome is uncertain, reuse the same body and key; do not submit a replacement key.
## Polling State Machine
Poll `statusUrl`, or `GET /api/external/v1/generations/{operationId}`, no faster than `pollAfterMs`:
- `queued` / `running`: retain `operationId`; show `phaseLabel`, `phaseDetail`, and `progress` when present; wait before querying again.
- `completed`: consume the compact `result` and all warning fields, then stop polling.
- `failed`: surface the safe `error`, stop polling, and do not infer provider or worker internals.
A caller-side timeout leaves the operation pending. Persist the ID for later query. Do not keep the original POST connection open and do not infer failure from a local wait budget.
The helper's convenience generation methods block only in the local process while sending short submit and status requests. Its default overall wait budget is 1800 seconds. For explicit orchestration:
```python
submission = client.submit_generation(
"/api/external/v1/editor/images/generations",
request_body,
idempotency_key=stable_key,
)
operation_id = submission["operationId"]
status = client.get_generation(operation_id)
completed = client.wait_for_generation(operation_id)
```
## Canvas and Asset-Library Completion
For endpoints that support these fields, include:
- `projectId`: target canvas project.
- `assetFolderId`: folder whose label matches the canvas name.
- `assetLabel` or UI extraction's `spritesheetLabel`: user-visible library label.
- `canvasCompletion`: backend canvas placement instructions.
A minimal `canvasCompletion` is:
```json
{
"title": "素材名称",
"placeholder": {
"x": 0,
"y": 0,
"width": 1024,
"height": 576,
"originalWidth": 1024,
"originalHeight": 576
}
}
```
`dialogId` is optional. Do not reconstruct canvas state from completion results. Reload the project and asset library when complete authoritative snapshots are needed.
Character animation accepts `assetFolderId` and `assetLabel` and persists the final transparent sequence directly. Its completed compact result includes the authoritative `assetKind="character-animation"` resource and asset with `imageSequenceFrames` and `imageSequenceDurationMs`. Use those records directly and never synthesize a duplicate asset from the first frame.
For the lower-level asset/resource creation endpoints, `generationInputs` is replayable request context rather than a media-runtime container. When `assetKind` is `character-animation`, the server rejects legacy runtime keys including `characterAnimation`, `frames`, `previewVideoPath`, `frameCount`, `fps`, and `durationSeconds`; send the formal sequence through `imageSequenceFrames` and `imageSequenceDurationMs`. Internal processing audit keys such as `screenColorHex`, `mattingProvider`, and `mattingModel` are removed before persistence.
## Art Spec and Image Request
Carry the current art spec in `generationInputs.artSpec` and reflect important constraints in the prompt:
```json
{
"prompt": "一张横版幻想森林背景,适合游戏主视觉,无文字",
"aspectRatio": "16:9",
"imageSize": "1K",
"projectId": "<projectId>",
"assetFolderId": "<assetFolderId>",
"assetLabel": "森林背景",
"generationInputs": {
"artSpec": {
"assetType": "background",
"subject": "幻想森林主视觉",
"style": "手绘游戏概念图",
"palette": "翡翠绿与金色光斑",
"composition": "横版,中心留出角色站位",
"format": "16:9, 1K",
"constraints": "无文字、无 UI 按钮",
"references": []
}
},
"canvasCompletion": {
"title": "森林背景",
"placeholder": {
"x": 0,
"y": 0,
"width": 1024,
"height": 576,
"originalWidth": 1024,
"originalHeight": 576
}
}
}
```
The top-level `style` field is not the art spec's visual-style prose. It appends a short server-side clause to the prompt sent to the provider and enables deterministic post-processing:
- Omitted, `null`, empty string, or `"none"`: no clause is appended and no post-processing runs, without warning.
- `"pixelArt"`: append one short pixel-art line to the end of the prompt sent to the provider, and enable pixel-art snapping, for ordinary image generation, `kind: "character"`, and icon spritesheet generation. The line is appended, not substituted — the rest of your prompt is unchanged. For the exact per-kind wording, read the `style` field description in the OpenAPI document; it is the contract, and this guide deliberately does not copy it.
- Unknown strings, or `"pixelArt"` on unsupported kinds such as `spec`, `quick-edit`, `ui-design`, or `publication-material`: continue without style processing and return `warning.code: "unsupported-image-style"`.
- Non-string JSON values: malformed request, HTTP `400`.
Keep this field extensible. Do not impose a closed client enum beyond the server contract.
## Local Reference Requests
Upload and confirm a local file before generation, then use the stable `objectKey`:
```python
client = GenarrativeExternalClient()
session = client.prepare_canvas_session("新画板")
reference = client.upload_reference_image("/path/to/reference.png")
client.generate_image(
"基于参考图生成一张 16:9 游戏背景",
canvasSession=session,
assetLabel="参考图背景",
aspectRatio="16:9",
imageSize="1K",
referenceImageSrcs=[reference["objectKey"]],
)
```
For character animation from a local-only source, use actual dimensions and a stable synthetic layer ID:
```json
{
"sourceLayerId": "external-reference-hero",
"sourceImageSrc": "<confirmed objectKey>",
"sourceWidth": 720,
"sourceHeight": 1280,
"promptText": "让角色自然呼吸并轻微转身",
"resolution": "720p",
"ratio": "9:16",
"frameCount": 40,
"durationSeconds": 5,
"model": "seedance2.0-fast",
"assetFolderId": "<assetFolderId>",
"assetLabel": "角色呼吸动画"
}
```
Do not guess dimensions or pass a temporary signed read URL. See `authentication-and-safety.md` for upload and credential rules.
## Compact Completed Result
The completed `result` may contain stable artifact fields such as:
- `objectKey`, media type, dimensions, or task ID.
- `resource`, `resourceId`, or equivalent canvas reference.
- `asset`, `assetId`, or equivalent library reference.
- `spritesheetResource`, `spritesheetAsset`, and stable spritesheet metadata.
- `warning` and `sliceWarning` structures.
It deliberately excludes a complete project/canvas/library snapshot, Data URL, Blob URL, expiring signed URL, worker lease, queue state, and internal provider diagnostics. Use `/assets/read-url` for temporary access to a stable `objectKey`.
## Warning Semantics
Interpret warnings only after the query reaches `status=completed`. The query-level `warning` is display-ready text. Compact `result.warning` and `result.sliceWarning` preserve structured artifact semantics.
### Source-preserved post-processing failure
When `result.warning.code` is `postprocess-failed-source-preserved`:
- Treat the saved provider source as the authoritative main result.
- For character output, do not claim a transparent derivative.
- For icon spritesheet or UI extraction, do not claim a transparent spritesheet or individual slices.
- Display the safe reason.
- Do not fabricate derivatives or restart generation automatically.
Use `resource` / `asset` for character results and `spritesheetResource` / `spritesheetAsset` for icon/UI results, then reload authoritative project/library state.
### Slice failure after transparent-sheet success
`result.sliceWarning` means transparent spritesheet post-processing succeeded but automatic splitting failed:
- Continue using the complete transparent spritesheet.
- Do not claim individual slices.
- Display the slice reason.
### Coexisting warnings
`warning` and `sliceWarning` are mutually exclusive only for `postprocess-failed-source-preserved`, because that path never reaches slicing. A general warning from unsupported style normalization or pixel-art snapping can coexist with `sliceWarning`. Render both reasons.
Before registering a requested transparent deliverable, verify the full sheet actually contains transparency. If source-preserved warning is present, do not register the opaque provider source as the requested transparent atlas. If only `sliceWarning` is present, the transparent full sheet remains valid.
## Output Handling Checklist
1. Require terminal `completed` before consuming artifacts.
2. Preserve stable IDs and `objectKey` values.
3. Surface all warning channels without downgrading completion to failure.
4. Avoid claiming absent transparent derivatives or slices.
5. Obtain temporary preview/download URLs only through `/assets/read-url`.
6. Reload authoritative project and library state when downstream logic needs complete records.
@@ -11,6 +11,7 @@ import re
import struct
import sys
import tempfile
import time
import urllib.error
import urllib.parse
import urllib.request
@@ -22,7 +23,7 @@ from typing import Any
BASE_URL = "https://www.genarrative.world/"
DEFAULT_CREDENTIALS_FILE = Path.home() / ".config/genarrative/external-editor-api.json"
DEFAULT_REQUEST_TIMEOUT_SECONDS = 60
GENERATION_REQUEST_TIMEOUT_SECONDS = 420
GENERATION_WAIT_TIMEOUT_SECONDS = 1800
class GenarrativeApiError(RuntimeError):
@@ -125,17 +126,18 @@ class GenarrativeExternalClient:
query: dict[str, Any] | None = None,
auth: bool = True,
timeout: int = DEFAULT_REQUEST_TIMEOUT_SECONDS,
headers: dict[str, str] | None = None,
) -> Any:
url = f"{self.base_url}{path}"
if query:
url = f"{url}?{urllib.parse.urlencode({k: v for k, v in query.items() if v is not None})}"
data = None if body is None else json.dumps(body).encode("utf-8")
headers = {"Accept": "application/json"}
request_headers = {"Accept": "application/json", **(headers or {})}
if data is not None:
headers["Content-Type"] = "application/json"
request_headers["Content-Type"] = "application/json"
if auth:
headers["Authorization"] = f"Bearer {self.api_key}"
request = urllib.request.Request(url, data=data, headers=headers, method=method.upper())
request_headers["Authorization"] = f"Bearer {self.api_key}"
request = urllib.request.Request(url, data=data, headers=request_headers, method=method.upper())
try:
with urllib.request.urlopen(request, timeout=timeout) as response:
payload = response.read()
@@ -270,11 +272,21 @@ class GenarrativeExternalClient:
fields[asset_label_field] = normalize_optional_text(asset_label) or "生成素材"
return fields
def save_canvas(self, project_id: str, viewport: dict[str, Any], layers: dict[str, Any]) -> Any:
def save_canvas(
self,
project_id: str,
viewport: dict[str, Any],
layers: dict[str, Any],
expected_revision: int,
) -> Any:
return self.request_json(
"PATCH",
f"/api/external/v1/editor/projects/{urllib.parse.quote(project_id, safe='')}/canvas",
{"viewport": viewport, "layers": layers},
{
"viewport": viewport,
"layers": layers,
"expectedRevision": expected_revision,
},
)
def _apply_art_spec(self, fields: dict[str, Any], prompt: str) -> str:
@@ -430,34 +442,153 @@ class GenarrativeExternalClient:
def read_url(self, object_key: str) -> Any:
return self.request_json("GET", "/api/external/v1/assets/read-url", query={"objectKey": object_key})
def submit_generation(
self,
path: str,
body: dict[str, Any],
idempotency_key: str | None = None,
) -> dict[str, Any]:
key = normalize_optional_text(idempotency_key) or str(uuid.uuid4())
submission = None
for attempt in range(2):
try:
submission = self.request_json(
"POST",
path,
body,
headers={"Idempotency-Key": key},
)
break
except (urllib.error.URLError, TimeoutError) as error:
if attempt == 0:
time.sleep(0.5)
continue
raise GenarrativeApiError(
"Generation submission transport outcome is unknown. "
f"Retry the same body with Idempotency-Key {key}; do not create a new key."
) from error
if not isinstance(submission, dict) or not normalize_optional_text(submission.get("operationId")):
raise GenarrativeApiError("Generation submission response missing operationId.")
submission.setdefault("idempotencyKey", key)
return submission
def get_generation(self, operation_id: str) -> dict[str, Any]:
result = self.request_json(
"GET",
f"/api/external/v1/generations/{urllib.parse.quote(operation_id, safe='')}",
)
if not isinstance(result, dict):
raise GenarrativeApiError("Generation status response must be an object.")
return result
def wait_for_generation(
self,
submission_or_operation_id: dict[str, Any] | str,
timeout_seconds: int = GENERATION_WAIT_TIMEOUT_SECONDS,
) -> dict[str, Any]:
operation_id = (
submission_or_operation_id.get("operationId")
if isinstance(submission_or_operation_id, dict)
else submission_or_operation_id
)
operation_id = normalize_optional_text(operation_id)
if not operation_id:
raise GenarrativeApiError("Generation operationId is required.")
deadline = time.monotonic() + max(1, timeout_seconds)
while True:
try:
job = self.get_generation(operation_id)
except GenarrativeApiError as error:
if any(f"HTTP {status}" in str(error) for status in (429, 502, 503, 504)):
if time.monotonic() >= deadline:
raise GenarrativeApiError(
f"Generation {operation_id} is still running; keep this operationId and continue polling."
) from error
time.sleep(1.5)
continue
raise
status = job.get("status")
if status == "completed":
result = job.get("result")
if not isinstance(result, dict):
raise GenarrativeApiError(
f"Generation {operation_id} completed without a result payload."
)
return result
if status == "failed":
raise GenarrativeApiError(
f"Generation {operation_id} failed: {job.get('error') or 'unknown error'}"
)
if time.monotonic() >= deadline:
raise GenarrativeApiError(
f"Generation {operation_id} is still running; keep this operationId and continue polling."
)
poll_after_ms = job.get("pollAfterMs", 1500)
if not isinstance(poll_after_ms, (int, float)):
poll_after_ms = 1500
time.sleep(max(0.25, min(float(poll_after_ms) / 1000.0, 5.0)))
def submit_and_wait_generation(
self,
path: str,
body: dict[str, Any],
idempotency_key: str | None = None,
timeout_seconds: int = GENERATION_WAIT_TIMEOUT_SECONDS,
) -> dict[str, Any]:
submission = self.submit_generation(path, body, idempotency_key=idempotency_key)
return self.wait_for_generation(submission, timeout_seconds=timeout_seconds)
def generate_image(self, prompt: str, **fields: Any) -> Any:
self._apply_canvas_session_fields(fields, prompt, 1024, 1024)
prompt = self._apply_art_spec(fields, prompt)
return self.request_json(
"POST",
idempotency_key = fields.pop("idempotencyKey", None)
return self.submit_and_wait_generation(
"/api/external/v1/editor/images/generations",
{"prompt": prompt, **fields},
timeout=GENERATION_REQUEST_TIMEOUT_SECONDS,
idempotency_key=idempotency_key,
)
def edit_image(self, prompt: str, source_image_src: str, **fields: Any) -> Any:
self._apply_canvas_session_fields(fields, prompt, 1024, 1024)
prompt = self._apply_art_spec(fields, prompt)
return self.request_json(
"POST",
idempotency_key = fields.pop("idempotencyKey", None)
return self.submit_and_wait_generation(
"/api/external/v1/editor/images/edits",
{"prompt": prompt, "sourceImageSrc": source_image_src, **fields},
timeout=GENERATION_REQUEST_TIMEOUT_SECONDS,
idempotency_key=idempotency_key,
)
def generate_icon_spritesheet(
self,
reference_image_src: str,
icon_descriptions: list[str],
**fields: Any,
) -> Any:
descriptions = [item.strip() for item in icon_descriptions if item.strip()]
if not descriptions:
raise GenarrativeApiError("icon_descriptions must contain at least one non-empty item")
label = fields.get("assetLabel", "图标图集")
self._apply_canvas_session_fields(fields, label, 1024, 1024)
fields.setdefault("screenColor", "auto")
idempotency_key = fields.pop("idempotencyKey", None)
return self.submit_and_wait_generation(
"/api/external/v1/editor/icon-spritesheets/generations",
{
"referenceImageSrc": reference_image_src,
"iconDescriptions": descriptions,
**fields,
},
idempotency_key=idempotency_key,
)
def extract_ui_assets(self, source_image_src: str, image_size: str = "1K", **fields: Any) -> Any:
fields.pop("aspectRatio", None)
self._apply_canvas_session_fields(fields, fields.get("spritesheetLabel", "UI 素材拆分"), 1024, 1024, "spritesheetLabel")
return self.request_json(
"POST",
idempotency_key = fields.pop("idempotencyKey", None)
return self.submit_and_wait_generation(
"/api/external/v1/editor/ui-designs/assets/extractions",
{"sourceImageSrc": source_image_src, "imageSize": image_size, **fields, "aspectRatio": "1:1"},
timeout=GENERATION_REQUEST_TIMEOUT_SECONDS,
idempotency_key=idempotency_key,
)
def animate_character(
@@ -469,16 +600,15 @@ class GenarrativeExternalClient:
source_layer_id: str,
**fields: Any,
) -> Any:
session, asset_label = self._apply_canvas_session_fields(
self._apply_canvas_session_fields(
fields,
fields.get("canvasTitle", "角色动画"),
source_width,
source_height,
asset_label_field=None,
asset_label_field="assetLabel",
)
prompt_text = self._apply_art_spec(fields, prompt_text)
fields.pop("assetFolderId", None)
fields.pop("assetLabel", None)
idempotency_key = fields.pop("idempotencyKey", None)
body = {
"sourceLayerId": source_layer_id,
"sourceImageSrc": source_image_src,
@@ -492,40 +622,17 @@ class GenarrativeExternalClient:
**fields,
"model": "seedance2.0-fast",
}
result = self.request_json(
"POST",
return self.submit_and_wait_generation(
"/api/external/v1/editor/character-animations/generations",
body,
timeout=GENERATION_REQUEST_TIMEOUT_SECONDS,
idempotency_key=idempotency_key,
)
if isinstance(session, dict) and isinstance(result, dict) and not result.get("asset"):
frames = result.get("frames")
first_frame = frames[0] if isinstance(frames, list) and frames else None
folder_id = normalize_optional_text(session.get("assetFolderId"))
if isinstance(first_frame, dict) and folder_id:
asset = self.create_asset(
folder_id,
asset_label,
first_frame["imageSrc"],
int(first_frame["width"]),
int(first_frame["height"]),
prompt=result.get("prompt"),
model=result.get("model"),
provider="ark",
taskId=result.get("taskId"),
assetKind="character-animation",
generationInputs={
"frames": frames,
"previewVideoPath": result.get("previewVideoPath"),
},
)
result["asset"] = unwrap_envelope(asset).get("asset")
return result
def generate_video(self, prompt: str, **fields: Any) -> Any:
fields.pop("mode", None)
self._apply_canvas_session_fields(fields, prompt, 1280, 720)
prompt = self._apply_art_spec(fields, prompt)
idempotency_key = fields.pop("idempotencyKey", None)
body = {
"prompt": prompt,
"model": fields.pop("model", "seedance2.0-fast"),
@@ -536,31 +643,30 @@ class GenarrativeExternalClient:
**fields,
"mode": "std",
}
return self.request_json(
"POST",
return self.submit_and_wait_generation(
"/api/external/v1/editor/videos/generations",
body,
timeout=GENERATION_REQUEST_TIMEOUT_SECONDS,
idempotency_key=idempotency_key,
)
def generate_sound_effect(self, prompt: str, duration: int, **fields: Any) -> Any:
self._apply_canvas_session_fields(fields, prompt, 360, 120)
prompt = self._apply_art_spec(fields, prompt)
return self.request_json(
"POST",
idempotency_key = fields.pop("idempotencyKey", None)
return self.submit_and_wait_generation(
"/api/external/v1/editor/audios/sound-effects/generations",
{"prompt": prompt, "duration": duration, **fields},
timeout=GENERATION_REQUEST_TIMEOUT_SECONDS,
idempotency_key=idempotency_key,
)
def generate_background_music(self, description: str, **fields: Any) -> Any:
self._apply_canvas_session_fields(fields, description, 360, 120)
description = self._apply_art_spec(fields, description)
return self.request_json(
"POST",
idempotency_key = fields.pop("idempotencyKey", None)
return self.submit_and_wait_generation(
"/api/external/v1/editor/audios/background-music/generations",
{"gptDescriptionPrompt": description, **fields, "makeInstrumental": True},
timeout=GENERATION_REQUEST_TIMEOUT_SECONDS,
idempotency_key=idempotency_key,
)
@@ -592,17 +698,46 @@ def _self_test() -> None:
query: dict[str, Any] | None = None,
auth: bool = True,
timeout: int = DEFAULT_REQUEST_TIMEOUT_SECONDS,
headers: dict[str, str] | None = None,
) -> Any:
calls.append({"method": method, "path": path, "body": body, "timeout": timeout})
if path == "/api/external/v1/editor/assets":
return {"asset": {"assetId": "editor-asset-demo"}}
return {
calls.append({
"method": method,
"path": path,
"body": body,
"timeout": timeout,
"headers": headers,
})
generated = {
"taskId": "task-demo",
"model": "seedance2.0-fast",
"prompt": "角色呼吸",
"previewVideoPath": "/generated/preview.mp4",
"frames": [{"frameIndex": 1, "imageSrc": "/generated/frame01.png", "width": 512, "height": 768}],
"frames": [{"imageSrc": "/generated/frame01.png", "width": 512, "height": 768}],
"resource": {
"resourceId": "editor-resource-demo",
"assetKind": "character-animation",
"sourceResourceId": "editor-resource-preview-demo",
"imageSequenceFrames": [
{"imageSrc": "/generated/frame01.png", "width": 512, "height": 768},
{"imageSrc": "/generated/frame02.png", "width": 512, "height": 768},
],
"imageSequenceDurationMs": 4000,
},
"asset": {
"assetId": "editor-asset-demo",
"assetKind": "character-animation",
"imageSequenceFrames": [
{"imageSrc": "/generated/frame01.png", "width": 512, "height": 768},
{"imageSrc": "/generated/frame02.png", "width": 512, "height": 768},
],
"imageSequenceDurationMs": 4000,
},
}
if method == "POST":
return {"operationId": "task-operation-demo", "status": "queued", "pollAfterMs": 1}
if path == "/api/external/v1/generations/task-operation-demo":
return {"operationId": "task-operation-demo", "status": "completed", "result": generated}
return generated
client.request_json = fake_request_json # type: ignore[method-assign]
result = client.animate_character(
@@ -614,11 +749,29 @@ def _self_test() -> None:
canvasSession=session,
canvasTitle="角色呼吸动画",
)
assert calls[0]["timeout"] == GENERATION_REQUEST_TIMEOUT_SECONDS
assert calls[0]["timeout"] == DEFAULT_REQUEST_TIMEOUT_SECONDS
assert calls[0]["headers"]["Idempotency-Key"]
assert calls[0]["body"]["projectId"] == "proj-demo"
assert calls[0]["body"]["assetFolderId"] == "editor-asset-folder-demo"
assert calls[0]["body"]["assetLabel"] == "角色呼吸动画"
assert calls[0]["body"]["canvasCompletion"]["title"] == "角色呼吸动画"
assert calls[1]["path"] == "/api/external/v1/editor/assets"
assert calls[1]["path"] == "/api/external/v1/generations/task-operation-demo"
assert result["asset"]["assetId"] == "editor-asset-demo"
assert result["asset"]["assetKind"] == "character-animation"
assert len(result["asset"]["imageSequenceFrames"]) == 2
assert result["asset"]["imageSequenceDurationMs"] == 4000
calls.clear()
client.generate_icon_spritesheet(
"editor-resource-spec",
["蛇头向上", "蛇身直线", "转角", "尾部", "四类食物"],
canvasSession=session,
assetLabel="贪吃蛇透明图集",
)
assert calls[0]["path"] == "/api/external/v1/editor/icon-spritesheets/generations"
assert calls[0]["body"]["referenceImageSrc"] == "editor-resource-spec"
assert calls[0]["body"]["screenColor"] == "auto"
assert calls[0]["body"]["iconDescriptions"][0] == "蛇头向上"
assert calls[1]["path"] == "/api/external/v1/generations/task-operation-demo"
print("self-test ok")
+50 -6
View File
@@ -67,7 +67,7 @@ jobs:
echo "SPACETIME_SCHEMA_BASE_REF=${base_ref}" >> "${GITHUB_ENV}"
- name: Install npm dependencies
run: npm ci
run: bash scripts/ci-npm-ci-with-retry.sh
- name: Run repository lint gates
run: npm run lint
@@ -101,7 +101,10 @@ jobs:
run: GENARRATIVE_GITEA_CI_CHECK_RUNTIME=1 bash scripts/check-gitea-ci-job-image.sh
- name: Install npm dependencies
run: npm ci
run: bash scripts/ci-npm-ci-with-retry.sh
- name: Install AI game creator dependencies
run: bash scripts/ci-npm-ci-with-retry.sh --prefix apps/ai-game-creator-shell
- name: Run frontend and script tests
run: npm run test
@@ -156,7 +159,24 @@ jobs:
echo "SPACETIME_SCHEMA_BASE_REF=${base_ref}" >> "${GITHUB_ENV}"
- name: Install npm dependencies
run: npm ci
run: bash scripts/ci-npm-ci-with-retry.sh
- name: Prepare server-rs Rust dependencies
shell: bash
run: |
set -euo pipefail
for attempt in $(seq 1 5); do
if cargo fetch --locked \
--target x86_64-unknown-linux-gnu \
--manifest-path server-rs/Cargo.toml; then
break
fi
if [[ "${attempt}" -eq 5 ]]; then
echo 'server-rs Cargo dependency fetch failed after 5 attempts.' >&2
exit 1
fi
sleep $((attempt * 2))
done
- name: Check server-rs boundaries
run: npm run check:server-rs-ddd
@@ -184,10 +204,34 @@ jobs:
run: GENARRATIVE_GITEA_CI_CHECK_RUNTIME=1 bash scripts/check-gitea-ci-job-image.sh
- name: Install npm dependencies
run: npm ci
run: bash scripts/ci-npm-ci-with-retry.sh
- name: Install AI game creator dependencies
run: bash scripts/ci-npm-ci-with-retry.sh --prefix apps/ai-game-creator-shell
- name: Prepare native Rust dependencies
shell: bash
run: |
set -euo pipefail
for manifest_path in \
apps/desktop-shell/src-tauri/Cargo.toml \
apps/ai-game-creator-shell/src-tauri/Cargo.toml; do
for attempt in $(seq 1 5); do
if cargo fetch --locked \
--target x86_64-unknown-linux-gnu \
--manifest-path "${manifest_path}"; then
break
fi
if [[ "${attempt}" -eq 5 ]]; then
echo "Cargo dependency fetch failed after 5 attempts: ${manifest_path}" >&2
exit 1
fi
sleep $((attempt * 2))
done
done
- name: Run native shell gates
run: npm run check:native-shells
- name: Ensure native lockfile is unchanged
run: git diff --exit-code -- apps/desktop-shell/src-tauri/Cargo.lock
- name: Ensure native lockfiles are unchanged
run: git diff --exit-code -- apps/desktop-shell/src-tauri/Cargo.lock apps/ai-game-creator-shell/src-tauri/Cargo.lock
+7
View File
@@ -31,6 +31,12 @@ temp*build*/
/apps/desktop-shell/src-tauri/target/
/apps/desktop-shell/src-tauri/gen/
/apps/desktop-shell/src-tauri/permissions/autogenerated/
/apps/ai-game-creator-shell/src-tauri/target/
/apps/ai-game-creator-shell/src-tauri/gen/
/apps/ai-game-creator-shell/src-tauri/logs/
/apps/ai-game-creator-shell/logs/
/apps/ai-game-creator-shell/.llm-drafts/
/apps/ai-game-creator-shell/game-creator.config.local.json
/apps/mobile-shell/.expo/
/apps/mobile-shell/.expo-export-smoke/
/server-rs/.spacetimedb/
@@ -47,6 +53,7 @@ temp*build*/
/.playwright-cli/
**/.playwright-cli/
/output/playwright/
/output/external-api-smoke/
/server-rs/crates/*/logs/
.worktrees/
.rag/
+2
View File
@@ -33,6 +33,7 @@
- Issue 使用自托管 Gitea;优先用 Gitea UI/API 或 `tea` CLI,不使用 GitHub `gh` 或 GitLab `glab`,除非仓库已迁移。默认 triage 标签:`needs-triage``needs-info``ready-for-agent``ready-for-human``wontfix`
- 需要仓库级 Hermes skills/plugins 时,再读取 [`.hermes/README.md`](.hermes/README.md)。
- 涉及 AI 游戏创作独立 App、多智能体 Runtime、本地项目产物或本地 HTTP 预览时,先读取 [`docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md`](docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md)。
- 新增、补齐、迁移或重构玩法入口、玩法类型、创作工作台、生成页、结果页、发布、运行态、作品架、广场或公开 read model 前,必须读取并按 [`genarrative-play-type-integration`](.codex/skills/genarrative-play-type-integration/SKILL.md) 执行。
- 涉及 `npm run dev` / `npm run dev:spacetime` / `npm run dev:api-server` / `npm run dev:web` / `npm run dev:admin-web` 的端口探测、端口漂移、SpacetimeDB publish server、api-server 环境变量、Vite 代理目标或后台 dev 端口时,按 [`.hermes/skills/genarrative-dev-stack-port-routing/SKILL.md`](.hermes/skills/genarrative-dev-stack-port-routing/SKILL.md) 执行。
- 涉及 SpacetimeDB 的设计、实现、脚本、调试、发布、绑定生成、schema、reducer、procedure、view 或 Rust API 时,必须读取并按 [`spacetimedb-cli`](.codex/skills/spacetimedb-cli/SKILL.md)、[`spacetimedb-rust`](.codex/skills/spacetimedb-rust/SKILL.md)、[`spacetimedb-concepts`](.codex/skills/spacetimedb-concepts/SKILL.md) 中相关 skill 执行。
@@ -44,6 +45,7 @@
- DDD 分层边界按总纲执行:领域规则沉到 `module-*`SpacetimeDB 表和事务编排留在 `spacetime-module`,后端访问 SpacetimeDB 统一经 `spacetime-client` facadeHTTP/SSE/BFF 留在 `api-server`,外部副作用留在 `platform-*`,前后端 DTO 留在 `shared-contracts`
- 前端只做表现、交互和临时 UI 状态,不承接正式业务真相,不绕过后端投影或后端 API 直接实现业务规则。
- 契约、路由、DTO 去留和 breaking change 以当前后端架构文档、`server-rs/crates/api-server/src/app.rs``shared-contracts``packages/shared` 为准;不得在前端、`api-server` 或临时兼容层中重新发明旧接口。
- 凡修改 `/api/external/v1` 的路由、HTTP 方法、请求 / 响应 DTO、请求头、状态码、鉴权或异步语义,必须在同一次变更中同步更新权威契约 [`docs/openapi/genarrative-external-v1.openapi.json`](docs/openapi/genarrative-external-v1.openapi.json) 及对应契约测试;Rust 实现与 OpenAPI 未保持一致时任务不得视为完成。
- SpacetimeDB 已有表新增字段时,字段必须放在 Rust 表结构体最后,并设置明确默认值;需要删除、改名、重排或改类型时,必须先询问用户并确认迁移计划。
- 修改 SpacetimeDB schema 后必须同步 `migration.rs`、表目录和生成绑定,并运行 `npm run check:spacetime-schema`
- 除 CI/CD 脚本内部受控用法外,人工命令、本地联调、排障步骤和文档示例禁止继续使用 `spacetime --root-dir`
+4
View File
@@ -16,6 +16,10 @@ _Avoid_: 在玩法页面内手写上传、参考图、重绘、预览、删除
独立 `/editor` 中可保存、恢复和继续编辑的图片画布工作状态,包含画布视图、图层布局和资源引用;用于多图对比、生成结果衍生和画布级编辑,不替代玩法页面内的单图资产编辑。
_Avoid_: 玩法结果页单图槽位、发布态作品、只存在前端内存里的临时画布
**项目开发画布**:
GameAgent 独立客户端中某个本地游戏项目的开发工作区概念,用于承载项目名、路径、首条需求、附件导入结果、最近 run 状态,以及后续真正的项目开发画布与 Agent 协作界面;当前首页改造阶段先落占位页。它属于 AI 游戏创作本地项目域,不等同于 `/editor` 的图片画布工程。
_Avoid_: `/editor` 图片画布工程、画布资源 / 图层布局、启动器 / 主窗口切换概念、只用于首页输入的临时草稿
**画布Agent对话**:
图片画布工程右侧的对话式编辑器工具,用户通过自然语言调度画布已有的图片类生成与编辑能力(生成图片、生成角色形象、生成图标素材、生成 UI 设计图、基于附件的图片修改),并可附加画布素材或素材库图片作为参考;对话归属单个图片画布工程,可保存历史、新开会话和软删会话。属于画布域工具,不承接玩法创作、不产出玩法作品或模板,与「表单/图片输入创作工作台」的 Avoid 边界不冲突。
_Avoid_: 对话式玩法创作工作台、绕过模型定价收口的生成入口、把对话消息当作画布布局真相、复用拼图专用 creative-agent 内存会话
+68 -1
View File
@@ -6,17 +6,19 @@ import {
getAdminFeatureGateConfig,
getAdminUserDetail,
listAdminRechargeOrders,
reconcileAdminUserConsumption,
resolveAdminRechargeRefundManualReview,
updateAdminAccount,
uploadAdminEditorShowcaseCampaignImage,
upsertAdminFeatureGateConfig,
upsertProfileWalletConfig,
} from './adminApiClient';
afterEach(() => {
vi.unstubAllGlobals();
});
test('后台账号创建和更新携带 owner 会话与 Tab 权限', async () => {
test('后台账号创建和更新同时携带 Tab 与独立操作权限', async () => {
const fetchMock = vi.fn().mockImplementation(() =>
Promise.resolve(
new Response(JSON.stringify({ account: { accountId: 'member-1' } }), {
@@ -31,11 +33,13 @@ test('后台账号创建和更新携带 owner 会话与 Tab 权限', async () =>
displayName: '运营',
password: 'secret123',
tabPermissions: ['dashboard', 'tracking'],
actionPermissions: ['profile-wallet-consumption-reconcile'],
enabled: true,
});
await updateAdminAccount('owner-token', 'member/1', {
displayName: '运营二组',
tabPermissions: ['tracking'],
actionPermissions: [],
enabled: false,
});
@@ -44,6 +48,14 @@ test('后台账号创建和更新携带 owner 会话与 Tab 权限', async () =>
expect.objectContaining({
method: 'POST',
headers: expect.objectContaining({ Authorization: 'Bearer owner-token' }),
body: JSON.stringify({
username: 'operator',
displayName: '运营',
password: 'secret123',
tabPermissions: ['dashboard', 'tracking'],
actionPermissions: ['profile-wallet-consumption-reconcile'],
enabled: true,
}),
}),
);
expect(fetchMock.mock.calls[1]?.[0]).toBe('/admin/api/accounts/member%2F1');
@@ -53,12 +65,40 @@ test('后台账号创建和更新携带 owner 会话与 Tab 权限', async () =>
body: JSON.stringify({
displayName: '运营二组',
tabPermissions: ['tracking'],
actionPermissions: [],
enabled: false,
}),
}),
);
});
test('账号配置一次提交初始和每日免费泥点', async () => {
const fetchMock = vi.fn().mockResolvedValue(
new Response(JSON.stringify({configId: 'profile_wallet'}), {
status: 200,
headers: {'content-type': 'application/json'},
}),
);
vi.stubGlobal('fetch', fetchMock);
await upsertProfileWalletConfig('owner-token', {
initialMudPoints: 100,
dailyFreePointsPerDay: 35,
});
expect(fetchMock).toHaveBeenCalledWith(
'/admin/api/profile/wallet-config',
expect.objectContaining({
method: 'POST',
headers: expect.objectContaining({Authorization: 'Bearer owner-token'}),
body: JSON.stringify({
initialMudPoints: 100,
dailyFreePointsPerDay: 35,
}),
}),
);
});
test('灰度配置读写只使用通用 feature-gates 管理接口', async () => {
const fetchMock = vi.fn().mockImplementation(() =>
Promise.resolve(
@@ -238,6 +278,33 @@ test('用户详情只发送实际提供的用户定位字段', async () => {
});
});
test('历史花费手动对账使用独立管理员写接口', async () => {
const fetchMock = vi.fn().mockResolvedValue(
new Response(
JSON.stringify({
userId: 'user-1',
historicalConsumedPoints: 1300,
changed: true,
}),
{ status: 200 },
),
);
vi.stubGlobal('fetch', fetchMock);
await reconcileAdminUserConsumption('token-1', { userId: 'user-1' });
expect(String(fetchMock.mock.calls[0]?.[0])).toBe(
'/admin/api/profile/users/reconcile-consumption',
);
expect(fetchMock.mock.calls[0]?.[1]).toEqual(
expect.objectContaining({
method: 'POST',
headers: expect.objectContaining({ Authorization: 'Bearer token-1' }),
body: JSON.stringify({ userId: 'user-1' }),
}),
);
});
test('退款执行使用独立 execute 管理员路由', async () => {
const fetchMock = vi.fn().mockResolvedValue(
new Response(JSON.stringify({ outRefundNo: 'refund-1' }), {
+12
View File
@@ -48,6 +48,8 @@ import type {
AdminUpsertProfileRedeemCodeRequest,
AdminUpsertProfileTaskConfigRequest,
AdminUpsertProfileWalletConfigRequest,
AdminUserConsumptionReconcileRequest,
AdminUserConsumptionReconcileResponse,
AdminUserDetailQuery,
AdminUserDetailResponse,
AdminWalletRestrictionRequest,
@@ -577,6 +579,16 @@ export function getAdminUserDetail(token: string, query: AdminUserDetailQuery) {
);
}
export function reconcileAdminUserConsumption(
token: string,
payload: AdminUserConsumptionReconcileRequest,
) {
return request<AdminUserConsumptionReconcileResponse>(
'/admin/api/profile/users/reconcile-consumption',
{ method: 'POST', token, body: payload },
);
}
export function previewAdminRechargeRefund(
token: string,
payload: AdminRechargeRefundPreviewRequest,
+32
View File
@@ -38,6 +38,7 @@ export interface AdminSessionPayload {
roles: string[];
accountRole: 'owner' | 'member';
tabPermissions: string[];
actionPermissions: string[];
issuedAt: string;
expiresAt: string;
}
@@ -48,6 +49,7 @@ export interface AdminAccountPayload {
displayName: string;
accountRole: 'owner' | 'member';
tabPermissions: string[];
actionPermissions: string[];
enabled: boolean;
tokenVersion: number;
createdBy: string;
@@ -65,6 +67,7 @@ export interface AdminCreateAccountRequest {
displayName: string;
password: string;
tabPermissions: string[];
actionPermissions: string[];
enabled: boolean;
}
@@ -76,6 +79,7 @@ export interface AdminUpdateAccountRequest {
displayName: string;
password?: string;
tabPermissions: string[];
actionPermissions: string[];
enabled: boolean;
}
@@ -328,6 +332,14 @@ export interface AdminEditorAssetListQuery {
limit?: number | null;
}
export interface AdminEditorImageSequenceFramePayload {
imageSrc: string;
objectKey?: string | null;
assetObjectId?: string | null;
width: number;
height: number;
}
export interface AdminEditorAssetPayload {
assetId: string;
ownerUserId: string;
@@ -358,6 +370,8 @@ export interface AdminEditorAssetPayload {
taskGenerator: string;
taskCostMudPoints: number;
children: AdminEditorAssetPayload[];
imageSequenceFrames?: AdminEditorImageSequenceFramePayload[] | null;
imageSequenceDurationMs?: number | null;
}
export interface AdminEditorAssetListResponse {
@@ -409,6 +423,8 @@ export interface AdminEditorShowcaseAssetPayload {
rejectedAt?: string | null;
updatedAt: string;
showcaseCategory?: string | null;
imageSequenceFrames?: AdminEditorImageSequenceFramePayload[] | null;
imageSequenceDurationMs?: number | null;
}
export interface AdminEditorShowcaseListResponse {
@@ -556,6 +572,7 @@ export interface AdminUpsertProfileRechargeProductRequest {
export interface AdminUpsertProfileWalletConfigRequest {
initialMudPoints: number;
dailyFreePointsPerDay: number;
}
export interface ProfileRedeemCodeAdminResponse {
@@ -657,6 +674,7 @@ export interface ProfileRechargeProductConfigAdminListResponse {
export interface ProfileWalletConfigAdminResponse {
configId: string;
initialMudPoints: number;
dailyFreePointsPerDay: number;
createdBy: string;
createdByDisplayName: string;
createdAt: string;
@@ -819,10 +837,24 @@ export interface AdminUserDetailResponse {
bindingStatus: string;
phoneBound: boolean;
wechatBound: boolean;
historicalConsumedPoints: number;
canReconcileConsumption: boolean;
wallet: AdminProfileWalletPayload;
rechargeOrders: AdminRechargeOrderEntryPayload[];
}
export interface AdminUserConsumptionReconcileRequest {
userId: string;
}
export interface AdminUserConsumptionReconcileResponse {
userId: string;
previousHistoricalConsumedPoints?: number | null;
historicalConsumedPoints: number;
changed: boolean;
reconciledAtMicros: number;
}
export interface AdminRechargeRefundPreviewRequest {
orderId: string;
refundAmountCents: number;
@@ -0,0 +1,354 @@
/* @vitest-environment jsdom */
import { act, fireEvent, render, screen, within } from '@testing-library/react';
import { afterEach, expect, test, vi } from 'vitest';
import { getAdminAssetReadUrl } from '../api/adminApiClient';
import { AdminEditorAssetPreviewDialog } from './AdminEditorAssetMedia';
vi.mock('../api/adminApiClient', () => ({
getAdminAssetReadUrl: vi.fn(),
isAdminApiError: vi.fn(
(error: unknown) =>
typeof error === 'object' &&
error !== null &&
'status' in error &&
typeof error.status === 'number',
),
}));
afterEach(() => {
vi.clearAllMocks();
vi.useRealTimers();
});
function createDeferred<T>() {
let resolve!: (value: T | PromiseLike<T>) => void;
let reject!: (reason?: unknown) => void;
const promise = new Promise<T>((resolvePromise, rejectPromise) => {
resolve = resolvePromise;
reject = rejectPromise;
});
return { promise, resolve, reject };
}
test('角色动作预览跨窗口回播时复用父级换签缓存并等待目标帧就绪', async () => {
vi.useFakeTimers();
vi.setSystemTime(new Date('2026-07-04T10:50:00Z'));
const frameObjectKeys = [
'generated-animations/editor/task-cache/frame00.png',
'generated-animations/editor/task-cache/frame01.png',
'generated-animations/editor/task-cache/frame02.png',
'generated-animations/editor/task-cache/frame03.png',
'generated-animations/editor/task-cache/frame04.png',
] as const;
const delayedFrame = createDeferred<{
read: {
objectKey: string;
signedUrl: string;
expiresAt: string;
};
}>();
vi.mocked(getAdminAssetReadUrl).mockImplementation((_token, request) => {
const objectKey = request.objectKey ?? '';
if (objectKey === frameObjectKeys[3]) {
return delayedFrame.promise;
}
return Promise.resolve({
read: {
objectKey,
signedUrl: `https://signed.example.com/${objectKey}`,
expiresAt: '2026-07-04T11:00:00Z',
},
});
});
render(
<AdminEditorAssetPreviewDialog
entry={{
assetId: 'asset-character-animation-cache',
label: '缓存回播动作',
imageSrc: `/${frameObjectKeys[0]}`,
objectKey: frameObjectKeys[0],
assetKind: 'character-animation',
imageSequenceFrames: frameObjectKeys.map((objectKey) => ({
imageSrc: `/${objectKey}`,
objectKey,
width: 192,
height: 256,
})),
imageSequenceDurationMs: 500,
}}
token="admin-token"
onClose={vi.fn()}
/>,
);
const dialog = screen.getByRole('dialog', { name: '素材预览' });
fireEvent.click(within(dialog).getByRole('button', { name: '暂停角色动作' }));
await act(async () => {
await vi.advanceTimersByTimeAsync(120);
});
const initialFrames = Array.from(
dialog.querySelectorAll<HTMLImageElement>(
'.admin-asset-query-sequence-frame',
),
);
expect(initialFrames).toHaveLength(3);
initialFrames.forEach((frame) => fireEvent.load(frame));
fireEvent.click(within(dialog).getByRole('button', { name: '播放角色动作' }));
for (const elapsedMs of [100, 40, 60, 40, 60]) {
await act(async () => {
await vi.advanceTimersByTimeAsync(elapsedMs);
});
}
expect(getAdminAssetReadUrl).toHaveBeenCalledWith('admin-token', {
objectKey: frameObjectKeys[3],
expireSeconds: 300,
});
expect(resolveVisibleFrameSrc(dialog)).toBe(
`https://signed.example.com/${frameObjectKeys[2]}`,
);
await act(async () => {
delayedFrame.resolve({
read: {
objectKey: frameObjectKeys[3],
signedUrl: `https://signed.example.com/${frameObjectKeys[3]}`,
expiresAt: '2026-07-04T11:00:00Z',
},
});
await Promise.resolve();
});
const fourthFrame = resolveFrameByObjectKey(dialog, frameObjectKeys[3]);
expect(fourthFrame?.style.opacity).toBe('0');
expect(resolveVisibleFrameSrc(dialog)).toBe(
`https://signed.example.com/${frameObjectKeys[2]}`,
);
fireEvent.load(fourthFrame!);
fireEvent.load(resolveFrameByObjectKey(dialog, frameObjectKeys[4])!);
for (let index = 0; index < 3; index += 1) {
await act(async () => {
await vi.advanceTimersByTimeAsync(100);
});
}
expect(within(dialog).getByText('1/5')).toBeTruthy();
expect(resolveVisibleFrameSrc(dialog)).toBe(
`https://signed.example.com/${frameObjectKeys[0]}`,
);
expect(
vi
.mocked(getAdminAssetReadUrl)
.mock.calls.filter(
([, request]) => request.objectKey === frameObjectKeys[0],
),
).toHaveLength(1);
expect(
dialog.querySelectorAll('.admin-asset-query-sequence-frame').length,
).toBeLessThanOrEqual(3);
});
test('角色动作预览打开超过五分钟后回绕播放会在过期窗口内自动换签', async () => {
vi.useFakeTimers();
vi.setSystemTime(new Date('2099-01-01T00:00:00Z'));
const frameObjectKeys = Array.from(
{ length: 5 },
(_, index) => `generated-animations/editor/task-expiry/frame0${index}.png`,
);
const requestCounts = new Map<string, number>();
vi.mocked(getAdminAssetReadUrl).mockImplementation((_token, request) => {
const objectKey = request.objectKey ?? '';
const requestCount = (requestCounts.get(objectKey) ?? 0) + 1;
requestCounts.set(objectKey, requestCount);
return Promise.resolve({
read: {
objectKey,
signedUrl: `https://signed.example.com/v${requestCount}/${objectKey}`,
expiresAt:
requestCount === 1 ? '2099-01-01T00:05:00Z' : '2099-01-01T00:10:00Z',
},
});
});
render(
<AdminEditorAssetPreviewDialog
entry={{
assetId: 'asset-character-animation-expiry',
label: '过期换签动作',
imageSrc: `/${frameObjectKeys[0]}`,
objectKey: frameObjectKeys[0],
assetKind: 'character-animation',
imageSequenceFrames: frameObjectKeys.map((objectKey) => ({
imageSrc: `/${objectKey}`,
objectKey,
width: 192,
height: 256,
})),
imageSequenceDurationMs: 5_000,
}}
token="admin-token"
onClose={vi.fn()}
/>,
);
const dialog = screen.getByRole('dialog', { name: '素材预览' });
fireEvent.click(within(dialog).getByRole('button', { name: '暂停角色动作' }));
await act(async () => {
await vi.advanceTimersByTimeAsync(120);
});
loadMountedFrames(dialog);
for (let index = 0; index < frameObjectKeys.length; index += 1) {
fireEvent.click(
within(dialog).getByRole('button', { name: '播放角色动作' }),
);
await act(async () => {
await vi.advanceTimersByTimeAsync(1_000);
});
fireEvent.click(
within(dialog).getByRole('button', { name: '暂停角色动作' }),
);
await act(async () => {
await vi.advanceTimersByTimeAsync(120);
});
loadMountedFrames(dialog);
}
expect(within(dialog).getByText('1/5')).toBeTruthy();
frameObjectKeys.forEach((objectKey) => {
expect(requestCounts.get(objectKey)).toBe(1);
});
await act(async () => {
await vi.advanceTimersByTimeAsync(300_001);
});
loadMountedFrames(dialog);
expect(resolveVisibleFrameSrc(dialog)).toContain('/v2/');
for (let index = 0; index < frameObjectKeys.length; index += 1) {
fireEvent.click(
within(dialog).getByRole('button', { name: '播放角色动作' }),
);
await act(async () => {
await vi.advanceTimersByTimeAsync(1_000);
});
fireEvent.click(
within(dialog).getByRole('button', { name: '暂停角色动作' }),
);
await act(async () => {
await vi.advanceTimersByTimeAsync(120);
});
loadMountedFrames(dialog);
}
expect(within(dialog).getByText('1/5')).toBeTruthy();
expect(resolveVisibleFrameSrc(dialog)).toBe(
`https://signed.example.com/v2/${frameObjectKeys[0]}`,
);
frameObjectKeys.forEach((objectKey) => {
expect(requestCounts.get(objectKey)).toBe(2);
});
expect(within(dialog).queryByText(//u)).toBeNull();
});
test('角色动作预览提前换签失败时保留已就绪帧并有限重试', async () => {
vi.useFakeTimers();
vi.setSystemTime(new Date('2099-01-01T00:00:00Z'));
const frameObjectKeys = [
'generated-animations/editor/task-refresh-failure/frame00.png',
'generated-animations/editor/task-refresh-failure/frame01.png',
] as const;
const requestCounts = new Map<string, number>();
vi.mocked(getAdminAssetReadUrl).mockImplementation((_token, request) => {
const objectKey = request.objectKey ?? '';
const requestCount = (requestCounts.get(objectKey) ?? 0) + 1;
requestCounts.set(objectKey, requestCount);
if (objectKey === frameObjectKeys[0] && requestCount > 1) {
return Promise.reject(new Error('refresh unavailable'));
}
return Promise.resolve({
read: {
objectKey,
signedUrl: `https://signed.example.com/v${requestCount}/${objectKey}`,
expiresAt:
requestCount === 1 ? '2099-01-01T00:05:00Z' : '2099-01-01T00:10:00Z',
},
});
});
render(
<AdminEditorAssetPreviewDialog
entry={{
assetId: 'asset-character-animation-refresh-failure',
label: '换签失败动作',
imageSrc: `/${frameObjectKeys[0]}`,
objectKey: frameObjectKeys[0],
assetKind: 'character-animation',
imageSequenceFrames: frameObjectKeys.map((objectKey) => ({
imageSrc: `/${objectKey}`,
objectKey,
width: 192,
height: 256,
})),
imageSequenceDurationMs: 2_000,
}}
token="admin-token"
onClose={vi.fn()}
/>,
);
const dialog = screen.getByRole('dialog', { name: '素材预览' });
fireEvent.click(within(dialog).getByRole('button', { name: '暂停角色动作' }));
await act(async () => {
await vi.advanceTimersByTimeAsync(120);
});
loadMountedFrames(dialog);
const readyFrameSrc = resolveVisibleFrameSrc(dialog);
expect(readyFrameSrc).toBe(
`https://signed.example.com/v1/${frameObjectKeys[0]}`,
);
await act(async () => {
await vi.advanceTimersByTimeAsync(270_100);
});
expect(resolveVisibleFrameSrc(dialog)).toBe(readyFrameSrc);
expect(within(dialog).queryByText(//u)).toBeNull();
for (const retryWindowMs of [450, 1_250, 3_050]) {
await act(async () => {
await vi.advanceTimersByTimeAsync(retryWindowMs);
});
expect(resolveVisibleFrameSrc(dialog)).toBe(readyFrameSrc);
}
expect(requestCounts.get(frameObjectKeys[0])).toBe(5);
expect(within(dialog).queryByText(//u)).toBeNull();
await act(async () => {
await vi.advanceTimersByTimeAsync(20_000);
});
expect(requestCounts.get(frameObjectKeys[0])).toBe(5);
expect(resolveVisibleFrameSrc(dialog)).toBe(readyFrameSrc);
});
function loadMountedFrames(dialog: HTMLElement) {
dialog
.querySelectorAll<HTMLImageElement>('.admin-asset-query-sequence-frame')
.forEach((frame) => fireEvent.load(frame));
}
function resolveFrameByObjectKey(dialog: HTMLElement, objectKey: string) {
return Array.from(
dialog.querySelectorAll<HTMLImageElement>(
'.admin-asset-query-sequence-frame',
),
).find((frame) => frame.src.endsWith(objectKey));
}
function resolveVisibleFrameSrc(dialog: HTMLElement) {
return Array.from(
dialog.querySelectorAll<HTMLImageElement>(
'.admin-asset-query-sequence-frame',
),
).find((frame) => frame.style.opacity === '1')?.src;
}
File diff suppressed because it is too large Load Diff
@@ -6,6 +6,7 @@ import {beforeEach, expect, test, vi} from 'vitest';
import {
getAdminUserDetail,
reconcileAdminUserConsumption,
updateAdminWalletRestriction,
} from '../api/adminApiClient';
import type {
@@ -20,6 +21,7 @@ vi.mock('../api/adminApiClient', () => ({
),
getAdminUserDetail: vi.fn(),
isAdminApiError: vi.fn(() => false),
reconcileAdminUserConsumption: vi.fn(),
updateAdminWalletRestriction: vi.fn(),
}));
@@ -48,6 +50,8 @@ const detail: AdminUserDetailResponse = {
bindingStatus: 'bound',
phoneBound: true,
wechatBound: true,
historicalConsumedPoints: 1234,
canReconcileConsumption: true,
wallet,
rechargeOrders: [
{
@@ -82,6 +86,13 @@ const detail: AdminUserDetailResponse = {
beforeEach(() => {
vi.clearAllMocks();
vi.mocked(getAdminUserDetail).mockResolvedValue(detail);
vi.mocked(reconcileAdminUserConsumption).mockResolvedValue({
userId: 'user-1',
previousHistoricalConsumedPoints: 1234,
historicalConsumedPoints: 1300,
changed: true,
reconciledAtMicros: 1_720_000_000_000_000,
});
vi.mocked(updateAdminWalletRestriction).mockResolvedValue({wallet});
});
@@ -111,6 +122,8 @@ test('用户查看按钮按内部 ID 查询并展示脱敏资料、余额与退
expect(screen.getByText('138****5678')).toBeTruthy();
expect(screen.getByText('退款欠账限制')).toBeTruthy();
expect(screen.getByText('25', {selector: 'strong'})).toBeTruthy();
expect(screen.getByText('历史花费')).toBeTruthy();
expect(screen.getByText('1234', {selector: 'strong'})).toBeTruthy();
expect(screen.getByText('order-1')).toBeTruthy();
await user.keyboard('{Escape}');
@@ -136,6 +149,50 @@ test('只有陶泥号时按 publicUserCode 查询用户', async () => {
});
});
test('历史花费支持手动对账并用权威结果校准展示', async () => {
const user = userEvent.setup();
render(
<AdminUserReferenceButton
token="admin-token"
userId="user-1"
onUnauthorized={vi.fn()}
/>,
);
await user.click(screen.getByRole('button', {name: '查看用户信息'}));
await screen.findByText('陶泥用户');
await user.click(screen.getByRole('button', {name: '手动对账历史花费'}));
await user.click(screen.getByRole('button', {name: '确认'}));
await waitFor(() => {
expect(reconcileAdminUserConsumption).toHaveBeenCalledWith('admin-token', {
userId: 'user-1',
});
});
expect(await screen.findByText('对账完成,历史花费已校准')).toBeTruthy();
expect(screen.getByText('1300', {selector: 'strong'})).toBeTruthy();
});
test('没有独立操作权限时不显示历史花费对账按钮', async () => {
vi.mocked(getAdminUserDetail).mockResolvedValue({
...detail,
canReconcileConsumption: false,
});
const user = userEvent.setup();
render(
<AdminUserReferenceButton
token="admin-token"
userId="user-1"
onUnauthorized={vi.fn()}
/>,
);
await user.click(screen.getByRole('button', {name: '查看用户信息'}));
await screen.findByText('陶泥用户');
expect(screen.queryByRole('button', {name: '手动对账历史花费'})).toBeNull();
});
test('人工冻结和解除人工冻结分别提交原因且不解除退款欠账限制', async () => {
const user = userEvent.setup();
const manuallyFrozenWallet: AdminProfileWalletPayload = {
@@ -6,6 +6,7 @@ import {
formatAdminApiError,
getAdminUserDetail,
isAdminApiError,
reconcileAdminUserConsumption,
updateAdminWalletRestriction,
} from '../api/adminApiClient';
import type {
@@ -34,6 +35,8 @@ export function AdminUserDetailDialog({
const [errorMessage, setErrorMessage] = useState('');
const [restrictionReason, setRestrictionReason] = useState('');
const [isSavingRestriction, setIsSavingRestriction] = useState(false);
const [isReconcilingConsumption, setIsReconcilingConsumption] = useState(false);
const [reconcileMessage, setReconcileMessage] = useState('');
const closeButtonRef = useRef<HTMLButtonElement | null>(null);
const requestVersionRef = useRef(0);
const {confirmWrite, confirmDialog, isConfirming} = useAdminWriteConfirm();
@@ -60,7 +63,12 @@ export function AdminUserDetailDialog({
useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key === 'Escape' && !isSavingRestriction && !isConfirming) {
if (
event.key === 'Escape' &&
!isSavingRestriction &&
!isReconcilingConsumption &&
!isConfirming
) {
event.preventDefault();
onClose();
}
@@ -69,13 +77,14 @@ export function AdminUserDetailDialog({
return () => {
window.removeEventListener('keydown', handleKeyDown);
};
}, [isConfirming, isSavingRestriction, onClose]);
}, [isConfirming, isReconcilingConsumption, isSavingRestriction, onClose]);
async function loadDetail() {
const requestVersion = requestVersionRef.current + 1;
requestVersionRef.current = requestVersion;
setIsLoading(true);
setErrorMessage('');
setReconcileMessage('');
try {
const response = await getAdminUserDetail(token, {
userId: userId?.trim() || undefined,
@@ -144,6 +153,47 @@ export function AdminUserDetailDialog({
}
}
async function handleConsumptionReconcile() {
if (!detail || isReconcilingConsumption) {
return;
}
const confirmed = await confirmWrite({
action: '手动对账历史花费',
target: `${detail.displayName || detail.publicUserCode} / ${detail.userId}`,
});
if (!confirmed) {
return;
}
setIsReconcilingConsumption(true);
setErrorMessage('');
setReconcileMessage('');
try {
const response = await reconcileAdminUserConsumption(token, {
userId: detail.userId,
});
setDetail((current) =>
current
? {
...current,
historicalConsumedPoints: response.historicalConsumedPoints,
}
: current,
);
setReconcileMessage(
response.changed ? '对账完成,历史花费已校准' : '对账完成,数据一致',
);
} catch (error: unknown) {
if (isAdminApiError(error) && error.status === 401) {
onUnauthorized('登录状态已失效');
} else {
setErrorMessage(formatAdminApiError(error));
}
} finally {
setIsReconcilingConsumption(false);
}
}
if (typeof document === 'undefined') {
return null;
}
@@ -158,6 +208,7 @@ export function AdminUserDetailDialog({
if (
event.target === event.currentTarget &&
!isSavingRestriction &&
!isReconcilingConsumption &&
!isConfirming
) {
onClose();
@@ -174,7 +225,7 @@ export function AdminUserDetailDialog({
<button
aria-label="刷新用户信息"
className="admin-ghost-button"
disabled={isLoading}
disabled={isLoading || isReconcilingConsumption}
title="刷新"
type="button"
onClick={() => void loadDetail()}
@@ -185,7 +236,7 @@ export function AdminUserDetailDialog({
ref={closeButtonRef}
aria-label="关闭用户详情"
className="admin-ghost-button"
disabled={isSavingRestriction}
disabled={isSavingRestriction || isReconcilingConsumption}
title="关闭"
type="button"
onClick={onClose}
@@ -222,7 +273,15 @@ export function AdminUserDetailDialog({
{errorMessage}
</div>
) : null}
<WalletSection wallet={detail.wallet} />
<WalletSection
wallet={detail.wallet}
historicalConsumedPoints={detail.historicalConsumedPoints}
canReconcileConsumption={detail.canReconcileConsumption}
isBusy={isReconcilingConsumption || isSavingRestriction}
isReconciling={isReconcilingConsumption}
reconcileMessage={reconcileMessage}
onReconcile={() => void handleConsumptionReconcile()}
/>
<section className="admin-user-restriction-section">
<div className="admin-panel-heading">
@@ -251,7 +310,7 @@ export function AdminUserDetailDialog({
<span></span>
<input
aria-label="人工冻结操作原因"
disabled={isSavingRestriction}
disabled={isSavingRestriction || isReconcilingConsumption}
value={restrictionReason}
onChange={(event) => setRestrictionReason(event.target.value)}
/>
@@ -262,7 +321,11 @@ export function AdminUserDetailDialog({
? 'admin-secondary-button'
: 'admin-danger-button'
}
disabled={isSavingRestriction || !restrictionReason.trim()}
disabled={
isSavingRestriction ||
isReconcilingConsumption ||
!restrictionReason.trim()
}
type="button"
onClick={() => void handleRestrictionChange()}
>
@@ -369,7 +432,23 @@ function UserIdentityHeader({detail}: {detail: AdminUserDetailResponse}) {
);
}
function WalletSection({wallet}: {wallet: AdminProfileWalletPayload}) {
function WalletSection({
wallet,
historicalConsumedPoints,
canReconcileConsumption,
isBusy,
isReconciling,
reconcileMessage,
onReconcile,
}: {
wallet: AdminProfileWalletPayload;
historicalConsumedPoints: number;
canReconcileConsumption: boolean;
isBusy: boolean;
isReconciling: boolean;
reconcileMessage: string;
onReconcile: () => void;
}) {
const metrics = [
['总余额', wallet.totalBalance],
['可消费', wallet.spendableBalance],
@@ -378,19 +457,41 @@ function WalletSection({wallet}: {wallet: AdminProfileWalletPayload}) {
['会员限时', wallet.membershipLimitedPoints],
['退款占用', wallet.heldPoints],
['退款欠账', wallet.refundDebtPoints],
['历史花费', historicalConsumedPoints],
] as const;
return (
<section className="admin-user-wallet-section">
<div className="admin-panel-heading">
<h3></h3>
<div className="admin-tag-list">
{wallet.manualFrozen ? <span className="admin-tag"></span> : null}
{wallet.refundDebtFrozen ? (
<span className="admin-tag">退</span>
<div className="admin-detail-actions">
{canReconcileConsumption ? (
<button
aria-label="手动对账历史花费"
className="admin-ghost-button admin-user-wallet-reconcile-button"
disabled={isBusy}
type="button"
onClick={onReconcile}
>
<RefreshCcw size={15} aria-hidden="true" />
<span>{isReconciling ? '对账中' : '手动对账'}</span>
</button>
) : null}
{!wallet.walletFrozen ? <span className="admin-status admin-status-ok"></span> : null}
<div className="admin-tag-list">
{wallet.manualFrozen ? <span className="admin-tag"></span> : null}
{wallet.refundDebtFrozen ? (
<span className="admin-tag">退</span>
) : null}
{!wallet.walletFrozen ? (
<span className="admin-status admin-status-ok"></span>
) : null}
</div>
</div>
</div>
{reconcileMessage ? (
<div className="admin-alert" role="status">
{reconcileMessage}
</div>
) : null}
<div className="admin-user-wallet-grid">
{metrics.map(([label, value]) => (
<div className="admin-recharge-metric" key={label}>
@@ -17,6 +17,7 @@ interface AdminAccountsPageProps {
}
const assignableRoutes = adminRoutes.filter((route) => !route.ownerOnly);
const consumptionReconcilePermission = 'profile-wallet-consumption-reconcile';
export function AdminAccountsPage({
token,
@@ -29,6 +30,7 @@ export function AdminAccountsPage({
const [password, setPassword] = useState('');
const [enabled, setEnabled] = useState(true);
const [tabPermissions, setTabPermissions] = useState<string[]>([]);
const [actionPermissions, setActionPermissions] = useState<string[]>([]);
const [isLoading, setIsLoading] = useState(false);
const [isSaving, setIsSaving] = useState(false);
const [errorMessage, setErrorMessage] = useState('');
@@ -65,6 +67,7 @@ export function AdminAccountsPage({
setPassword('');
setEnabled(true);
setTabPermissions([]);
setActionPermissions([]);
setErrorMessage('');
}
@@ -75,6 +78,7 @@ export function AdminAccountsPage({
setPassword('');
setEnabled(account.enabled);
setTabPermissions(account.tabPermissions);
setActionPermissions(account.actionPermissions ?? []);
setErrorMessage('');
}
@@ -127,6 +131,7 @@ export function AdminAccountsPage({
displayName: normalizedDisplayName,
...(password ? {password} : {}),
tabPermissions,
actionPermissions,
enabled,
})
: await createAdminAccount(token, {
@@ -134,6 +139,7 @@ export function AdminAccountsPage({
displayName: normalizedDisplayName,
password,
tabPermissions,
actionPermissions,
enabled,
});
setAccounts((current) => {
@@ -289,6 +295,28 @@ export function AdminAccountsPage({
</div>
</fieldset>
<fieldset className="admin-permission-fieldset">
<legend></legend>
<div className="admin-permission-grid">
<label>
<input
checked={actionPermissions.includes(
consumptionReconcilePermission,
)}
type="checkbox"
onChange={(event) =>
setActionPermissions(
event.target.checked
? [consumptionReconcilePermission]
: [],
)
}
/>
<span></span>
</label>
</div>
</fieldset>
<button
className="admin-primary-button"
disabled={isSaving}
@@ -1068,7 +1068,7 @@ test('后台素材查询点击图片缩略图可打开放大预览', async () =>
});
});
test('后台素材查询将角色动画首帧 PNG 作为图片预览', async () => {
test('后台素材查询在现有预览弹窗播放完整角色动作序列', async () => {
const user = userEvent.setup();
vi.mocked(listAdminEditorAssets).mockResolvedValueOnce({
entries: [
@@ -1081,17 +1081,65 @@ test('后台素材查询将角色动画首帧 PNG 作为图片预览', async ()
assetKind: 'character-animation',
thumbnailSrc:
'/generated-animations/editor/source-1/task-1/frame00.png',
imageSequenceFrames: [
{
imageSrc:
'/generated-animations/editor/source-1/task-1/frame00.png',
objectKey:
'generated-animations/editor/source-1/task-1/frame00.png',
width: 192,
height: 256,
},
{
imageSrc:
'/generated-animations/editor/source-1/task-1/frame01.png',
objectKey:
'generated-animations/editor/source-1/task-1/frame01.png',
width: 192,
height: 256,
},
{
imageSrc:
'/generated-animations/editor/source-1/task-1/frame02.png',
objectKey:
'generated-animations/editor/source-1/task-1/frame02.png',
width: 192,
height: 256,
},
{
imageSrc:
'/generated-animations/editor/source-1/task-1/frame03.png',
objectKey:
'generated-animations/editor/source-1/task-1/frame03.png',
width: 192,
height: 256,
},
{
imageSrc:
'/generated-animations/editor/source-1/task-1/frame04.png',
objectKey:
'generated-animations/editor/source-1/task-1/frame04.png',
width: 192,
height: 256,
},
],
imageSequenceDurationMs: 250,
},
],
nextCursor: null,
});
vi.mocked(getAdminAssetReadUrl).mockResolvedValue({
read: {
objectKey: 'generated-animations/editor/source-1/task-1/frame00.png',
signedUrl: 'https://signed.example.com/character-animation-frame00.png',
expiresAt: '2026-07-04T11:00:00Z',
vi.mocked(getAdminAssetReadUrl).mockImplementation(
async (_token, request) => {
const objectKey = request.objectKey ?? undefined;
return {
read: {
objectKey,
signedUrl: `https://signed.example.com/${objectKey ?? ''}`,
expiresAt: '2099-01-01T00:05:00Z',
},
};
},
});
);
render(
<AdminEditorAssetQueryPage token="admin-token" onUnauthorized={vi.fn()} />,
@@ -1102,15 +1150,56 @@ test('后台素材查询将角色动画首帧 PNG 作为图片预览', async ()
);
const dialog = await screen.findByRole('dialog', { name: '素材预览' });
const image = await within(dialog).findByRole('img', {
name: '图片预览:角色动作首帧',
});
await user.click(
await within(dialog).findByRole('button', {
name: '暂停角色动作',
}),
);
await waitFor(() => {
expect(image.getAttribute('src')).toBe(
'https://signed.example.com/character-animation-frame00.png',
expect(
dialog.querySelectorAll('.admin-asset-query-sequence-frame'),
).toHaveLength(3);
});
expect(getAdminAssetReadUrl).toHaveBeenCalledWith('admin-token', {
objectKey: 'generated-animations/editor/source-1/task-1/frame00.png',
expireSeconds: 300,
});
expect(getAdminAssetReadUrl).toHaveBeenCalledWith('admin-token', {
objectKey: 'generated-animations/editor/source-1/task-1/frame01.png',
expireSeconds: 300,
});
expect(getAdminAssetReadUrl).toHaveBeenCalledWith('admin-token', {
objectKey: 'generated-animations/editor/source-1/task-1/frame02.png',
expireSeconds: 300,
});
expect(getAdminAssetReadUrl).not.toHaveBeenCalledWith('admin-token', {
objectKey: 'generated-animations/editor/source-1/task-1/frame03.png',
expireSeconds: 300,
});
const failedFrame = dialog.querySelector(
'.admin-asset-query-sequence-frame',
) as HTMLImageElement;
fireEvent.error(failedFrame);
expect(await within(dialog).findByText('1 帧加载失败')).toBeTruthy();
await waitFor(() => {
expect(getAdminAssetReadUrl).toHaveBeenCalledWith('admin-token', {
objectKey: 'generated-animations/editor/source-1/task-1/frame03.png',
expireSeconds: 300,
});
});
const callsBeforeRetry = vi.mocked(getAdminAssetReadUrl).mock.calls.length;
await user.click(
within(dialog).getByRole('button', { name: '重试失败帧' }),
);
await waitFor(() => {
expect(vi.mocked(getAdminAssetReadUrl).mock.calls.length).toBeGreaterThan(
callsBeforeRetry,
);
});
expect(within(dialog).queryByLabelText('视频预览:角色动作首帧')).toBeNull();
expect(
within(dialog).getByRole('button', { name: '暂停角色动作' }),
).toBeTruthy();
});
test('后台素材查询音频素材使用统一封面缩略图', async () => {
@@ -318,6 +318,101 @@ test('后台精选审核缩略图进入视口后换签并可打开图片预览',
expect(screen.queryByRole('dialog', { name: '精选素材详情' })).toBeNull();
});
test('后台精选审核在共用预览弹窗播放完整角色动作', async () => {
vi.mocked(listAdminEditorShowcaseAssets).mockResolvedValueOnce({
entries: [
{
...pendingShowcaseAsset,
label: '待机动作',
assetKind: 'character-animation',
imageSrc: '/generated/action/frame-01.png',
objectKey: 'generated/action/frame-01.png',
imageSequenceFrames: [
{
imageSrc: '/generated/action/frame-01.png',
objectKey: 'generated/action/frame-01.png',
width: 192,
height: 256,
},
{
imageSrc: '/generated/action/frame-02.png',
objectKey: 'generated/action/frame-02.png',
width: 192,
height: 256,
},
],
imageSequenceDurationMs: 250,
},
],
nextCursor: null,
});
vi.mocked(getAdminAssetReadUrl).mockImplementation(
async (_token, request) => {
const objectKey = request.objectKey ?? undefined;
return {
read: {
objectKey,
signedUrl: `https://signed.example.com/${objectKey ?? ''}`,
expiresAt: '2099-01-01T00:05:00Z',
},
};
},
);
render(
<AdminEditorShowcaseReviewPage
token="admin-token"
onUnauthorized={vi.fn()}
/>,
);
fireEvent.click(await screen.findByTitle('预览素材'));
const dialog = await screen.findByRole('dialog', { name: '素材预览' });
expect(
await within(dialog).findByRole('button', { name: '暂停角色动作' }),
).toBeTruthy();
await waitFor(() => {
expect(
dialog.querySelectorAll('.admin-asset-query-sequence-frame'),
).toHaveLength(2);
});
expect(getAdminAssetReadUrl).toHaveBeenCalledWith('admin-token', {
objectKey: 'generated/action/frame-02.png',
expireSeconds: 300,
});
});
test('后台精选审核对损坏角色动作显示错误而不回退首帧', async () => {
vi.mocked(listAdminEditorShowcaseAssets).mockResolvedValueOnce({
entries: [
{
...pendingShowcaseAsset,
label: '损坏动作',
assetKind: 'character-animation',
imageSequenceFrames: null,
imageSequenceDurationMs: null,
},
],
nextCursor: null,
});
render(
<AdminEditorShowcaseReviewPage
token="admin-token"
onUnauthorized={vi.fn()}
/>,
);
fireEvent.click(await screen.findByTitle('预览素材'));
const dialog = await screen.findByRole('dialog', { name: '素材预览' });
expect(
within(dialog).getByLabelText('角色动作序列损坏:损坏动作'),
).toBeTruthy();
expect(
within(dialog).queryByRole('img', { name: '图片预览:损坏动作' }),
).toBeNull();
});
test('后台精选审核将无 objectKey 的绝对 OSS 图片地址换签后预览', async () => {
vi.mocked(listAdminEditorShowcaseAssets).mockResolvedValueOnce({
entries: [
@@ -0,0 +1,58 @@
/* @vitest-environment jsdom */
import {fireEvent, render, screen, waitFor} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import {beforeEach, expect, test, vi} from 'vitest';
import {getProfileWalletConfig, upsertProfileWalletConfig} from '../api/adminApiClient';
import type {ProfileWalletConfigAdminResponse} from '../api/adminApiTypes';
import {AdminProfileWalletConfigPage} from './AdminProfileWalletConfigPage';
vi.mock('../api/adminApiClient', () => ({
formatAdminApiError: vi.fn((error: unknown) => error instanceof Error ? error.message : '请求失败'),
getProfileWalletConfig: vi.fn(),
isAdminApiError: vi.fn(() => false),
upsertProfileWalletConfig: vi.fn(),
}));
const configResponse: ProfileWalletConfigAdminResponse = {
configId: 'profile_wallet', initialMudPoints: 100, dailyFreePointsPerDay: 20,
createdBy: 'owner-1', createdByDisplayName: '管理员',
createdAt: '2026-07-31T01:00:00Z', updatedBy: 'owner-1',
updatedByDisplayName: '管理员', updatedAt: '2026-07-31T01:00:00Z',
};
beforeEach(() => {
vi.clearAllMocks();
vi.mocked(getProfileWalletConfig).mockResolvedValue(configResponse);
vi.mocked(upsertProfileWalletConfig).mockResolvedValue({...configResponse, initialMudPoints: 120, dailyFreePointsPerDay: 35});
});
test('账号配置页加载并展示每日免费泥点', async () => {
render(<AdminProfileWalletConfigPage token="admin-token" result={configResponse} onUnauthorized={vi.fn()} onResultChange={vi.fn()} />);
expect((await screen.findByLabelText('每日免费泥点数') as HTMLInputElement).value).toBe('20');
expect(getProfileWalletConfig).toHaveBeenCalledWith('admin-token');
expect(screen.getByText('每日免费泥点')).toBeTruthy();
});
test('账号配置页一次保存初始和每日免费泥点', async () => {
const user = userEvent.setup();
const onResultChange = vi.fn();
render(<AdminProfileWalletConfigPage token="admin-token" result={configResponse} onUnauthorized={vi.fn()} onResultChange={onResultChange} />);
await screen.findByLabelText('每日免费泥点数');
fireEvent.change(screen.getByLabelText('账号初始泥点数'), {target: {value: '120'}});
fireEvent.change(screen.getByLabelText('每日免费泥点数'), {target: {value: '35'}});
await user.click(screen.getByRole('button', {name: '保存'}));
expect(screen.getByText('初始 120 泥点,每日免费 35 泥点')).toBeTruthy();
await user.click(screen.getByRole('button', {name: '确认'}));
await waitFor(() => expect(upsertProfileWalletConfig).toHaveBeenCalledWith('admin-token', {initialMudPoints: 120, dailyFreePointsPerDay: 35}));
expect(onResultChange).toHaveBeenLastCalledWith(expect.objectContaining({initialMudPoints: 120, dailyFreePointsPerDay: 35}));
});
test('账号配置页拒绝非正整数每日免费额度', async () => {
render(<AdminProfileWalletConfigPage token="admin-token" result={configResponse} onUnauthorized={vi.fn()} onResultChange={vi.fn()} />);
const input = await screen.findByLabelText('每日免费泥点数');
fireEvent.change(input, {target: {value: '1.5'}});
expect((screen.getByRole('button', {name: '保存'}) as HTMLButtonElement).disabled).toBe(true);
expect(upsertProfileWalletConfig).not.toHaveBeenCalled();
});
@@ -23,6 +23,7 @@ export function AdminProfileWalletConfigPage({
onResultChange,
}: AdminProfileWalletConfigPageProps) {
const [initialMudPoints, setInitialMudPoints] = useState('100');
const [dailyFreePointsPerDay, setDailyFreePointsPerDay] = useState('20');
const [isLoading, setIsLoading] = useState(false);
const [isSaving, setIsSaving] = useState(false);
const [loadErrorMessage, setLoadErrorMessage] = useState('');
@@ -41,6 +42,7 @@ export function AdminProfileWalletConfigPage({
const response = await getProfileWalletConfig(token);
onResultChange(response);
setInitialMudPoints(String(response.initialMudPoints));
setDailyFreePointsPerDay(String(response.dailyFreePointsPerDay));
} catch (error: unknown) {
handlePageError(error, onUnauthorized, setLoadErrorMessage);
} finally {
@@ -53,6 +55,13 @@ export function AdminProfileWalletConfigPage({
if (isSaving) {
return;
}
const normalizedDailyFreePointsPerDay = parsePositiveInteger(
dailyFreePointsPerDay,
);
if (!normalizedDailyFreePointsPerDay) {
setErrorMessage('每日免费泥点数必须是大于 0 的整数');
return;
}
const normalizedInitialMudPoints = parsePositiveInteger(initialMudPoints);
if (!normalizedInitialMudPoints) {
@@ -63,7 +72,7 @@ export function AdminProfileWalletConfigPage({
setErrorMessage('');
const confirmed = await confirmWrite({
action: '保存账号配置',
target: `${normalizedInitialMudPoints}泥点`,
target: `初始 ${normalizedInitialMudPoints} 泥点,每日免费 ${normalizedDailyFreePointsPerDay} 泥点`,
});
if (!confirmed) {
return;
@@ -73,9 +82,11 @@ export function AdminProfileWalletConfigPage({
try {
const response = await upsertProfileWalletConfig(token, {
initialMudPoints: normalizedInitialMudPoints,
dailyFreePointsPerDay: normalizedDailyFreePointsPerDay,
});
onResultChange(response);
setInitialMudPoints(String(response.initialMudPoints));
setDailyFreePointsPerDay(String(response.dailyFreePointsPerDay));
} catch (error: unknown) {
handlePageError(error, onUnauthorized, setErrorMessage);
} finally {
@@ -120,6 +131,17 @@ export function AdminProfileWalletConfigPage({
/>
</label>
<label className="admin-field">
<span></span>
<input
min={1}
step={1}
type="number"
value={dailyFreePointsPerDay}
onChange={(event) => setDailyFreePointsPerDay(event.target.value)}
/>
</label>
{errorMessage ? (
<div className="admin-alert" role="status">
{errorMessage}
@@ -128,7 +150,11 @@ export function AdminProfileWalletConfigPage({
<button
className="admin-primary-button"
disabled={isSaving || !parsePositiveInteger(initialMudPoints)}
disabled={
isSaving ||
!parsePositiveInteger(initialMudPoints) ||
!parsePositiveInteger(dailyFreePointsPerDay)
}
type="submit"
>
<Save size={17} aria-hidden="true" />
@@ -147,6 +173,10 @@ export function AdminProfileWalletConfigPage({
<dt></dt>
<dd>{result.initialMudPoints}</dd>
</div>
<div>
<dt></dt>
<dd>{result.dailyFreePointsPerDay}</dd>
</div>
<div>
<dt></dt>
<dd>{result.updatedByDisplayName || '-'}</dd>
@@ -169,6 +199,6 @@ export function AdminProfileWalletConfigPage({
}
function parsePositiveInteger(value: string) {
const parsed = Number.parseInt(value, 10);
return Number.isFinite(parsed) && parsed > 0 ? parsed : 0;
const parsed = Number(value);
return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : 0;
}
+59
View File
@@ -1270,6 +1270,13 @@ button:disabled {
background: #f8efe7;
}
.admin-ghost-button.admin-user-wallet-reconcile-button {
width: auto;
min-width: 92px;
padding: 0 10px;
gap: 6px;
}
.admin-ghost-button.admin-query-reset-button {
width: auto;
min-width: 76px;
@@ -1696,6 +1703,58 @@ button:disabled {
object-fit: contain;
}
.admin-asset-query-sequence-preview {
position: relative;
width: min(100%, 720px);
min-height: min(64dvh, 560px);
overflow: hidden;
}
.admin-asset-query-sequence-frame {
position: absolute;
inset: 0;
display: block;
width: 100%;
height: 100%;
object-fit: contain;
object-position: center;
}
.admin-asset-query-sequence-controls {
position: absolute;
right: 12px;
bottom: 12px;
z-index: 2;
display: flex;
max-width: calc(100% - 24px);
flex-wrap: wrap;
align-items: center;
gap: 8px;
border-radius: 999px;
background: rgba(43, 31, 22, 0.82);
color: #fff;
padding: 6px 10px;
font-size: 12px;
}
.admin-asset-query-sequence-controls button {
display: grid;
min-width: 44px;
min-height: 44px;
border: 0;
background: transparent;
color: inherit;
cursor: pointer;
padding: 0;
place-items: center;
}
.admin-asset-query-sequence-error {
display: grid;
color: #9d3127;
place-items: center;
}
.admin-asset-query-preview-audio {
display: grid;
justify-items: center;

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