feat: MetonaAI Desktop 初始项目
- Electron + React + TypeScript 架构 - 三栏布局: Sidebar | ChatPanel | DetailPanel - 9 个内置工具 (文件系统/网络/记忆/命令) - SQLite 持久化 (better-sqlite3) - MUI 暗色/亮色主题系统 - Agent Loop ReAct 状态机引擎 - DeepSeek / Agnes AI / Ollama Provider 适配器 - MCP 协议集成 - 系统托盘 + 全局快捷键 - Tailwind CSS v4 + Tailwind Merge - 修复: Sidebar 缺失 TextField 导入导致黑屏
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Health Checker — 健康检查器
|
||||
*
|
||||
* @see docs/生产级通用 AI Agent 智能体桌面应用:完整设计与构建指南.html — 第十一章
|
||||
*/
|
||||
|
||||
import { existsSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import { app } from 'electron';
|
||||
|
||||
export interface HealthReport {
|
||||
healthy: boolean;
|
||||
checks: HealthCheck[];
|
||||
timestamp: Date;
|
||||
}
|
||||
|
||||
export interface HealthCheck {
|
||||
name: string;
|
||||
healthy: boolean;
|
||||
latencyMs?: number;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export class HealthChecker {
|
||||
constructor(private dbPath?: string) {}
|
||||
|
||||
async check(): Promise<HealthReport> {
|
||||
const checks: HealthCheck[] = [];
|
||||
checks.push(await this.checkDatabase());
|
||||
checks.push(await this.checkDiskSpace());
|
||||
checks.push(await this.checkMemoryUsage());
|
||||
const allHealthy = checks.every((c) => c.healthy);
|
||||
return { healthy: allHealthy, checks, timestamp: new Date() };
|
||||
}
|
||||
|
||||
private async checkDatabase(): Promise<HealthCheck> {
|
||||
const start = Date.now();
|
||||
try {
|
||||
if (this.dbPath && existsSync(this.dbPath)) {
|
||||
return { name: 'database', healthy: true, latencyMs: Date.now() - start };
|
||||
}
|
||||
return { name: 'database', healthy: false, error: 'Database file not found' };
|
||||
} catch (error) {
|
||||
return { name: 'database', healthy: false, error: (error instanceof Error ? error.message : String(error)) };
|
||||
}
|
||||
}
|
||||
|
||||
private async checkDiskSpace(): Promise<HealthCheck> {
|
||||
try {
|
||||
const userDataPath = app.getPath('userData');
|
||||
// 简单检查:userData 目录是否存在且可写
|
||||
if (existsSync(userDataPath)) {
|
||||
return { name: 'disk_space', healthy: true };
|
||||
}
|
||||
return { name: 'disk_space', healthy: false, error: 'User data path not accessible' };
|
||||
} catch (error) {
|
||||
return { name: 'disk_space', healthy: false, error: (error instanceof Error ? error.message : String(error)) };
|
||||
}
|
||||
}
|
||||
|
||||
private async checkMemoryUsage(): Promise<HealthCheck> {
|
||||
const used = process.memoryUsage();
|
||||
const heapUsedMB = used.heapUsed / 1024 / 1024;
|
||||
const thresholdMB = 512;
|
||||
return {
|
||||
name: 'memory_usage',
|
||||
healthy: heapUsedMB < thresholdMB,
|
||||
...(heapUsedMB >= thresholdMB ? { error: `Heap usage ${heapUsedMB.toFixed(0)}MB exceeds threshold ${thresholdMB}MB` } : {}),
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user