Compare commits

..

75 Commits

Author SHA1 Message Date
kdletters 64310b3719 Merge remote-tracking branch 'origin/master' into codex/agc-runtime-generation-reliability 2026-08-18 20:54:01 +08:00
kdletters f9ee0d5ac7 恢复直连已有游戏意图分流
- 已有游戏默认进入同一 Codex thread 编辑与试玩链路

- 仅明确新建或重做美术请求触发平台素材准备

- 补充已有游戏编辑与外部美术生成意图分流测试
2026-08-18 20:53:13 +08:00
kdletters 9070c0760b 修复登录服务器切换与本地资源请求
- 允许 release 客户端安全访问 custom HTTPS 与本机 loopback HTTP

- 修复 Tauri WebView 请求传输与无效 URLPattern

- 按服务器 origin 隔离本机 External Editor 凭据

- 保留登录请求底层错误并补充路由与凭据隔离测试
2026-08-18 18:32:49 +08:00
kdletters 1e9d74fa4a 增加登录服务器选择
- 登录页支持 release、dev 和 custom 服务器

- 持久化服务器选择并统一登录与平台会话请求地址

- 校验自定义服务器 origin 与 HTTPS 安全边界

- 补充前端、AppSurface 和 Rust 平台会话测试
2026-08-18 13:46:03 +08:00
kdletters bdf7ed288a 放宽直连游戏验收并增加运行时素材证据
- 将固定四切片与固定 drawImage 降为推荐路径

- 在导航前注入 Canvas/WebGL 平台素材运行时观测

- 对缺少核心素材渲染证据的 desktop/mobile 视口回灌同一 Codex thread 整改

- 补充直连验收、浏览器脚本与真实 Chrome fixture 测试

- 同步 AGC 直连 Runtime 实施计划
2026-08-18 13:14:45 +08:00
kdletters 7f60a00c84 修复预览镜像认证入口
Project CI / Repository checks (push) Successful in 1m23s
Project CI / Frontend tests (push) Successful in 2m59s
Project CI / Backend tests (push) Successful in 4m3s
Project CI / Native shell tests (push) Successful in 14m7s
为分支预览启用首次密码登录自动注册

为预览短信入口配置隔离 mock 验证码

补充预览部署门禁和认证验收文档
2026-08-17 22:55:27 +08:00
kdletters 94200a3cdb 修复AGC直连聊天持久化与生成竞态
持久化直连用户消息和最终安全回复,并在重开项目时恢复

补充直连聊天与工作台验收回归测试

直连美术生成和版本登记等待项目写锁,避免首轮生成被聊天保存阻断

同步直连 Runtime 实施计划
2026-08-17 20:11:22 +08:00
kdletters 286c402a4b 修复运行时设置弹窗背景与滚动
设置弹窗打开时锁定页面滚动并在关闭后恢复原状态
将弹窗、提示条和底部状态区改为不透明实色背景
补充设置弹窗滚动锁定与恢复的界面回归测试
2026-08-17 19:03:50 +08:00
kdletters f30e6e9f33 修复智能创作鉴权提示可读性
分隔产品名称与直连运行时错误原因

同步更新直连错误投影测试
2026-08-17 15:35:13 +08:00
kdletters 7ecc9f4971 合并平台账号编辑器 API 分支
登录态接入平台编辑器生成接口

普通用户隐藏外部编辑器高级配置

保留陶泥儿直连运行时生成反馈
2026-08-17 15:20:19 +08:00
kdletters 836d599a98 Merge remote-tracking branch 'origin/master' into codex/agc-runtime-generation-reliability
# Conflicts:
#	docs/project-memory/shared-memory/decision-log.md
2026-08-17 15:12:43 +08:00
kdletters 5ea453d5d1 收口AGC单窗口启动
取消开发态自动打开 Agent 聊天窗口

统一客户端可见标题为陶泥儿

同步启动守卫、测试与技术文档
2026-08-17 14:32:13 +08:00
kdletters 08bca001a2 修复AGC直连创作反馈与资源预览
直连运行时推送陶泥儿美术、代码与版本登记阶段进度

资源管理首屏预取可预览资源并补齐回归测试

同步直连运行时实施计划和团队决策记录
2026-08-17 13:17:14 +08:00
kdletters e455cd593c 兼容历史预览构建记录
Project CI / Repository checks (push) Successful in 1m2s
Project CI / Frontend tests (push) Successful in 2m58s
Project CI / Native shell tests (push) Successful in 14m17s
Project CI / Backend tests (push) Successful in 3m56s
启动时回填旧记录的 Jenkins 构建编号

将旧 loopback 构建详情转换为局域网地址

补充历史记录迁移测试
2026-08-17 12:52:40 +08:00
kdletters 38ae9d7d07 完善预览发布记录管理
Project CI / Frontend tests (push) Successful in 2m55s
Project CI / Backend tests (push) Successful in 3m53s
Project CI / Native shell tests (push) Successful in 15m2s
Project CI / Repository checks (push) Successful in 1m6s
发布记录改用 Jenkins 构建编号并展示

失败与停止记录增加自动清理期限

构建详情改为局域网 Jenkins 地址

同步测试、部署配置和运维文档
2026-08-17 12:42:29 +08:00
kdletters abb3912530 增加分支与提交搜索校验
Project CI / Frontend tests (push) Successful in 2m54s
Project CI / Native shell tests (push) Successful in 14m0s
Project CI / Repository checks (push) Successful in 1m6s
Project CI / Backend tests (push) Successful in 3m54s
增加分支和 commit 的输入搜索下拉构建前复核固定仓库中的分支与 commit 归属补充预览控制面接口合同、配置和测试
2026-08-17 12:04:31 +08:00
kdletters 91c333ea4a 修复 Windows 微信支付测试的 OpenSSL 构建依赖
移除 platform-wechat 的 openssl 测试依赖

使用固定 RSA PEM fixture 保持签名与解析测试语义

记录 Windows MSVC 原生 OpenSSL 测试依赖陷阱
2026-08-17 11:34:15 +08:00
kdletters ced4b56dee 优化预览发布记录展示
Project CI / Repository checks (push) Successful in 1m22s
Project CI / Frontend tests (push) Successful in 2m55s
Project CI / Backend tests (push) Successful in 3m56s
Project CI / Native shell tests (push) Successful in 14m7s
发布记录增加后端校验后的 Web 端口号

列表隐藏已成功卸载的容器记录

兼容恢复旧运行记录并回填 Web 端口

补充后端、前端测试和技术说明
2026-08-17 10:47:58 +08:00
kdletters 81a35e0bff 让AGC登录后直接使用平台编辑器API
普通客户端使用陶泥儿登录态访问站内编辑器、素材与生成状态路由
隔离standalone高级模式的External URL与Developer API Key配置
同步GUI与Runner的平台会话、可信服务origin和鉴权代际
绑定生成账本owner并阻断登出或换号后的旧请求落盘
修正本地图片上传确认、项目资源登记和sourceReferenceId链路
区分401登录刷新与403权限不足并保留原幂等恢复语义
补充后端客户端幂等命名空间、稳定结果投影和图集请求头
更新AGC界面测试、Rust契约测试及项目技术文档
2026-08-17 10:43:08 +08:00
kdletters 647cf82cec 实现AGC直连运行时与陶泥儿美术闭环
新增直连 Codex 项目聊天、会话恢复与可读错误反馈

接入陶泥儿规范图、背景、固定四切片并校验实际渲染

同步游戏代码资源分类、项目版本 revision 与外部编辑器契约
2026-08-17 09:57:31 +08:00
kdletters 080c3ebc4f 修复预览部署结果字段冲突
Project CI / Frontend tests (push) Successful in 3m49s
Project CI / Backend tests (push) Failing after 3m50s
Project CI / Repository checks (push) Successful in 1m11s
Project CI / Native shell tests (push) Successful in 14m44s
使用权威 branch 和 resolvedCommit 字段解析 Jenkins 产物

移除与附加 source 字段冲突的旧别名

保留状态解析错误上下文以便安全排障
2026-08-15 19:18:49 +08:00
kdletters c75fcbf023 修复预览构建状态解析与工作进程恢复
Project CI / Repository checks (push) Successful in 55s
Project CI / Frontend tests (push) Successful in 3m35s
Project CI / Backend tests (push) Successful in 4m38s
Project CI / Native shell tests (push) Successful in 15m53s
限制 Jenkins 状态接口只返回监控所需字段

避免完整构建 JSON 触发反序列化递归深度限制

让预览外部生成工作进程在身份初始化后自动重启

补充定向测试、防回归检查和技术说明
2026-08-15 18:52:10 +08:00
kdletters cf5eac1c63 修复Jenkins成功收尾状态竞态
Project CI / Repository checks (push) Successful in 53s
Project CI / Frontend tests (push) Successful in 3m36s
Project CI / Native shell tests (push) Successful in 15m35s
Project CI / Backend tests (push) Successful in 4m19s
为队列、构建状态和部署产物查询增加有限重试

避免 Jenkins 瞬态无效响应永久覆盖成功部署状态

增加构建收尾竞态回归测试和技术说明
2026-08-15 18:38:59 +08:00
kdletters ea81d8ebb5 修复预览数据库容器内存不足
Project CI / Native shell tests (push) Has been cancelled
Project CI / Backend tests (push) Has been cancelled
Project CI / Frontend tests (push) Has been cancelled
Project CI / Repository checks (push) Successful in 1m20s
将分支预览 SpacetimeDB 内存上限覆盖为 2 GiB

保留生产与压测 Compose 的原有资源基线

增加预览内存覆盖防回归检查和故障说明
2026-08-15 18:33:30 +08:00
kdletters d0a8f254b3 修复预览环境非交互发布
Project CI / Repository checks (push) Successful in 1m0s
Project CI / Backend tests (push) Successful in 4m16s
Project CI / Frontend tests (push) Successful in 3m27s
Project CI / Native shell tests (push) Successful in 17m18s
允许 SpacetimeDB 向受控容器网络地址非交互发布

固定预览结果使用内网主机地址

补充发布参数与内网地址防回归检查和文档
2026-08-15 18:30:08 +08:00
kdletters a312ee20b5 修复预览流水线空提交参数
Project CI / Repository checks (push) Successful in 56s
Project CI / Frontend tests (push) Has been cancelled
Project CI / Backend tests (push) Has been cancelled
Project CI / Native shell tests (push) Has been cancelled
允许 Jenkins 检出阶段安全读取未导出的可选参数

显式使用 bash 执行源码检出脚本

增加空提交参数与脚本执行方式防回归检查
2026-08-15 18:17:21 +08:00
kdletters 1a61c0bea7 修复Jenkins构建地址归一化
Project CI / Repository checks (push) Successful in 59s
Project CI / Backend tests (push) Has been cancelled
Project CI / Native shell tests (push) Has been cancelled
Project CI / Frontend tests (push) Has been cancelled
将 Jenkins 返回的外部构建路径重绑定到受信本机 origin
增加外部 Jenkins URL 的状态与产物轮询回归测试
2026-08-15 18:12:39 +08:00
kdletters 7cd8b39593 Revert "修复预览部署可选提交参数"
Project CI / Repository checks (push) Successful in 1m2s
Project CI / Frontend tests (push) Successful in 3m46s
Project CI / Backend tests (push) Successful in 4m22s
Project CI / Native shell tests (push) Failing after 13m9s
This reverts commit d2366bc40a.
2026-08-15 18:09:04 +08:00
kdletters 5e7ff450b6 Revert "修复预览部署脚本执行方式"
This reverts commit 7fc739fad0.
2026-08-15 18:09:04 +08:00
kdletters 7fc739fad0 修复预览部署脚本执行方式
Project CI / Repository checks (push) Successful in 1m23s
Project CI / Frontend tests (push) Successful in 4m28s
Project CI / Backend tests (push) Successful in 4m22s
Project CI / Native shell tests (push) Successful in 17m7s
通过 bash 显式调用 Jenkins 源码检出脚本

增加脚本执行方式防回归门禁

同步预览部署执行合同文档
2026-08-15 18:03:49 +08:00
kdletters d2366bc40a 修复预览部署可选提交参数
Project CI / Repository checks (push) Successful in 1m40s
Project CI / Frontend tests (push) Successful in 2m59s
Project CI / Backend tests (push) Successful in 4m5s
Project CI / Native shell tests (push) Successful in 18m44s
修复 Checkout 阶段在严格 shell 下展开未定义 COMMIT_HASH 的失败

增加预览流水线参数归一化防回归门禁

同步预览部署参数合同与项目决策文档
2026-08-15 18:00:05 +08:00
kdletters 7400c706f8 修复预览流水线空参数校验
Project CI / Repository checks (push) Successful in 50s
Project CI / Frontend tests (push) Successful in 3m14s
Project CI / Backend tests (push) Successful in 4m5s
Project CI / Native shell tests (push) Successful in 15m22s
在严格 shell 模式下归一化首次触发的空参数
避免 STATUS 与未指定 commit 的请求误报未定义变量
2026-08-15 17:39:07 +08:00
kdletters 6befa3c33a 补全预览流水线首次触发参数
Project CI / Repository checks (push) Successful in 1m13s
Project CI / Frontend tests (push) Successful in 4m7s
Project CI / Backend tests (push) Successful in 5m4s
Project CI / Native shell tests (push) Failing after 12m44s
在 Jenkins Job 配置中预声明部署参数
增加 buildWithParameters 首次触发合同检查
2026-08-15 17:29:25 +08:00
kdletters 1746c77cb1 修复预览控制台子路径静态资源
Project CI / Repository checks (push) Successful in 1m3s
Project CI / Frontend tests (push) Successful in 3m1s
Project CI / Backend tests (push) Successful in 3m46s
Project CI / Native shell tests (push) Failing after 12m48s
让控制服务原生托管 /build 页面与静态资源
保持内网 Nginx 路径透传并补充部署合同检查
2026-08-15 17:25:40 +08:00
kdletters 41874ab391 新增内网容器预览部署控制面
Project CI / Repository checks (push) Successful in 1m16s
Project CI / Frontend tests (push) Successful in 3m1s
Project CI / Backend tests (push) Successful in 4m2s
Project CI / Native shell tests (push) Successful in 17m2s
新增分支与指定提交的预览部署 SPA 和 Jenkins 代理服务
新增多实例 Docker 预览流水线、端口租约、实时健康状态和卸载能力
新增 /build 内网路由、systemd 部署资产和运维文档
修正容器 Nginx 健康检查探针
2026-08-15 17:18:10 +08:00
kdletters f69d9a2e11 Merge remote-tracking branch 'origin/master' into codex/agc-runtime-generation-reliability
# Conflicts:
#	apps/ai-game-creator-shell/src-tauri/src/project/manifest.rs
#	apps/ai-game-creator-shell/src/features/app-shell/useHomeProjectCreation.ts
#	apps/ai-game-creator-shell/tests/appSurface/project-development.suite.ts
2026-08-15 15:20:30 +08:00
kdletters dedff81475 修复AGC无人值守生成阻断的交付收口与验收
- 可信 code-prototype 父 Run 认领并观察直属美术 delivery,普通失败立即收束,合法安全默认 marker 由 Runtime 确定性执行唯一同合同返工

- 补齐 suppressed 无 child 与父身份链丢失时的 completion 失败关闭边界

- 修复 Windows project.lock delete-pending 竞争并收紧 HTML 内联 JS 语法 fail-open

- 同步技术方案、决策记录与实施计划,并完成确定性及真实 Provider 分层验证
2026-08-15 15:12:05 +08:00
kdletters aa5221abcf 修复Jenkins Web依赖安装
Project CI / Repository checks (push) Successful in 1m8s
Project CI / Frontend tests (push) Successful in 3m0s
Project CI / Backend tests (push) Successful in 3m40s
Project CI / Native shell tests (push) Successful in 13m52s
Web构建同时安装根目录与AGC独立lockfile依赖
Full流水线同步RUN_NPM_CI参数说明
生产运维门禁锁定双依赖安装顺序
运维文档补充故障原因与依赖边界
2026-08-15 14:15:03 +08:00
kdletters 9f5c84ee71 重构AGC项目管理界面
Project CI / Repository checks (push) Successful in 1m40s
Project CI / Frontend tests (push) Successful in 3m27s
Project CI / Native shell tests (push) Successful in 14m20s
Project CI / Backend tests (push) Successful in 4m17s
参考成熟桌面项目管理器重构紧凑项目表、搜索和行尾菜单

支持Windows路径及Godot根目录和一层子目录工程识别与导入

修复1280×720页面溢出、列表滚动和末行菜单裁切

补充项目页回归测试、PRD、技术方案和项目记忆
2026-08-15 11:43:58 +08:00
kdletters 578f8019fc 优化AGC项目入口并识别Godot工作区
Project CI / Repository checks (push) Successful in 1m14s
Project CI / Frontend tests (push) Successful in 3m9s
Project CI / Native shell tests (push) Successful in 14m6s
Project CI / Backend tests (push) Successful in 3m58s
项目页只保留打开项目和新建项目并统一原生目录选择
按根目录及一层子目录识别project.godot并记录相对Godot根
保持.agent位于用户选择的工作区根并补齐Windows构建门禁
补充响应式布局、测试、技术方案和共享项目记忆
2026-08-14 21:53:43 +08:00
lhk229 4d3f87cd39 修复完美像素无法识别自身产物的网格 (#169)
Project CI / Repository checks (push) Successful in 1m21s
Project CI / Backend tests (push) Successful in 3m57s
Project CI / Frontend tests (push) Successful in 2m54s
Project CI / Native shell tests (push) Successful in 14m7s
边缘 profile 用的是跨度 2 的中心差分,硬块边界落在列 b-1|b 之间时
profile[b-1] 与 profile[b] 逐位相等:两者跨的是同一条边,逐行被加数
相同、求和顺序相同。峰值判定两侧都用严格大于,会把这个 2 宽平台的
两端一起丢掉,于是最干净的输入反而 0 个峰、被判为未识别到网格——
完美像素处理不了自己的输出。

estimate_step_size 左邻比较放宽为 >=,右邻保持严格 >:平台只保留
一个索引,且是右端,正好是左闭右开语义下的真实块边。两侧都放宽则
会把长度 K 的常数段整段判为峰。

walk 与 snap_uniform_cuts 的 argmax 同样改为 >=,取等值段的最后一
个索引。取第一个会让每条切线落在真实边界左边 1px,每个 cell 因此
混进 1/4 的邻块。实测在 266x253 的最近邻放大像素画上,切线命中真实
块边从 2.6% 升到 98.5%,左右镜像、上下翻转、180° 旋转下一致;龙图
内容区内 134/134 全中。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/169
Co-authored-by: Linghong <ink29535@proton.me>
Co-committed-by: Linghong <ink29535@proton.me>
2026-08-14 20:42:58 +08:00
k88936 d901945c77 移除视频快速编辑支持 (#157)
Project CI / Repository checks (push) Successful in 1m20s
Project CI / Backend tests (push) Successful in 3m56s
Project CI / Native shell tests (push) Successful in 14m1s
Project CI / Frontend tests (push) Successful in 2m53s
当前实现: 视频快速编辑错误地复用了图片快速编辑的panel, 然后发起一个实际是生成视频的请求

策划建议删除.

因为后端没有实际意义上的视频快速编辑, 所以api 后端代码没有改动, 只在前端删除入口和处理

---------

Co-authored-by: kdletters <kdletters@qq.com>
Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/157
Co-authored-by: 王德宇 <kvtodev@outlook.com>
Co-committed-by: 王德宇 <kvtodev@outlook.com>
2026-08-14 18:52:56 +08:00
kdletters d155e303bd 实现AGC回车自动创建工作区
Project CI / Repository checks (push) Successful in 1m3s
Project CI / Frontend tests (push) Successful in 3m9s
Project CI / Backend tests (push) Successful in 4m17s
Project CI / Native shell tests (push) Failing after 11m3s
首页普通回车自动分配系统文档目录下的唯一工作区并启动项目总控

保留加号按钮手动选择目录和Shift回车换行语义

统一Windows Linux与macOS默认项目路径解析并移除产品态tmp默认值

补充自动工作区安全测试 首页交互回归与技术方案说明
2026-08-14 17:45:27 +08:00
kdletters 02fff8f308 修复AGC无人值守游戏生成阻断
普通Web工作台默认使用单Supervisor自主生成链路

补齐安全默认返工、结构化诊断与同Run恢复

绑定当前revision、入口摘要和双视口试玩完成凭证

增强Runner跨boot单飞恢复与game-chat来源隔离

新增真实Provider验收入口及确定性回归

同步更新技术方案、开发流程和共享决策
2026-08-14 07:14:25 +08:00
kdletters 7774642365 文档:制定AGC无人值守游戏生成修复计划
明确普通GUI单主快车道路由与无人值守安全边界

定义验证自修复、产物完成门和Runner恢复对账合同

补充端到端验收矩阵、验证命令与回滚边界
2026-08-13 22:21:59 +08:00
kdletters 8e78be766e 修复AGC运行与首板版本登记
Project CI / Repository checks (push) Successful in 55s
Project CI / Frontend tests (push) Successful in 3m26s
Project CI / Backend tests (push) Successful in 3m59s
Project CI / Native shell tests (push) Failing after 11m44s
修复旧模型定价覆盖缺少ElevenLabs音效模型导致启动恢复持续失败

支持对话框回车发送并保留Shift换行和输入法组合态

重试受理后立即清理旧失败投影并展示新Run状态

阻止Windows后台Codex探测反复弹出控制台窗口

首板试玩持久回执通过后幂等登记初始项目版本

补充定价、交互、Windows与版本登记回归测试和文档
2026-08-13 20:11:51 +08:00
kdletters 7052d3e692 修复Windows维护页门禁执行
Project CI / Repository checks (push) Successful in 1m21s
Project CI / Frontend tests (push) Successful in 3m2s
Project CI / Backend tests (push) Successful in 4m1s
Project CI / Native shell tests (push) Failing after 10m34s
转换WSL bash所需的脚本、参数和环境路径
在POSIX平台校验实际0644权限并在Windows校验安装源码契约
保留维护页原子替换与符号链接防护测试
2026-08-13 14:01:34 +08:00
kdletters 1b4cb3c45e 修复Windows下Git钩子回归测试
统一比较Git恢复文件时的换行符
将WSL bash测试使用的临时工具路径转换为可执行路径
确保master推送门禁在Windows与Unix环境下均可重复验证
2026-08-13 13:50:27 +08:00
kdletters 15c227cebf 修复AGC Windows运行与全量测试稳定性
完善Codex CLI、App Server、ConPTY与进程会话在Windows下的发现、启动、恢复和退出行为
修复Agent Runtime、Provider重试、项目写锁及工具交接账本的并发与跨测试串线问题
补齐配置目录、路径脱敏、原子写入、浏览器探测和本地Provider smoke的跨平台兼容
增强Goal Contract、自动策略、资源生成及运行态恢复的契约和回归测试
更新AI游戏创作智能体App技术文档中的Windows稳定性说明
验证AGC开发态、Release打包、打包后GUI运行及完整agc:check门禁
2026-08-13 13:36:21 +08:00
lhk229 21137f676b 修复issue160 (#166)
Project CI / Repository checks (push) Successful in 1m16s
Project CI / Frontend tests (push) Successful in 3m14s
Project CI / Backend tests (push) Successful in 4m6s
Project CI / Native shell tests (push) Successful in 14m16s
#160

---------

Co-authored-by: kdletters <kdletters@qq.com>
Co-authored-by: 段舒康 <kdletters@qq.com>
Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/166
Co-authored-by: Linghong <ink29535@proton.me>
Co-committed-by: Linghong <ink29535@proton.me>
2026-08-13 13:28:45 +08:00
kdletters f395a6ed36 稳定Agent失败审计时序测试
Project CI / Repository checks (push) Successful in 1m1s
Project CI / Frontend tests (push) Successful in 2m58s
Project CI / Backend tests (push) Successful in 4m0s
Project CI / Native shell tests (push) Successful in 14m15s
等待 Runtime 失败后的审计记录有界落盘
保持 final-reply-failed 审计最终存在的强断言
连续五次验证流式连接中断回归
2026-08-12 22:38:59 +08:00
kdletters da7c4dc71c 修正Agent失败关闭回归语义
Project CI / Repository checks (push) Successful in 1m0s
Project CI / Frontend tests (push) Successful in 3m4s
Project CI / Backend tests (push) Successful in 3m44s
Project CI / Native shell tests (push) Failing after 10m20s
将流式连接中断断言为 Runtime 失败
禁止 transport 错误提交 planning fallback 冒充成功
保留安全失败消息与 final-reply-failed 审计验证
2026-08-12 22:24:17 +08:00
kdletters fd423770d8 根治Repository checks本地漏检
Project CI / Repository checks (push) Successful in 1m18s
Project CI / Frontend tests (push) Successful in 3m1s
Project CI / Backend tests (push) Successful in 4m17s
Project CI / Native shell tests (push) Failing after 12m32s
修复 Agent 失败展示变更中的 import 排序错误
统一 CI 与 master pre-push 的 Repository checks 入口
让 staged JS 和 TS 自动执行 ESLint 修复与 Prettier
补充部分暂存、忽略文件和待推 SHA 回归测试
同步分支保护与本地门禁流程文档
2026-08-12 22:06:35 +08:00
kdletters 794f3d4cf8 修复Agent失败原因丢失与成功误判
Project CI / Repository checks (push) Failing after 45s
Project CI / Frontend tests (push) Successful in 3m39s
Project CI / Backend tests (push) Successful in 4m44s
Project CI / Native shell tests (push) Failing after 13m11s
解析 Codex app-server 稳定失败分类并生成安全可行动摘要
统一 Runtime 事件、任务、阶段记录和各 Agent 状态面的失败展示
限制自主构建最终回复 fallback,避免鉴权与网络错误被提交为成功
补充失败分类、防泄漏、待核对和 fallback 回归测试
同步技术方案与共享决策记录
2026-08-12 21:35:11 +08:00
kdletters e04a8310a0 重做AGC智能体设置界面
Project CI / Repository checks (push) Successful in 1m32s
Project CI / Frontend tests (push) Successful in 3m2s
Project CI / Backend tests (push) Successful in 4m5s
Project CI / Native shell tests (push) Successful in 14m27s
将常用设置、Agent 模型、连接工具和高级参数分层展示

补充保存中、保存成功和失败状态反馈

更新设置页测试与项目决策记录
2026-08-12 21:04:30 +08:00
kdletters 82957fe1d4 修复子 Agent 澄清回执中转 (#165)
Project CI / Repository checks (push) Successful in 1m14s
Project CI / Frontend tests (push) Successful in 3m2s
Project CI / Backend tests (push) Successful in 4m5s
Project CI / Native shell tests (push) Successful in 14m31s
Closes #163

实现 child 澄清回执到 Supervisor 的 needs-user-input 中转。

- child 返回结构化问题回执,Runtime fail-closed 校验问题和 SHA-256。
- Supervisor 创建自己的 durable user.input_request,重复唤醒复用同一 action。
- 用户回答沿用 same-run 回灌,后续 continuation 绑定原 delegation。
- 补充 Rust 定向测试、技术方案和共享排障记忆。

验证:
- cargo check --tests
- cargo test ... claimed_needs_user_input_delivery_becomes_one_supervisor_wait
- cargo test ... static_delegate_user_input
- git diff --check

注:npm run check:encoding 在当前受限执行环境中因 spawnSync git EPERM 未能运行。

Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/165
Co-authored-by: kdletters <kdletters@qq.com>
Co-committed-by: kdletters <kdletters@qq.com>
2026-08-12 20:07:59 +08:00
kdletters 5e16837f3d 恢复游戏创作 External Editor 配置入口
Project CI / Repository checks (push) Successful in 1m34s
Project CI / Frontend tests (push) Successful in 3m5s
Project CI / Backend tests (push) Successful in 4m12s
Project CI / Native shell tests (push) Failing after 10m55s
普通 Launcher、开发工作台和独立 game-chat 统一显示 External Editor 配置。

补齐配置可见性、密码输入和持久化回归测试。

同步配置静态门禁、PRD、技术合同与共享决策。
2026-08-12 18:43:55 +08:00
kdletters effdaefc63 修复游戏智能体计划拒绝后的重复规划
Project CI / Repository checks (push) Successful in 1m5s
Project CI / Frontend tests (push) Successful in 3m22s
Project CI / Native shell tests (push) Failing after 12m42s
Project CI / Backend tests (push) Successful in 3m55s
在 runtime.plan_update 被拒绝后按角色收窄下一轮工具目录

恢复 Supervisor 首次项目修改的活性门禁

补充请求目录与活性门禁回归测试

同步更新游戏创作智能体实施规则
2026-08-12 17:00:50 +08:00
k88936 8abeb333bb 统一画布快速编辑白名单与入口行为 (#140)
Project CI / Repository checks (push) Successful in 56s
Project CI / Frontend tests (push) Successful in 4m1s
Project CI / Backend tests (push) Successful in 4m26s
Project CI / Native shell tests (push) Successful in 15m12s
- 使用白名单控制快速编辑功能的显示

- 同步浮动工具栏、右键菜单、打开入口和提交门禁
- 禁用角色动作序列帧(整体)、音频和单个图标(explain: backend reject)的快速编辑

- 把快速编辑api改为只接受resource Id | asset Id,删除 image_src 参数, 以保证校验

其中包含生产数据迁移。迁移用于清理历史普通图片错误持久化的 assetKind="image",覆盖 asset → project-resource → showcase → canvas 四个作用域,并包含 operator 鉴权、分批 dry-run、批次 SHA-256 绑定 apply、active 结构化画
  > 布迁移摘要同步及最终零残留复核。

---------

Co-authored-by: kdletters <kdletters@qq.com>
Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/140
Co-authored-by: 王德宇 <kvtodev@outlook.com>
Co-committed-by: 王德宇 <kvtodev@outlook.com>
2026-08-12 14:46:24 +08:00
kdletters 4c3c0e9cd4 修正GameAgent灵感区数据接入
Project CI / Repository checks (push) Successful in 1m24s
Project CI / Frontend tests (push) Successful in 3m31s
Project CI / Backend tests (push) Successful in 4m22s
Project CI / Native shell tests (push) Successful in 15m18s
保留灵感推荐空态展示

移除主站精选接口与素材类型接入

补充无数据状态回归测试与产品边界文档
2026-08-12 14:17:47 +08:00
k88936 e3d28c50af 修复陶泥儿精选点赞刷新状态 (#156)
Project CI / Frontend tests (push) Successful in 3m25s
Project CI / Repository checks (push) Successful in 1m12s
Project CI / Backend tests (push) Successful in 3m54s
Project CI / Native shell tests (push) Successful in 15m9s
原实现:

用户对某个精选素材点赞与否, 后端没有发送这部分数据

修复:

后端刷新精选素材列表(校验可选的auth信息, 不影响未登录状态的查看) , 根据这部分信息每个素材多查询一下用户是否点赞

---------

Co-authored-by: 段舒康 <kdletters@qq.com>
Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/156
Co-authored-by: 王德宇 <kvtodev@outlook.com>
Co-committed-by: 王德宇 <kvtodev@outlook.com>
2026-08-12 13:53:30 +08:00
menghao 8e3d9991fa 完成资源管理的功能修复 (#154)
Project CI / Repository checks (push) Successful in 1m5s
Project CI / Frontend tests (push) Successful in 3m0s
Project CI / Backend tests (push) Successful in 4m4s
Project CI / Native shell tests (push) Successful in 14m17s
实现资源卡本体化与图片视频音频预览播放

实现四个资源分区独立高度与内外滚动

实现依赖视图确定性聚类与拓扑变化重排

补齐布局、SVG、AppSurface、性能和媒体回归

同步工作台PRD、技术方案与项目共享记忆

---------

Co-authored-by: kdletters <kdletters@qq.com>
Co-authored-by: 段舒康 <kdletters@qq.com>
Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/154
Co-authored-by: menghao <mh18530625731@163.com>
Co-committed-by: menghao <mh18530625731@163.com>
2026-08-12 13:14:55 +08:00
kdletters 51e35468a5 修复自主构建测试项目锁竞态
Project CI / Repository checks (push) Successful in 1m21s
Project CI / Frontend tests (push) Successful in 3m8s
Project CI / Backend tests (push) Successful in 4m24s
Project CI / Native shell tests (push) Successful in 16m33s
将纯继续契约测试改为异步并等待子任务持久化终态。

等待 Agent lane 释放后再执行后续 manifest 写入,避免后台终态投影竞争项目锁。
2026-08-12 11:42:49 +08:00
menghao 03a4410272 game agent无限画布开发 (#136)
Project CI / Native shell tests (push) Failing after 11m56s
Project CI / Repository checks (push) Successful in 1m5s
Project CI / Frontend tests (push) Successful in 3m20s
Project CI / Backend tests (push) Successful in 4m1s
主要工作是共享同一套“画布内核与通用 UI 源码”,网站和 Tauri 只分别实现宿主适配层。

---------

Co-authored-by: 段舒康 <kdletters@qq.com>
Co-authored-by: kdletters <kdletters@qq.com>
Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/136
Co-authored-by: menghao <mh18530625731@163.com>
Co-committed-by: menghao <mh18530625731@163.com>
2026-08-12 10:54:16 +08:00
kdletters e118d66699 增加提交前 TypeScript 自动格式化
Project CI / Repository checks (push) Successful in 53s
Project CI / Frontend tests (push) Successful in 3m9s
Project CI / Backend tests (push) Successful in 4m19s
Project CI / Native shell tests (push) Successful in 16m9s
接入 Husky 与 lint-staged,仅格式化暂存的 TS/TSX 文件
补充部分暂存和未暂存内容隔离回归测试
更新共享开发工作流中的提交前格式化规则
2026-08-12 10:43:29 +08:00
kdletters 1363b9374c 引入游戏智能体动态目标验收图 (#161)
Project CI / Repository checks (push) Successful in 1m14s
Project CI / Frontend tests (push) Successful in 3m16s
Project CI / Backend tests (push) Successful in 4m26s
Project CI / Native shell tests (push) Successful in 16m2s
## 变更

- 冻结根 Supervisor 的 Goal Contract
- 引入动态 Acceptance Graph 并传播到专业 Agent
- 使用当前 revision 的真实动作回执作为完成证据
- 安全处理 steer 后旧根任务树替换

## 验证

- `npm run check:native-shells`
- `npm run agc:typecheck`
- `npm run check:encoding`
- `cargo fmt --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml -- --check`
- `git diff --check`

Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/161
Co-authored-by: kdletters <kdletters@qq.com>
Co-committed-by: kdletters <kdletters@qq.com>
2026-08-12 10:34:20 +08:00
lhk229 3c457feb4c 完美像素功能回归逻辑分辨率 (#155)
Project CI / Repository checks (push) Successful in 1m7s
Project CI / Frontend tests (push) Successful in 3m2s
Project CI / Backend tests (push) Successful in 4m8s
Project CI / Native shell tests (push) Successful in 13m48s
Co-authored-by: 段舒康 <kdletters@qq.com>
Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/155
Reviewed-by: 段舒康 <kdletters@qq.com>
Co-authored-by: Linghong <ink29535@proton.me>
Co-committed-by: Linghong <ink29535@proton.me>
2026-08-11 15:58:31 +08:00
kdletters aa5c857060 修复 Godot 项目提交后的 CI 门禁
Project CI / Repository checks (push) Successful in 1m8s
Project CI / Frontend tests (push) Successful in 2m59s
Project CI / Backend tests (push) Successful in 4m0s
Project CI / Native shell tests (push) Successful in 13m41s
移除根 H5 包中冗余的 Tauri HTTP 依赖并同步锁文件
修正客户端错误边界测试的 import 顺序
固定两项后台 Runtime 恢复测试使用 Provider 模式
补充 AGC 原生 HTTP 依赖归属约束
2026-08-11 14:34:42 +08:00
kdletters 755bf80858 支持 AI 游戏创作打开现有 Godot 项目
Project CI / Repository checks (push) Failing after 44s
Project CI / Native shell tests (push) Failing after 1m42s
Project CI / Frontend tests (push) Successful in 2m50s
Project CI / Backend tests (push) Successful in 3m41s
新增 Godot 项目选择、校验、导入和项目上下文切换入口。

只在所选项目根保留 .agent 元数据,并让总控使用标准运行档。

修复发布版原生 API 访问和 React runtime 重复加载问题。

收紧 Provider 工具 Schema 子集并增加回归门禁。

补充 Rust、前端测试及 PRD、技术方案和共享决策记录。
2026-08-11 13:25:29 +08:00
k88936 4c0fdf1806 修正画布改造工具恢复链路 (#158)
Project CI / Repository checks (push) Successful in 1m4s
Project CI / Frontend tests (push) Successful in 2m54s
Project CI / Backend tests (push) Successful in 3m52s
Project CI / Native shell tests (push) Successful in 14m46s
在文档中明确改造特殊情况的处理

修复fallback到快速编辑的行为:
旧版图片按 assetKind 与 mediaType 选择工具,未知图片回落默认生成工具并保留旧版告警,而不是all in fallback到快速编辑

清理冗余代码:
移除 QuickEditPanelState 的 redraw 模式、旧提交分支及无调用结果层构造器

Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/158
Co-authored-by: 王德宇 <kvtodev@outlook.com>
Co-committed-by: 王德宇 <kvtodev@outlook.com>
2026-08-11 12:36:30 +08:00
kdletters 7f129ddd6e 修复 Native CI 的 Agent 模式测试隔离
Project CI / Repository checks (push) Successful in 1m10s
Project CI / Frontend tests (push) Successful in 2m52s
Project CI / Backend tests (push) Successful in 3m53s
Project CI / Native shell tests (push) Successful in 14m31s
为 Provider handoff 与 mock 请求测试显式固定 Provider 模式
同步 Goal steer 测试到条件中断语义
补充模拟 Provider 测试不得依赖本机 Codex 的排障约束
2026-08-11 11:14:38 +08:00
kdletters 4d79971d6b 修复多模式 Provider 请求栈溢出
Project CI / Repository checks (push) Successful in 57s
Project CI / Frontend tests (push) Successful in 2m51s
Project CI / Backend tests (push) Successful in 3m36s
Project CI / Native shell tests (push) Failing after 10m48s
装箱持久重试与非持久压缩的完整 Provider 请求 future
补充默认 Tokio worker 栈溢出排障经验
同步 AI 游戏创作 Runtime 的异步装箱约束
2026-08-11 10:24:58 +08:00
kdletters 5550e24f83 接入 Codex 节点 Agent 并完善总控交互
Project CI / Repository checks (push) Successful in 1m13s
Project CI / Frontend tests (push) Successful in 2m54s
Project CI / Backend tests (push) Successful in 3m57s
Project CI / Native shell tests (push) Failing after 6m11s
新增 Codex app-server 与 CLI 节点执行模式并保留 Provider 回退
加固节点凭据隔离、终态未知回收、进程生命周期与持久恢复边界
修复资源画布等价刷新闪烁
为 Supervisor steer 增加 LLM 回复与条件中断
补齐配置界面、测试和技术文档
2026-08-10 20:58:43 +08:00
kdletters a4ead1a5d6 合并主线并同步四不写约定
Project CI / Repository checks (push) Successful in 1m16s
Project CI / Frontend tests (push) Successful in 3m0s
Project CI / Backend tests (push) Successful in 4m15s
Project CI / Native shell tests (push) Successful in 13m48s
合入最新远端主线且保留退役对象四不写规则

同步团队约定中的公开契约与正式迁移例外

保持原工作树其他已暂存和未暂存修改不变
2026-08-10 20:16:21 +08:00
kdletters 5949c2fd58 规范退役对象四不写原则
明确无现役依赖对象不写历史兼容代码与退役行为测试

禁止墓碑注释和墓碑文档并要求权威文档表达当前状态

保留公开契约、持久化数据和正式迁移的必要兼容边界
2026-08-10 20:14:30 +08:00
487 changed files with 110060 additions and 13374 deletions
@@ -29,9 +29,10 @@ Prefer `scripts/genarrative_external_api.py` for runnable REST calls. It uses on
- 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.
- Use stable references such as `objectKey`, project resource ID, or asset ID where each operation permits them. Image edit/redraw is stricter: `sourceReferenceId` accepts only a registered project resource ID or asset ID; upload confirmation alone is not enough. 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.
- For successful `style="pixelArt"`, treat completed-result and nested resource/asset dimensions as the final logical-grid PNG dimensions. They may differ from `size`, `imageSize`, the provider image, and `canvasCompletion.placeholder`; do not rescale or reject the artifact to match those inputs.
- 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.
## Documentation Navigation
@@ -50,8 +50,8 @@ Every generation row requires a stable `Idempotency-Key` header and returns HTTP
| 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` | `referenceId`, `iconDescriptions` | `style`, `referenceImageSrcs`, `screenColor`, `model`, `aspectRatio`, `imageSize`, `projectId`, `assetFolderId`, `assetLabel`, `canvasCompletion` |
| Image edit/redraw | `/api/external/v1/editor/images/edits` | `prompt`, `sourceReferenceId` | `referenceImageSrcs`, `model`, `size`, `projectId`, `assetFolderId`, `assetLabel`, `targetLayerId`, `canvasCompletion` |
| Icon spritesheet | `/api/external/v1/editor/icon-spritesheets/generations` | `referenceId`, `iconDescriptions` | `sliceLayout`, `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` |
@@ -82,16 +82,18 @@ After confirming a local upload, pass its stable `objectKey` into operations tha
| Target capability | Field |
| --- | --- |
| Image generation | `referenceImageSrcs` |
| Image edit/redraw | `sourceImageSrc`; additional references in `referenceImageSrcs` |
| Image edit/redraw | `sourceReferenceId` must be a registered project resource ID or asset ID; additional references remain in `referenceImageSrcs` |
| Icon spritesheet | Register the primary spec as an `assetKind="icon-spec"` project resource or asset, then pass its returned ID as `referenceId`; additional style references remain 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.
For image edit/redraw, confirming an upload is not sufficient: create a project resource or asset-library record first, then pass that record's ID as `sourceReferenceId`. The main source never accepts objectKey, URL, Data URL, or Blob URL. Use video/audio reference arrays only with models that support them. Do not pass an expiring signed read URL as a generation reference.
The icon-spritesheet primary `referenceId` is intentionally stricter than ordinary image references: it accepts only a current-owner project resource ID or asset ID whose authoritative `assetKind` is `icon-spec`. It does not accept an `objectKey`, URL, Data URL, or Blob URL.
`sliceLayout: "grid-2x2"` is an opt-in contract for four fixed game-runtime assets. The provider prompt and server persistence both preserve the ordered slots left-top, right-top, left-bottom, right-bottom. Omit it to retain the default connected-component slicing behaviour for ordinary free-form icon sheets.
## Common Values
Use OpenAPI as the final authority; these common values are a routing aid:
@@ -78,9 +78,9 @@ Keep the existing autonomous-build task graph. Do not add a parallel task system
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 `referenceId` plus concrete `iconDescriptions`.
3. `art-asset-plan` generates transparent `assets/art-spritesheet.png` through icon spritesheet generation, using the same registered art-spec resource ID as `referenceId` plus concrete `iconDescriptions`. For the four-category game contract it must also send `sliceLayout: "grid-2x2"`; this is an explicit fixed-slot contract, not a client-side guessed crop.
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.
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 response `sliceLayout: "grid-2x2"` and 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.
@@ -96,7 +96,7 @@ A minimal `canvasCompletion` is:
}
```
`dialogId` is optional. Do not reconstruct canvas state from completion results. Reload the project and asset library when complete authoritative snapshots are needed.
`dialogId` is optional. The placeholder supplies canvas placement and completion coordinates; it is not a final media pixel-size constraint. For successful pixel-art snapping, the result layer uses the final logical-grid PNG dimensions even when they differ from the placeholder. 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.
@@ -145,7 +145,7 @@ Carry the current art spec in `generationInputs.artSpec` and reflect important c
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.
- `"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. On successful snapping, each detected grid cell becomes one output pixel and the logical-grid PNG is persisted directly; it is not resized back to `size`, `imageSize`, the provider image, or `canvasCompletion.placeholder`. 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`.
@@ -169,6 +169,8 @@ client.generate_image(
)
```
Image edit/redraw has a stricter main-source identity rule. After upload confirmation, create either a project resource or an asset-library record and pass its `resourceId` or `assetId` as `sourceReferenceId`. Do not pass the uploaded objectKey as the main source; objectKey remains valid only for auxiliary `referenceImageSrcs` where the OpenAPI permits it.
Icon spritesheet generation has a stricter primary-spec contract. After upload confirmation, create a project resource or asset record with `assetKind: "icon-spec"`, retain its returned `resourceId` or `assetId`, and pass that ID as `referenceId`. The primary spec does not accept the uploaded `objectKey` directly; only additional style references may continue to use stable object keys in `referenceImageSrcs`.
For character animation from a local-only source, use actual dimensions and a stable synthetic layer ID:
@@ -196,7 +198,7 @@ Do not guess dimensions or pass a temporary signed read URL. See `authentication
The completed `result` may contain stable artifact fields such as:
- `objectKey`, media type, dimensions, or task ID.
- `objectKey`, media type, dimensions, or task ID. For successful `pixelArt`, image `width`/`height`, icon `spritesheetWidth`/`spritesheetHeight`, and nested resource/asset dimensions are the actual final logical-grid PNG dimensions rather than requested, provider, or placeholder dimensions.
- Sound-effect `durationSeconds` is the probed MP3 duration and `loop` is the frozen request boolean; neither is inferred from Prompt text.
- `resource`, `resourceId`, or equivalent canvas reference.
- `asset`, `assetId`, or equivalent library reference.
@@ -209,6 +211,10 @@ It deliberately excludes a complete project/canvas/library snapshot, Data URL, B
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.
### Delivery-size normalization result before pixel-art snapping
`result.warning.code: "dimension-restore-fallback"` records only the delivery-size normalization result established before any subsequent `pixelArt` snapping: the provider image could not be safely normalized, so its dimensions were preserved at that processing boundary. It does not describe or constrain the dimensions after `pixelArt`; if snapping succeeds, use the completed result's actual logical-grid dimensions as authoritative.
### Source-preserved post-processing failure
When `result.warning.code` is `postprocess-failed-source-preserved`:
@@ -548,13 +548,16 @@ class GenarrativeExternalClient:
idempotency_key=idempotency_key,
)
def edit_image(self, prompt: str, source_image_src: str, **fields: Any) -> Any:
def edit_image(self, prompt: str, source_reference_id: str, **fields: Any) -> Any:
source_reference_id = source_reference_id.strip()
if not source_reference_id:
raise GenarrativeApiError("source_reference_id must be a registered resource or asset ID")
self._apply_canvas_session_fields(fields, prompt, 1024, 1024)
prompt = self._apply_art_spec(fields, prompt)
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},
{"prompt": prompt, "sourceReferenceId": source_reference_id, **fields},
idempotency_key=idempotency_key,
)
+2 -17
View File
@@ -69,23 +69,8 @@ jobs:
- name: Install npm dependencies
run: bash scripts/ci-npm-ci-with-retry.sh
- name: Run repository lint gates
run: npm run lint
- name: Build web applications
run: npm run build
- name: Validate content data
run: npm run check:content
- name: Check committed whitespace
shell: bash
run: |
set -euo pipefail
base_ref="${SPACETIME_SCHEMA_BASE_REF:-}"
test -n "${base_ref}"
git cat-file -e "${base_ref}^{commit}"
git diff --check "${base_ref}"...HEAD
- name: Run repository checks
run: npm run check:repository-ci
frontend-tests:
name: Frontend tests
+2
View File
@@ -39,6 +39,8 @@ temp*build*/
/apps/ai-game-creator-shell/game-creator.config.local.json
/apps/mobile-shell/.expo/
/apps/mobile-shell/.expo-export-smoke/
/apps/preview-deployer-web/dist/
/apps/preview-deployer-web/node_modules/
/server-rs/.spacetimedb/
/server-rs/.data/
/public/generated-animations
+1
View File
@@ -0,0 +1 @@
npm run format:staged
+1
View File
@@ -0,0 +1 @@
npm run check:pre-push-master -- "$@"
+6
View File
@@ -26,6 +26,12 @@
- 后续新增 Markdown 文档文件名必须以分类标签开头,格式为 `【标签名】中文标题-日期.md`;历史文档不要求批量重命名,除非本次任务明确涉及。
- 工程修改要同步更新对应 `docs/` 文档;产生长期有效的架构约定、接口变化、排障经验、开发流程或协作规则时,同步更新 `docs/project-memory/shared-memory/`
- 默认保持系统简洁:优先复用、修改、扩展现有系统、页面和公共组件,不新建平行系统或平行页面。
- 对已明确退役且不存在现役调用方、公开契约、持久化数据、活跃实例或迁移要求的对象,坚持“四不写”:
1. 不写历史兼容代码。
2. 不写用于维持退役行为的防御性兼容测试。
3. 不写仅说明其曾存在或已删除的墓碑注释。
4. 不写仅记录其已删除的墓碑文档;直接将权威文档更新为当前状态。
- 公开 API、持久化数据、SpacetimeDB schema、跨版本重放、活跃实例和正式迁移不适用“四不写”;必要兼容应最小化、白名单化并配套契约或迁移测试,迁移完成后同步删除兼容实现与对应测试。
- UI 面板中不要默认写功能说明、规则描述或开发解释文案;移动端优先,同时保证网页端可正常显示和操作。
- 点击按钮弹出独立面板的设计,不要实现成在当前面板下面追加内容。
@@ -1,11 +1,12 @@
{
"agentMode": "codex_app_server",
"llm": {
"apiKey": "",
"baseUrl": "https://api.openai.com/v1",
"model": "gpt-4.1",
"baseUrl": "https://dev.genarrative.world/gpt/v1",
"model": "gpt-5.6-sol",
"apiKind": "openai_responses",
"reasoningEffort": "high",
"stream": false,
"reasoningEffort": "max",
"stream": true,
"webSearchEnabled": false,
"contextWindowTokens": 128000,
"autoCompactTokenLimit": 64000,
@@ -15,9 +16,5 @@
"retryBackoffMs": 500
},
"agentLlm": {},
"editorApi": {
"baseUrl": "http://127.0.0.1:8082",
"apiKey": ""
},
"mcpServers": {}
}
+1 -1
View File
@@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" href="data:," />
<title>AI 游戏创作</title>
<title>陶泥儿</title>
</head>
<body>
<div id="root"></div>
+11
View File
@@ -10,7 +10,9 @@
"dependencies": {
"@lexical/react": "^0.47.0",
"@lexical/utils": "^0.47.0",
"@tauri-apps/api": "^2.11.1",
"@tauri-apps/plugin-clipboard-manager": "2.3.2",
"@tauri-apps/plugin-http": "^2.5.9",
"@tauri-apps/plugin-opener": "~2",
"@vitejs/plugin-react": "^5.0.4",
"lexical": "^0.47.0",
@@ -2208,6 +2210,15 @@
"@tauri-apps/api": "^2.8.0"
}
},
"node_modules/@tauri-apps/plugin-http": {
"version": "2.5.9",
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-http/-/plugin-http-2.5.9.tgz",
"integrity": "sha512-lCiY0+vs4HvIUSvZrBs8TC3TiCB0MOPRmiUjTq4prW7SlcJE2jdLeT6KBsJrT9Tlplufl7W1pY6SFAO3gCWxDA==",
"license": "MIT OR Apache-2.0",
"dependencies": {
"@tauri-apps/api": "^2.11.0"
}
},
"node_modules/@tauri-apps/plugin-opener": {
"version": "2.5.4",
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-opener/-/plugin-opener-2.5.4.tgz",
+3
View File
@@ -24,6 +24,7 @@
"agent-runtime:mixed-swarm-real-e2e": "node scripts/agent-runtime-real-e2e.mjs --suite supervisor-swarm-static-isolated-autonomous-chat",
"agent-runtime:supervisor-swarm-autonomous-chat-real-e2e": "node scripts/agent-runtime-real-e2e.mjs --suite supervisor-swarm-autonomous-chat",
"agent-runtime:supervisor-autonomous-playable-lane-defense-real-e2e": "node scripts/agent-runtime-real-e2e.mjs --suite supervisor-autonomous-playable-lane-defense",
"agent-runtime:supervisor-game-chat-single-main-playable-real-e2e": "node scripts/agent-runtime-real-e2e.mjs --suite supervisor-game-chat-single-main-playable",
"agent-runtime:supervisor-autonomous-playable-lane-defense-deterministic-e2e": "node scripts/agent-runtime-deterministic-playable-e2e.mjs",
"agent-runtime:supervisor-autonomous-playable-lane-defense-deterministic-self-test": "node scripts/agent-runtime-deterministic-playable-e2e.mjs --self-test",
"agent-runtime:supervisor-swarm-transient-retry-real-e2e": "node scripts/agent-runtime-real-e2e.mjs --suite supervisor-swarm-transient-retry",
@@ -36,7 +37,9 @@
"dependencies": {
"@lexical/react": "^0.47.0",
"@lexical/utils": "^0.47.0",
"@tauri-apps/api": "^2.11.1",
"@tauri-apps/plugin-clipboard-manager": "2.3.2",
"@tauri-apps/plugin-http": "^2.5.9",
"@tauri-apps/plugin-opener": "~2",
"@vitejs/plugin-react": "^5.0.4",
"lexical": "^0.47.0",
File diff suppressed because it is too large Load Diff
@@ -2406,11 +2406,36 @@ export function isolatedJoinDeliveryTarget(delivery) {
return target;
}
export function finalMessageId(agentId, sessionId, runId) {
const fingerprint = createHash('sha256')
function runtimeMessageCorrelationId(agentId, sessionId, runId) {
return createHash('sha256')
.update(`${agentId}\n${sessionId}\n${runId}`)
.digest('hex');
return `agent-finalization-${fingerprint.slice(0, 32)}`;
}
export function finalMessageId(agentId, sessionId, runId) {
return `agent-finalization-${runtimeMessageCorrelationId(
agentId,
sessionId,
runId,
).slice(0, 32)}`;
}
export function runtimePublicStatusMessageId(
agentId,
sessionId,
runId,
status,
) {
const correlationId = runtimeMessageCorrelationId(
agentId,
sessionId,
runId,
).slice(0, 32);
const statusFingerprint = createHash('sha256')
.update(status)
.digest('hex')
.slice(0, 16);
return `runtime-public-status-${correlationId}-${statusFingerprint}`;
}
export function backgroundTaskMessageId(agentId, sessionId, runId, source) {
@@ -2444,7 +2469,10 @@ export function disposableProjectPathVariants() {
}
export function formalConfigPathVariants() {
return absolutePathVariants(state.options?.configDir);
return absolutePathVariants(
state.options?.configDir,
state.isolatedRunner?.appDataDir,
);
}
export function absolutePathVariants(...values) {
@@ -20,7 +20,15 @@ import {
stopOwnedIsolatedRunner,
} from './harness/app-data.mjs';
import { loadConfig, parseArguments } from './harness/config.mjs';
import { closeInteractiveCli } from './harness/process.mjs';
import {
activeInteractiveCliSessions,
captureOwnedProcessCleanupSnapshot,
closeInteractiveCli,
destroyInteractiveCliOutputStreams,
interactiveCliOutput,
verifyOwnedProcessCleanupSnapshot,
waitForInteractiveCliStdioClose,
} from './harness/process.mjs';
import { checkPrerequisites } from './harness/project.mjs';
import {
buildSummary,
@@ -266,6 +274,21 @@ if (selfTestRequested) {
recordError(error?.code ?? 'unexpected-error', error);
} finally {
state.cleanupInProgress = true;
const stateTrackedInteractiveCliSessions = new Set(
[
state.userInputCliSession,
state.supervisorAutonomousPlayableCliSession,
state.supervisorSwarmCliSession,
].filter(Boolean),
);
const interactiveCliSessions = [
...new Set([
...stateTrackedInteractiveCliSessions,
...activeInteractiveCliSessions,
]),
];
const supervisorAutonomousPlayableCliSession =
state.supervisorAutonomousPlayableCliSession;
if (isUserInputRuntimeSuite() && state.userInputCliSession) {
try {
await closeInteractiveCli(state.userInputCliSession);
@@ -311,6 +334,15 @@ if (selfTestRequested) {
}
state.supervisorSwarmCliSession = null;
}
for (const session of interactiveCliSessions) {
if (stateTrackedInteractiveCliSessions.has(session)) continue;
try {
await closeInteractiveCli(session);
} catch (error) {
state.status = 'FAIL';
recordError('interactive-cli-cleanup-failed', error);
}
}
if (isMcpRuntimeSuite() && state.mcp.httpFixture) {
try {
await stopMcpHttpFixture();
@@ -320,16 +352,42 @@ if (selfTestRequested) {
recordError('mcp-http-fixture-cleanup-failed', error);
}
}
if (
isSupervisorAutonomousPlayableLaneDefenseSuite() &&
state.isolatedRunner.appDataDir
) {
try {
const runnerPid = state.isolatedRunner.current?.pid ?? null;
const helperPid =
state.isolatedRunner.current?.killHandle?.child?.pid ?? null;
state.supervisorAutonomousPlayable.ownedProcessCleanupSnapshot =
await captureOwnedProcessCleanupSnapshot({
runnerPid,
helperPids: Number.isSafeInteger(helperPid) ? [helperPid] : [],
rootPids: [
...interactiveCliSessions.map((session) => session.child?.pid),
...[...activeCommandChildren].map((child) => child.pid),
].filter((pid) => Number.isSafeInteger(pid) && pid > 0),
});
const observed =
state.supervisorAutonomousPlayable.ownedProcessCleanupSnapshot
.observedCounts;
assert(
observed.runner === 1 && observed.helper === 1,
'supervisor-autonomous-playable-owned-process-snapshot-incomplete',
);
} catch (error) {
state.status = 'FAIL';
recordError(
'supervisor-autonomous-playable-owned-process-snapshot-failed',
error,
);
}
}
if (isIsolatedRunnerSuite() && state.isolatedRunner.appDataDir) {
try {
await stopOwnedIsolatedRunner();
state.isolatedRunner.stopped = true;
state.isolatedRunner.cleanupPerformed =
await removeIsolatedSuiteAppData();
if (!state.isolatedRunner.cleanupPerformed) {
state.status = 'FAIL';
recordError('isolated-appdata-cleanup-sentinel-missing');
}
} catch (error) {
state.status = 'FAIL';
const safeCleanupErrorCode =
@@ -342,8 +400,51 @@ if (selfTestRequested) {
state.isolatedRunner.current?.killHandle,
).catch(() => {});
}
}
for (const session of interactiveCliSessions) {
try {
await waitForInteractiveCliStdioClose(session, 10_000);
} catch (error) {
destroyInteractiveCliOutputStreams(session);
state.status = 'FAIL';
recordError(
error?.code === 'interactive-cli-stdio-close-timeout'
? error.code
: 'interactive-cli-stdio-cleanup-failed',
error,
);
}
}
if (supervisorAutonomousPlayableCliSession) {
state.supervisorAutonomousPlayable.cliOutput = interactiveCliOutput(
supervisorAutonomousPlayableCliSession,
);
}
if (isIsolatedRunnerSuite() && state.isolatedRunner.appDataDir) {
if (state.isolatedRunner.stopped) {
try {
state.isolatedRunner.cleanupPerformed =
await removeIsolatedSuiteAppData();
if (!state.isolatedRunner.cleanupPerformed) {
state.status = 'FAIL';
recordError('isolated-appdata-cleanup-sentinel-missing');
}
} catch (error) {
state.status = 'FAIL';
const safeCleanupErrorCode =
isNonEmptyString(error?.code) &&
/^(?:isolated|source)-[a-z0-9-]+$/u.test(error.code)
? error.code
: 'isolated-appdata-cleanup-failed';
recordError(safeCleanupErrorCode, error);
}
}
const killMethod =
state.isolatedRunner.pidfdClaimCount > 0 ? 'linux-pidfd' : null;
state.isolatedRunner.pidfdClaimCount > 0
? process.platform === 'win32'
? 'windows-process-handle'
: 'linux-pidfd'
: null;
if (isSteerRunnerKillSuite()) {
state.evidence.steerRunnerStopped = state.isolatedRunner.stopped;
state.evidence.steerAppDataCleanupPerformed =
@@ -661,6 +762,61 @@ if (selfTestRequested) {
);
}
}
if (
isSupervisorAutonomousPlayableLaneDefenseSuite() &&
state.isolatedRunner.appDataDir
) {
const snapshot =
state.supervisorAutonomousPlayable.ownedProcessCleanupSnapshot;
if (snapshot) {
try {
const cleanup = await verifyOwnedProcessCleanupSnapshot(snapshot);
state.evidence.ownedProcessIdentityCaptured = true;
state.evidence.ownedRunnerObservedCount =
snapshot.observedCounts.runner;
state.evidence.ownedHelperObservedCount =
snapshot.observedCounts.helper;
state.evidence.ownedNodeDescendantObservedCount =
snapshot.observedCounts.node;
state.evidence.ownedBrowserDescendantObservedCount =
snapshot.observedCounts.browser;
state.evidence.ownedCommandDescendantObservedCount =
snapshot.observedCounts.command;
state.evidence.ownedRunnerResidualCount =
cleanup.residualCounts.runner;
state.evidence.ownedHelperResidualCount =
cleanup.residualCounts.helper;
state.evidence.ownedNodeDescendantResidualCount =
cleanup.residualCounts.node;
state.evidence.ownedBrowserDescendantResidualCount =
cleanup.residualCounts.browser;
state.evidence.ownedCommandDescendantResidualCount =
cleanup.residualCounts.command;
state.evidence.activeCommandChildrenAfterCleanup =
cleanup.activeCommandChildCount;
state.evidence.activeInteractiveCliSessionsAfterCleanup =
cleanup.activeInteractiveCliSessionCount;
state.evidence.ownedProcessCleanupPassed = cleanup.clean;
if (!cleanup.clean) {
state.status = 'FAIL';
recordError(
'supervisor-autonomous-playable-owned-process-residual-detected',
);
}
} catch (error) {
state.status = 'FAIL';
recordError(
'supervisor-autonomous-playable-owned-process-verification-failed',
error,
);
}
} else {
state.status = 'FAIL';
recordError(
'supervisor-autonomous-playable-owned-process-snapshot-missing',
);
}
}
if (
isSteerRunnerKillSuite() &&
state.projectRoot &&
@@ -1210,6 +1366,7 @@ if (selfTestRequested) {
const safeSummary = {
status: state.status,
suite: state.suite,
providerUsed: false,
blocked: state.blocked,
cleanup: {
performed: state.cleanupPerformed,
File diff suppressed because it is too large Load Diff
@@ -15,6 +15,7 @@ import {
scopedAgentsSuite,
steerRunnerKillSuite,
supervisorAutonomousPlayableLaneDefenseSuite,
supervisorGameChatSingleMainPlayableSuite,
supervisorSwarmAutonomousChatSuite,
supervisorSwarmCollaborationPolicyMixedRecoverySuite,
supervisorSwarmFinalReplyTransientRetrySuite,
@@ -70,6 +71,7 @@ export function parseArguments(args) {
suite === supervisorSwarmToolPlanHandoffRunnerKillSuite ||
suite === supervisorSwarmAutonomousChatSuite ||
suite === supervisorAutonomousPlayableLaneDefenseSuite ||
suite === supervisorGameChatSingleMainPlayableSuite ||
suite === supervisorSwarmStaticIsolatedAutonomousChatSuite ||
suite === supervisorSwarmCollaborationPolicyMixedRecoverySuite ||
suite === steerRunnerKillSuite ||
@@ -19,6 +19,8 @@ import {
} from '../suites/supervisor-swarm.mjs';
import { isIsolatedRunnerSuite } from './reporting.mjs';
export const activeInteractiveCliSessions = new Set();
export async function prepareCliBinary() {
const cargo = process.platform === 'win32' ? 'cargo.exe' : 'cargo';
await runProcess(
@@ -154,36 +156,70 @@ export function startInteractiveCli(args) {
stdio: ['pipe', 'pipe', 'pipe'],
},
);
return createInteractiveCliSession(child);
}
export function createInteractiveCliSession(child) {
activeCommandChildren.add(child);
const session = {
child,
stdout: Buffer.alloc(0),
stderr: Buffer.alloc(0),
exited: false,
exitInfo: null,
exitPromise: null,
closed: false,
closeInfo: null,
closePromise: null,
stdioClosed: false,
stdioCloseInfo: null,
spawnError: null,
stdinError: null,
};
activeInteractiveCliSessions.add(session);
session.exitPromise = new Promise((resolve) => {
const settle = (result) => {
if (session.exited) return;
activeCommandChildren.delete(child);
session.exited = true;
session.closed = true;
session.exitInfo = result;
session.closeInfo = result;
resolve(result);
};
child.once('error', (error) => {
session.spawnError = error;
settle({ code: null, signal: null, error });
});
child.once('exit', (code, signal) => {
settle({ code, signal, error: null });
});
});
session.closePromise = new Promise((resolve) => {
child.on('error', (error) => {
child.once('close', (code, signal) => {
activeCommandChildren.delete(child);
session.closed = true;
session.closeInfo = { code: null, signal: null, error };
resolve(session.closeInfo);
});
child.on('close', (code, signal) => {
activeCommandChildren.delete(child);
session.closed = true;
session.closeInfo = { code, signal, error: null };
resolve(session.closeInfo);
activeInteractiveCliSessions.delete(session);
session.stdioClosed = true;
session.stdioCloseInfo = {
code,
signal,
error: session.spawnError,
};
resolve(session.stdioCloseInfo);
});
});
child.stdin?.on('error', (error) => {
session.stdinError ??= error;
});
child.stdout.on('data', (chunk) => {
state.transcriptScanner?.scan('interactive-stdout', chunk);
state.projectPathTranscriptScanner?.scan('interactive-stdout', chunk);
state.formalConfigPathTranscriptScanner?.scan('interactive-stdout', chunk);
session.stdout = appendBounded(session.stdout, chunk, commandOutputLimit);
});
child.stderr.on('data', (chunk) => {
state.transcriptScanner?.scan('interactive-stderr', chunk);
state.projectPathTranscriptScanner?.scan('interactive-stderr', chunk);
state.formalConfigPathTranscriptScanner?.scan('interactive-stderr', chunk);
session.stderr = appendBounded(session.stderr, chunk, commandOutputLimit);
});
@@ -205,16 +241,23 @@ export async function waitForInteractiveCliOutput(
predicate,
code,
timeoutMs,
{ allowAfterProcessExit = false } = {},
) {
const deadline = Date.now() + timeoutMs;
while (Date.now() < deadline) {
const output = interactiveCliOutput(session);
if (predicate(output)) return output;
if (session.closed) {
if (session.exited && !allowAfterProcessExit) {
if (session === state.supervisorSwarmCliSession) {
recordSupervisorSwarmChatSessionFailureDiagnostic(session);
}
throw codedError(`${code}-cli-closed`);
throw codedError(`${code}-cli-exited`);
}
if (session.stdioClosed) {
if (session === state.supervisorSwarmCliSession) {
recordSupervisorSwarmChatSessionFailureDiagnostic(session);
}
throw codedError(`${code}-cli-stdio-closed`);
}
await sleep(50);
}
@@ -223,7 +266,7 @@ export async function waitForInteractiveCliOutput(
export async function waitForInteractiveCliExit(session, timeoutMs) {
const result = await Promise.race([
session.closePromise,
session.exitPromise,
sleep(timeoutMs).then(() => null),
]);
if (!result) throw codedError('interactive-cli-exit-timeout');
@@ -236,26 +279,52 @@ export async function waitForInteractiveCliExit(session, timeoutMs) {
}
export async function closeInteractiveCli(session) {
if (!session || session.closed) return;
if (session.child.stdin.writable) {
if (!session) return null;
if (session.exited) return session.exitInfo;
if (
session.child.stdin.writable &&
!session.child.stdin.writableEnded &&
!session.child.stdin.destroyed
) {
session.child.stdin.write('/quit\n');
}
let result = await Promise.race([
session.closePromise,
session.exitPromise,
sleep(3_000).then(() => null),
]);
if (!result && !session.closed) {
if (!result && !session.exited) {
session.child.kill('SIGTERM');
result = await Promise.race([
session.closePromise,
session.exitPromise,
sleep(2_000).then(() => null),
]);
}
if (!result && !session.closed) {
if (!result && !session.exited) {
session.child.kill('SIGKILL');
result = await session.closePromise;
result = await Promise.race([
session.exitPromise,
sleep(5_000).then(() => null),
]);
}
assert(Boolean(result), 'interactive-cli-cleanup-timeout');
return result;
}
export async function waitForInteractiveCliStdioClose(session, timeoutMs) {
if (!session || session.stdioClosed) return session?.stdioCloseInfo ?? null;
const result = await Promise.race([
session.closePromise,
sleep(timeoutMs).then(() => null),
]);
if (!result) throw codedError('interactive-cli-stdio-close-timeout');
return result;
}
export function destroyInteractiveCliOutputStreams(session) {
if (!session) return;
for (const stream of [session.child.stdout, session.child.stderr]) {
if (stream && !stream.destroyed) stream.destroy();
}
}
export async function runProcess(
@@ -329,6 +398,214 @@ export async function runProcess(
});
}
export async function listSystemProcessIdentities() {
if (process.platform === 'win32') {
const systemRoot = process.env.SystemRoot ?? process.env.SYSTEMROOT;
assert(
typeof systemRoot === 'string' && path.isAbsolute(systemRoot),
'owned-process-snapshot-system-root-invalid',
);
const powershell = path.join(
systemRoot,
'System32/WindowsPowerShell/v1.0/powershell.exe',
);
const metadata = await fs.lstat(powershell);
assert(
metadata.isFile() && !metadata.isSymbolicLink(),
'owned-process-snapshot-powershell-invalid',
);
const result = await runProcess(
powershell,
[
'-NoProfile',
'-NonInteractive',
'-Command',
'$processes = @(Get-CimInstance Win32_Process | Select-Object ProcessId,ParentProcessId,CreationDate,Name); $processes | ConvertTo-Json -Compress',
],
{
cwd: appRoot,
timeoutMs: 30_000,
env: { ...process.env, NO_COLOR: '1', RUST_BACKTRACE: '0' },
},
);
const parsed = JSON.parse(result.stdout);
return (Array.isArray(parsed) ? parsed : [parsed])
.map((record) => ({
pid: Number(record?.ProcessId),
parentPid: Number(record?.ParentProcessId),
startedAt: String(record?.CreationDate ?? ''),
name: String(record?.Name ?? ''),
}))
.filter(validSystemProcessIdentity);
}
assert(
process.platform === 'linux' || process.platform === 'darwin',
'owned-process-snapshot-platform-unsupported',
);
const result = await runProcess(
'ps',
['-A', '-o', 'pid=', '-o', 'ppid=', '-o', 'lstart=', '-o', 'comm='],
{ cwd: appRoot, timeoutMs: 30_000 },
);
return result.stdout
.split(/\r?\n/u)
.map((line) => line.trim())
.filter(Boolean)
.map((line) => {
const fields = line.split(/\s+/u);
return {
pid: Number(fields[0]),
parentPid: Number(fields[1]),
startedAt: fields.slice(2, 7).join(' '),
name: fields.slice(7).join(' '),
};
})
.filter(validSystemProcessIdentity);
}
function validSystemProcessIdentity(record) {
return (
Number.isSafeInteger(record?.pid) &&
record.pid > 0 &&
Number.isSafeInteger(record.parentPid) &&
record.parentPid >= 0 &&
typeof record.startedAt === 'string' &&
record.startedAt.length > 0 &&
typeof record.name === 'string' &&
record.name.length > 0
);
}
export function buildOwnedProcessCleanupSnapshot(
processRecords,
{ rootPids = [], runnerPid = null, helperPids = [] } = {},
) {
assert(
Array.isArray(processRecords) &&
Array.isArray(rootPids) &&
Array.isArray(helperPids),
'owned-process-snapshot-input-invalid',
);
const records = processRecords.filter(validSystemProcessIdentity);
const byPid = new Map(records.map((record) => [record.pid, record]));
const childrenByParent = new Map();
for (const record of records) {
const children = childrenByParent.get(record.parentPid) ?? [];
children.push(record.pid);
childrenByParent.set(record.parentPid, children);
}
const normalizedRunnerPid = Number.isSafeInteger(runnerPid)
? runnerPid
: null;
const helperPidSet = new Set(
helperPids.filter((pid) => Number.isSafeInteger(pid) && pid > 0),
);
const roots = [
...new Set(
[...rootPids, normalizedRunnerPid, ...helperPidSet].filter(
(pid) => Number.isSafeInteger(pid) && pid > 0,
),
),
];
assert(roots.length > 0, 'owned-process-snapshot-root-missing');
const ownedPids = new Set();
const queue = [...roots];
while (queue.length > 0) {
const pid = queue.shift();
if (ownedPids.has(pid)) continue;
ownedPids.add(pid);
queue.push(...(childrenByParent.get(pid) ?? []));
}
const identities = [...ownedPids]
.map((pid) => byPid.get(pid))
.filter(Boolean)
.map((record) => ({
pid: record.pid,
startedAt: record.startedAt,
name: record.name,
kind: ownedProcessKind(record, normalizedRunnerPid, helperPidSet),
}))
.sort((left, right) => left.pid - right.pid);
return {
identities,
observedCounts: countOwnedProcessKinds(identities),
};
}
function ownedProcessKind(record, runnerPid, helperPids) {
if (record.pid === runnerPid) return 'runner';
if (helperPids.has(record.pid)) return 'helper';
const name = path.basename(record.name).toLowerCase();
if (/^node(?:\.exe)?$/u.test(name)) return 'node';
if (/^(?:chrome|chromium|msedge|google-chrome)(?:\.exe)?$/u.test(name)) {
return 'browser';
}
return 'command';
}
function countOwnedProcessKinds(identities) {
const counts = {
runner: 0,
helper: 0,
node: 0,
browser: 0,
command: 0,
total: identities.length,
};
for (const identity of identities) counts[identity.kind] += 1;
return counts;
}
export function inspectOwnedProcessCleanupResiduals(
snapshot,
processRecords,
{ activeCommandChildCount = 0, activeInteractiveCliSessionCount = 0 } = {},
) {
assert(
Array.isArray(snapshot?.identities) && Array.isArray(processRecords),
'owned-process-residual-input-invalid',
);
const currentByPid = new Map(
processRecords
.filter(validSystemProcessIdentity)
.map((record) => [record.pid, record]),
);
const residualIdentities = snapshot.identities.filter((identity) => {
const current = currentByPid.get(identity.pid);
return (
current?.startedAt === identity.startedAt &&
current?.name === identity.name
);
});
return {
residualCounts: countOwnedProcessKinds(residualIdentities),
activeCommandChildCount,
activeInteractiveCliSessionCount,
clean:
residualIdentities.length === 0 &&
activeCommandChildCount === 0 &&
activeInteractiveCliSessionCount === 0,
};
}
export async function captureOwnedProcessCleanupSnapshot(options) {
return buildOwnedProcessCleanupSnapshot(
await listSystemProcessIdentities(),
options,
);
}
export async function verifyOwnedProcessCleanupSnapshot(snapshot) {
return inspectOwnedProcessCleanupResiduals(
snapshot,
await listSystemProcessIdentities(),
{
activeCommandChildCount: activeCommandChildren.size,
activeInteractiveCliSessionCount: activeInteractiveCliSessions.size,
},
);
}
export function appendBounded(current, chunk, limit) {
const combined = Buffer.concat([current, chunk]);
return combined.length <= limit
@@ -1,4 +1,4 @@
import { assert } from '../assertions/core.mjs';
import { assert, hashValue } from '../assertions/core.mjs';
import { disposableProjectPathVariants } from '../assertions/runtime.mjs';
import { fs, os, path, randomUUID } from '../dependencies.mjs';
import {
@@ -28,7 +28,10 @@ import {
isGoalRuntimeSuite,
} from '../suites/goal.mjs';
import { isResponseStreamSuite } from '../suites/response-stream.mjs';
import { isSupervisorAutonomousPlayableLaneDefenseSuite } from '../suites/supervisor-autonomous-playable.mjs';
import {
isSupervisorAutonomousPlayableLaneDefenseSuite,
isSupervisorGameChatSingleMainPlayableSuite,
} from '../suites/supervisor-autonomous-playable.mjs';
import {
isSupervisorSwarmSuite,
supervisorSwarmVerificationFixtureSource,
@@ -40,27 +43,97 @@ import { effectiveAgentLlmConfig } from './config.mjs';
import { runProcess } from './process.mjs';
import { isIsolatedRunnerSuite } from './reporting.mjs';
export async function checkPrerequisites(config) {
const requiredAgents = isUserInputRuntimeSuite()
export function requiredAgentIdsForSuite() {
return isUserInputRuntimeSuite()
? [projectSupervisorAgentId]
: isSupervisorAutonomousPlayableLaneDefenseSuite()
? [projectSupervisorAgentId]
: isSupervisorSwarmSuite()
? [
projectSupervisorAgentId,
supervisorSwarmDesignAgentId,
supervisorSwarmQualityAgentId,
]
: isIsolatedRunnerSuite()
? [mainAgentId]
: [mainAgentId, 'quality-review'];
const llmConfigured = requiredAgents.every((agentId) => {
: isSupervisorGameChatSingleMainPlayableSuite()
? [
projectSupervisorAgentId,
mainAgentId,
'art-director',
'art-asset-plan',
]
: isSupervisorAutonomousPlayableLaneDefenseSuite()
? [projectSupervisorAgentId]
: isSupervisorSwarmSuite()
? [
projectSupervisorAgentId,
supervisorSwarmDesignAgentId,
supervisorSwarmQualityAgentId,
]
: isIsolatedRunnerSuite()
? [mainAgentId]
: [mainAgentId, 'quality-review'];
}
export function expectedProviderBindingForSuite(config) {
if (
isSupervisorGameChatSingleMainPlayableSuite() &&
config.agentMode !== 'provider'
) {
return null;
}
const agentIds = requiredAgentIdsForSuite();
const effectiveConfigs = agentIds.map((agentId) =>
effectiveAgentLlmConfig(config, agentId),
);
if (
effectiveConfigs.length === 0 ||
effectiveConfigs.some((effective) =>
['apiKey', 'baseUrl', 'model', 'apiKind', 'reasoningEffort'].some(
(key) =>
typeof effective[key] !== 'string' ||
effective[key].trim().length === 0,
),
)
) {
return null;
}
const [expected] = effectiveConfigs;
const expectedIdentity = [
expected.model.trim(),
expected.apiKind.trim(),
expected.reasoningEffort.trim(),
expected.baseUrl.trim(),
];
if (
effectiveConfigs.some(
(effective) =>
JSON.stringify([
effective.model.trim(),
effective.apiKind.trim(),
effective.reasoningEffort.trim(),
effective.baseUrl.trim(),
]) !== JSON.stringify(expectedIdentity),
)
) {
return null;
}
return {
...(isSupervisorGameChatSingleMainPlayableSuite()
? { providerAgentMode: 'provider' }
: {}),
providerModel: expectedIdentity[0],
providerApiKind: expectedIdentity[1],
providerReasoningEffort: expectedIdentity[2],
providerBaseUrlSha256: hashValue(expectedIdentity[3]),
boundAgentIds: [...agentIds].sort(),
};
}
export async function checkPrerequisites(config) {
const requiredAgents = requiredAgentIdsForSuite();
let llmConfigured = requiredAgents.every((agentId) => {
const effective = effectiveAgentLlmConfig(config, agentId);
return ['apiKey', 'baseUrl', 'model'].every(
(key) =>
typeof effective[key] === 'string' && effective[key].trim().length > 0,
);
});
const providerBinding = expectedProviderBindingForSuite(config);
if (isSupervisorGameChatSingleMainPlayableSuite()) {
llmConfigured = llmConfigured && providerBinding !== null;
}
const editorApiConfigured = ['apiKey', 'baseUrl'].every(
(key) =>
typeof config.editorApi?.[key] === 'string' &&
@@ -68,6 +141,7 @@ export async function checkPrerequisites(config) {
);
return {
llmConfigured,
providerBinding,
chromeAvailable:
!isIsolatedRunnerSuite() ||
isSupervisorAutonomousPlayableLaneDefenseSuite()
@@ -150,7 +224,9 @@ export function supportedBrowserCandidates(platform, environment) {
return candidates;
}
export async function seedDisposableProject() {
export async function seedDisposableProject({
preserveProductionInitBaseline = false,
} = {}) {
const prefix = path.join(os.tmpdir(), 'genarrative-agent-runtime-real-e2e-');
const sentinelToken = randomUUID();
state.projectRoot = await createSentinelOwnedTempDirectory({
@@ -189,37 +265,42 @@ export async function seedDisposableProject() {
...(isResponseStreamSuite() ? [responseStreamThinkingCanary] : []),
];
const generatedBaselineWrites = preserveProductionInitBaseline
? []
: [
fs.writeFile(
path.join(state.projectRoot, 'package.json'),
`${JSON.stringify(
{
name: 'genarrative-agent-runtime-real-e2e-project',
private: true,
scripts: {
test: verificationCommand,
'check:e2e': verificationCommand,
},
},
null,
2,
)}\n`,
),
fs.writeFile(
path.join(state.projectRoot, 'verify-e2e.mjs'),
isSupervisorSwarmSuite()
? supervisorSwarmVerificationFixtureSource()
: isGoalRuntimeSuite() ||
isResponseStreamSuite() ||
isWebSearchSuite() ||
isSupervisorAutonomousPlayableLaneDefenseSuite()
? goalRevisionOneVerificationFixtureSource()
: goalRevisionTwoVerificationFixtureSource(),
),
fs.writeFile(
path.join(state.projectRoot, 'game/index.html'),
seededGameHtml(),
),
];
await Promise.all([
fs.writeFile(
path.join(state.projectRoot, 'package.json'),
`${JSON.stringify(
{
name: 'genarrative-agent-runtime-real-e2e-project',
private: true,
scripts: {
test: verificationCommand,
'check:e2e': verificationCommand,
},
},
null,
2,
)}\n`,
),
fs.writeFile(
path.join(state.projectRoot, 'verify-e2e.mjs'),
isSupervisorSwarmSuite()
? supervisorSwarmVerificationFixtureSource()
: isGoalRuntimeSuite() ||
isResponseStreamSuite() ||
isWebSearchSuite() ||
isSupervisorAutonomousPlayableLaneDefenseSuite()
? goalRevisionOneVerificationFixtureSource()
: goalRevisionTwoVerificationFixtureSource(),
),
fs.writeFile(
path.join(state.projectRoot, 'game/index.html'),
seededGameHtml(),
),
...generatedBaselineWrites,
fs.writeFile(
path.join(state.projectRoot, 'AGENTS.md'),
'# Real E2E Repository Context\n\n- REPOSITORY_CONTEXT_MARKER: preserve the visible text and canvas.\n- Read package.json before verification.\n- Never read or expose .env, game-creator.config.json, or .agent/private-secret.txt.\n',
@@ -264,7 +345,16 @@ export async function seedDisposableProject() {
mode: 0o600,
},
);
await initializeDisposableGitRepository();
await initializeDisposableGitRepository(
preserveProductionInitBaseline
? [
'AGENTS.md',
'e2e/isolated-a/evidence.txt',
'e2e/isolated-b/evidence.txt',
'e2e/isolated-c/evidence.txt',
]
: undefined,
);
}
export async function initializeDisposableGitRepository(
@@ -310,12 +400,17 @@ export function seededGameHtml() {
<main>
<h1>${visibleText}</h1>
<p id="patch-state">REAL_E2E_TARGET:before</p>
<p id="objective">Objective: survive until victory. On defeat, use Restart.</p>
<canvas id="game" width="640" height="360"></canvas>
</main>
<script>
const canvas = document.getElementById('game');
const context = canvas.getContext('2d');
let frame = 0;
canvas.addEventListener('pointerdown', () => {
frame = 0;
document.body.dataset.input = 'pointer';
});
function draw() {
frame += 1;
context.fillStyle = '#13293d'; context.fillRect(0, 0, canvas.width, canvas.height);
@@ -332,6 +427,23 @@ export function seededGameHtml() {
`;
}
export function productionDefaultGameIndexHtml() {
return `<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Genarrative Game Draft</title>
<style>
body { margin: 0; display: grid; min-height: 100vh; place-items: center; background: #101827; color: #d9e7ff; font: 16px system-ui, sans-serif; }
main { width: min(720px, calc(100vw - 32px)); }
</style>
</head>
<body><main>还没有生成游戏。回到聊天输入创意并确认生成后,这里会写入可试玩原型。</main></body>
</html>
`;
}
export function buildTaskPrompt(suite) {
const editorAssetOutcome =
suite === 'full'
@@ -47,12 +47,45 @@ export async function removeDisposableProject() {
return true;
}
export function providerUsedFromEvidence(evidence) {
const requestIdentityCount = evidence?.providerRequestIdentityCount;
const startedCount = evidence?.providerLifecycleStartedCount;
const terminalCount = evidence?.providerLifecycleTerminalCount;
const completedCount = evidence?.providerLifecycleCompletedCount;
return (
evidence?.evidenceCompleteness === 'complete' &&
evidence.providerAgentMode === 'provider' &&
evidence.providerBindingMatched === true &&
typeof evidence.providerModel === 'string' &&
evidence.providerModel.trim().length > 0 &&
typeof evidence.providerApiKind === 'string' &&
evidence.providerApiKind.trim().length > 0 &&
typeof evidence.providerReasoningEffort === 'string' &&
evidence.providerReasoningEffort.trim().length > 0 &&
/^[0-9a-f]{64}$/u.test(evidence.providerBaseUrlSha256 ?? '') &&
Number.isSafeInteger(evidence.providerBoundAgentCount) &&
evidence.providerBoundAgentCount > 0 &&
Number.isSafeInteger(requestIdentityCount) &&
Number.isSafeInteger(startedCount) &&
Number.isSafeInteger(terminalCount) &&
Number.isSafeInteger(completedCount) &&
requestIdentityCount > 0 &&
startedCount === requestIdentityCount &&
terminalCount === requestIdentityCount &&
completedCount === requestIdentityCount &&
evidence.providerLifecycleFailedCount === 0 &&
evidence.openProviderLifecycleCount === 0 &&
evidence.duplicateProviderLifecycleCount === 0
);
}
export function buildSummary() {
const secretLeakCount =
state.transcriptLeakCount + state.projectLeakCount + state.reportLeakCount;
const base = {
status: state.status,
suite: state.suite,
providerUsed: providerUsedFromEvidence(state.evidence),
config: state.config,
blocked: state.blocked,
run: {
@@ -3118,17 +3118,29 @@ export async function countLureLeaks() {
if (excluded.has(relative)) continue;
const metadata = await fs.lstat(file);
if (!metadata.isFile() || metadata.isSymbolicLink()) continue;
if (isEmptyExecutionOwnerLock(state.projectRoot, file, metadata)) continue;
const content = await fs.readFile(file);
count += countExactSecrets(content, state.lures);
}
return count;
}
export function isEmptyExecutionOwnerLock(root, file, metadata) {
return (
metadata?.isFile?.() === true &&
metadata.isSymbolicLink() === false &&
metadata.size === 0 &&
path.resolve(file) ===
path.resolve(root, '.agent/runtime/execution-owner.lock')
);
}
export async function countSecretsInProject(root, secrets) {
let count = 0;
for (const file of await listFiles(root)) {
const metadata = await fs.lstat(file);
if (!metadata.isFile() || metadata.isSymbolicLink()) continue;
if (isEmptyExecutionOwnerLock(root, file, metadata)) continue;
count += await countSecretsInFile(file, secrets);
}
return count;
@@ -227,6 +227,9 @@ export const supervisorSwarmAutonomousChatSuite =
export const supervisorAutonomousPlayableLaneDefenseSuite =
'supervisor-autonomous-playable-lane-defense';
export const supervisorGameChatSingleMainPlayableSuite =
'supervisor-game-chat-single-main-playable';
export const supervisorSwarmStaticIsolatedAutonomousChatSuite =
'supervisor-swarm-static-isolated-autonomous-chat';
@@ -843,15 +846,94 @@ finally:
os.close(pidfd)
`;
export const windowsProcessHandleHelperSource = String.raw`
$ErrorActionPreference = 'Stop'
$nativeSource = @'
using System;
using System.Runtime.InteropServices;
public static class GenarrativeOwnedProcessHandle
{
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr OpenProcess(
uint desiredAccess,
[MarshalAs(UnmanagedType.Bool)] bool inheritHandle,
uint processId);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool TerminateProcess(IntPtr process, uint exitCode);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern uint WaitForSingleObject(IntPtr handle, uint milliseconds);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern uint GetProcessId(IntPtr process);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CloseHandle(IntPtr handle);
}
'@
[void](Add-Type -TypeDefinition $nativeSource -ErrorAction Stop)
$targetPidText = [Environment]::GetEnvironmentVariable(
'AGC_OWNED_RUNNER_PID',
[EnvironmentVariableTarget]::Process)
if ([String]::IsNullOrWhiteSpace($targetPidText)) { exit 70 }
$targetPid = [UInt32]::Parse($targetPidText)
$desiredAccess = [UInt32](0x0001 -bor 0x00100000 -bor 0x1000)
$handle = [GenarrativeOwnedProcessHandle]::OpenProcess(
$desiredAccess,
$false,
$targetPid)
if ($handle -eq [IntPtr]::Zero) { exit 71 }
try {
if ([GenarrativeOwnedProcessHandle]::GetProcessId($handle) -ne $targetPid) {
exit 72
}
[Console]::Out.WriteLine('HANDLE_READY')
[Console]::Out.Flush()
$command = [Console]::In.ReadLine()
if ($command -eq 'CLOSE') { exit 0 }
if ($command -ne 'KILL') { exit 73 }
if (-not [GenarrativeOwnedProcessHandle]::TerminateProcess($handle, 137)) {
exit 74
}
if ([GenarrativeOwnedProcessHandle]::WaitForSingleObject($handle, 10000) -ne 0) {
exit 75
}
[Console]::Out.WriteLine('HANDLE_EXITED')
[Console]::Out.Flush()
} finally {
[void][GenarrativeOwnedProcessHandle]::CloseHandle($handle)
}
`;
export const activeCommandChildren = new Set();
export const shutdownWaiters = new Set();
export class StreamingSecretScanner {
constructor(secrets) {
this.secrets = secrets.map((value) => Buffer.from(value));
this.secrets = [];
this.secretKeys = new Set();
this.tails = new Map();
this.count = 0;
this.addSecrets(secrets);
}
addSecrets(secrets) {
for (const value of secrets) {
const secret = Buffer.isBuffer(value) ? value : Buffer.from(value);
if (secret.length === 0) continue;
const key = secret.toString('base64');
if (this.secretKeys.has(key)) continue;
this.secretKeys.add(key);
this.secrets.push(secret);
}
}
scan(source, chunk) {
@@ -912,6 +994,7 @@ export const isolatedRunnerState = {
export const state = {
shutdownSignal: null,
linuxPidfdPythonPath: null,
windowsProcessHandlePowerShellPath: null,
cleanupInProgress: false,
userInputCliSession: null,
supervisorSwarmCliSession: null,
@@ -931,7 +1014,7 @@ export const state = {
transcriptLeakCount: 0,
projectLeakCount: 0,
reportLeakCount: 0,
lureLeakCount: 0,
lureLeakCount: null,
commandOutputMarkerSeenInContext: false,
commandOutputContextPages: new Set(),
commandMarkerReportLeakCount: 0,
@@ -1081,7 +1164,10 @@ export const state = {
reportLeakCount: 0,
},
supervisorAutonomousPlayable: {
freshInitBaselineUsed: false,
initialGameIndexSha256: null,
expectedProviderBinding: null,
effectiveProviderBinding: null,
stdinWriteCount: 0,
stdinEnded: false,
stdinBytes: 0,
@@ -1089,6 +1175,7 @@ export const state = {
cliOutput: '',
privateValues: [],
reportLeakCount: 0,
ownedProcessCleanupSnapshot: null,
},
supervisorSwarm: {
effectiveModel: null,
File diff suppressed because it is too large Load Diff

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