diff --git a/apps/ai-game-creator-shell/src/components/AppUpdateNotice.tsx b/apps/ai-game-creator-shell/src/components/AppUpdateNotice.tsx index 27ce8c6e2..2d09967e3 100644 --- a/apps/ai-game-creator-shell/src/components/AppUpdateNotice.tsx +++ b/apps/ai-game-creator-shell/src/components/AppUpdateNotice.tsx @@ -9,6 +9,7 @@ import { installAppUpdate, subscribeToAppUpdate, } from '../services/appUpdate'; +import { visibleClientErrorMessage } from '../services/errorReporting'; type DownloadState = 'idle' | 'downloading' | 'completed' | 'error'; @@ -60,7 +61,7 @@ export function AppUpdateNotice() { await installAppUpdate(setDownloadProgress); setDownloadState('completed'); } catch (error) { - setDownloadError(error instanceof Error ? error.message : String(error)); + setDownloadError(visibleClientErrorMessage(error, '下载更新失败')); setDownloadState('error'); } } diff --git a/apps/ai-game-creator-shell/src/features/app-shell/ProjectCreation.tsx b/apps/ai-game-creator-shell/src/features/app-shell/ProjectCreation.tsx index 925a01cd9..66ff41f08 100644 --- a/apps/ai-game-creator-shell/src/features/app-shell/ProjectCreation.tsx +++ b/apps/ai-game-creator-shell/src/features/app-shell/ProjectCreation.tsx @@ -19,6 +19,7 @@ import { } from 'react'; import { closeDialogOnEscape } from '../../app/dialogs'; +import { visibleClientErrorMessage } from '../../services/errorReporting'; import type { RecentProjectRow } from './model'; import type { HomeProjectCreationController } from './useHomeProjectCreation'; import type { RecentProjectsController } from './useRecentProjects'; @@ -236,7 +237,7 @@ export function ProjectsPage({ await recentProjects.refreshRecentWorkspace(renamingPath); cancelRename(); } catch (error) { - setRenameError(error instanceof Error ? error.message : '重命名项目失败'); + setRenameError(visibleClientErrorMessage(error, '重命名项目失败')); } finally { setRenameSaving(false); } diff --git a/apps/ai-game-creator-shell/src/features/app-shell/useAccountWallet.ts b/apps/ai-game-creator-shell/src/features/app-shell/useAccountWallet.ts index 1d6f0a339..5c5017ba2 100644 --- a/apps/ai-game-creator-shell/src/features/app-shell/useAccountWallet.ts +++ b/apps/ai-game-creator-shell/src/features/app-shell/useAccountWallet.ts @@ -14,6 +14,7 @@ import { getClientProfileWalletLedger, redeemClientProfileRewardCode, } from '../../services/accountHost'; +import { visibleClientErrorMessage } from '../../services/errorReporting'; import { useWalletStore } from '../../stores/useWalletStore'; export function useAccountWallet(currentUserId: string) { @@ -144,7 +145,7 @@ export function useAccountWallet(currentUserId: string) { } setWalletLedger(null); setWalletLedgerError( - error instanceof Error ? error.message : '读取泥点账单失败', + visibleClientErrorMessage(error, '读取泥点账单失败'), ); } finally { if ( @@ -202,7 +203,7 @@ export function useAccountWallet(currentUserId: string) { currentUserIdRef.current === snapshotOwnerUserId ) { setRechargeError( - error instanceof Error ? error.message : '读取泥点购买信息失败', + visibleClientErrorMessage(error, '读取泥点购买信息失败'), ); } } finally { @@ -266,7 +267,7 @@ export function useAccountWallet(currentUserId: string) { redeemLifecycleRef.current === lifecycle && currentUserIdRef.current === owner ) { - setRedeemCodeError(error instanceof Error ? error.message : '兑换失败'); + setRedeemCodeError(visibleClientErrorMessage(error, '兑换失败')); } } finally { if ( @@ -317,7 +318,7 @@ export function useAccountWallet(currentUserId: string) { rechargeLifecycleRef.current === rechargeLifecycle && currentUserIdRef.current === snapshotOwnerUserId ) { - setRechargeError(error instanceof Error ? error.message : '充值失败'); + setRechargeError(visibleClientErrorMessage(error, '充值失败')); } } finally { if ( diff --git a/apps/ai-game-creator-shell/src/features/app-shell/useHomeProjectCreation.ts b/apps/ai-game-creator-shell/src/features/app-shell/useHomeProjectCreation.ts index 92be119ec..8848f6f06 100644 --- a/apps/ai-game-creator-shell/src/features/app-shell/useHomeProjectCreation.ts +++ b/apps/ai-game-creator-shell/src/features/app-shell/useHomeProjectCreation.ts @@ -36,7 +36,10 @@ import { createClientOperation, transitionClientOperation, } from '../../services/clientOperation'; -import { appendWebviewLog } from '../../services/errorReporting'; +import { + appendWebviewLog, + visibleClientErrorMessage, +} from '../../services/errorReporting'; import type { HomeAttachmentDraft, HomeCreationType, @@ -141,7 +144,7 @@ export async function uploadLocalFilesAsAttachments( fileName: file.name, mediaType, status: 'failed', - error: error instanceof Error ? error.message : String(error), + error: visibleClientErrorMessage(error), size: file.size, }); } @@ -584,7 +587,7 @@ export function useHomeProjectCreation({ analytics, ); } catch (error) { - setStatus(error instanceof Error ? error.message : String(error)); + setStatus(visibleClientErrorMessage(error)); } finally { if (projectActionRef.current === 'creating') { projectActionRef.current = null; @@ -757,7 +760,7 @@ export function useHomeProjectCreation({ analytics, ); } catch (error) { - setStatus(error instanceof Error ? error.message : String(error)); + setStatus(visibleClientErrorMessage(error)); } finally { if (projectActionRef.current === 'opening') { projectActionRef.current = null; @@ -786,7 +789,7 @@ export function useHomeProjectCreation({ } await createProjectFromProjectPage(pendingProject.projectPath, true); } catch (error) { - setStatus(error instanceof Error ? error.message : String(error)); + setStatus(visibleClientErrorMessage(error)); } } @@ -1033,7 +1036,7 @@ export function useHomeProjectCreation({ setProjectAction(null); await openProject(selectedPath, 'open', analytics); } catch (error) { - setStatus(error instanceof Error ? error.message : String(error)); + setStatus(visibleClientErrorMessage(error)); } finally { if (projectActionRef.current === 'opening') { projectActionRef.current = null; @@ -1075,7 +1078,7 @@ export function useHomeProjectCreation({ analytics, ); } catch (error) { - setStatus(error instanceof Error ? error.message : String(error)); + setStatus(visibleClientErrorMessage(error)); } finally { if (projectActionRef.current === 'creating') { projectActionRef.current = null; diff --git a/apps/ai-game-creator-shell/src/features/app-shell/useProjectCreationDirectory.ts b/apps/ai-game-creator-shell/src/features/app-shell/useProjectCreationDirectory.ts index f7b9c2146..55e581bf9 100644 --- a/apps/ai-game-creator-shell/src/features/app-shell/useProjectCreationDirectory.ts +++ b/apps/ai-game-creator-shell/src/features/app-shell/useProjectCreationDirectory.ts @@ -1,6 +1,7 @@ import { useCallback, useEffect, useRef, useState } from 'react'; import { resolveTauriInvoke } from '../../app/tauri'; +import { visibleClientErrorMessage } from '../../services/errorReporting'; import { readWorkspacePreferences, setProjectCreationDirectory, @@ -52,9 +53,7 @@ export function useProjectCreationDirectory() { }); } catch (error) { if (!disposed) { - setProjectCreationDirectoryStatus( - error instanceof Error ? error.message : String(error), - ); + setProjectCreationDirectoryStatus(visibleClientErrorMessage(error)); } } if (disposed) { @@ -73,9 +72,7 @@ export function useProjectCreationDirectory() { } } catch (error) { if (!disposed) { - setProjectCreationDirectoryStatus( - error instanceof Error ? error.message : String(error), - ); + setProjectCreationDirectoryStatus(visibleClientErrorMessage(error)); } } }; @@ -116,9 +113,7 @@ export function useProjectCreationDirectory() { applyWorkspacePreferencesSnapshot(snapshot.projectCreationDirectory); setProjectCreationDirectoryStatus('已更新项目创建目录'); } catch (error) { - setProjectCreationDirectoryStatus( - error instanceof Error ? error.message : String(error), - ); + setProjectCreationDirectoryStatus(visibleClientErrorMessage(error)); } finally { pickInFlightRef.current = false; setProjectCreationDirectoryBusy(false); @@ -132,9 +127,7 @@ export function useProjectCreationDirectory() { setProjectCreationDirectoryStatus('已恢复默认位置'); }) .catch((error) => { - setProjectCreationDirectoryStatus( - error instanceof Error ? error.message : String(error), - ); + setProjectCreationDirectoryStatus(visibleClientErrorMessage(error)); }); }, []); diff --git a/apps/ai-game-creator-shell/src/features/app-shell/useRecentProjects.ts b/apps/ai-game-creator-shell/src/features/app-shell/useRecentProjects.ts index 5f905aa68..d2dfb6e6a 100644 --- a/apps/ai-game-creator-shell/src/features/app-shell/useRecentProjects.ts +++ b/apps/ai-game-creator-shell/src/features/app-shell/useRecentProjects.ts @@ -9,6 +9,7 @@ import { import { resolveTauriInvoke } from '../../app/tauri'; import type { LocalProjectDirectoryStatus, TauriInvoke } from '../../app/types'; +import { visibleClientErrorMessage } from '../../services/errorReporting'; import { isAbsoluteProjectPath, projectPathHasControlCharacter, @@ -158,9 +159,7 @@ export function useRecentProjects(setStatus: Dispatch>) { }); } catch (error) { if (!disposed) { - setStatusRef.current( - error instanceof Error ? error.message : String(error), - ); + setStatusRef.current(visibleClientErrorMessage(error)); } } if (disposed) { @@ -179,9 +178,7 @@ export function useRecentProjects(setStatus: Dispatch>) { } } catch (error) { if (!disposed) { - setStatusRef.current( - error instanceof Error ? error.message : String(error), - ); + setStatusRef.current(visibleClientErrorMessage(error)); } } }; @@ -304,9 +301,7 @@ export function useRecentProjects(setStatus: Dispatch>) { } }) .catch((error) => { - setStatusRef.current( - error instanceof Error ? error.message : String(error), - ); + setStatusRef.current(visibleClientErrorMessage(error)); }); } @@ -355,9 +350,7 @@ export function useRecentProjects(setStatus: Dispatch>) { }); }) .catch((error) => { - setStatusRef.current( - error instanceof Error ? error.message : String(error), - ); + setStatusRef.current(visibleClientErrorMessage(error)); }); } @@ -382,7 +375,7 @@ export function useRecentProjects(setStatus: Dispatch>) { }); setStatus('已打开项目目录'); } catch (error) { - setStatus(error instanceof Error ? error.message : String(error)); + setStatus(visibleClientErrorMessage(error)); } } diff --git a/apps/ai-game-creator-shell/src/features/project-workspace/ConversationModelSelect.tsx b/apps/ai-game-creator-shell/src/features/project-workspace/ConversationModelSelect.tsx index 2bc9df75c..da8c8fc2f 100644 --- a/apps/ai-game-creator-shell/src/features/project-workspace/ConversationModelSelect.tsx +++ b/apps/ai-game-creator-shell/src/features/project-workspace/ConversationModelSelect.tsx @@ -10,6 +10,7 @@ import { import { resolveTauriInvoke } from '../../app/tauri'; import type { GameCreatorAppConfigView } from '../../app/types'; +import { visibleClientErrorMessage } from '../../services/errorReporting'; import { cachedLlmModelCatalog, type ClientLlmModel, @@ -48,8 +49,10 @@ class ModelSelectionConfigError extends Error {} * 渲染层错误类型,也不把服务端原文(可能含内部地址)直接铺给用户。 */ function modelCatalogErrorMessage(error: unknown) { - if (error instanceof LlmModelCatalogConfigError) return error.message; - const message = error instanceof Error ? error.message : String(error ?? ''); + if (error instanceof LlmModelCatalogConfigError) { + return visibleClientErrorMessage(error); + } + const message = visibleClientErrorMessage(error, '模型列表加载失败'); if (message.includes('authentication-required')) { return '模型列表加载失败:登录已失效,请重新登录'; } diff --git a/apps/ai-game-creator-shell/src/features/project-workspace/importDesignFiles.ts b/apps/ai-game-creator-shell/src/features/project-workspace/importDesignFiles.ts index f8c4bf9f8..f912c5682 100644 --- a/apps/ai-game-creator-shell/src/features/project-workspace/importDesignFiles.ts +++ b/apps/ai-game-creator-shell/src/features/project-workspace/importDesignFiles.ts @@ -1,4 +1,5 @@ import type { TauriInvoke } from '../../app/types'; +import { visibleClientErrorMessage } from '../../services/errorReporting'; /** 策划附件只写工作区;返回界面提示,不生成回合附件或资源清单。 */ export async function importDesignFiles( @@ -18,9 +19,7 @@ export async function importDesignFiles( }); imported += 1; } catch (error) { - failures.push( - `${file.name}:${error instanceof Error ? error.message : String(error)}`, - ); + failures.push(`${file.name}:${visibleClientErrorMessage(error)}`); } } const summary = `已导入 ${imported} 个文件到策划工作区`; diff --git a/apps/ai-game-creator-shell/src/features/template-library/useTemplateLibrary.ts b/apps/ai-game-creator-shell/src/features/template-library/useTemplateLibrary.ts index fab31d47a..47d817c42 100644 --- a/apps/ai-game-creator-shell/src/features/template-library/useTemplateLibrary.ts +++ b/apps/ai-game-creator-shell/src/features/template-library/useTemplateLibrary.ts @@ -14,6 +14,7 @@ import { beginProjectOpenAnalytics, type ProjectOpenAnalytics, } from '../../services/clientAnalytics'; +import { visibleClientErrorMessage } from '../../services/errorReporting'; import { currentPlatformSessionGeneration, subscribePlatformSessionGeneration, @@ -45,7 +46,7 @@ type UseTemplateLibraryOptions = { }; function errorMessage(error: unknown): string { - return error instanceof Error ? error.message : String(error); + return visibleClientErrorMessage(error); } export function useTemplateLibrary({ 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 699dc0588..3f99aa3b6 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 @@ -281,7 +281,7 @@ import { } from '../../features/resource-canvas/resourceVersionReplacementTransport'; import { useResourceCanvasGenerationPlaceholders } from '../../features/resource-canvas/useResourceCanvasGenerationPlaceholders'; import { createUiDesignDocFromImages } from '../../features/ui-editor/uiDesignResourceBridge'; -import { normalizeDiagnosticText } from '../../services/errorReporting'; +import { visibleClientErrorMessage } from '../../services/errorReporting'; import { currentPlatformSessionGeneration, requestPlatformSessionRefresh, @@ -521,12 +521,7 @@ function projectDevelopmentErrorMessage( error: unknown, fallback = '未提供具体错误正文', ) { - const raw = error instanceof Error ? error.message : String(error ?? ''); - const safe = normalizeDiagnosticText(raw.replace(/\s+/gu, ' ').trim()).slice( - 0, - 400, - ); - return safe || fallback; + return visibleClientErrorMessage(error, fallback); } function isPlatformAuthenticationRequired(error: unknown) {