Merge remote-tracking branch 'origin/master' into feat/support-more-node
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled

This commit is contained in:
2026-10-07 14:05:26 +08:00
204 changed files with 7383 additions and 2285 deletions
@@ -20,7 +20,8 @@ DirectProject 聊天区(`apps/ai-game-creator-shell/src/view/project-developme
- 触发一(滚动):`scrollTop <= 24` 且 `historyHasMore` 且不在加载中且没有失败记录时自动加载。
- 触发二(填充视口):首帧之后内容填不满视口(`scrollHeight <= clientHeight`)时继续加载,直到填满或 `hasMore=false`;不允许出现「历史比视口短、又没有按钮」的死局。
- 两个触发都不越过既有的首屏订阅锚点 `lastCompletedItemId`;一次加载仍最多连拉 5 页(口径见 [`【ADR】DirectProject对话历史单一事实源-2026-09-16`](./【ADR】DirectProject对话历史单一事实源-2026-09-16.md))。
- 加载中在列表最上方(比最旧一条回合更靠上)挂载一行 `role="status"`、`aria-live="polite"` 的「正在加载更早的对话」,带旋转圈;延迟 150ms 才显示,加载结束即卸载。它按需挂载,靠位置补偿(见第 2 条)保证下面的消息不跳。
- 加载中在列表最上方(比最旧一条回合更靠上)挂载一行 `role="status"`、`aria-live="polite"` 的「正在加载更早的对话」,带旋转圈;延迟 150ms 才显示,加载态转假后再留 300ms 才卸载(隐藏滞回)。它按需挂载,靠位置补偿(见第 2 条)保证下面的消息不跳。
- 隐藏滞回是必须的:填充视口的自动加载是连续翻页的(一次加载落地后下一帧又起一次),两次之间只有一个 effect 回流;立即卸载会把加载行一帧内拆了又挂。全是工具调用时更明显——工具组折在收起的 `<details>` 里,每页几乎不增加可见高度,视口一直填不满,加载行就在「页与页之间」忽隐忽现。300ms 的隐藏延迟让连续加载之间的小空隙不卸载,真正结束(超时后仍为假)照常卸载。
- 失败:挂起自动加载,列表顶部保留一行内联错误行——`role="alert"` 只包住「加载更早对话失败」文案本身,重试是可聚焦按钮、留在 live region 之外(assertive + atomic 的 live region 里不放交互控件);**不自动重试**,只有点重试(或切换项目)才重新开始;重试成功后错误行消失。
- 一次加载与它所属的**世代**绑定:切换项目或新起一次读取都推进世代号(`historyLoadTokenRef`),旧世代落地时整段失效——不合并条目、不写游标、不关加载态。只比项目路径不够:A→B→A 之后在飞的旧读取又落回同一个路径,原守卫放行,会把新一代的加载行与 `historyLoadingRef` 这道并发闸门一起改掉。换项目的推进放在**渲染期**(与 `projectPathRef` 同一处),不放在复位 effect 里:passive effect 走宏任务、promise 续体走微任务,旧读取可能在「切换提交完成、复位 effect 还没跑」的窗口里落地,那时世代号还是旧的,守卫会放行。
@@ -37,8 +38,9 @@ DirectProject 聊天区(`apps/ai-game-creator-shell/src/view/project-developme
### 3. 回到底部胶囊
- 列表底部居中的悬浮胶囊(`sticky`),跟着滚动容器走、不随内容滚走。
- 列表底部居中的悬浮胶囊,**位置基于列表可见底边**:列表是 flex 列容器,胶囊是最后一个 flex 项,`margin-top: auto` 在内容不足一屏时把它顶到可见底边,内容溢出一屏时 auto 归零、再由 `sticky bottom-3` 上拉贴底。只用 `sticky` 不够——它只能把元素**上拉**、不能下推,内容不足一屏时胶囊会停在文档流里(悬空),所以必须由 flex 的 auto margin 兜住「不足一屏」这一半。
- 距底部超过 48px 时出现,文案「回到底部」;用户不跟随时来了新的终态内容就改成「有新回复 · 回到底部」。
- 贴底判定不能只认 `onScroll`:内容**变短**到一屏以内时不会再有任何滚动事件(回合收口把过程折进收起的 `<details>`、历史加载行卸载),`atBottom` 会停在离开底部时的假值,胶囊就永远挂在一个滚不动的列表上(短历史一屏显示完却还悬着「回到底部」)。因此每次布局变化(`ResizeObserver`)、子元素增删(`MutationObserver`)与内容变化后都按真实几何复核一次 `isNearBottom`,复核为真即收起胶囊并清掉「有新回复」。
- 点击:平滑滚到底部 + 恢复跟随最新 + 清除「有新回复」,随后按钮自行消失。
- 平滑滚动期间滚动位置归这次程序化滚动所有:滚动事件不再翻转「跟随最新」,布局补偿也不写 `scrollTop`(写一次就会取消动画并把画面拉回原处,表现为「点了只下去一屏、到不了底」)。滚到贴底阈值即交还控制权;用户中途用滚轮 / 触摸 / 键盘打断则立刻交还,不会卡住后续跟随。
- 动画期间内容变高(流式正文、图片撑开)时,点击瞬间记下的 `scrollHeight` 已经不是底部:补偿不写 `scrollTop`,而是把动画目标重新对准新的底部。否则动画停在旧目标上、等不到「贴底」那次滚动事件,`programmaticScrollRef` 不会交还——跟随与布局补偿整段挂起,而 `scrollToBottom` 已把胶囊按「已贴底」隐掉,用户停在底部之上却没有任何指示与自动跟随。
@@ -67,7 +69,7 @@ DirectProject 聊天区(`apps/ai-game-creator-shell/src/view/project-developme
## 备选方案与取舍
1. **保留按钮 + 只加自动加载**:加载中仍靠按钮做唯一反馈,且删掉按钮后失败路径没有补救入口;按钮本身与滚动自动加载重复。
2. **在列表外面套一层 viewport 做浮层定位**:`PlanningChatView` 共用同一套容器规则,且工作台里 `.project-chat-conversation` 是 `display: block` + `height: 100%` 几何,套一层就会让 `height: 100%` 的列表塌成内容高度;改公共类会连带策划对话。改用列表内的 `sticky` 胶囊,零结构改动。
2. **在列表外面套一层 viewport 做浮层定位**:`PlanningChatView` 共用同一套容器规则,且工作台里 `.project-chat-surface.is-direct-codex > .project-chat-conversation` 是纵向 flex、`.project-chat-message-list` 是其中 `flex: 1 1 auto` 的唯一滚动项,套一层定位容器会让列表塌成内容高度;改公共类会连带策划对话。改用列表内的 flex 项(`margin-top: auto` + `sticky`),零结构改动。
3. **只依赖原生 CSS scroll anchoring**:前插能免费对齐,但做不到「跟随时展开要贴底」,也无法在加载期间冻结同一套锚点;因此显式补偿 + 关闭原生锚定。
4. **展开后总是把正文滚进视口**:对正文比视口矮的折叠块会把画面大幅上移,打断正在读历史的用户;采用「跟随时贴底 / 否则冻结折叠头 + 只滚到刚好露出新展开正文的最小位移」。
5. **平滑滚动期间照常处理滚动事件与布局补偿**:程序化滚动会被应用自己的补偿打断(第一次写 `scrollTop` 即取消动画),用户点了「回到底部」也停在半路;因此改为滚动期间冻结这两条路径。
@@ -80,6 +82,6 @@ DirectProject 聊天区(`apps/ai-game-creator-shell/src/view/project-developme
- 历史加载失败不再只写顶部状态行,而是落到列表里的内联错误行;顶部状态行仍保留首屏读取失败等其它用途。
- 滚动是表现层行为,正式状态仍在后端投影与运行态事件;本 ADR 不新增领域概念。
- 阈值(触顶 24px、贴底 48px、spinner 150ms)是可按手感调整的常量,集中放在 `components/DirectProjectConversation/conversationScrollPolicy.ts`。
- 阈值(触顶 24px、贴底 48px、spinner 显示 150ms / 隐藏滞回 300ms)是可按手感调整的常量,集中放在 `components/DirectProjectConversation/conversationScrollPolicy.ts`。
- 验收:纯函数与 jsdom 组件测试覆盖阈值、锚点还原(含收口后按块身份仍指向同一块、锚点块被折叠隐藏时放弃还原)、加载/错误行、胶囊文案与显隐;滚动观感(顶部加载圈、胶囊出现与消失、底部展开回贴、历史前插不跳、长回合收口时视口不跳、切项目后首屏贴底且不误报「有新回复」)必须真机手动验收——jsdom 没有布局。
- 明确的后续项(不在本次范围):`PlanningChatView` 与 `App.tsx` 遗留 `message-history-more` 路径的同款改造、未读条数徽标、Playwright 端到端。
@@ -0,0 +1,47 @@
# AGC 错误具体文本展示实施计划
Version: 1.1
Status: implemented-awaiting-runtime-acceptance
Date: 2026-10-04
Parent Milestone: `【里程碑】AGC错误具体文本展示-2026-10-04.md`
## 修改边界
1. 在前端回合失败映射中新增统一的安全 detail 投影,按 typed variant 保留 HTTP 状态、错误分类和脱敏文本。
2. 对 `ModelCallKind`、`TransportClosed`、`TurnInterrupted`、阶段失败和 `Unclassified` 使用各自载荷,不再无条件返回通用文案。
3. 检查并补强 Rust 错误脱敏测试,确保敏感值替换而不是整行删除。
4. 补充 upstream、transport、stream、IPC、内存不足与 HostDropped 边界测试。
5. 更新 ADR 的当前行为口径。
6. HostDropped 的可选 detail 由 Rust 单点脱敏;panic hook 把可读负载和位置关联到原回合占用,Drop 与旧无字段事件分别验证,不更改回合排队、重试或计费行为。
7. DirectProject 控制器的取消、上传、历史读取和前置异常统一复用前端精确脱敏出口,保留 IPC/OS 正文并替换凭据值、URL 与路径。
8. 项目资源编辑/上传/预览/恢复队列/生成结果回读的 UI 错误统一使用 `normalizeDiagnosticText`,不再直出 `Error.message`。
9. 应用壳、运行配置、认证状态、插件启动、运行预览和策划会话的非结构化错误统一使用 `visibleClientErrorMessage`。
10. 资产导入、邀请码、策划工作区、发布封面/截图和素材命令的 UI 错误沿用同一共享出口。
11. Codex CLI / Claude sidecar 的解析失败、失败终态、缺失终态、超时和空回执保留有界脱敏正文;即使平台 `LlmError` 变体没有 detail 字段,也由统一 Direct `ModelCallFailed.detail` 继续携带原始原因。
12. 扩展统一正文口径到账户、模型目录、External Editor/资源编辑、发布、素材上传、错误报告与客户端受控工具桥,保留 HTTP 状态、响应安全片段、JSON 解析原因、网络因链和 IPC/桥接原因。
13. 浏览器启动/DevTools 握手与 Codex model-catalog 子进程错误保留 stderr、退出状态、解析原因和阶段信息,机器码只作为分类字段。
14. Node/npm 探测与 Web scaffold 构建失败保留有界脱敏 stdout/stderr、退出状态和超时原因;`preflight_web_game_creation` 不再只返回机器码。
## 实现顺序
先锁定脱敏输入输出用例,再实现前端可见文案;随后补 Rust 映射/诊断测试,最后运行类型、编码和差异检查。
## 风险与回滚
- 风险:直接展示未经精确脱敏的 provider detail 会泄露凭据或项目路径;前端和 Rust 双重检查,发现敏感 assignment 时替换值,不删除整条错误。
- 风险:错误文本过长遮住分类;保留分类前缀并将 detail 限制在有界字符数。
- 回滚:恢复 `directTurnFailureNoticeText` 的分类文案,保留 typed detail 和诊断落盘,不改协议。
## 验证结果
- 前端 DirectProject 错误展示:18 个定向测试通过;含 HostDropped detail / 旧载荷兼容。
- AGC shell TypeScript 类型检查:通过。
- Rust app-server 上游 detail 映射:6 passed。
- CC sidecar 状态码/超时映射与非支付 409 回归通过;侧车非零退出、RPC error、解析失败统一补充有界 stderr detail。
- 真实 AGC dev smoke 复现并定位 `Reached maximum number of turns (8)` → `transport-closed`;修复后客户端已热重编译重启,未再次触发付费 Provider 请求。
- Rust 应用日志/启动诊断精确脱敏回归:通过。
- Rust HostDropped panic detail + 旧无字段载荷兼容回归:定向通过。
- DirectProject 控制器错误正文:新增脱敏与空错误专用提示回归,前端定向测试通过。
- 资源工作台错误正文:项目开发页所有用户可见资源错误路径完成统一脱敏收口,TypeScript 与编码检查覆盖。
- 真实 Provider、IPC 断链和内存压力尚未执行。
- 2026-10-05 当前代码真实 `npm run agc` 构建启动通过;客户端与 Runner 已启动,前端/后台/API/worker/数据库健康检查通过,停止本次自有客户端后保留原有后端。
@@ -0,0 +1,44 @@
# 【实施计划】CC复用Codex运行态事件
| 字段 | 值 |
| --------- | --- |
| Milestone | `docs/project-memory/plans/【里程碑】CC复用Codex运行态事件-2026-10-04.md` |
| Status | implemented-pending-acceptance |
| Owner | Codex |
## 修改边界
- 允许修改:CC sidecar stdout 事件读取、`claude_code_cli.rs` 事件投影与历史收尾、Rust/前端定向测试、AGC 主技术方案和本里程碑文件。
- 明确不修改:Codex app-server 协议、外部 API、SpacetimeDB schema、MCP 工具实现、现有前端通用展示组件。
## 实现顺序
1. 给 sidecar 回合读取增加逐事件回调,同时保留终态和错误收口。
2. 在 Rust CC adapter 中建立有界、可归属的事件投影:文本/过程增量、工具开始、工具结果、进度与未知帧忽略。
3. 复用 ThreadEvent/ThreadItem 和现有历史追加逻辑,处理重复、缺失 id、失败结果和最终回复兜底。
4. 补 Rust parser/adapter、Thread wire 与前端 reducer/工具卡片定向测试。
5. 运行编码、diff、Rust/TS 定向门禁;若环境允许再做真实 CC Direct smoke。
## 验证命令
1. `cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --offline --bin genarrative-ai-game-creator-shell agent::claude_code_cli --test-threads=1`
2. `cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --offline --bin genarrative-ai-game-creator-shell agent::thread_manager::wire --test-threads=1`
3. `npx vitest run tests/directThreadChat.test.tsx tests/appSurface/tool-call-group.suite.ts apps/ai-game-creator-shell/tests/AgentMessageContent.test.tsx --root apps/ai-game-creator-shell`
4. `npm run check:encoding`
5. `git diff --check`
## 风险与回滚点
- SDK 事件类型会随版本增加:只读取白名单字段,未知事件忽略,不能因未知帧打断整轮。
- 文本/工具事件可能在同一 SDK 消息中并行出现:身份必须由 message id、content block index 或 tool_use id 组成,不能按到达顺序猜测。
- 真实 Provider/SDK 不可用时不宣称实时 smoke 通过;保留 fixture 测试作为替代证据。
- 若 Rust 事件投影破坏 Codex 回归,回滚只限 CC adapter 与其测试,不回退 ThreadEvent 合同。
## 当前验收证据
- Rust adapter `cargo check` 通过;本地缺失随包资源校验通过临时环境开关跳过,未改变最终代码。
- CC stream fixture 定向测试通过:增量正文、MCP started/completed、观察器状态均已验证。
- `cargo fmt --check`、`npm run check:encoding`、`git diff --check` 通过。
- 前端 Vitest 未执行:当前 worktree 缺少 `@tailwindcss/vite`、`vite` 等 npm 依赖。
- 真实 CC Provider smoke 未执行:当前 worktree 的随包资源校验素材不完整,且未启动真实项目回合。
- `npm run check:doc-index` 被既有未分类文件 `docs/technical/【技术方案】Ubuntu离线AI游戏创作部署与传统工作流对比-2026-10-03.md` 阻断。
@@ -0,0 +1,108 @@
# AGC 错误具体文本展示
Version: 1.1
Status: implemented-awaiting-runtime-acceptance
Date: 2026-10-04
Parent Spec: `docs/adr/【ADR】AGC命令错误结构化与错误报告口径-2026-10-01.md`
## 目标
DirectProject 回合失败在确认不是客户端内部不可归类故障时,向用户显示可行动的脱敏事实:上游 HTTP 状态、上游返回文本、网络/IPC/进程传输原因、流协议错误、内存不足等操作系统错误。保留机器字段用于诊断,但不再用通用“执行通道中断”覆盖可识别原因。
## 范围
- `turn.completed.failure` 的前端展示:按 typed 变体显示分类、状态码和脱敏后的 `detail` / `diagnostic`。
- Rust 侧错误文本脱敏:只替换敏感值、URL、绝对路径和私钥内容,保留 HTTP 状态、错误码、字段名和可行动描述。
- app-server `codexErrorInfo` 只有嵌套机器字段时,保留经有界脱敏的结构化值;`error` 是字符串或未知 JSON 形状时也保留正文;`fields=codexErrorInfo` 不能成为唯一正文。
- 素材/参考图/资源编辑上传、资源编辑轮询、模型目录初始化和 Direct MCP stdio 的网络、JSON、写入、读写失败保留底层错误正文;不能由 `map_err(|_| 固定句)` 把它们压成无因的连接或失败提示。
- 插件 stdout RPC 的 `fill_buf`、UTF-8 和响应大小错误通过挂起 RPC 传播,不能在读取线程里吞掉后统一说“插件进程已退出”。
- Codex CLI/Agent Runner 及本地素材/字体读取保留 stderr、join、序列化/解析、UTF-8 和 OS 错误正文;路径边界拒绝仍保留稳定安全码。
- Codex Provider proxy 的请求体改写、上游发送、响应构造和 SSE 错误保留底层正文,避免代理层再次把具体网络/解析故障压成单一 unavailable。
- 浏览器健康检查不再把发现、配置、DevTools 版本和清理失败只返回机器码;阶段码保留,同时带底层错误或明确的超时预算。
- WebView 结构化对象错误保留 `message/detail/reason/code` 或有界 JSON 正文,避免 `[object Object]` 触发普通错误兜底。
- Direct 工具桥图片与真实试玩证据读取/哈希错误保留 OS 正文,安全边界拒绝继续使用稳定码。
- `agc_read_project_context` 保留 `file-read-failed` 等稳定码,同时在能取得时附带文件打开/读取/复核的 OS 正文。
- Direct 交付复核和执行账本的 worker、产物读取、执行器摘要及宿主目录/锁失败保留底层原因,分类码不再单独承载正文。
- Transport / Stream / IPC / host process / memory exhaustion 的回归测试与错误事件证据。
## 不做
- 不把 access token、Cookie、API Key、私钥、完整 URL 查询参数、绝对路径原文显示给用户。
- 不改变上游协议、重试预算、计费和项目写入安全边界。
- 无法获得更深原因时仅展示宿主真实观测事实,不把 Drop 伪造成网络中断;不回填旧版本缺失的原因。
## 验收标准
1. HTTP 401/403/408/429/5xx 显示状态码与脱敏后的上游错误文本。
2. `connectionFailed`、`transportBroken`、`streamUnavailable`、`transportClosed` 显示对应分类及安全 detail;detail 不为空时不得落到通用错误句。
3. 包含 `authorization=...`、`token=...`、Cookie、URL query、Windows/Unix 路径、私钥块的错误,只替换敏感值并保留同一行中的状态码和其它诊断字段。
4. 包含 `out of memory`、`ENOMEM`、Windows 内存不足文本或 IPC/stdio 失败文本时,用户能看到对应安全文本。
5. HostDropped 保留 panic hook 可取得的负载和位置,普通 Drop 明确仅观测到任务未写终态退出;显式捕获的 panic/transport/IPC 错误继续走 typed failure。旧无 detail 载荷可重放,新 detail 脱敏后进入同一条失败事件。
6. 运行前端 DirectProject 错误映射测试、Rust redaction/runtime_error/turn_error 定向测试、TypeScript 类型检查、编码检查和 `git diff --check`。
## 当前证据
- `npx vitest run tests/directTurnFailure.test.ts`:15 passed。
- `npx tsc --noEmit -p apps/ai-game-creator-shell/tsconfig.json`:通过。
- Rust app-server 上游映射定向测试:9 passed;覆盖嵌套 `codexErrorInfo`、只有机器字段和非对象错误正文;应用日志脱敏测试与启动诊断脱敏测试均通过。
- CC 错误分类回归:Claude sidecar 状态码/超时映射与非支付 409 保留上游状态的定向测试通过;侧车失败统一补充有界 stderr detail。
- 真实 AGC dev smoke:客户端使用 `3080`、后端 `8084`、数据库 `3101`、后台 `3103` 启动;真实 CC 回合复现 `Reached maximum number of turns (8)` 被旧代码错误记为 `transport-closed`,修复后 Tauri 已热重编译重启。修复后的真实 Provider 回放未再次发送,避免无必要的付费请求。
- 真实 AGC 项目诊断发现真实请求 HTTP 400 曾被摘要为 `codex-app-server-error:other detail=fields=codexErrorInfo`,另有 401 仅显示 `codex-app-server-error:unauthorized`;该漏损已在 app-server 投影边界修复。真实 Provider、真实 IPC 断链和真实内存压力仍未在本轮主动制造。
- 继续扫描发现素材/参考图/资源编辑上传、模型目录初始化和 Direct MCP stdio 仍有固定 `map_err(|_| ...)` 丢正文,已改为保留底层网络、serde、写入和 OS 错误;平台素材上传定向 3 项、模型目录定向 4 项、Direct MCP 断输出定向 1 项通过。资源编辑全套并行测试本轮 54 项通过、11 项因共享 fixture/本地端口或账号环境超时失败,不能把该套结果记为全绿。
- 本轮继续扫出三类未收敛口:外部 MCP HTTP 的 401/429/桥上下文缺失原先只有空状态码响应,现改为保留 HTTP 状态、稳定错误码和中文正文;认证 5xx 结构化载荷、账户/素材上传/发行发布的 401/403 现保留服务端 message/code(仍精确脱敏)。
- 前端历史错误文本此前会把含有敏感字段的整条 Direct 诊断直接丢弃,现改为只替换凭据、链接和路径;旧版已经落盘且无法恢复正文的“执行通道中断”条目会明确追加“宿主未提供具体错误正文”,不再伪装成当前仍在吞错。
- 新增/通过:外部 MCP HTTP 401/429 定向 2 项、前端 Direct/Runtime 错误正文 25 项、旧历史通用中断脱敏回归 1 项;认证 Rust 定向 19 项、素材上传响应错误定向 1 项通过。`appSurface` 全套仍有环境/fixture 相关失败,不能据此宣称全绿。
- 继续扫描又发现画板项目/资产下载、模板库、图片分离、参考图上传、External Editor 生成恢复、资源编辑上传/轮询、项目快照和错误报告提交仍有“HTTP 只有编号”或未脱敏正文路径;已统一补上状态码 + 有界正文 + 精确脱敏。资源编辑拒绝原因继续复用既有 `details.message` 解析,避免丢掉平台具体原因。
- 前端继续发现两个静默出口:模板库权限检查失败会直接清空入口,Direct 线程订阅/consume/bootstrap 的 IPC 失败会只 settle anchor 而不显示正文;现分别保留权限检查错误,并把订阅链错误正文送入项目状态栏/运行错误出口。认证失败回归已验证显示 `authentication-required`,不再变成泛化“执行失败,请稍后重试”。
- UI 编辑器复制路径的原生剪贴板 IPC 失败也曾只显示“复制失败,请手动复制路径”,现保留脱敏后的剪贴板错误正文并同时给出手动复制指引。
- 受控联网搜索的上游非 2xx 响应原来只返回 HTTP 状态;现保留有界、脱敏的服务端正文,错误码/限流原因不再丢失。
- 窗口标题栏的 Direct 活动回合快照读取失败原来只给“读取失败”标志并保留旧快照;现额外保留脱敏后的 IPC/读取正文,面板不会把真实原因吞掉。
- 项目打开时读取 `conversation.read` 权限策略的 IPC 失败原来静默 return;现把脱敏错误正文写入项目状态和聊天错误提示。
- 错误报告通知读取本地待报告快照失败原来只重试后静默消失;现显示“项目诊断读取失败”及安全正文,并提供重试入口。
- 共享 Prompt Polish hook 的注入请求/规范化/回填异常原来只显示固定失败提示;现保留精确脱敏后的异常正文,聊天输入和资源润色共用同一口径。
- 资源画布历史生成任务账本读取失败原来统一显示“暂时无法恢复历史任务”;现在保留 Tauri/文件读取正文,非数组响应仍单独保留契约错误提示。
- 发现默认 `requestChatPromptPolish` 还会把 Tauri 润色命令异常吞成 `null`,导致共享 hook 无法看到平台正文;现仅对空回包/桥不可用保留 `null`,原生异常继续上抛并统一脱敏。
- 润色提醒偏好读取失败原来被当成“未关闭”默认值,写入失败只进错误上报池;现把读取/保存的 IPC 正文显示在输入区状态提示中,同时仍维持安全默认和回退行为。
- Direct 项目清单首次读取和清单事件订阅失败原来只让 `@` 候选退化为空;现把脱敏后的读取/订阅正文送入项目聊天状态条。
- Direct 活动回合事件桥注册失败原来只退回启动快照,面板没有说明后续更新已失联;现保留事件桥 IPC 正文并在标题栏/活动项目面板显示。
- 首页富文本输入的原生剪贴板图片/文本读取失败原来直接按空剪贴板处理;现通过输入区错误提示保留脱敏后的剪贴板 IPC 正文。
- 账号邀请码复制和微信充值状态确认仍有固定“复制失败/暂时没能确认到账”路径;现保留剪贴板/支付查询错误正文并继续给操作指引。
- 游戏发布面板的截图上传、发布进度订阅和最终发布异常也有固定文案/裸 `Error.message` 路径;现统一通过可见错误脱敏出口展示正文。
- 进入项目时预览活体核验的 IPC 失败原来只按“没有可复用预览”处理;现在保留安全正文并写入工作区状态,同时不误停未知活体。
- 继续真实客户端启动和旁路扫描又发现三处仍会损失事实:旧历史通用中断文案遇到换行/多空格时未命中“正文缺失”标记,非 2xx 响应正文读取失败被 `unwrap_or_default()` 抹掉,CC sidecar 的 stderr 排空超时/读取任务失败也被当成“没有 stderr”。现分别改为折叠空白识别、保留“响应正文读取失败:底层原因”和保留 stderr 排空阶段/底层原因;不改变状态码、重试和脱敏边界。
- 第二轮 Agent/CC 旁路扫描继续发现执行许可/执行会话/MCP 本地读取/编辑器 worker/Cocos worker 的 JoinError,以及 MCP future panic,会被固定成“任务未返回/异常/需要核对”;现把 join/panic 正文并入既有 ToolFailure / MCP 错误载荷,保留 `needs-reconciliation` 的不可自动重放语义。Native 定向测试:Direct MCP 33 项、Direct Tool Bridge 41 项、CC 14 项均通过。
- 最新漏扫又补出 Direct Tools MCP 启动/运行退出码、Skill `resources/read` 索引与资源读取、交付 `finish_sealing` 错误三处固定句;现在分别写入 stderr、MCP 错误正文和交付复核底层原因,避免只剩退出码或“暂不可用/复核失败”。
- 前端继续实测发现预览活体复用的 IPC / 权限拒绝会被当成“没有活体”并静默重启,资源生成事件订阅失败也只回退轮询;现在两条回退仍保留,但分别把复用失败正文附到重启结果、把订阅失败正文附到任务阶段。预览与生成队列定向测试 25 项通过。
- 继续扫前端外围又发现 Direct 回合后的清单刷新、资源卡片预览未知错误、UI 编辑器单图预览读取失败仍会静默或使用无因固定句;现分别进入运行错误出口、保留脱敏后的预览错误正文并在编辑器状态提示中显示。
- 资源依赖图读取失败原先只切到 fallback 布局状态,用户看不到 IPC/权限正文;现把安全错误保存到状态并在依赖画布内联显示。
- 资源画布布局读写失败原先只把原因写日志、界面仍显示固定“布局失败”;现把脱敏后的 revision/IPC/权限/磁盘正文附到读取与保存提示,原有回退布局行为不变。
- 又扫出发布状态、扩展列表、应用更新和生成任务的“无正文时固定句”分支;这些分支现在明确显示“未提供具体错误正文”,不再让空原因伪装成完整错误。
- 项目权限策略读取还有两条调用方会在 IPC 异常时直接返回 `false`;现把脱敏后的读取错误同时写入工作台状态和项目聊天错误,不再把“未获权限”与“策略读取失败”混为一谈。
- 策划 Agent 的 Tauri 事件订阅失败原先只放行回合等待、没有任何用户提示;现把订阅 IPC 正文写入项目聊天错误出口,避免只收到不完整的最终态。
- 专业 Agent 历史回读与项目清单同步的后台 Promise 失败原先只返回 `failed` 或静默结束;现把具体读取/同步正文写入项目聊天错误出口。
- Direct 交付计划/合同 JSON 解析、策划工作区目录枚举与文本搜索还有 `map_err(|_|)` / `Err(_)` 丢细节;现保留 serde、目录和文件读取正文,安全路径边界仍单独拒绝。
- 直连 Codex 输出指纹此前把除 `NotFound` 之外的所有读取错误都当成“文件不存在”,可能误判产物未变化;现只对确实不存在的文件保留空位,其余磁盘/权限错误沿回合失败正文上送。
- DirectProject 上下文的外部路径元数据读取失败原先统一成 `file-not-found`;现区分确实不存在与权限/磁盘读取错误,后者保留底层正文。
- 错误报告对话框读取最新错误事件或诊断日志失败时原先只显示“暂不可用/使用快照”;现把读取 IPC/文件正文附在状态提示中,快照回退行为保持不变。
- WorkspaceLauncher 的清单版本读取、失效事件重读和事件订阅失败原先只写日志或静默回退;现把安全正文送入启动器状态提示,仍保留已有回退刷新路径。
- Direct 补丁事务的目标指纹读取原先把元数据、打开、正文读取和文件超限都折叠为 `None`,可能误判文件缺失或继续比较;现只对确实 `NotFound` 保留 `missing`,其余失败返回目标相对路径、阶段和底层正文,避免补丁结果被错误归因。
- CC/Direct 工具桥的执行前后成果指纹、回执结算 JoinError/落盘失败,以及外部 MCP journal 的读取/JSON 行解析原先仍会被 `.ok()`、固定回执句或“无记录”吞掉;现分别保留指纹阶段、回执任务/落盘原因、journal 行号和底层正文,只有真实 `NotFound` 才视为空记录。
- 外部 MCP `resources/read` 仍把已能返回具体原因的 Codex journal 读取错误 `unwrap_or_default()` 成空资源;现把读取失败按 MCP 错误响应返回,Direct 执行会话当前项目 canonicalize 也保留底层 I/O 正文。
- Direct 交付终态读取原先把 `session.snapshot()` 锁/状态错误折叠成 `None`,上层继续显示“尚未确认交付完成”;现沿 `code-generation` 失败出口保留终态读取正文,并在已有回合失败时同时保留原始失败与终态读取失败。
- 对话模型选择器读取 native 配置原先把 IPC/文件异常 `.catch(() => null)` 后只显示“读取客户端配置失败”;现通过统一可见错误脱敏出口保留具体正文,并保留配置不可读时不猜测模型路由的安全行为。
- 策划工作区事件订阅失败仍有一处直接静默结束,导致文件刷新失联却没有提示;现把订阅 IPC 正文写入工作区错误状态,继续保留手动刷新与已有清单读取错误出口。
- 新一轮原生扫出 app-server 进程与上下文漏损:Codex 执行器核验/OAuth 保存/回合身份的 JoinError、图片 base64 解码、Direct 上下文 canonicalize,以及进程树归属、Job、等待、终止和 Drop 清理错误原先只剩固定码;现保留 JoinError、解码器、OS/Job、等待和终止阶段正文,并为进程树 Drop 清理失败写入诊断日志。
- 继续扫出浏览器收割的 Job/root kill/wait 错误原先压成 `bool`、External Editor 本机凭据 JSON/目录创建/保存错误丢底层正文,以及生成任务中断收口把项目清单读取失败当成“状态未知”;现分别保留浏览器清理阶段正文、凭据解析/存储正文,并让非“项目尚未初始化”的清单读取失败直接返回具体错误。
- 受控 command 执行路径仍会把 leader 启动身份读取、进程组终止、root kill、Job/wait 失败折叠为“身份未确认/退出未确认”;现拒绝无身份接管并保留身份读取、终止兜底、等待和 OS 错误正文。
- 继续扫到本地资源导入、平台素材 data URL、External Editor binding origin、项目模型记录读取/JSON 解析等错误仍丢底层正文;现区分真实 NotFound 与权限/元数据失败,并保留 base64、URL、文件读取和 JSON 解析细节。
- 资源编辑上游 4xx 正文的流读取失败、正文超限、非 UTF-8 和未知 JSON 形状原先都会回落到笼统失败;现保留读取阶段、大小上限、编码错误和有界脱敏原文。
- 认证状态订阅底层原先先把 IPC 失败转成空注销函数,导致上层新增的错误提示也收不到;现让订阅拒绝向登录页传播,后台身份投影失败时清除身份并留痕。
- 发布构建预检原先把 `package.json` 元数据/读取/解析错误当成“没有 build”,把 `package-lock.json` 读取/解析错误当成“没有锁定版本”;现分别区分 NotFound 与真实读盘/JSON 错误,保留相对工作区路径和底层正文。
- 发布尝试账本和工作区偏好文件原先把损坏、权限、类型和 JSON 解析失败当成空账本/默认偏好;现只有文件不存在才使用默认,其他读取错误沿发布幂等和建项目录命令返回具体正文。
- 插件主机扫描工作区、读取进程状态、停止插件和禁用插件时原先吞掉目录项/`try_wait`/kill/wait 错误;现保留插件状态错误并阻止“停止失败却显示已禁用”,正常主动 kill 的非零退出码不再误报。
- 插件进程 stderr 原先使用 `Stdio::null()`,即使进程退出也只能显示退出码;现以有界脱敏 sidecar 保留插件 stderr,并在退出状态中附带正文。
- 新增发布尝试账本损坏回归:损坏记录现在阻止生成新的根幂等键,并返回账本 JSON 解析正文,避免静默重复发布。
- 首页建项/打开项目读取本地 revision 失败原先吞成 `null` 并继续进入项目;现保留降级进入行为,同时把 IPC/文件读取正文写入首页状态。
- 发布面板读取封面生成价格失败原先只清空价格并继续显示泛化消耗提示;现保留价格查询的脱敏正文并在确认弹窗中展示。
- 资源模型卡、素材引用选择器和本地图片导入预览原先失败只降级成图标/文件名;现保留脱敏后的 WebGL、IPC、远程读取原因,并通过卡面 title/aria 或提示文本展示,降级预览行为不变。
- 项目快照工作区登记失败原先只写固定诊断键,实际 IPC/权限/路径原因丢失;现把统一脱敏正文写入应用诊断日志,并保留重试登记行为。
@@ -0,0 +1,45 @@
# 【里程碑】CC复用Codex运行态事件
| 字段 | 值 |
| ----------- | --- |
| Version | 1.0 |
| Status | implemented-pending-acceptance |
| Date | 2026-10-04 |
| Parent Spec | `docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md` |
## 目标
让 CC DirectProject 的流式文本、过程、MCP 工具调用和工具结果实时进入现有 Thread Manager 事件合同,并由现有聊天 reducer、工具卡片和历史投影统一展示。
## 范围
- sidecar 事件逐条回调到 Rust。
- Claude stream event、assistant tool_use、user tool_result、工具进度和终态的安全投影。
- CC 事件对应的 `ThreadItem` 历史追加与重复事件幂等。
- Rust adapter、ThreadEvent/ThreadItem 现有合同的定向测试和前端 reducer/工具卡片回归。
## 不在范围内
- Claude Code 原生权限、MCP server、模型路由、会话恢复和取消语义重构。
- 新增前端 CC 专用组件、公开 API、OpenAPI 或 SpacetimeDB 迁移。
- 将未经安全投影的内部控制帧或完整思维链直接展示。
## 依赖与前置条件
- 现有 `ThreadEvent` / `ThreadItem` / `directThreadChat` 合同保持兼容。
- Claude Agent SDK 当前 stream-json 消息包含 assistant content blocks 和 user tool_result。
- 工作树已有的无关未跟踪文档保持不动。
## 验收标准
- [ ] CC `stream_event` 文本在 `result` 前生成 `item.delta`。
- [ ] CC 工具调用先生成运行中 `mcpToolCall`,结果生成同身份完成/失败条目。
- [ ] CC 过程文本使用现有 reasoning 条目,不增加前端 agentMode 分支。
- [ ] 成功回合历史可重读,重复追加幂等;失败回合不伪造成功终态。
- [ ] Codex 现有定向测试保持通过。
## 证据要求
- 自动化:Rust `claude_code_cli` / thread wire / Direct runtime 定向测试,前端 `directThreadChat` 与工具卡片测试。
- 运行时:若本地 Claude SDK/Provider 可用,执行一次真实 CC Direct 回合;否则用 SDK stream-json fixture 明确记录未完成项。
- 边界:tool_result 错误、缺失 tool id、未知控制帧、重复结果、取消/失败终态。
@@ -65,7 +65,7 @@ Node/npm 版本探测清空继承环境后,必须设置客户端创建的临
- **网络与凭据只在 Rust**。平台 origin、Bearer/refresh 凭据、OSS 直传票据、Provider 与更新清单请求都由 `src-tauri` 承担;渲染层通过 typed command 提交结构化意图,不再持有 access token,也不再声明 `http:default` 权限(`capabilities/main.json`)。`src/services/clientApi.ts` 与 `fetchClientHttp` 已删除。
- **状态变更由 Rust 事件驱动**。正式状态归 Rust:Direct 活动回合的唯一事实源是 Direct 线程管理器的活动回合快照(`list_direct_active_turns` 只读它),登记、进度内容变化、收口各广播一次 `game-creator-direct-active-turns-changed`;素材生成与插件状态同理。渲染层进入入口时**先订阅、再读一次受控快照**,事件重复或内容未变时保持数组身份,卸载后迟到事件不写回;不恢复任何固定频率轮询(纯 UI 计时器、拖拽重复器与动画 tick 除外)。
- **维护态判定归 Rust,渲染层只订阅**。平台请求的错误分支统一经 `platform_maintenance::watch_platform_response` 分类(只有 `503` 且命中 `MAINTENANCE` 或「维护」才算,对象存储自身的 503 不误伤),命中后广播 `genarrative-client-maintenance-detected`;渲染层由 `clientMaintenance.subscribeClientMaintenanceEvent` 订阅并打开唯一的「系统维护中」弹窗,业务面板各自的错误文案保持不变,同一批并发失败只弹一次。
- **失败文案只展示宿主给的脱敏摘要**。`turn.completed.failure` 是失败说明的唯一来源,渲染层不做 HTTP 判定、不预读诊断正文;失败线索留在 `.agent/runtime/errors`、应用日志与错误上报池(`5398a53e6` 起用户可见文案不再带诊断引用)。
- **失败文案展示宿主给的精确脱敏事实**。`turn.completed.failure` 是失败说明的唯一来源,渲染层按 typed 变体展示 HTTP 状态、错误码、IPC/stdio、操作系统错误和上游正文;只替换凭据值、完整 URL、绝对路径与私钥,不再因命中 `authorization/token/credential` 删除整条错误。失败线索仍写入 `.agent/runtime/errors`、应用日志与错误上报池。
- **活动回合之外的两条配套约束**:命令返回 `Ok` 只代表接单成立,整轮收场只由 `turn.completed` 回答;渲染层的队列、忙态与提示都以事件流的这些终态为准。
证据入口:`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --offline -- direct_thread_manager --test-threads=1`、`-- platform_maintenance --test-threads=1`、`npx vitest run tests/directActiveTurns.test.tsx tests/maintenanceNotice.test.tsx --root apps/ai-game-creator-shell`。
@@ -62,7 +62,7 @@
### 前端合并与渲染(回合唯一归属,连续工具成块)
- 加载对话时按历史条目进入 `project.jsonl` 的原始顺序投影:用户消息、文本与工具块保持原序,连续工具合为一块、遇到文本另起一块,不按 `turnId` 重新归并、也不再有 `seq` 交替。
- 回合完成后,中间文本及所有工具块统一收进默认关闭的“执行过程”;最终回复及失败提示留在外面。展开后仍按原顺序查看中间输出和工具详情;运行中不使用外层折叠区。用户消息的发送时间从消息自身的历史时间读取,不能拿工具起点补造。
- 回合完成后,中间文本及所有工具块统一收进默认展开的“执行过程”;最终回复及失败提示留在外面。用户仍可收起过程块,重开项目后过程默认再次可见;运行中不使用外层折叠区。用户消息的发送时间从消息自身的历史时间读取,不能拿工具起点补造。
- 实时与回读共用同一投影,正文、工具和耗时不另建实时/未归属渲染出口。先在完整历史按消息身份关联,再分页;禁止按第 N 个工具回合匹配第 N 条用户消息。详情通过当前回合 `callId` 关联;同项目回读与实时增量幂等合并,切项目清空旧状态。完整合同见 [AGC 实施计划](./【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md) 的“DirectProject 回合展示唯一归属”。
- 块 DOM 与交互(对齐 Codex):
@@ -105,7 +105,7 @@
- 当前 Agent 与策划 Agent 共用 `packages/shared` 的 `AgentMessageContent` 表现组件:正文为 14px / `--platform-text-strong`,思考、中间输出和工具调用为 12px / `--platform-text-soft`。实时与历史思考共用同一个折叠入口;工具输入输出继承过程色,失败状态保留错误色。Markdown 标题、表格及代码高亮在过程区同步弱化,最终回复和文档预览仍保留正常排版,不按 Agent 类型复制样式。输入提示与禁用状态保持原有反馈。
- Windows 命令展示:仅 `command` 卡片识别 `pwsh` / `powershell`(含完整路径、`.exe`、常见启动选项)的 `-Command` / `-c` 外层包装,摘要和展开输入只展示脚本正文,并解开单个 shell 参数的引用拼接。摘要优先读取已脱敏的 `detail.command`,再按首行 120 字符截断,避免历史摘要被可执行文件路径占满。无法识别的启动方式、`-File`、`-EncodedCommand`、普通命令和 MCP 输入原样展示;执行参数、持久化原文、脱敏和输出均不改变。
- 调试属性:块与行都带 `data-duration-ms`(原始毫秒,无法计算时为空串)与稳定 `data-testid`(块 `agent-tool-call-group`、行 `agent-tool-call-row`)。
- 必须用 `<button aria-expanded>` + `hidden` 控制展开(键盘可达、可读屏),块头与行都是按钮:`aria-label` = 汇总 / 行文案 + 耗时;默认折叠。
- 必须用 `<button aria-expanded>` + `hidden` 控制行级展开(键盘可达、可读屏),块头与行都是按钮:`aria-label` = 汇总 / 行文案 + 耗时;回合完成后的外层过程块默认展开,用户可手动收起。
- 输入框、消息气泡、消息列表滚动模型**不变**;块只是消息流里的一个块。
## 验收判据(每条都要有可复现证据)