diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/controller/useDirectProjectChatController.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/controller/useDirectProjectChatController.ts index 0dfcbb040..d88da118b 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/controller/useDirectProjectChatController.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/controller/useDirectProjectChatController.ts @@ -603,8 +603,12 @@ export function useDirectProjectChatController({ async function refreshDirectManifest(nextProjectPath: string) { try { await refreshManifest(nextProjectPath); - } catch { - // 回合结果仍是聊天的权威来源:清单缺失或过旧不能藏掉 Codex 回复。 + } catch (error) { + // 回合结果仍是聊天的权威来源,但清单刷新失败也不能静默:资源/版本面板可能因此 + // 过期,必须把 IPC/读取正文送到同一条运行错误出口。 + if (projectPathRef.current === nextProjectPath) { + onRuntimeError(`项目清单刷新失败:${visibleClientErrorMessage(error)}`); + } } } diff --git a/apps/ai-game-creator-shell/src/view/project-development/index.tsx b/apps/ai-game-creator-shell/src/view/project-development/index.tsx index 484daa99d..03a7eb114 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/index.tsx +++ b/apps/ai-game-creator-shell/src/view/project-development/index.tsx @@ -2924,12 +2924,14 @@ export default function ProjectDevelopmentView({ status: 'idle' | 'loading' | 'ready' | 'failed'; graph: ProjectResourceGraph; hasSnapshot: boolean; + error: string | null; }>({ projectScopeKey: '', scopeKey: '', status: 'idle', graph: EMPTY_PROJECT_RESOURCE_GRAPH, hasSnapshot: false, + error: null, }); useEffect(() => { @@ -2941,6 +2943,7 @@ export default function ProjectDevelopmentView({ status: 'idle', graph: EMPTY_PROJECT_RESOURCE_GRAPH, hasSnapshot: false, + error: null, }); return () => { cancelled = true; @@ -2954,6 +2957,7 @@ export default function ProjectDevelopmentView({ status: 'failed', graph: EMPTY_PROJECT_RESOURCE_GRAPH, hasSnapshot: false, + error: '需要在客户端内读取资源依赖图', }); return () => { cancelled = true; @@ -2969,6 +2973,7 @@ export default function ProjectDevelopmentView({ status: 'loading', graph: canReuseSnapshot ? current.graph : EMPTY_PROJECT_RESOURCE_GRAPH, hasSnapshot: canReuseSnapshot, + error: null, }; }); void invoke( @@ -2987,14 +2992,19 @@ export default function ProjectDevelopmentView({ status: 'ready', graph: normalizeProjectResourceGraph(readModel), hasSnapshot: true, + error: null, }); } }) - .catch(() => { + .catch((error) => { if (!cancelled) { setResourceGraphState((current) => current.scopeKey === resourceGraphScopeKey - ? { ...current, status: 'failed' } + ? { + ...current, + status: 'failed', + error: visibleClientErrorMessage(error, '读取资源依赖图失败'), + } : current, ); } @@ -3020,6 +3030,9 @@ export default function ProjectDevelopmentView({ const resourceGraphReady = resourceGraphAvailable; const resourceGraphFailed = resourceGraphScopeMatches && resourceGraphState.status === 'failed'; + const resourceGraphError = resourceGraphScopeMatches + ? resourceGraphState.error + : null; const resourceGraph = resourceGraphAvailable ? resourceGraphState.graph : EMPTY_PROJECT_RESOURCE_GRAPH; @@ -10912,6 +10925,16 @@ export default function ProjectDevelopmentView({ onPointerCancel={stopResourceCanvasPan} onLostPointerCapture={stopResourceCanvasPan} > + {sortMode === 'dependency' && + resourceGraphFailed && + resourceGraphError ? ( +

+ 资源依赖图读取失败:{resourceGraphError} +

+ ) : null} {sortMode === 'dependency' && dependencyRelationshipDescriptions.length > 0 ? (
{ fireEvent.click(await screen.findByRole('button', { name: '仍然保存' })); expect((await screen.findByRole('dialog')).textContent).toContain( - '保存失败,请稍后重试。', + '临时存储不可用', ); expect(screen.getByRole('button', { name: '重试保存' })).toBeTruthy(); expect(stateStore.save).toHaveBeenCalledTimes(1); diff --git a/docs/project-memory/plans/【里程碑】AGC错误具体文本展示-2026-10-04.md b/docs/project-memory/plans/【里程碑】AGC错误具体文本展示-2026-10-04.md index 90ab4729f..5f77e0821 100644 --- a/docs/project-memory/plans/【里程碑】AGC错误具体文本展示-2026-10-04.md +++ b/docs/project-memory/plans/【里程碑】AGC错误具体文本展示-2026-10-04.md @@ -73,3 +73,5 @@ DirectProject 回合失败在确认不是客户端内部不可归类故障时, - 第二轮 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/权限正文;现把安全错误保存到状态并在依赖画布内联显示。