diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/design_runtime.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/design_runtime.rs index 53441925d..40afd5dad 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/design_runtime.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/design_runtime.rs @@ -1689,7 +1689,9 @@ pub(crate) async fn continue_design_agent_session( input, capture, |event| { - let _ = app.emit("design-agent-update", event); + if let Err(error) = app.emit("design-agent-update", event) { + app_log!("design_agent.update.emit_failed detail={error}"); + } }, ) .await @@ -1716,7 +1718,9 @@ pub(crate) async fn decide_design_phase( approved, capture, |event| { - let _ = app.emit("design-agent-update", event); + if let Err(error) = app.emit("design-agent-update", event) { + app_log!("design_agent.update.emit_failed detail={error}"); + } }, ) .await diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/design_tools.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/design_tools.rs index 5237b0715..796dbdd21 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/design_tools.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/design_tools.rs @@ -551,7 +551,7 @@ pub(crate) fn import_design_workspace_file( ) -> Result { let root = PathBuf::from(project_path.trim()); let relative_path = import_design_workspace_file_at(&root, &file_name, &bytes)?; - let _ = app.emit( + if let Err(error) = app.emit( "design-agent-update", serde_json::json!({ "projectPath": root.to_string_lossy(), @@ -561,7 +561,9 @@ pub(crate) fn import_design_workspace_file( "text": null, "view": null, }), - ); + ) { + app_log!("design_agent.workspace.emit_failed detail={error}"); + } Ok(relative_path) } diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/generation/loop_orchestration.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/generation/loop_orchestration.rs index c8612377b..828d206b8 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/generation/loop_orchestration.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/generation/loop_orchestration.rs @@ -16,14 +16,19 @@ impl<'a> AgentProgressEmitter<'a> { } fn emit(&self, stage: &str, message: &str) { - let _ = self.app.emit( + if let Err(error) = self.app.emit( "game-creator-agent-progress", GameCreatorAgentProgressEvent { project_path: self.project_path.clone(), stage: stage.to_string(), message: message.to_string(), }, - ); + ) { + app_log!( + "agent.generation.progress.emit_failed stage={} detail={error}", + stage + ); + } } } diff --git a/apps/ai-game-creator-shell/src-tauri/src/auth_session.rs b/apps/ai-game-creator-shell/src-tauri/src/auth_session.rs index 8428740fe..680d0ef6a 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/auth_session.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/auth_session.rs @@ -795,7 +795,12 @@ fn auth_state_view( } fn emit_auth_state(app: &tauri::AppHandle, view: &ClientAuthStateView) { - let _ = app.emit(CLIENT_AUTH_STATE_CHANGED_EVENT, view.clone()); + if let Err(error) = app.emit(CLIENT_AUTH_STATE_CHANGED_EVENT, view.clone()) { + app_log!( + "auth_session.state.emit_failed status={} detail={error}", + view.status + ); + } } fn phone_is_valid(phone: &str) -> bool { diff --git a/apps/ai-game-creator-shell/src-tauri/src/commands/desktop.rs b/apps/ai-game-creator-shell/src-tauri/src/commands/desktop.rs index fdf1bd148..151fc6760 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/commands/desktop.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/commands/desktop.rs @@ -1215,7 +1215,7 @@ pub(crate) async fn upload_local_project_game_package( session_identity: None, }, move |received_bytes, total_bytes| { - let _ = emit_handle.emit( + if let Err(error) = emit_handle.emit( crate::game_package_upload::GAME_PACKAGE_UPLOAD_PROGRESS_EVENT, crate::game_package_upload::progress_event_payload( &progress_version_id, @@ -1225,10 +1225,15 @@ pub(crate) async fn upload_local_project_game_package( received_bytes, total_bytes, ), - ); + ) { + app_log!( + "game_package_upload.progress.emit_failed versionId={} detail={error}", + progress_version_id + ); + } }, move || { - let _ = verify_handle.emit( + if let Err(error) = verify_handle.emit( crate::game_package_upload::GAME_PACKAGE_UPLOAD_PROGRESS_EVENT, crate::game_package_upload::progress_event_payload( &verify_version_id, @@ -1238,7 +1243,12 @@ pub(crate) async fn upload_local_project_game_package( 0, 0, ), - ); + ) { + app_log!( + "game_package_upload.verify.emit_failed versionId={} detail={error}", + verify_version_id + ); + } }, ) .await diff --git a/apps/ai-game-creator-shell/src-tauri/src/error_report/notifications.rs b/apps/ai-game-creator-shell/src-tauri/src/error_report/notifications.rs index b6f8bb86d..58f7a1f8b 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/error_report/notifications.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/error_report/notifications.rs @@ -36,12 +36,17 @@ pub(crate) fn schedule_notification() { let (events, current_generation) = snapshot_with_generation(); LAST_EMITTED_GENERATION.store(current_generation, Ordering::Release); if !events.is_empty() { - let _ = handle.emit( + if let Err(error) = handle.emit( "error-report-updated", serde_json::json!({ "generation": current_generation, }), - ); + ) { + let _ = crate::append_application_log_line(&format!( + "RUST error_report::notifications: error_report.notification.emit_failed generation={} detail={error}", + current_generation + )); + } } if let Some(active) = TIMER_ACTIVE.get() { *active diff --git a/apps/ai-game-creator-shell/src-tauri/src/game_distribution_publish.rs b/apps/ai-game-creator-shell/src-tauri/src/game_distribution_publish.rs index a5ec62dc8..1accf3094 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/game_distribution_publish.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/game_distribution_publish.rs @@ -1286,7 +1286,7 @@ fn emit_publish_progress( received_bytes: u64, total_bytes: u64, ) { - let _ = app.emit( + if let Err(error) = app.emit( PACKAGE_UPLOAD_PROGRESS_EVENT, crate::game_package_upload::progress_event_payload( version_id, @@ -1296,7 +1296,14 @@ fn emit_publish_progress( received_bytes, total_bytes, ), - ); + ) { + app_log!( + "game_distribution.publish_progress.emit_failed publishId={} versionId={} phase={} detail={error}", + publish_id, + version_id, + phase + ); + } } #[tauri::command] diff --git a/apps/ai-game-creator-shell/src-tauri/src/plugin_host/desktop.rs b/apps/ai-game-creator-shell/src-tauri/src/plugin_host/desktop.rs index b1856306d..b403d7ca5 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/plugin_host/desktop.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/plugin_host/desktop.rs @@ -153,7 +153,12 @@ pub(crate) async fn set_agc_plugin_project_path( } fn emit_plugin_state_changed(app: &tauri::AppHandle, host: &PluginHost) { - if let Ok(extensions) = host.list_extensions() { - let _ = app.emit(AGC_PLUGIN_STATE_CHANGED_EVENT, extensions); + match host.list_extensions() { + Ok(extensions) => { + if let Err(error) = app.emit(AGC_PLUGIN_STATE_CHANGED_EVENT, extensions) { + app_log!("agc.plugin_state.emit_failed detail={error}"); + } + } + Err(error) => app_log!("agc.plugin_state.list_failed detail={error}"), } } diff --git a/apps/ai-game-creator-shell/src-tauri/src/workspace_preferences.rs b/apps/ai-game-creator-shell/src-tauri/src/workspace_preferences.rs index c9ee47a32..d13c0995f 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/workspace_preferences.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/workspace_preferences.rs @@ -258,7 +258,9 @@ fn update_preferences_for_app( } write_preferences_at(&path, next) })?; - let _ = app.emit(WORKSPACE_PREFERENCES_CHANGED_EVENT, snapshot.clone()); + if let Err(error) = app.emit(WORKSPACE_PREFERENCES_CHANGED_EVENT, snapshot.clone()) { + app_log!("workspace_preferences.emit_failed detail={error}"); + } Ok(snapshot) } diff --git a/docs/project-memory/shared-memory/pitfalls.md b/docs/project-memory/shared-memory/pitfalls.md index 2a20eeb37..fb7d47f6c 100644 --- a/docs/project-memory/shared-memory/pitfalls.md +++ b/docs/project-memory/shared-memory/pitfalls.md @@ -22,6 +22,8 @@ MCP stdio 收到非法 JSON 时,JSON-RPC `-32700` 响应也要保留解析器 Direct 的 Tauri 进度、活动回合和 manifest 事件不能忽略 `app.emit` 返回值;GUI IPC 投递失败时必须写入应用诊断日志,否则用户只会看到“没有中间过程”而诊断包没有传输失败事实。 +同一边界适用于发布进度、插件状态、认证状态、工作区偏好、错误报告通知和策划 Agent 事件;所有 GUI 事件出口都要保留 emit 错误正文,不能只让业务操作继续返回成功。 + ## 2026-10-03 AGC 随包 plugins 的 feature 档位必须与消费方一致,且门禁会因 build.rs 未重跑而假通过 - **现象**:Windows 本机 `npm run check:generated-bindings`(`npm run lint` 链内,`scripts/check-repository-ci.sh` 的 Repository checks 也走它)在 `build.rs:167:29` panic:`插件随包资源校验失败:随包插件存在未声明文件:.../src-tauri/resources/plugins/agc-godot-editor/native/gdextension/bin/win-x64/agc_godot_editor.dll(目标 x86_64-pc-windows-msvc 与当前 feature 组合不允许;请先执行随包资源准备步骤)`;树上换成 `agc-unity-editor/dotnet/publish/win-x64/Agc.Unity.Attach.exe` 时报同一类错。反向还有更隐蔽的形态:门禁 2 秒就 exit 0 说「通过」,但 tree 上其实带着编辑器产物。