diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/thread_manager/mod.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/thread_manager/mod.rs index 6d61660be..14f43e3e4 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/thread_manager/mod.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/thread_manager/mod.rs @@ -1006,11 +1006,16 @@ fn notify_subscribers(thread_id: &str) { }; if let Some(app) = THREAD_MANAGER_APP_HANDLE.get() { for subscription_id in subscriber_ids { - let _ = tauri::Emitter::emit( + if let Err(error) = tauri::Emitter::emit( app, THREAD_NOTIFY_EVENT, serde_json::json!({ "subscriptionId": subscription_id }), - ); + ) { + app_log!( + "agent.thread_manager.notify.emit_failed subscriptionId={} detail={error}", + subscription_id + ); + } } } } diff --git a/apps/ai-game-creator-shell/src-tauri/src/asset_generation_tasks.rs b/apps/ai-game-creator-shell/src-tauri/src/asset_generation_tasks.rs index faec7fda0..329fdd10c 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/asset_generation_tasks.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/asset_generation_tasks.rs @@ -63,14 +63,19 @@ fn emit_asset_generation_task_changed(root: &Path, task_id: &str) { let Some(app) = ASSET_GENERATION_TASK_APP_HANDLE.get() else { return; }; - let _ = tauri::Emitter::emit( + if let Err(error) = tauri::Emitter::emit( app, ASSET_GENERATION_TASK_CHANGED_EVENT, serde_json::json!({ "projectPath": root.to_string_lossy(), "taskId": task_id, }), - ); + ) { + app_log!( + "asset_generation_task.emit_failed taskId={} detail={error}", + task_id + ); + } } const ASSET_GENERATION_TASK_PHASE_QUEUED: &str = "排队中。"; diff --git a/apps/ai-game-creator-shell/src-tauri/src/platform_maintenance.rs b/apps/ai-game-creator-shell/src-tauri/src/platform_maintenance.rs index 8135d41d7..c0ddf7ff1 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/platform_maintenance.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/platform_maintenance.rs @@ -39,11 +39,16 @@ pub(crate) fn emit_platform_maintenance_notice(status: u16) { let Some(app) = PLATFORM_MAINTENANCE_APP_HANDLE.get() else { return; }; - let _ = tauri::Emitter::emit( + if let Err(error) = tauri::Emitter::emit( app, PLATFORM_MAINTENANCE_EVENT, serde_json::json!({ "code": "MAINTENANCE", "status": status }), - ); + ) { + app_log!( + "platform_maintenance.emit_failed status={} detail={error}", + status + ); + } } /// 在平台响应的错误分支上分类维护态:命中就广播一次,未命中什么都不做。 diff --git a/apps/ai-game-creator-shell/src/services/pluginHost.ts b/apps/ai-game-creator-shell/src/services/pluginHost.ts index 12b7795a0..1684c5e25 100644 --- a/apps/ai-game-creator-shell/src/services/pluginHost.ts +++ b/apps/ai-game-creator-shell/src/services/pluginHost.ts @@ -4,6 +4,7 @@ import type { AgcPluginPanel, AgcPluginSummary, } from '../app/types'; +import { appendWebviewLog, visibleClientErrorMessage } from './errorReporting'; export const AGC_PLUGIN_STATE_CHANGED_EVENT = 'game-creator-plugin-state-changed'; @@ -115,7 +116,12 @@ export async function setAgcPluginProjectPath(projectPath: string | null) { const invoke = invokeOrThrow(); // 项目 effect 的 cleanup(null) 与下个项目的设置必须按提交顺序抵达宿主。 const next = pluginProjectUpdate - .catch(() => undefined) + .catch((error) => { + appendWebviewLog('error', [ + '[AGC] 上一次编辑器插件项目路径更新失败', + visibleClientErrorMessage(error), + ]); + }) .then( () => invoke('set_agc_plugin_project_path', { projectPath }) as Promise, diff --git a/docs/project-memory/shared-memory/pitfalls.md b/docs/project-memory/shared-memory/pitfalls.md index a270964e7..6906d9b0a 100644 --- a/docs/project-memory/shared-memory/pitfalls.md +++ b/docs/project-memory/shared-memory/pitfalls.md @@ -32,6 +32,8 @@ Direct 的 Tauri 进度、活动回合和 manifest 事件不能忽略 `app.emit` 插件项目路径清理和本地权限审计属于旁路,但失败仍要写 WebView 诊断;旁路不阻断业务不等于可以静默丢失 IPC/I/O 事实。 +资源生成任务变更、平台维护通知和 Thread Manager 对话通知也是用户状态事实;这些事件的 `emit` 失败会直接造成任务/维护弹窗/聊天停在旧状态,必须记录投递错误。 + 窗口标题栏的最大化状态读取、resize 订阅、最小化、最大化和关闭失败也要保留 WebView 诊断,不能用空 catch 让原生窗口 IPC 失败无迹可寻。 `WindowChrome.test.tsx` 当前没有在用例间清理挂载的 `WindowChrome`,多用例运行会出现重复标题和重复窗口按钮;这属于测试隔离问题,不能把它误判成窗口 IPC 行为回归。