Merge remote-tracking branch 'origin/master' into feat/project-name
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
- [DirectProject 本轮附件路径映射](./technical/【技术方案】DirectProject本轮附件路径映射-2026-08-31.md):Direct 首轮只映射附件原名与项目相对路径,不灌正文、不区别 GDD。
|
||||
- [Direct 回合行为审计账本](./technical/【技术方案】Direct回合行为审计账本-2026-08-31.md):Direct GUI 回合把 native 读 / MCP / 写文件落成项目内有界时间线,用于判断有没有打开本轮附件。
|
||||
- [项目开发工作台 PRD](./prd/【AI游戏创作】项目开发工作台PRD-2026-07-20.md):当前工作台页面和验收边界。
|
||||
- [AGC 错误报告与诊断上传](./technical/【技术方案】AGC错误报告与诊断上传-2026-08-31.md):当前进程错误事件、应用级日志和管理员查看器合同。
|
||||
- [立项策划 Agent(Fast GDD)](<./technical/【技术方案】立项策划Agent(Fast GDD)-2026-08-10.md>):当前策划入口、审批和恢复合同。
|
||||
- [GameAgent 资源自由画板与快速编辑](./technical/【技术方案】GameAgent资源自由画板与快速编辑-2026-08-20.md)
|
||||
- [UI 工作流资源桥接与 Runtime 执行](./【技术方案】UI工作流资源桥接与Runtime执行-2026-08-24.md)
|
||||
|
||||
@@ -7794,8 +7794,8 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在
|
||||
## 2026-08-23 AI 游戏运行视窗按预览文档实际尺寸自适应
|
||||
|
||||
- 背景:项目开发工作台的中央运行视窗尺寸小于部分生成游戏的页面布局高度时,滚动条来自 loopback iframe 内部;宿主只隐藏 overflow 会直接裁掉标题、Canvas 或控制区,不能满足完整试玩。
|
||||
- 决策:客户端本地 preview server 为 UTF-8 HTML 注入固定同源尺寸桥;注入器按真实 HTML tokenizer 边界保守处理注释异常结束、DOCTYPE 引号、script escaped / double-escaped、raw-text、template、plaintext、foreign content 与重复 `src`,省略结束标签时只在已证明安全的文档位置注入。桥通过根节点 `ResizeObserver`、页面 load、窗口 resize 与字体就绪重新测量;页面可见时以 `500ms` 低频兜底探测至多 `512` 个元素边界,探测截断时不采用可能低估的部分样本,并排除随 viewport 同步变化的布局自反馈。它不订阅整页 DOM 突变,并只在尺寸元组真实变化时上报文档与浏览上下文宽高。宿主只接受当前 iframe source 与当前授权 loopback origin 的固定版本消息,按实际内容和可用容器计算最大为 `1` 的等比缩放并居中显示;首次缩放后仍接受内容宽高真实变化,重复内容尺寸或仅 viewport 回灌不更新状态,容器 resize 后重新以原生视口测量。运行视窗不再提供 iframe 横纵滚动条,内容适配不改游戏文件、manifest、PreviewRegistry 或运行业务状态,非 UTF-8 HTML 保持原样。
|
||||
- 验证:前端纯函数覆盖无需缩放、纵向超高缩放、首次缩放后的增高 / 缩短、重复内容尺寸去重、过期 viewport 与非法消息;Rust preview server 测试锁定尺寸去重、无全页 MutationObserver、低频有界探测、截断保护、固定 body 与 viewport 耦合布局不振荡、真实 HTML 上下文注入、注释异常结束、DOCTYPE 引号、script escaped / double-escaped、raw-text / template / plaintext / foreign content、省略结束标签、大小写结束标签、重复 `src` 和幂等注入;再以桌面最小窗口和更高窗口人工确认完整画面、动态内容变化后仍适配、无纵向滚动条且指针 / 键盘交互仍可用。
|
||||
- 决策:客户端本地 preview server 为 UTF-8 HTML 注入固定同源尺寸桥;注入器按真实 HTML tokenizer 边界保守处理注释异常结束、DOCTYPE 引号、script escaped / double-escaped、raw-text、template、plaintext、foreign content 与重复 `src`,省略结束标签时只在已证明安全的文档位置注入。桥通过根节点 `ResizeObserver`、页面 load、窗口 resize 与字体就绪重新测量;页面可见时以 `500ms` 低频兜底探测至多 `512` 个元素边界,探测截断时不采用可能低估的部分样本,并排除随 viewport 同步变化的布局自反馈。它不订阅整页 DOM 突变,并只在尺寸元组真实变化时上报文档与浏览上下文宽高。宿主只接受当前 iframe source 与当前授权 loopback origin 的固定版本消息,按实际内容和可用容器计算最大为 `1` 的等比缩放并居中显示;宿主把最近一次合法上报的 viewport 与正式内容尺寸分开保存,首次收到自身 fit 切换产生的新 viewport 测量时只推进观察值、不反向改写 fit,viewport 稳定后的真实内容增减仍可重新适配。容器 resize 期间保留当前内容尺寸和已观察 viewport,只按新的可用空间连续重算缩放,避免拖动窗口时在原生尺寸与 fit 之间闪烁;preview URL 变化时才清空两者并重新测量。陈旧 viewport、重复内容尺寸和首次宿主回灌均不更新状态。运行视窗不再提供 iframe 横纵滚动条,内容适配不改游戏文件、manifest、PreviewRegistry 或运行业务状态,非 UTF-8 HTML 保持原样。
|
||||
- 验证:前端组件测试锁定容器 resize 时 iframe 不恢复原生尺寸;纯函数覆盖无需缩放、纵向超高缩放、宿主首次应用 viewport 时保持当前 fit、容器 resize 后保持当前 fit、稳定 viewport 下内容增高 / 缩短、重复内容尺寸去重、过期 viewport 与非法消息;Rust preview server 测试锁定尺寸去重、无全页 MutationObserver、低频有界探测、截断保护、固定 body 与 viewport 耦合布局不振荡、真实 HTML 上下文注入、注释异常结束、DOCTYPE 引号、script escaped / double-escaped、raw-text / template / plaintext / foreign content、省略结束标签、大小写结束标签、重复 `src` 和幂等注入;再以 Issue #250 附件的 `min-height: 100vh` 页面在桌面最小窗口和更高窗口人工确认完整画面、无循环缩放、拖动窗口时无原生尺寸闪切、动态内容变化后仍适配、无纵向滚动条且指针 / 键盘交互仍可用。
|
||||
|
||||
## 2026-08-23 Direct Codex 显式重生成与切片一等资源
|
||||
|
||||
@@ -7901,6 +7901,23 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在
|
||||
- 任务最终状态不再提前绑定平台画布、preview、static smoke 或发布产物检查;这些内容不参与该档位的完成判定,也不会因缺失而重置已完成任务。父 run 在任务图进入终态后直接收束并回复。
|
||||
- 本档位仍沿用现有项目根和工具权限边界;本次调整只解除流程编排与平台产物验收前置,不新增第二套任务系统。
|
||||
|
||||
## 2026-08-31 AGC 错误报告与诊断上传
|
||||
|
||||
- AGC 采用 IDEA 风格的当前进程错误池:按 fingerprint 合并 React / window / Promise / Tauri / Agent 错误,重启后不恢复,不使用 run 或 run_id。
|
||||
- 应用级日志持续写入 Tauri AppData 并滚动;报告系统完全忽略项目 `.agent/logs`、源码、prompt、配置、项目产物和截图。用户只可补充文字描述。
|
||||
- 用户点击独立“报告问题”面板并确认后,批量提交当前进程事件和可取消的脱敏应用日志;失败只允许当前进程手动再次提交。
|
||||
- 上传接口为登录态 `/api/error-reports`,后台新增 error-reports Tab、专用文件化诊断包、状态与受控下载;管理员查看/下载进入审计链路。
|
||||
- `/bug-report` 仅作为打开该面板的快捷入口,追加简短提示,不再生成包含项目、run 或截图口径的缺陷模板。
|
||||
- 2026-08-31 追加:事件 DTO 精简为 `eventId/fingerprint/source/message/stack/occurredAt/count`,提交请求携带 `submissionId` 做幂等。归档固定为 `events.jsonl`,服务端使用 `agc/error-reports/v1/{batchId}.zip` 私有 OSS key;元数据只保留 batch、用户、状态、大小、SHA-256 和 OSS key,事件正文/说明/日志从归档读取。OSS 不可用或上传失败时不写数据库,客户端可重新提交。
|
||||
- 2026-09-01 追加:`application.log` 不再写结构化错误事件;Rust `app_log!` 和 WebView console 都写入普通文本 raw log,结构化事件仅保留在当前进程内,提交时才生成 ZIP 内的 `events.jsonl`。
|
||||
- 2026-09-01 review 收口:错误报告修复详情请求竞态、下载 anchor 生命周期、客户端采集脱敏/指纹降级与 4xx 噪声、用户级幂等隔离、`agc` 私有 OSS 前缀越权、日志读取链接检查、ZIP 同名日志和元数据/归档清理一致性;同步在 `review.txt` 标注仍需产品/运维决定的架构项。
|
||||
- 2026-09-01 追加:错误报告不依赖 api-server 本地文件、目录锁或同步文件 I/O;ZIP 只在请求内存构建后上传 OSS。管理员详情路由不属于 External OpenAPI;不存在返回 404,归档损坏返回 500。
|
||||
- 2026-09-01 追加:错误报告不落本地文件;请求内存构建 ZIP 后直接上传 OSS,成功后写入 SpacetimeDB `error_report` 元数据。OSS key 固定为 `agc/error-reports/v1/{batchId}.zip`,不含日期;同一用户 `userId + submissionId` 幂等。管理员查询 DB,详情/下载按 object key 读取 OSS;每日清理先删 OSS,再删 DB,失败留待下次重试。
|
||||
- 2026-09-01 review minor 修复:错误报告每日清理改为完整分页扫描,DB 删除失败显式返回以便下周期重试;OSS 读取按 `Content-Length` 与流式累计执行大小上限;管理员归档解析限制解压后 `events.jsonl` 为 24 MiB / 100 条事件。
|
||||
- 2026-09-02 review breaking 项落地:错误报告 create/update procedure 删除 `user_id`、`now_micros` 输入字段,分别改用 `ctx.sender()`、`ctx.timestamp`;首个 fingerprint/source 强制 512 字符上限,备注超过 2,000 字显式拒绝;内部 OSS 对象键收紧为 `agc/error-reports/v1/`,凭据脱敏覆盖空白/分隔符变体。发布需同步 module、spacetime-client bindings 与 api-server。
|
||||
- 2026-09-02 客户端错误报告提交成功与本地队列 ack 解耦:POST 成功即显示提交成功并关闭,ack 使用有限重试且失败只记录日志;同一批 eventId 在进程内复用稳定 submissionId,避免 ack 失败后重新提交产生重复报告。
|
||||
- 2026-09-02 review 后续收口:错误报告创建增加服务 identity 门禁与单 identity 每小时 100 次配额;开发期将已验证登录用户 `user_id` 由 api-server 注入 procedure 并由 module 校验;module 收紧固定 OSS key、SHA-256、归档大小和计数;管理员 PATCH 返回轻量元数据并在详情弹窗提供备注编辑器;列表无过滤查询使用 `created_at` BTree 索引。
|
||||
|
||||
## 2026-09-01 UI 编辑器代码导出与填充预览边界
|
||||
|
||||
- UI 编辑器导出的 `ui/generated-*.js` 是派生本地产物。代码生成只写文件,绝不推进项目 revision、UI State revision、manifest 阶段或 Runtime 验证门;写入失败只返回生成错误,不能把生成文件写入冒充项目 mutation。
|
||||
|
||||
@@ -2,6 +2,13 @@
|
||||
|
||||
> 当前口径:本文件保留可复用的排障经验;历史条目的旧路由、旧版本和已删除文档仅作根因背景,不得据此恢复退役入口。当前命令、路由和 schema 以代码与 `docs/README.md` 为准。
|
||||
|
||||
## 2026-09-02 Tauri 事件桥在浏览器预览中必须 fail-safe
|
||||
|
||||
- **现象**:Vitest/jsdom 挂载 AGC 客户端时,错误报告通知调用 `@tauri-apps/api/event.listen`,因缺少 `window.__TAURI_INTERNALS__` 产生未处理拒绝;测试断言虽通过,CI 仍以 unhandled errors 失败。
|
||||
- **原因**:错误报告订阅是非阻塞唤醒通道,不能假定所有渲染环境都已初始化 Tauri IPC;模块级 `listen` 在 API 调用前就会访问 `transformCallback`,仅在调用方包一层 `.then` 无法消除该环境差异。
|
||||
- **处理**:订阅桥先复用 `window.__TAURI__.event.listen`(含 globalTauri/native shim),其次仅在 `__TAURI_INTERNALS__` 存在时调用模块 API;浏览器预览或订阅失败统一返回 no-op,并在消费层收口 rejection。错误快照读取、焦点和可见性刷新仍是权威路径。
|
||||
- **验证**:`errorReporting.test.ts` 覆盖无 Tauri 环境无未处理拒绝;`appSurface.test.ts` 全部 385 条用例通过且无 Vitest unhandled errors。
|
||||
|
||||
## 2026-08-27 Provider 成功 handoff 失败时需要保留本地私有原始响应
|
||||
|
||||
- **现象**:Provider 已返回响应,但 tool-plan handoff 因绝对路径或其它内容安全校验失败,Runtime 只留下 `failureKind`、哈希和被压平的 JSON pointer;排障时无法确认实际工具名和完整 arguments。
|
||||
|
||||
@@ -10,12 +10,12 @@
|
||||
|
||||
## 2. 当前基线与目标
|
||||
|
||||
当前后台由 `GENARRATIVE_ADMIN_USERNAME`、`GENARRATIVE_ADMIN_PASSWORD` 提供唯一管理员账号,`apps/admin-web/src/app/adminRoutes.ts` 定义 15 个可分配业务 Tab,并另有 owner-only 的“账号管理”Tab;`server-rs/crates/api-server/src/modules/admin.rs` 中的后台路由只校验统一的管理员 JWT。
|
||||
当前后台由 `GENARRATIVE_ADMIN_USERNAME`、`GENARRATIVE_ADMIN_PASSWORD` 提供唯一管理员账号,`apps/admin-web/src/app/adminRoutes.ts` 定义 16 个可分配业务 Tab,并另有 owner-only 的“账号管理”Tab;`server-rs/crates/api-server/src/modules/admin.rs` 中的后台路由只校验统一的管理员 JWT。
|
||||
|
||||
改造后的目标如下:
|
||||
|
||||
1. 现有环境变量账号升级为 `owner`,仍由部署环境提供,不迁移、不复制到 SpacetimeDB。
|
||||
2. owner 始终拥有全部 15 个业务 Tab 权限,并独占“账号管理”Tab 和账号管理 API。
|
||||
2. owner 始终拥有全部 16 个业务 Tab 权限,并独占“账号管理”Tab 和账号管理 API。
|
||||
3. owner 可以创建、修改、启停 member;member 保存在 SpacetimeDB 私有表 `admin_account`。
|
||||
4. member 按一级 Tab 分配常规权限;获得一个 Tab 权限即获得该页面内常规读写能力。历史花费手动对账必须另行授予 `profile-wallet-consumption-reconcile`,任何 Tab 都不隐式包含。
|
||||
5. member JWT 每次请求都重新读取当前账号并校验 `enabled`、`token_version`、实时 Tab 权限和独立操作权限,权限、密码或启停变更应立即让旧 JWT 失效。
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
- owner 用户名和密码继续读取 `GENARRATIVE_ADMIN_USERNAME`、`GENARRATIVE_ADMIN_PASSWORD`。
|
||||
- owner 是环境变量构造的虚拟账号,不写入 `admin_account`,不允许通过后台改名、改密、禁用或删除。
|
||||
- owner 始终拥有本文列出的全部 15 个 Tab 权限和全部独立操作权限,不能在前端取消,也不从数据库加载权限。
|
||||
- owner 始终拥有本文列出的全部 16 个 Tab 权限和全部独立操作权限,不能在前端取消,也不从数据库加载权限。
|
||||
- “账号管理”是 owner-only 能力。它可以作为新增一级路由 `accounts` / `#accounts` 展示,但 `accounts` 不进入 `ADMIN_TAB_PERMISSIONS` 或 `ADMIN_ACTION_PERMISSIONS`,不能写入 member 的权限 JSON。
|
||||
- owner 会话返回 `accountRole = "owner"`、`roles = ["admin", "owner"]`;账号管理权限必须根据服务端确认的 `accountRole` 判断,不能只相信前端角色字符串。
|
||||
- owner 配置缺失时,后台整体保持未启用状态;不能依赖数据库中的 member 绕过 owner 引导配置启动后台。
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
## 4. 权限标识
|
||||
|
||||
`ADMIN_TAB_PERMISSIONS` 必须是 shared-contracts 与 admin-web 共用的闭合集合,值与现有 `AdminRouteId` 一致。15 个可分配权限如下,顺序同时作为前端寻找“第一可访问项”的稳定顺序:
|
||||
`ADMIN_TAB_PERMISSIONS` 必须是 shared-contracts 与 admin-web 共用的闭合集合,值与现有 `AdminRouteId` 一致。16 个可分配权限如下,顺序同时作为前端寻找“第一可访问项”的稳定顺序:
|
||||
|
||||
| permission id | 一级 Tab | hash |
|
||||
| --------------------------- | --------- | ---------------------------- |
|
||||
@@ -50,6 +50,7 @@
|
||||
| `tables` | 表查询 | `#tables` |
|
||||
| `debug` | API 调试 | `#debug` |
|
||||
| `tracking` | 埋点数据 | `#tracking` |
|
||||
| `error-reports` | 错误报告 | `#error-reports` |
|
||||
| `gray-release` | 灰度发布 | `#gray-release` |
|
||||
| `redeem` | 兑换码 | `#redeem` |
|
||||
| `invite` | 邀请码 | `#invite` |
|
||||
@@ -86,7 +87,7 @@ Tab 权限数组必须去重并按上表顺序规范化后保存。保存时拒
|
||||
| `username` | `String` | `unique`;登录名,创建后不可修改;按 `trim + ASCII lowercase` 规范化 |
|
||||
| `display_name` | `String` | 展示名,去除首尾空白后 1 至 64 字符 |
|
||||
| `password_hash` | `String` | Argon2id PHC 字符串;只在内部登录查询中返回给 api-server,永不进入 HTTP DTO、日志或前端状态 |
|
||||
| `tab_permissions_json` | `String` | 规范化后的 Tab permission JSON;只允许第 4 节 15 个值,空数组为 `[]` |
|
||||
| `tab_permissions_json` | `String` | 规范化后的 Tab permission JSON;只允许第 4 节 16 个值,空数组为 `[]` |
|
||||
| `enabled` | `bool` | 是否允许登录和继续使用现有 JWT |
|
||||
| `token_version` | `u64` | 初始为 `1`;权限、密码或启停状态发生有效变化时加 `1` |
|
||||
| `created_by` | `String` | 创建者后台 subject;当前只能是 owner subject |
|
||||
@@ -168,7 +169,7 @@ tabPermissions: string[]
|
||||
actionPermissions: string[]
|
||||
```
|
||||
|
||||
owner 返回全部 15 个 Tab permission id 和全部独立操作权限;member 返回数据库中的两组实时规范化数组。`GET /admin/api/me` 同样执行逐请求校验并返回实时权限,供刷新页面后恢复导航和操作按钮。
|
||||
owner 返回全部 16 个 Tab permission id 和全部独立操作权限;member 返回数据库中的两组实时规范化数组。`GET /admin/api/me` 同样执行逐请求校验并返回实时权限,供刷新页面后恢复导航和操作按钮。
|
||||
|
||||
后台所有面向运营展示的管理员身份统一使用 `displayName`。审计表继续保存稳定 subject,例如 owner subject 或 `admin-account-<uuid>`;api-server 在返回兑换码、邀请码等操作记录时,按 owner 运行态和 `admin_account` 批量解析显示名称,同时兼容历史用户名记录。已无法解析的历史主体统一展示“已停用管理员”,前端不得直接渲染 `operatorUserId`、账号 ID 或登录用户名代替显示名称。对写接口,显示名目录必须在主事务前加载,或在主事务成功后降级为占位文案;不得因二次读取失败把已提交写入伪装成失败。
|
||||
|
||||
@@ -309,7 +310,7 @@ accounts: Array<{
|
||||
|
||||
### 11.1 路由与导航
|
||||
|
||||
- `adminRoutes` 增加权限元数据;15 个业务路由使用同名 permission id。
|
||||
- `adminRoutes` 增加权限元数据;16 个业务路由使用同名 permission id。
|
||||
- `accounts` 路由只在 `admin.accountRole === "owner"` 时加入侧栏和移动底栏,不属于 member 可分配列表。
|
||||
- member 导航只渲染 `admin.tabPermissions` 包含的业务路由。页面组件也必须只在当前路由已授权时挂载,避免隐藏导航后仍发起无权限 API。
|
||||
- owner 渲染全部业务路由和账号管理路由。
|
||||
@@ -321,13 +322,13 @@ accounts: Array<{
|
||||
1. 当前 hash 对应可访问路由时保持不变。
|
||||
2. hash 未知、属于无权限业务 Tab,或 member 访问 `#accounts` 时,使用 `replaceState` 回落到按第 4 节顺序找到的第一可访问业务 Tab。
|
||||
3. member 权限为空时,不回落 Dashboard;渲染独立的零权限空态,只保留账号信息和退出登录,不挂载任何业务页,也不发起业务 API。
|
||||
4. owner 的默认项仍可保持 Dashboard;账号管理不改变 15 个业务路由的排序。
|
||||
4. owner 的默认项仍可保持 Dashboard;账号管理不改变 16 个业务路由的排序。
|
||||
|
||||
后端返回 `403` 时,前端重新请求 `/me` 获取实时权限并执行上述回落。即使前端状态陈旧或被篡改,后端权限 middleware 仍必须拒绝越权请求。
|
||||
|
||||
### 11.3 账号管理页
|
||||
|
||||
- 权限编辑器分为 15 个 Tab checkbox 和独立操作权限区;当前独立区只显示“手动对账用户历史花费”。不能展示或提交 `accounts`。
|
||||
- 权限编辑器分为 16 个 Tab checkbox 和独立操作权限区;当前独立区只显示“手动对账用户历史花费”。不能展示或提交 `accounts`。
|
||||
- 创建和编辑使用独立弹窗或抽屉,不在列表下方追加表单。
|
||||
- 编辑时密码字段默认空,空表示请求中省略 `password`;页面永不展示现有密码或 hash。
|
||||
- 停用使用开关并二次确认。保存成功后以 API 返回 account snapshot 更新列表。
|
||||
@@ -403,7 +404,7 @@ spacetime publish <database> \
|
||||
|
||||
### 14.2 前端
|
||||
|
||||
- owner 看到 15 个业务 Tab 和账号管理;member 只看到被分配的业务 Tab。
|
||||
- owner 看到 16 个业务 Tab 和账号管理;member 只看到被分配的业务 Tab。
|
||||
- 常规二级 Tab、弹窗和写操作继承一级权限;历史花费对账按钮只在用户详情返回 `canReconcileConsumption=true` 时显示。
|
||||
- 直接输入无权限 hash 自动替换为第一可访问项,不短暂挂载无权限页面。
|
||||
- 当前 Tab 权限被 owner 收回后,下一请求触发重新登录;新会话恢复后落到第一可访问项。
|
||||
|
||||
@@ -38,9 +38,9 @@ OSS 请求失败、清单格式错误或版本无效会终止发布,避免覆
|
||||
生成包含版本、下载地址、大小和 SHA-256 的清单。可通过 `AGC_BUILD_TARGET` 显式覆盖目标(发布仍应使用
|
||||
Windows x64),通过 `AGC_UPDATE_ARTIFACT` 指定要发布的安装包,通过 `AGC_UPDATE_OSS_BASE_URL` 指定
|
||||
OSS 前缀,通过 `AGC_RELEASE_VERSION` 指定三段版本号(仅在明确需要复现指定版本时使用),通过
|
||||
`AGC_UPDATE_RELEASE_NOTES` 写入发布说明;`--no-bundle` smoke 构建不会读取 OSS、修改版本或生成清单。
|
||||
`AGC_UPDATE_RELEASE_NOTES` 写入发布说明,支持多行文本且保留内部换行;`--no-bundle` smoke 构建不会读取 OSS、修改版本或生成清单。
|
||||
|
||||
每次发布安装包上传完成后,再上传同一目录生成的 `latest.json`,确保 `downloadUrl` 指向已存在的 OSS 对象;清单和安装包均使用公开可读对象,不在清单中保存凭据、签名或本地路径。构建脚本本身不负责上传 OSS,发布流水线通过 `release:upload` 完成上传。
|
||||
每次发布安装包上传完成后,再使用 ossutil 的 `--force` 覆盖上传同一目录生成的 `latest.json`,确保固定的 latest 指针和 `downloadUrl` 指向已存在的 OSS 对象;未显式强制覆盖时,ossutil 在目标已存在时会交互询问并按默认值跳过,不能作为 Jenkins 非交互发布方式。清单和安装包均使用公开可读对象,不在清单中保存凭据、签名或本地路径。构建脚本本身不负责上传 OSS,发布流水线通过 `release:upload` 完成上传。
|
||||
|
||||
如需一键构建并上传,可执行 `npm run ai-game-creator-shell:release:upload`。该命令要求本机已安装并配置 `ossutil`,
|
||||
先按上述规则比较 OSS 版本、递增 patch、构建 Windows x64 NSIS,再上传安装包和 `latest.json`。默认上传到
|
||||
@@ -56,7 +56,7 @@ Jenkins Agent 服务必须能在同一用户环境中找到这些命令。Tauri
|
||||
`tauri.windows.conf.json` 中的 `bundle.useLocalToolsDir: true`,把固定版本的 NSIS 工具缓存到
|
||||
`src-tauri/target/.tauri/NSIS`,不依赖 Jenkins 服务账户的 `%LOCALAPPDATA%\tauri` 或 PATH 中的系统 NSIS。
|
||||
Jenkins Checkout 的 `git clean -fdx` 会清理该构建目录,因此每次全新工作区可能重新下载 NSIS;这只影响构建耗时,不改变工具来源或执行权限要求。
|
||||
流水线执行根 workspace 的 `npm ci`,然后调用
|
||||
流水线参数 `AGC_UPDATE_RELEASE_NOTES` 使用 Jenkins `text` 类型,可直接输入多行发布说明;执行根 workspace 的 `npm ci`,然后调用
|
||||
`npm run ai-game-creator-shell:release:upload`,并归档 Windows 安装包、`latest.json` 与源码 commit。
|
||||
流水线会将未导出的空参数按空字符串处理:`COMMIT_HASH` 留空时沿用 Jenkins SCM 当前提交,`OSSUTIL_BIN` 留空时使用节点 PATH 中的 `ossutil`,不会因 PowerShell 对空环境变量调用 `.Trim()` 而提前失败。
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
# AGC 错误报告与诊断上传
|
||||
|
||||
## 范围
|
||||
|
||||
AI Game Creator Shell 采用 IDEA 风格的当前进程错误报告:错误事件在内存池中按 fingerprint 合并;应用级诊断日志持续写入 Tauri AppData 的滚动文件;用户打开“报告问题”面板并确认后,一次提交当前进程选中的错误事件和脱敏应用日志。项目目录 `.agent/logs/*`、源码、prompt、配置、项目产物和截图不进入报告包。
|
||||
|
||||
## 客户端
|
||||
|
||||
- 捕获 React render error、`window.onerror`、`unhandledrejection` 以及显式标记的 Tauri/API/Agent 错误。Agent Runtime 的终态失败、预算耗尽和启动确认失败由 Rust 失败投影统一入池;Direct Codex 与专业 Agent 的前台裸 Tauri invoke catch 作为补充入口,重复事件由同一 fingerprint 合并,主动取消和“同一 turn 已在运行”不作为错误采集。
|
||||
- 事件字段包括 eventId、fingerprint、source、message、stack、时间和次数;重复事件合并。不再携带 severity、errorCode、page、action、requestId 等无法稳定关联的字段。
|
||||
- 指纹计算可使用调用方的 page/action 及脱敏后的首个调用点作为进程内区分输入,但这些上下文不会作为事件字段上传;消息与 stack 在入池前统一脱敏,WebCrypto 失败时降级为稳定可读指纹,采集本身不得产生新的未处理拒绝。
|
||||
- 客户端 API 自动采集只覆盖网络错误、408 和 5xx;预期的 4xx 登录/鉴权失败不进入错误报告池。
|
||||
- Rust 侧通过 `app_log!` 将普通文本日志同时输出到 stderr 和 AppData `diagnostics/application.log`,超出 256 KiB 滚动到 `application.previous.log`;WebView 的 console 输出通过 `append_application_log` 镜像到同一 raw log,并在客户端桥接处再次脱敏;`read_diagnostic_logs` 只读取应用级日志。
|
||||
- 报告面板只由自动诊断通知中的“查看并报告”打开,不提供聊天命令、崩溃页按钮或其他手动入口;默认选中最新事件,其他事件可勾选。允许填写最多 2,000 字中文描述并取消日志附件;本版本不支持截图或任意文件附件。
|
||||
- Rust 是结构化错误队列的唯一真相源:`src-tauri/src/error_report/` 负责脱敏、调用点指纹、eventId、计数、100 条上限、5 秒聚合和 ack 生命周期;WebView 仅通过 Tauri bridge 上报、读取快照并保存短暂 React 展示状态,不维护第二份事件 Map。Runtime 错误上报统一使用 `source=agent-runtime`、`action=agent-runtime` 和 Agent ID 作为 page;包含 `kind=codex-app-server-*` 或 `codex-app-server-error:*` 的消息在入池前归一为稳定类别(例如 `codex-app-server-error:other`),不把 public summary 中的动态 fingerprint/长度作为分桶输入。Rust emit 只作为无状态唤醒,携带单调递增的 generation,不携带错误正文或事件 ID。
|
||||
- 错误事件先在当前进程内存池按 fingerprint 合并,经过 5 秒聚合后只发出一次非阻塞存在性唤醒;WebView 挂载、收到唤醒、重新获得焦点或恢复可见时都查询完整未 ack 快照,并在桥接暂时失败时做有限退避重试。通知支持“查看并报告”和“忽略”,同一 fingerprint 仅在新增时唤醒一次。通知不直接打开阻塞式报告面板。忽略只关闭当前 UI,不删除事件;提交成功后由 bridge ack/delete 选中事件。
|
||||
- 上传失败只在当前进程显示失败并允许用户再次提交,不跨重启恢复事件池,不后台自动重试。
|
||||
|
||||
## HTTP 与存储
|
||||
|
||||
- 登录态客户端使用 `POST /api/error-reports`,请求 DTO 位于 `shared-contracts::error_reports`。
|
||||
- api-server 对请求体设置 24 MiB 上限,并校验 schemaVersion、submissionId、事件/日志数量和 20 MiB 压缩包上限;事件字段、用户说明和日志名/内容均做长度限制与凭据脱敏(匹配归一化覆盖 Unicode 空白字符),归档使用 `events.jsonl`(每行一个事件)。结构化事件只保存在当前进程内,用户提交时才生成 `events.jsonl`,不在磁盘单独持久化。submissionId 提供重放幂等;客户端对同一批事件复用稳定 submissionId,服务端提交成功后立即反馈成功,本地事件 ack 独立重试,不因 ack 失败误报提交失败;SpacetimeDB procedure 使用服务 identity 门禁,`user_id` 由 api-server 注入并在 module 校验,时间戳仍使用 `ctx.timestamp`。创建 procedure 额外限制单 identity 每小时 100 次提交。
|
||||
- 归档构建只在请求生命周期内使用受 20 MiB 上限约束的内存 `Vec<u8>`,随后直接 PUT 到私有 OSS;服务端不写本地报告文件,也不保留本地索引。OSS 上传失败不写入数据库,调用方可稍后重新提交。
|
||||
- 归档对象使用固定私有 OSS key:`agc/error-reports/v1/{batchId}.zip`;key 只由报告 UUID 决定,不包含时间戳。上传成功后才写入 SpacetimeDB `error_report` 元数据表;`userId + submissionId` 由唯一幂等键保证重放返回已有记录。完整事件、说明和日志只存在 OSS ZIP。
|
||||
- `agc` 是服务端专用私有前缀;公共直传票据、通用 object-key 规范化和 legacy 公开路径均拒绝该前缀。归档内同名日志会自动加数字后缀,读取本机诊断日志时拒绝符号链接/非普通文件。
|
||||
- 后台接口:`GET/PATCH /admin/api/error-reports/{batchId}`、`GET /admin/api/error-reports` 和受保护的 `/download`。列表支持 `limit`/`offset` 分页并返回 `total`、`hasMore`;OSS 读取先检查 `Content-Length` 并在流式累计超过上限时立即中止,不把超限对象完整缓存在内存中。
|
||||
- 这些是 api-server 内部登录/管理员路由,不属于 `/api/external/v1`,不纳入 External OpenAPI;管理员详情对不存在返回 404,对归档/元数据损坏返回 500。
|
||||
- admin viewer 仅接受 error-reports Tab 权限,支持列表筛选、分页、详情、状态 `new/in-progress/resolved`、处理备注和受控下载;不存在的更新目标返回 404,存储损坏返回 500。列表行支持键盘 Enter/Space 打开详情,详情事件预览最多显示 20 条,完整内容通过诊断包下载获取。
|
||||
- 管理员列表、筛选、状态和备注全部读取/更新 SpacetimeDB;错误报告的 list/get/update procedure 要求 `require_editor_generation_runtime_service_identity`,详情先读表再从 OSS 下载并解析 ZIP,下载接口直接从 OSS 返回 ZIP。PATCH 更新直接返回元数据,不重新下载归档;详情弹窗提供备注编辑器。无需新增管理员 DELETE HTTP 接口。每日清理任务按分页扫描全部报告,删除过期 OSS 对象后再删 DB;任一 DB 删除失败会保留错误并在后续周期重试。详情解析对解压后的 `events.jsonl` 设置 24 MiB(与请求体上限一致)与 100 条事件上限。管理员备注超过 2,000 字会被明确拒绝;module 同时校验固定 OSS key、SHA-256、归档大小和事件/日志计数上限;OSS 读取仅将明确不存在映射为 404,其余错误按请求无效或上游故障返回。内部 OSS 读写只允许 `agc/error-reports/v1/`。旧本地报告不迁移。
|
||||
|
||||
SpacetimeDB `error_report` 表字段:`batch_id` 主键、`user_id`、`submission_id`、`idempotency_key` 唯一键、`object_key`、`archive_sha256`、`archive_size_bytes`、`event_count`、`log_count`、首个 fingerprint/source、`review_status`、`admin_note`、`created_at`、`updated_at`;索引为 `(user_id, submission_id)`、`created_at`、`review_status`。
|
||||
|
||||
## 验收
|
||||
|
||||
```text
|
||||
npm run typecheck --workspace @genarrative/ai-game-creator-shell
|
||||
npx tsc -p apps/admin-web/tsconfig.json --noEmit
|
||||
npx vitest run apps/ai-game-creator-shell/tests/errorReporting.test.ts apps/ai-game-creator-shell/tests/clientRuntimeErrorBoundary.test.ts apps/admin-web/src/app/adminRoutes.test.ts
|
||||
cargo test -p api-server --bin api-server error_reports -- --nocapture
|
||||
cargo fmt -p api-server -p shared-contracts -- --check
|
||||
npm run check:encoding
|
||||
git diff --check
|
||||
```
|
||||
|
||||
Rust 全量检查还受现有 `platform-llm` ProviderReasoningEffort::Max 编译错误阻塞;本变更未修改该历史问题。
|
||||
@@ -568,7 +568,7 @@ game-project/
|
||||
- 中间主视窗提供 `resource-overview / asset-canvas / resource-editor / run` 四种状态。2026-08-10 起普通用户“新增资源”显示为禁用态且处理函数拒绝 create;所有现役资源从聚焦态“编辑资源”进入非破坏性派生。静态图片继续进入 refine 素材创作无限画布,SVG、视频、音频、文档/代码、Agent 回执和项目版本进入统一资源编辑壳并按能力分流;底层 create 合同仅保留兼容。编辑面板只替换中央区域,不覆盖右侧 Supervisor 或底部 Agent。`code-prototype` 任务完成前运行入口保持视觉不可用,但仍可点击查看“当前无可运行版本”,不能使用会阻断说明交互的原生 `disabled` 或 `aria-disabled`;完成后才允许进入运行表现层。切回资源总览只修改前端展示态,不伪造后端预览暂停结果。
|
||||
- 资源管理从当前 `GameCreationAppManifest`(包含可选 `versions`)、合法 Agent 文本回执、已导入附件和已完成任务明确登记的产物派生资源,固定按文档、项目版本、美术资源、音乐音效资源分区;未知任务产物不再兜底为版本,未完成任务或未在 `artifacts` 中登记的任意本地音频也不冒充正式资源。`按依赖 / 按类型` 使用各自前端排列,dependency 模式额外绘制当前 manifest 与资源投影可证明的依赖关系。排列与图层都不写回 manifest,不能推断或伪造缺失依赖。
|
||||
- 资源卡支持点击聚焦、搜索和类型筛选。2026-07-28 起完成两套二维坐标与本地 CAS sidecar;2026-07-31 起 dependency 模式增加不持久化的原生 SVG 关系图层。2026-08-03 mentor 决定暂缓资源总览卡片拖动,当前卡片不挂载 Pointer Down / Move / Up / Cancel 拖动入口,只允许自动布局和点击聚焦。聚焦态替换中央主视窗内容,保留左侧导航、右侧对话和底部 Agent 状态栏,退出后恢复搜索、布局模式、滚动位置与选中资源;不提供通用工具栏、工具侧边栏或可拖动标题栏。阶段四已补齐安全本地文档、扩展美术媒体与音频聚焦,正文独立滚动,视频 / 音频使用内置媒体控件,失败显示空态。2026-08-30 视觉验收修正:资源总览所有栏目初次适配与复位最多以 `1.5` 倍缩放卡片,避免单个低尺寸卡片被插值放大成糊图;用户主动缩放仍沿用通用画布倍率,并按“排序模式 + 栏目”保留当前会话内的平移和缩放。美术资源聚焦态改为视口级大预览,保留原始资源读取与元数据,不生成第二份缩略图,图片 / 视频预览按弹窗可用高度展示并允许正文滚动。该资源总览边界不限制后续素材创作无限画布内的图片图层移动/缩放、生成和正式回写。
|
||||
- 运行表现层首版直接嵌入当前项目的 loopback 游戏画面,并保留素材信息和数值微调面板;两个面板保持原有 `156px` 最小高度,没有真实数据时只让正文为空,不渲染预设字段、默认数值、未载入控件或自然语言功能占位,也不随空内容收缩。`preview.start` 启动本地 server 后把真实 URL 回写工作台,`preview.open` 只激活客户端内运行视图,不再调用系统浏览器;参数调整首版仍只保留本地 UI 草稿,不修改代码或 manifest。preview server 对 UTF-8 HTML 响应注入固定同源尺寸桥脚本;注入点通过真实 HTML tokenizer 边界定位,保守处理注释异常结束、DOCTYPE 引号、script escaped / double-escaped、raw-text、template、plaintext、foreign content 与重复 `src`,并支持省略 `</body>` / `</html>`。桥以 `ResizeObserver` 观察 `documentElement / body` 根布局,结合页面 load、窗口 resize 与字体就绪重新测量;页面可见时另以 `500ms` 低频兜底探测至多 `512` 个元素的实际边界,探测截断时保留 body / scroll 上界,并按连续测量排除随 viewport 同步变化的 `100vh / 100% / bottom / right` 自反馈。相同尺寸元组去重后才以固定版本 `postMessage` 上报,不订阅整页 `MutationObserver`。宿主同时校验消息 origin 和 `event.source`,以实际内容宽高与当前容器宽高计算不超过 `1` 的等比缩放;首次适配后仍接受内容宽高的真实变化,但仅 viewport 回灌或重复内容尺寸不更新 React 状态。容器 resize 后回到原生视口重新测量;放得下时保持 `1:1`,超出时完整缩小并居中,iframe 禁止横纵滚动条,不能以 `overflow: hidden` 直接裁掉超出内容。非 UTF-8 HTML 原样返回,不因适配桥破坏已有预览。
|
||||
- 运行表现层首版直接嵌入当前项目的 loopback 游戏画面,并保留素材信息和数值微调面板;两个面板保持原有 `156px` 最小高度,没有真实数据时只让正文为空,不渲染预设字段、默认数值、未载入控件或自然语言功能占位,也不随空内容收缩。`preview.start` 启动本地 server 后把真实 URL 回写工作台,`preview.open` 只激活客户端内运行视图,不再调用系统浏览器;参数调整首版仍只保留本地 UI 草稿,不修改代码或 manifest。preview server 对 UTF-8 HTML 响应注入固定同源尺寸桥脚本;注入点通过真实 HTML tokenizer 边界定位,保守处理注释异常结束、DOCTYPE 引号、script escaped / double-escaped、raw-text、template、plaintext、foreign content 与重复 `src`,并支持省略 `</body>` / `</html>`。桥以 `ResizeObserver` 观察 `documentElement / body` 根布局,结合页面 load、窗口 resize 与字体就绪重新测量;页面可见时另以 `500ms` 低频兜底探测至多 `512` 个元素的实际边界,探测截断时保留 body / scroll 上界,并按连续测量排除随 viewport 同步变化的 `100vh / 100% / bottom / right` 自反馈。相同尺寸元组去重后才以固定版本 `postMessage` 上报,不订阅整页 `MutationObserver`。宿主同时校验消息 origin 和 `event.source`,以实际内容宽高与当前容器宽高计算不超过 `1` 的等比缩放;宿主单独记录最近一次合法上报的 iframe viewport,首次收到由自身 fit 切换产生的新 viewport 测量时只确认该 viewport、不反向改写内容尺寸,待 viewport 稳定后仍接受真实内容宽高变化,从而阻断 `100vh` / 百分比布局在两个适配尺寸之间回灌振荡。重复内容尺寸不更新 React 状态,陈旧 viewport 消息继续忽略。容器 resize 期间保留内容尺寸与已观察 viewport,只按新容器尺寸连续重算缩放,避免拖动窗口时在原生尺寸和 fit 之间闪烁;preview URL 变化时才清空状态并重新测量。放得下时保持 `1:1`,超出时完整缩小并居中,iframe 禁止横纵滚动条,不能以 `overflow: hidden` 直接裁掉超出内容。非 UTF-8 HTML 原样返回,不因适配桥破坏已有预览。
|
||||
- 右侧继续复用现有 Project Supervisor 会话、Runtime 澄清和确认链路;输入区展示 `严格审批 / 风险审批 / 无需审批` 独立面板。P0 只有严格审批可选;风险审批和无需审批保持视觉不可用但允许点击查看原因,不替代 Runtime 的逐动作权限、确认、sandbox 或 reconciliation 门禁。风险 Rank 算法记录在 `docs/project-memory/todos/【待解决】AI游戏创作高风险审批Rank-2026-07-20.md`,前端不得自行计算。
|
||||
- 底部状态栏默认展示策划、美术、程序 3 组,并允许在同一栏展开数值、音频、发布组;状态来自 manifest 与当前 Supervisor run 的 Runtime,悬停显示当前任务与进度。累计泥点必须等待后端计费归因投影;Agent.md 编辑和自定义 Skill 在来源审核、版本、权限、sandbox 与回滚合同完备前不向普通用户开放。
|
||||
- 当前 run 专业状态与项目历史成果分离:状态继续严格匹配当前 `parentRunId`;已有文本成果从专业 Agent 持久对话中合法的 `agent-finalization-<32 lower hex>` assistant 恢复,并以“历史成果”来源投影到资源管理文档区。新 run 失败、待确认、候选为空或持久对话瞬时读取失败不得清除已恢复的旧成功回执,普通失败 assistant 也不得被当作成果。
|
||||
@@ -681,7 +681,7 @@ game-project/
|
||||
- 聊天输入 `/test-plan` 可在普通聊天消息里准备手动测试计划,不读取文件、不启动或打开预览、不直接继续 run,也不新增普通用户测试面板。
|
||||
- 聊天输入 `/audience` 可在普通聊天消息里查看首批试玩对象,不读取文件、不启动或打开预览、不导出试玩包、不写项目,也不新增普通用户对象面板。
|
||||
- 聊天输入 `/invite` 可在普通聊天消息里准备试玩邀请文案,不读取文件、不启动或打开预览、不导出试玩包、不写项目,也不新增普通用户邀请面板。
|
||||
- 聊天输入 `/bug-report` 可在普通聊天消息里准备缺陷复现记录,不读取文件、不启动或打开预览、不导出试玩包、不写项目,也不新增普通用户缺陷面板。
|
||||
- 聊天输入 `/bug-report` 只打开独立“报告问题”面板并允许填写用户说明;不读取项目文件、不启动或打开预览、不导出试玩包、不上传截图或任意文件、不写项目,也不依赖 run / run_id。
|
||||
- 聊天输入 `/survey` 可在普通聊天消息里准备试玩问卷问题,不读取文件、不启动或打开预览、不导出试玩包、不写项目,也不新增普通用户问卷面板。
|
||||
- 聊天输入 `/cover` 可在普通聊天消息里准备封面与缩略图检查,不截屏、不裁剪、不读取文件、不启动或打开预览、不导出试玩包、不上传云端、不发布作品、不写项目,也不新增普通用户封面面板。
|
||||
- 聊天输入 `/screenshots` 可在普通聊天消息里准备宣传截图清单,不截屏、不读取文件、不启动或打开预览、不导出试玩包、不写项目,也不新增普通用户截图面板。
|
||||
@@ -756,7 +756,7 @@ game-project/
|
||||
- `/test-plan` 聊天入口由 `appSurface.test.ts` 主窗口 smoke 覆盖:只基于当前已加载 manifest、最近 run trace 和 preview 状态准备手动测试用例、关联任务和试玩证据,提供 `/run`、`/open-preview`、`/trace`、`/review` 或 `/next` 草稿,不触发 Tauri 读写、不读取文件、不启动或打开预览、不直接继续 run、不新增普通用户测试面板。
|
||||
- `/audience` 聊天入口由 `appSurface.test.ts` 主窗口 smoke 覆盖:只基于当前已加载 manifest、最近 run trace、preview 和试玩任务状态汇总首批试玩对象、邀请顺序和观察重点,提供 `/run`、`/feedback`、`/review`、`/trace` 或 `/next` 草稿,不触发 Tauri 读写、不读取文件、不启动或打开预览、不导出试玩包、不写项目、不新增普通用户对象面板。
|
||||
- `/invite` 聊天入口由 `appSurface.test.ts` 主窗口 smoke 覆盖:只基于当前已加载 manifest、最近 run trace 和 preview 状态准备测试者邀请对象、邀请文案、发送前检查和收反馈口径,提供 `/run`、`/feedback`、`/review`、`/trace` 或 `/next` 草稿,并在 `/next` 与 `/help` 暴露入口;不触发 Tauri 读写、不读取文件、不启动或打开预览、不导出试玩包、不写项目、不新增普通用户邀请面板。
|
||||
- `/bug-report` 聊天入口由 `appSurface.test.ts` 主窗口 smoke 覆盖:只基于当前已加载 manifest、最近 run trace 和 preview 状态准备问题一句话、复现步骤、期望 / 实际、设备 / 输入方式、严重度和附件口径,提供 `/run`、`/agent-resume 缺陷修复:`、`/review`、`/trace` 或 `/next` 草稿,并在 `/next` 与 `/help` 暴露入口;不触发 Tauri 读写、不读取文件、不启动或打开预览、不导出试玩包、不写项目、不新增普通用户缺陷面板。
|
||||
- `/bug-report` 聊天入口由 `appSurface.test.ts` 主窗口 smoke 覆盖:只追加“已打开报告问题面板”提示并触发独立面板;面板提交前读取应用级诊断日志(不读取 `.agent/logs/*`),只上传当前进程错误事件、脱敏日志和用户文字说明,不上传截图或任意文件,不触发项目读写、预览、导出或 run / run_id。
|
||||
- `/survey` 聊天入口由 `appSurface.test.ts` 主窗口 smoke 覆盖:只基于当前已加载 manifest、最近 run trace 和 preview 状态准备首批测试者问卷、五个核心问题、记录格式和追踪方式,提供 `/run`、`/invite`、`/review`、`/trace` 或 `/next` 草稿,并在 `/next` 与 `/help` 暴露入口;不触发 Tauri 读写、不读取文件、不启动或打开预览、不导出试玩包、不写项目、不新增普通用户问卷面板。
|
||||
- `/retention` 聊天入口由 `appSurface.test.ts` 主窗口 smoke 覆盖:只基于当前已加载 manifest、最近 run trace、preview、最近试玩证据、素材数量、发布说明和导出状态准备首轮复玩/留存观察清单,提供 `/run`、`/feedback`、`/review`、`/trace` 或 `/next` 草稿,并在 `/next` 与 `/help` 暴露入口;不触发 Tauri 读写、不读取文件、不启动或打开预览、不导出试玩包、不上传云端、不发布作品、不写项目、不新增普通用户留存面板,也不做真实埋点、留存报表、用户画像、A/B 实验、排行榜或账号留存。
|
||||
- `/cover` 聊天入口由 `appSurface.test.ts` 主窗口 smoke 覆盖:只基于当前已加载 manifest、最近 run trace、preview 和资产状态准备封面与缩略图候选、用途尺寸、选择口径和补齐路径,提供 `/run`、`/art`、`/listing`、`/review`、`/trace` 或 `/next` 草稿,并在 `/next` 与 `/help` 暴露入口;不触发 Tauri 读写、不截屏、不裁剪、不读取文件、不启动或打开预览、不导出试玩包、不上传云端、不发布作品、不写项目、不新增普通用户封面面板。
|
||||
|
||||
@@ -633,6 +633,13 @@ Responses 的终态载荷既是工具调用的恢复源,也是正文的恢复
|
||||
- 说明:外部 OpenAPI 调用使用的账号级 API Key 凭据表,只保存 key prefix、SHA-256 hash、作用域、撤销状态和使用时间;明文 Key 只在 `/api/profile/api-keys` 创建接口返回一次,不进入 SpacetimeDB,且 API Key 管理接口不写入外部 OpenAPI JSON。v1 默认作用域为 `editor:project`、`editor:canvas`、`editor:image-generate`、`editor:asset`;其中 `editor:project` 覆盖项目列表、最近项目、创建、读取、重命名和删除,`editor:canvas` 覆盖默认画布布局保存,`editor:image-generate` 覆盖编辑器现有图片生成、重绘 / 调整、去背景、规范图、宣发素材、图标 spritesheet 生成 / 拆分、UI 设计图素材拆分、角色动画、视频、音效和背景音乐生成,`editor:asset` 覆盖素材直传凭证、素材对象确认、签名读取、账号级素材库和项目画布资源记录操作。
|
||||
- 索引:`by_external_api_key_owner_user_id` 用于登录态 API Key 列表;`key_hash` 唯一索引用于外部 API 鉴权。
|
||||
|
||||
### `error_report`
|
||||
|
||||
- Rust 结构体:`ErrorReport`
|
||||
- 源码:`server-rs/crates/spacetime-module/src/error_report.rs`
|
||||
- 说明:错误报告只在请求内存中构建 ZIP 并上传私有 OSS;SpacetimeDB 仅保存 batch、幂等、对象键、摘要、计数和管理员审核元数据。管理员列表/筛选/更新走 `spacetime-client` facade,详情和下载再从 OSS 读取 ZIP。OSS key 固定为 `agc/error-reports/v1/{batchId}.zip`,不含时间戳;上传失败不写表。
|
||||
- 索引:`by_error_report_user_submission` 用于用户提交幂等;`by_error_report_created_at`、`by_error_report_review_status` 用于后台查询与清理。
|
||||
|
||||
### `admin_account`
|
||||
|
||||
- Rust 结构体:`AdminAccount`
|
||||
|
||||
@@ -58,7 +58,7 @@ Linux 本机多用户并发开发时,`npm run dev`、`npm run dev:*` 单模块
|
||||
|
||||
后端日志默认写入 `logs/api-server/`,独立 BgFilter worker 日志默认写入 `logs/bgfilter-worker/`。后端 API smoke 使用 `npm run dev:api-server`,先检查 BgFilter worker `/readyz`,再检查 API `/healthz`;需要确认 API 实例可接生产流量时检查 API `/readyz`。不要使用旧 `api-server:maincloud` 或任何 `GENARRATIVE_SPACETIME_MAINCLOUD_*` 口径。
|
||||
|
||||
AI 游戏创作客户端使用 `npm run agc`。该入口由 `apps/ai-game-creator-shell/scripts/start-tauri-dev.mjs` 解析 AGC Vite 实际端口:Linux 默认取当前用户端口段的 `start + 5`,占用时只在本用户段内漂移;Windows / macOS 保留 `3080` 为兼容首选并允许统一漂移。最终端口通过 `GENARRATIVE_AGC_VITE_PORT` 传给 `beforeDevCommand` 和配套后端端口解析器,通过 Tauri CLI 动态 `build.devUrl` 配置传给 WebView,并通过 Vite CLI `--port` 启动严格监听;Vite 继续使用 `strictPort`,任何一层都不得自行改到另一个端口。启动器在创建原生窗口前预检最终地址;若竞态中该地址被 AGC Vite、无响应监听器或其它服务占用,一律失败关闭,不复用、也不擅自终止无法证明归属的进程。
|
||||
AI 游戏创作客户端使用 `npm run agc`。该入口由 `apps/ai-game-creator-shell/scripts/start-tauri-dev.mjs` 解析 AGC Vite 实际端口:Linux 默认取当前用户端口段的 `start + 5`,占用时只在本用户段内漂移;Windows / macOS 保留 `3080` 为兼容首选并允许统一漂移。最终端口通过 `GENARRATIVE_AGC_VITE_PORT` 传给 `beforeDevCommand` 和配套后端端口解析器,通过 Tauri CLI 动态 `build.devUrl` 配置传给 WebView,并通过 Vite CLI `--port` 启动严格监听;Vite 继续使用 `strictPort`,任何一层都不得自行改到另一个端口。AGC 配套后端的 `backend` 模式启动 SpacetimeDB、独立 `bgfilter-worker` 和 `api-server`,并在复用现有后端前同时检查三者状态及 `/v1/ping`、`/readyz`、`/healthz`;worker 缺失时不得把不完整的 API/数据库组合误判为 ready。启动器在创建原生窗口前预检最终地址;若竞态中该地址被 AGC Vite、无响应监听器或其它服务占用,一律失败关闭,不复用、也不擅自终止无法证明归属的进程。
|
||||
|
||||
Tauri `beforeDevCommand` 默认与客户端构建并行,不能把上述检查只放在 `beforeDevCommand` 内:选定地址上若已有旧 Vite,Tauri 可能先创建加载旧前端的窗口,随后配套后端才因代理不匹配退出。外层启动器会把 Tauri CLI 放入受控进程树;CLI 正常退出、启动失败或收到终止信号后,POSIX 先向保留的 PGID 发送 `SIGTERM`、有界等待后升级 `SIGKILL`,Windows 使用 `taskkill /PID <pid> /T /F`。Linux 容器中的孤儿后代退出后可能暂时保留为 zombie,`kill(-PGID, 0)` 仍会返回成功;启动器必须结合 `/proc/<pid>/stat` 判断同组是否还存在非 zombie 成员,不能把等待 PID 1 回收误报为清理失败。配套后端和 Vite 仍由 `start-dev-stack.mjs` 各自持有,退出时同样有界收束,避免只剩客户端、Runner、Cargo 或旧订阅进程。排障时同时核对控制台输出的 AGC Vite 实际地址及其 marker、`.app/dev-stack.json` 的实际 API URL 和进程 cwd;不要把“终端已返回”当成客户端及其 Runner 已退出的证据。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user