diff --git a/desktop/src/App.tsx b/desktop/src/App.tsx
index f13ef1b..be29be0 100644
--- a/desktop/src/App.tsx
+++ b/desktop/src/App.tsx
@@ -3,6 +3,7 @@ import './index.css';
import { Sidebar } from './components/Sidebar';
import { ChatArea } from './components/ChatArea';
import { RightPanel } from './components/RightPanel';
+import { ErrorBoundary } from './components/ui/ErrorBoundary';
import { SettingsLayout } from './components/Settings/SettingsLayout';
import { AgentOnboardingWizard } from './components/AgentOnboardingWizard';
import { HandApprovalModal } from './components/HandApprovalModal';
@@ -458,7 +459,9 @@ function App() {
{/* 主聊天区域 */}
- setShowDetailDrawer(true)} />
+ 聊天区域加载失败
}>
+ setShowDetailDrawer(true)} />
+
{/* 详情抽屉 - 简洁模式仅 状态/Agent/管家 */}
@@ -467,7 +470,9 @@ function App() {
onClose={() => setShowDetailDrawer(false)}
title="详情"
>
-
+ 详情面板加载失败}>
+
+
{/* Hand Approval Modal (global) */}
@@ -502,7 +507,9 @@ function App() {
/>
{/* 聊天区域 */}
-
+ 聊天区域加载失败,请刷新页面}>
+
+
{/* 详情抽屉 - 按需显示 */}
@@ -511,7 +518,9 @@ function App() {
onClose={() => setShowDetailDrawer(false)}
title="详情"
>
-
+ 详情面板加载失败}>
+
+
{/* Hand Approval Modal (global) */}
diff --git a/desktop/src/components/SaaS/SaaSStatus.tsx b/desktop/src/components/SaaS/SaaSStatus.tsx
index d17d51b..8e94611 100644
--- a/desktop/src/components/SaaS/SaaSStatus.tsx
+++ b/desktop/src/components/SaaS/SaaSStatus.tsx
@@ -49,7 +49,8 @@ export function SaaSStatus({ isLoggedIn, account, saasUrl, onLogout, onLogin }:
signal: AbortSignal.timeout(5000),
});
setHealthOk(response.ok);
- } catch {
+ } catch (e) {
+ console.warn('[SaaSStatus] Health check failed:', e);
setHealthOk(false);
} finally {
setCheckingHealth(false);
diff --git a/desktop/src/components/SaaS/TOTPSettings.tsx b/desktop/src/components/SaaS/TOTPSettings.tsx
index 4489048..4ba947b 100644
--- a/desktop/src/components/SaaS/TOTPSettings.tsx
+++ b/desktop/src/components/SaaS/TOTPSettings.tsx
@@ -30,7 +30,8 @@ export function TOTPSettings() {
setVerifyCode('');
try {
await setupTotp();
- } catch {
+ } catch (e) {
+ console.warn('[TOTP] Setup failed:', e);
// error already in store
}
};
@@ -43,7 +44,8 @@ export function TOTPSettings() {
await verifyTotp(verifyCode);
setVerifyCode('');
setSuccess('TOTP 已成功启用');
- } catch {
+ } catch (e) {
+ console.warn('[TOTP] Enable failed:', e);
// error already in store
}
};
@@ -60,7 +62,8 @@ export function TOTPSettings() {
setDisablePassword('');
setShowDisable(false);
setSuccess('TOTP 已成功禁用');
- } catch {
+ } catch (e) {
+ console.warn('[TOTP] Disable failed:', e);
// error already in store
}
};
diff --git a/desktop/src/components/Settings/MCPServices.tsx b/desktop/src/components/Settings/MCPServices.tsx
index 9a01fc5..e8837a4 100644
--- a/desktop/src/components/Settings/MCPServices.tsx
+++ b/desktop/src/components/Settings/MCPServices.tsx
@@ -25,7 +25,8 @@ export function MCPServices() {
try {
const running = await listMcpServices();
setRunningServices(running);
- } catch {
+ } catch (e) {
+ console.warn('[MCPServices] Failed to list services:', e);
// MCP might not be available yet
setRunningServices([]);
}
diff --git a/desktop/src/components/Settings/ModelsAPI.tsx b/desktop/src/components/Settings/ModelsAPI.tsx
index e34ec8b..2d5bdf6 100644
--- a/desktop/src/components/Settings/ModelsAPI.tsx
+++ b/desktop/src/components/Settings/ModelsAPI.tsx
@@ -80,8 +80,8 @@ function loadEmbeddingConfigBase(): Omit & { apiKey:
const parsed = JSON.parse(stored);
return { ...parsed, apiKey: '' };
}
- } catch {
- // ignore
+ } catch (e) {
+ console.warn('[ModelsAPI] Failed to load embedding config:', e);
}
return {
provider: 'local',
@@ -99,8 +99,8 @@ function loadEmbeddingConfigBase(): Omit & { apiKey:
function saveEmbeddingConfigBase(config: Omit): void {
try {
localStorage.setItem(EMBEDDING_STORAGE_KEY, JSON.stringify(config));
- } catch {
- // ignore
+ } catch (e) {
+ console.warn('[ModelsAPI] Failed to save embedding config:', e);
}
}
@@ -129,8 +129,8 @@ function loadCustomModelsBase(): CustomModel[] {
if (stored) {
return JSON.parse(stored);
}
- } catch {
- // ignore
+ } catch (e) {
+ console.warn('[ModelsAPI] Failed to load model config:', e);
}
return [];
}
@@ -143,8 +143,8 @@ function saveCustomModelsBase(models: CustomModel[]): void {
return rest;
});
localStorage.setItem(STORAGE_KEY, JSON.stringify(sanitized));
- } catch {
- // ignore
+ } catch (e) {
+ console.warn('[ModelsAPI] Failed to save model config:', e);
}
}
diff --git a/desktop/src/components/Settings/SettingsLayout.tsx b/desktop/src/components/Settings/SettingsLayout.tsx
index 96af5ab..f47c242 100644
--- a/desktop/src/components/Settings/SettingsLayout.tsx
+++ b/desktop/src/components/Settings/SettingsLayout.tsx
@@ -149,7 +149,14 @@ export function SettingsLayout({ onBack }: SettingsLayoutProps) {
);
- case 'audit': return ;
+ case 'audit': return (
+ 审计日志加载失败}
+ onError={(err, info) => console.error('[Settings] Audit page error:', err, info.componentStack)}
+ >
+
+
+ );
case 'tasks': return (
定时任务
@@ -159,11 +166,23 @@ export function SettingsLayout({ onBack }: SettingsLayoutProps) {
);
case 'heartbeat': return (
-
-
-
+ 心跳配置加载失败}
+ onError={(err, info) => console.error('[Settings] Heartbeat page error:', err, info.componentStack)}
+ >
+
+
+
+
+ );
+ case 'viking': return (
+ 语义记忆加载失败}
+ onError={(err, info) => console.error('[Settings] Viking page error:', err, info.componentStack)}
+ >
+
+
);
- case 'viking': return ;
case 'feedback': return ;
case 'about': return ;
default: return ;
diff --git a/desktop/src/components/VikingPanel.tsx b/desktop/src/components/VikingPanel.tsx
index f44b748..3286d2e 100644
--- a/desktop/src/components/VikingPanel.tsx
+++ b/desktop/src/components/VikingPanel.tsx
@@ -50,7 +50,8 @@ export function VikingPanel() {
try {
const resources = await listVikingResources('');
setMemoryCount(resources.length);
- } catch {
+ } catch (e) {
+ console.warn('[VikingPanel] Failed to list resources:', e);
setMemoryCount(null);
}
}
@@ -99,7 +100,8 @@ export function VikingPanel() {
try {
const fullContent = await readVikingResource(uri, 'L2');
setExpandedContent(fullContent);
- } catch {
+ } catch (e) {
+ console.warn('[VikingPanel] Failed to read resource:', e);
setExpandedContent(null);
} finally {
setIsLoadingL2(false);