feat: MEMORY.md 访问保护、格式简化及预存问题修复
MEMORY.md 保护: 新建 file-guard.ts 共享守卫模块; read_file/write_file/search_files/run_command 禁止访问根目录 MEMORY.md; permissions.ts 增加 deniedPatterns 深度防御。格式简化: 元数据从 # 注释改为 > 引用语法; 校验规则从 6 条简化为 3 条; context-builder extractContent 适配。预存问题: 修复路径遍历前缀碰撞漏洞; 移除 browser_extract 内容截断; SearXNG 配置实时读取; web_search/web_fetch 移除截断; 侧边栏动态获取工具列表; 版本号 0.1.1
This commit is contained in:
+64
-5
@@ -16,6 +16,7 @@
|
||||
|
||||
import { app, shell, Menu } from 'electron';
|
||||
import { join } from 'path';
|
||||
import { existsSync, readFileSync, writeFileSync } from 'fs';
|
||||
import { electronApp, optimizer } from '@electron-toolkit/utils';
|
||||
import log from 'electron-log';
|
||||
import { DatabaseService } from './services/database.service';
|
||||
@@ -37,9 +38,10 @@ import { AgnesAdapter } from './harness/adapters/agnes-ai.adapter';
|
||||
import { OllamaAdapter } from './harness/adapters/ollama.adapter';
|
||||
import {
|
||||
ReadFileTool, WriteFileTool, ListDirectoryTool, SearchFilesTool,
|
||||
WebSearchTool, WebExtractTool,
|
||||
WebSearchTool, WebFetchTool,
|
||||
MemoryStoreTool, MemorySearchTool,
|
||||
RunCommandTool,
|
||||
browserTools, cleanupBrowser,
|
||||
} from './harness/tools/built-in';
|
||||
import { AuditLogHook, MemoryTriggerHook, PermissionCheckHook, RateLimitHook } from './harness/hooks';
|
||||
import { PolicyEngine } from './harness/sandbox/permissions';
|
||||
@@ -52,6 +54,31 @@ import { UpdateService } from './services/update.service';
|
||||
log.transports.file.level = 'info';
|
||||
log.transports.console.level = 'debug';
|
||||
|
||||
// ===== 工作空间路径独立存储(解决 DB 在 workspace 内的鸡生蛋问题)=====
|
||||
const WORKSPACE_CONFIG_FILE = join(app.getPath('userData'), 'workspace-config.json');
|
||||
|
||||
function readWorkspacePathFromFile(): string | null {
|
||||
try {
|
||||
if (existsSync(WORKSPACE_CONFIG_FILE)) {
|
||||
const data = JSON.parse(readFileSync(WORKSPACE_CONFIG_FILE, 'utf-8'));
|
||||
return data.workspacePath ?? null;
|
||||
}
|
||||
} catch {
|
||||
// 忽略读取错误
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function writeWorkspacePathToFile(workspacePath: string): void {
|
||||
try {
|
||||
writeFileSync(WORKSPACE_CONFIG_FILE, JSON.stringify({ workspacePath }, null, 2), 'utf-8');
|
||||
} catch (err) {
|
||||
log.error('Failed to write workspace config file:', err);
|
||||
}
|
||||
}
|
||||
|
||||
export { readWorkspacePathFromFile, writeWorkspacePathToFile };
|
||||
|
||||
let databaseService: DatabaseService | null = null;
|
||||
let trayManager: TrayManager | null = null;
|
||||
let windowManager: WindowManager | null = null;
|
||||
@@ -67,9 +94,14 @@ async function initialize(): Promise<void> {
|
||||
optimizer.watchWindowShortcuts(window);
|
||||
});
|
||||
|
||||
// ===== 步骤 2: 工作空间 =====
|
||||
const workspaceService = new WorkspaceService();
|
||||
// ===== 步骤 2: 工作空间(优先从独立配置文件读取路径)=====
|
||||
const savedWorkspacePath = readWorkspacePathFromFile();
|
||||
const workspaceService = new WorkspaceService(savedWorkspacePath ?? undefined);
|
||||
const workspaceInfo = workspaceService.initialize();
|
||||
// 持久化工作空间路径(供下次启动读取)
|
||||
if (savedWorkspacePath !== workspaceInfo.path) {
|
||||
writeWorkspacePathToFile(workspaceInfo.path);
|
||||
}
|
||||
log.info(`Workspace: ${workspaceInfo.path} (missing: ${workspaceInfo.missingFiles.join(', ') || 'none'})`);
|
||||
|
||||
// ===== 步骤 3: SQLite =====
|
||||
@@ -122,11 +154,16 @@ async function initialize(): Promise<void> {
|
||||
toolRegistry.registerBuiltin(new WriteFileTool());
|
||||
toolRegistry.registerBuiltin(new ListDirectoryTool());
|
||||
toolRegistry.registerBuiltin(new SearchFilesTool());
|
||||
toolRegistry.registerBuiltin(new WebSearchTool());
|
||||
toolRegistry.registerBuiltin(new WebExtractTool());
|
||||
toolRegistry.registerBuiltin(new WebSearchTool(configService));
|
||||
toolRegistry.registerBuiltin(new WebFetchTool());
|
||||
toolRegistry.registerBuiltin(new MemoryStoreTool(memoryManager));
|
||||
toolRegistry.registerBuiltin(new MemorySearchTool(memoryManager));
|
||||
toolRegistry.registerBuiltin(new RunCommandTool());
|
||||
|
||||
// 注册 9 个 Browser 浏览器工具
|
||||
for (const tool of browserTools) {
|
||||
toolRegistry.registerBuiltin(tool);
|
||||
}
|
||||
log.info(`Registered ${toolRegistry.size} built-in tools`);
|
||||
|
||||
// ===== MCP Manager =====
|
||||
@@ -159,11 +196,15 @@ async function initialize(): Promise<void> {
|
||||
const ollamaNumCtx = configService.get<number>('ollama.numCtx');
|
||||
const agentMaxIter = configService.get<number>('agent.maxIterations');
|
||||
const agentTimeout = configService.get<number>('agent.totalTimeoutMs');
|
||||
const agentThinkingEnabled = configService.get<boolean>('agent.enableThinking');
|
||||
const agentThinkingEffort = configService.get<string>('agent.thinkingEffort') as 'low' | 'medium' | 'high' | 'max' | null;
|
||||
const agentLoop = new AgentLoopEngine(
|
||||
{
|
||||
maxIterations: agentMaxIter ?? 20,
|
||||
totalTimeoutMs: agentTimeout ?? 600_000,
|
||||
contextLength: ollamaNumCtx ?? undefined,
|
||||
thinkingEnabled: agentThinkingEnabled ?? true,
|
||||
thinkingEffort: agentThinkingEffort ?? 'high',
|
||||
},
|
||||
adapter, toolRegistry, preToolHooks, postToolHooks,
|
||||
);
|
||||
@@ -245,9 +286,27 @@ async function initialize(): Promise<void> {
|
||||
trayManager?.destroy();
|
||||
windowManager?.closeAll();
|
||||
try { await mcpManager.shutdown(); } catch (err) { log.error('[Shutdown] MCP shutdown failed:', err); }
|
||||
cleanupBrowser();
|
||||
if (databaseService) { databaseService.close(); databaseService = null; }
|
||||
});
|
||||
|
||||
// ===== 应用日志级别配置 =====
|
||||
const logLevel = configService.get<string>('logging.level') as 'error' | 'warn' | 'info' | 'debug' | 'verbose' | 'silly' | null;
|
||||
if (logLevel) {
|
||||
log.transports.file.level = logLevel;
|
||||
log.transports.console.level = logLevel;
|
||||
log.info(`Log level applied: ${logLevel}`);
|
||||
}
|
||||
|
||||
// ===== 恢复工具启用/禁用状态 =====
|
||||
for (const toolDef of toolRegistry.listAllTools()) {
|
||||
const stored = configService.get<boolean>(`tools.${toolDef.name}.enabled`);
|
||||
if (stored === false) {
|
||||
toolRegistry.setToolEnabled(toolDef.name, false);
|
||||
log.info(`Tool restored as disabled: ${toolDef.name}`);
|
||||
}
|
||||
}
|
||||
|
||||
log.info(`MetonaAI Desktop initialized [Provider: ${configService.get<string>('llm.provider') ?? 'none'}, Model: ${configService.get<string>('llm.model') ?? 'none'}, Tools: ${toolRegistry.size}]`);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user