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:
@@ -405,6 +405,44 @@ export function registerAllIPCHandlers(
|
||||
log.info(`[CONFIG] LLM config changed (${key}), adapter reloaded`);
|
||||
}
|
||||
|
||||
// Agent 配置变更时热更新 Engine
|
||||
if (key === 'agent.maxIterations') {
|
||||
agentLoop.updateConfig({ maxIterations: value as number });
|
||||
log.info(`[CONFIG] Agent maxIterations updated to ${value}`);
|
||||
} else if (key === 'agent.totalTimeoutMs') {
|
||||
agentLoop.updateConfig({ totalTimeoutMs: value as number });
|
||||
log.info(`[CONFIG] Agent totalTimeoutMs updated to ${value}`);
|
||||
} else if (key === 'agent.enableThinking') {
|
||||
agentLoop.updateConfig({ thinkingEnabled: value as boolean });
|
||||
log.info(`[CONFIG] Agent thinkingEnabled updated to ${value}`);
|
||||
} else if (key === 'agent.thinkingEffort') {
|
||||
agentLoop.updateConfig({ thinkingEffort: value as 'low' | 'medium' | 'high' | 'max' });
|
||||
log.info(`[CONFIG] Agent thinkingEffort updated to ${value}`);
|
||||
} else if (key === 'ollama.numCtx') {
|
||||
// numCtx 同时更新 Engine 的 contextLength
|
||||
agentLoop.updateConfig({ contextLength: (value as number) || undefined });
|
||||
log.info(`[CONFIG] Agent contextLength updated to ${value}`);
|
||||
}
|
||||
|
||||
// 日志级别变更时即时应用
|
||||
if (key === 'logging.level') {
|
||||
const level = value as 'error' | 'warn' | 'info' | 'debug' | 'verbose' | 'silly';
|
||||
log.transports.file.level = level;
|
||||
log.transports.console.level = level;
|
||||
log.info(`[CONFIG] Log level updated to ${level}`);
|
||||
}
|
||||
|
||||
// 工作空间路径变更时写入独立文件(下次启动生效)
|
||||
if (key === 'workspace.path') {
|
||||
try {
|
||||
const { writeWorkspacePathToFile } = await import('../main');
|
||||
if (value) writeWorkspacePathToFile(value as string);
|
||||
log.info(`[CONFIG] Workspace path saved (restart required): ${value}`);
|
||||
} catch (err) {
|
||||
log.error('[CONFIG] Failed to save workspace path:', err);
|
||||
}
|
||||
}
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
|
||||
@@ -439,18 +477,23 @@ export function registerAllIPCHandlers(
|
||||
// ===== 工具管理 =====
|
||||
|
||||
ipcMain.handle('tools:list', async () => {
|
||||
return toolRegistry.listTools().map((t) => ({
|
||||
return toolRegistry.listAllTools().map((t) => ({
|
||||
name: t.name,
|
||||
description: t.description,
|
||||
category: t.category,
|
||||
riskLevel: t.riskLevel,
|
||||
requiresPermission: t.requiresPermission,
|
||||
enabled: t.enabled,
|
||||
}));
|
||||
});
|
||||
|
||||
ipcMain.handle('tools:toggle', async (_event, toolName: string, enabled: boolean) => {
|
||||
// 工具开关通过配置持久化
|
||||
configService.set(`tools.${toolName}.enabled`, enabled);
|
||||
// 同步到 ToolRegistry(立即生效)
|
||||
toolRegistry.setToolEnabled(toolName, enabled);
|
||||
// 同步到 AgentLoop 的工具列表
|
||||
agentLoop.setTools(toolRegistry.listTools());
|
||||
log.info(`Tool ${toolName} ${enabled ? 'enabled' : 'disabled'}`);
|
||||
return { success: true };
|
||||
});
|
||||
@@ -528,5 +571,41 @@ export function registerAllIPCHandlers(
|
||||
}
|
||||
});
|
||||
|
||||
// ===== SearXNG =====
|
||||
|
||||
ipcMain.handle('searxng:testConnection', async (_event, url: string, authKey: string, authType: string) => {
|
||||
try {
|
||||
if (!url || !/^https?:\/\//.test(url)) {
|
||||
return { success: false, error: 'URL 需以 http:// 或 https:// 开头' };
|
||||
}
|
||||
|
||||
const startTime = Date.now();
|
||||
const headers: Record<string, string> = {};
|
||||
|
||||
if (authKey) {
|
||||
if (authType === 'bearer') {
|
||||
headers['Authorization'] = `Bearer ${authKey}`;
|
||||
} else if (authType === 'basic') {
|
||||
headers['Authorization'] = `Basic ${Buffer.from(authKey).toString('base64')}`;
|
||||
}
|
||||
}
|
||||
|
||||
const testUrl = `${url.replace(/\/$/, '')}/search?q=test&format=json&pageno=1`;
|
||||
const response = await fetch(testUrl, {
|
||||
headers,
|
||||
signal: AbortSignal.timeout(10_000),
|
||||
});
|
||||
|
||||
const latencyMs = Date.now() - startTime;
|
||||
|
||||
if (response.ok) {
|
||||
return { success: true, statusCode: response.status, latencyMs };
|
||||
}
|
||||
return { success: false, statusCode: response.status, latencyMs, error: `HTTP ${response.status} ${response.statusText}` };
|
||||
} catch (error) {
|
||||
return { success: false, error: (error as Error).message };
|
||||
}
|
||||
});
|
||||
|
||||
log.info('[SYS] All IPC handlers registered');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user