foliko 1.1.73 → 1.1.76

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/.claude/settings.local.json +5 -1
  2. package/.dockerignore +45 -45
  3. package/.env.example +56 -56
  4. package/cli/src/ui/chat-ui.js +56 -126
  5. package/cli/src/ui/components/agent-mention-provider.js +175 -0
  6. package/cli/src/ui/components/chained-autocomplete-provider.js +64 -0
  7. package/cli/src/ui/{footer-bar.js → components/footer-bar.js} +2 -2
  8. package/docker-compose.yml +33 -33
  9. package/docs/features.md +120 -120
  10. package/docs/quick-reference.md +160 -160
  11. package/package.json +1 -1
  12. package/plugins/ai-plugin.js +3 -3
  13. package/plugins/ambient-agent/ExplorerLoop.js +17 -17
  14. package/plugins/ambient-agent/index.js +2 -2
  15. package/plugins/data-splitter-plugin.js +9 -9
  16. package/plugins/default-plugins.js +7 -8
  17. package/plugins/extension-executor-plugin.js +2 -2
  18. package/plugins/feishu-plugin.js +5 -5
  19. package/plugins/install-plugin.js +4 -4
  20. package/plugins/memory-plugin.js +1 -1
  21. package/plugins/plugin-manager-plugin.js +9 -8
  22. package/plugins/python-plugin-loader.js +2 -2
  23. package/plugins/qq-plugin.js +4 -4
  24. package/plugins/rules-plugin.js +2 -2
  25. package/plugins/scheduler-plugin.js +13 -13
  26. package/plugins/session-plugin.js +2 -2
  27. package/plugins/subagent-plugin.js +1 -1
  28. package/plugins/telegram-plugin.js +6 -6
  29. package/plugins/think-plugin.js +4 -4
  30. package/plugins/tools-plugin.js +1 -1
  31. package/plugins/web-plugin.js +16 -16
  32. package/skills/find-skills/SKILL.md +133 -133
  33. package/skills/foliko-dev/AGENTS.md +236 -236
  34. package/skills/mcp-usage/SKILL.md +200 -200
  35. package/skills/subagent-guide/SKILL.md +237 -237
  36. package/skills/workflow-guide/SKILL.md +646 -646
  37. package/src/capabilities/skill-manager.js +6 -5
  38. package/src/capabilities/workflow-engine.js +5 -5
  39. package/src/core/agent-chat.js +8 -8
  40. package/src/core/agent.js +80 -5
  41. package/src/core/branch-summary-auto.js +4 -4
  42. package/src/core/chat-session.js +1 -0
  43. package/src/core/session-entry.js +14 -6
  44. package/src/core/session-manager.js +15 -3
  45. package/src/executors/mcp-executor.js +21 -25
  46. package/src/utils/data-splitter.js +3 -3
  47. package/src/utils/message-validator.js +1 -1
  48. package/website_v2/styles/animations.css +7 -7
  49. package/.cli_default_systemPrompt.md +0 -242
  50. /package/cli/src/ui/{message-bubble.js → components/message-bubble.js} +0 -0
  51. /package/cli/src/ui/{status-bar.js → components/status-bar.js} +0 -0
@@ -247,6 +247,7 @@ class Skill {
247
247
  sessionId: framework?._currentSessionId || 'unknown',
248
248
  agent: null,
249
249
  framework: framework,
250
+ cwd: process.cwd(), // 工作目录,用于路径解析
250
251
  };
251
252
  // 支持 argumentParser 先解析参数
252
253
  let parsedArgs = toolArgs.args || '';
@@ -267,7 +268,7 @@ class Skill {
267
268
  }
268
269
 
269
270
  if (this._commands.length > 0) {
270
- log.info(`[${skillName}] Registered ${this._commands.length} commands: ${this._commands.join(', ')}`);
271
+ // log.info(`[${skillName}] Registered ${this._commands.length} commands: ${this._commands.join(', ')}`);
271
272
  }
272
273
  } catch (err) {
273
274
  log.warn(`Failed to load commands from ${indexPath}:`, err.message);
@@ -558,7 +559,7 @@ class SkillManagerPlugin extends Plugin {
558
559
  // 2. 扫描插件目录下的 SKILL.md
559
560
  this._loadSkillsFromPlugins();
560
561
 
561
- log.info(` Loaded ${this._skills.size} skills`);
562
+ // log.info(` Loaded ${this._skills.size} skills`);
562
563
  this._loaded = true;
563
564
  }
564
565
 
@@ -603,7 +604,7 @@ class SkillManagerPlugin extends Plugin {
603
604
 
604
605
  try {
605
606
  this._loadSkillFromFile(skillName, skillMdPath, pluginDir);
606
- log.info(` Loaded skill from plugin '${pluginName}': ${skillName}`);
607
+ // log.info(` Loaded skill from plugin '${pluginName}': ${skillName}`);
607
608
  } catch (err) {
608
609
  log.warn(` Failed to load skill from plugin '${pluginName}':`, err.message);
609
610
  }
@@ -748,7 +749,7 @@ class SkillManagerPlugin extends Plugin {
748
749
 
749
750
  const refsInfo = references.size > 0 ? `, ${references.size} refs` : '';
750
751
  const scriptsInfo = scripts.size > 0 ? `, ${scripts.size} scripts` : '';
751
- //log.info(` Loaded skill: ${name}${refsInfo}${scriptsInfo}`)
752
+ //// log.info(` Loaded skill: ${name}${refsInfo}${scriptsInfo}`)
752
753
  }
753
754
 
754
755
  /**
@@ -921,7 +922,7 @@ class SkillManagerPlugin extends Plugin {
921
922
  }
922
923
 
923
924
  reload(framework) {
924
- log.info(' Reloading...');
925
+ // log.info(' Reloading...');
925
926
  this._skills.clear();
926
927
  this._loaded = false;
927
928
  this._framework = framework;
@@ -884,7 +884,7 @@ class WorkflowPlugin extends Plugin {
884
884
  const dir = path.resolve(process.cwd(), this._workflowsDir);
885
885
  if (!fs.existsSync(dir)) {
886
886
  fs.mkdirSync(dir, { recursive: true });
887
- log.info(` Created workflows directory: ${dir}`);
887
+ // log.info(` Created workflows directory: ${dir}`);
888
888
  return;
889
889
  }
890
890
  try {
@@ -911,7 +911,7 @@ class WorkflowPlugin extends Plugin {
911
911
  }
912
912
  if (workflowDef && workflowDef.steps) {
913
913
  this._workflows.set(workflowName, workflowDef);
914
- //log.info(` Loaded: ${workflowName}`)
914
+ //// log.info(` Loaded: ${workflowName}`)
915
915
  }
916
916
  } catch (err) {
917
917
  log.error(` Failed to load ${file}:`, err.message);
@@ -946,7 +946,7 @@ class WorkflowPlugin extends Plugin {
946
946
  },
947
947
  });
948
948
  this._workflowTools.set(name, toolName);
949
- log.info(` Registered tool: ${toolName}`);
949
+ // log.info(` Registered tool: ${toolName}`);
950
950
  }
951
951
  }
952
952
  /**
@@ -958,7 +958,7 @@ class WorkflowPlugin extends Plugin {
958
958
  if (require.cache[modulePath]) {
959
959
  delete require.cache[modulePath];
960
960
  }
961
- log.info(' Reloading...');
961
+ // log.info(' Reloading...');
962
962
  this._framework = framework;
963
963
  // 重新创建 engine(确保使用最新代码)
964
964
  this._engine = new (require('./src/capabilities/workflow-engine').WorkflowEngine)(framework);
@@ -1012,7 +1012,7 @@ class WorkflowPlugin extends Plugin {
1012
1012
  // 重新加载
1013
1013
  this._loadWorkflows();
1014
1014
  this._registerWorkflowTools();
1015
- log.info(` Reloaded. Total workflows: ${this._workflows.size}`);
1015
+ // log.info(` Reloaded. Total workflows: ${this._workflows.size}`);
1016
1016
  }
1017
1017
  /**
1018
1018
  * 执行工作流
@@ -753,12 +753,12 @@ class AgentChatHandler extends EventEmitter {
753
753
  const totalTokens = cachedMsgTokens + toolsTokens + systemPromptTokens;
754
754
  const limit = this._maxContextTokens * 0.5;
755
755
 
756
- logger.info(`BEFORE: messages=${messages.length}, tokens=${totalTokens}/${limit}`);
756
+ // logger.info(`BEFORE: messages=${messages.length}, tokens=${totalTokens}/${limit}`);
757
757
 
758
758
  if (totalTokens > limit || messages.length > 100) {
759
- logger.info(
760
- `Context large (${messages.length} msgs, ${totalTokens}/${this._maxContextTokens} tokens), compressing...`
761
- );
759
+ // logger.info(
760
+ // `Context large (${messages.length} msgs, ${totalTokens}/${this._maxContextTokens} tokens), compressing...`
761
+ // );
762
762
  await this._compressContext(sessionId, messages, messageStore);
763
763
  // 压缩后消息被截断/替换,缓存已失效,下次 _getCachedMessageTokens 会重新计算
764
764
  this._invalidateMessageTokensCache(messageStore);
@@ -863,7 +863,7 @@ class AgentChatHandler extends EventEmitter {
863
863
 
864
864
  // 执行工具
865
865
  this.emit('tool-call', { name: toolName, args: cleanedArgs });
866
- logger.info(`[Tool] Call: ${toolName}`);
866
+ // logger.info(`[Tool] Call: ${toolName}`);
867
867
  try {
868
868
  const result = await toolDef.execute(cleanedArgs, this.agent.framework);
869
869
 
@@ -874,9 +874,9 @@ class AgentChatHandler extends EventEmitter {
874
874
  const splitCheck = await autoSplitToolResult(toolName, result, this.agent.framework);
875
875
  if (splitCheck.wasSplit && splitCheck.result) {
876
876
  finalResult = splitCheck.result;
877
- logger.info(
878
- `[AutoSplit] 工具 "${toolName}" 结果过大,已自动分拆处理`
879
- );
877
+ // logger.info(
878
+ // `[AutoSplit] 工具 "${toolName}" 结果过大,已自动分拆处理`
879
+ // );
880
880
  }
881
881
  } catch (splitErr) {
882
882
  // 分拆失败不阻断主流程,继续使用原始结果
package/src/core/agent.js CHANGED
@@ -674,13 +674,88 @@ class Agent extends EventEmitter {
674
674
  }
675
675
 
676
676
  /**
677
- * 清空对话历史
677
+ * 清空对话历史(所有存储层)
678
+ * @param {string} sessionId
678
679
  */
679
- clearHistory() {
680
- if (this._chatHandler) {
681
- this._chatHandler.clearHistory();
680
+ clearContext(sessionId) {
681
+ if (!sessionId || !this._chatHandler) return;
682
+
683
+ this._chatHandler._chatSession?.clearSessionMessages(sessionId, true);
684
+
685
+ const sessionCtx = this.framework?.getSessionContext(sessionId);
686
+ if (sessionCtx) {
687
+ sessionCtx.clearMessages();
688
+ if (sessionCtx.compressionState) sessionCtx.compressionState.count = 0;
689
+ if (sessionCtx.metadata) sessionCtx.metadata.compressionCount = 0;
682
690
  }
683
- return this;
691
+
692
+ // 持久化 CLEAR 标记到 SessionManager
693
+ const sessionManager = this.framework?._sessionContexts?.get(sessionId);
694
+ if (sessionManager) {
695
+ const { generateEntryId, EntryTypes } = require('./session-entry');
696
+ sessionManager._appendEntry({
697
+ id: generateEntryId(sessionManager.byId),
698
+ type: EntryTypes.SESSION_INFO,
699
+ info: 'context_cleared',
700
+ timestamp: Date.now(),
701
+ });
702
+ }
703
+ }
704
+
705
+ /**
706
+ * 压缩上下文(委托给 AgentChatHandler.ContextCompressor)
707
+ * @param {string} sessionId
708
+ * @returns {Promise<{before: number, after: number}>}
709
+ */
710
+ async compressContext(sessionId) {
711
+ if (!sessionId || !this._chatHandler) {
712
+ throw new Error('AgentChatHandler not available');
713
+ }
714
+
715
+ const chatHandler = this._chatHandler;
716
+ const messageStore = chatHandler._chatSession?.getSessionMessageStore(sessionId);
717
+ if (!messageStore) throw new Error('MessageStore not available');
718
+
719
+ messageStore.historyLoaded = false;
720
+ chatHandler._chatSession?.loadHistory(sessionId);
721
+
722
+ let messages = messageStore.messages;
723
+ const sessionCtx = this.framework?.getSessionContext(sessionId);
724
+ if (!messages?.length && sessionCtx) {
725
+ messages = sessionCtx.getMessages();
726
+ messageStore.messages = messages;
727
+ }
728
+
729
+ if (!messages?.length) {
730
+ throw new Error('No messages to compress');
731
+ }
732
+
733
+ if (!chatHandler._contextCompressor) {
734
+ throw new Error('ContextCompressor not available');
735
+ }
736
+
737
+ const before = messages.length;
738
+ await chatHandler._contextCompressor.compress(sessionId, messages, messageStore);
739
+ const after = messages.length;
740
+
741
+ if (sessionCtx) sessionCtx.replaceMessages(messages);
742
+
743
+ // 持久化 COMPACTION 条目到 SessionManager
744
+ const sessionManager = this.framework?._sessionContexts?.get(sessionId);
745
+ if (sessionManager) {
746
+ const { generateEntryId, EntryTypes } = require('./session-entry');
747
+ const compactionEntry = {
748
+ id: generateEntryId(sessionManager.byId),
749
+ type: EntryTypes.COMPACTION,
750
+ summary: messages.find(m => m.role === 'assistant' && m.content?.startsWith('['))?.content || '',
751
+ firstKeptEntryId: null,
752
+ tokensBefore: before,
753
+ timestamp: Date.now(),
754
+ };
755
+ sessionManager._appendEntry(compactionEntry);
756
+ }
757
+
758
+ return { before, after, keepRecent: chatHandler._contextCompressor._keepRecentMessages };
684
759
  }
685
760
 
686
761
  /**
@@ -54,7 +54,7 @@ class BranchSummaryAuto {
54
54
  return originalBranchWithSummary(branchFromId, summary, details, true);
55
55
  };
56
56
 
57
- logger.info('[BranchSummaryAuto] Attached to SessionManager');
57
+ // log.info('[BranchSummaryAuto] Attached to SessionManager');
58
58
  return this;
59
59
  }
60
60
 
@@ -65,7 +65,7 @@ class BranchSummaryAuto {
65
65
  if (this._sessionManager) {
66
66
  // 恢复原始方法需要保存引用,但为了简单,这里只是标记
67
67
  this._sessionManager = null;
68
- logger.info('[BranchSummaryAuto] Detached from SessionManager');
68
+ // log.info('[BranchSummaryAuto] Detached from SessionManager');
69
69
  }
70
70
  return this;
71
71
  }
@@ -142,7 +142,7 @@ class BranchSummaryAuto {
142
142
  }
143
143
  }
144
144
 
145
- logger.info(`[BranchSummaryAuto] Summary generated (${entries.length} entries, ${prep.totalTokens} tokens)`);
145
+ // log.info(`[BranchSummaryAuto] Summary generated (${entries.length} entries, ${prep.totalTokens} tokens)`);
146
146
  }
147
147
  } catch (err) {
148
148
  logger.error('[BranchSummaryAuto] Failed to generate summary:', err.message);
@@ -191,7 +191,7 @@ class BranchSummaryAuto {
191
191
  */
192
192
  setEnabled(enabled) {
193
193
  this._autoSummaryEnabled = enabled;
194
- logger.info(`[BranchSummaryAuto] Auto summary ${enabled ? 'enabled' : 'disabled'}`);
194
+ // log.info(`[BranchSummaryAuto] Auto summary ${enabled ? 'enabled' : 'disabled'}`);
195
195
  return this;
196
196
  }
197
197
 
@@ -175,6 +175,7 @@ class ChatSession extends EventEmitter {
175
175
  messages: [],
176
176
  historyLoaded: false,
177
177
  usage: null,
178
+ sessionId,
178
179
  compressionState: {
179
180
  count: 0,
180
181
  lastCompressedAt: null,
@@ -54,6 +54,8 @@ function createSessionId() {
54
54
  return uuidv7();
55
55
  }
56
56
 
57
+ const MAX_SESSION_ENTRIES = 50000; // Hard limit to prevent memory issues
58
+
57
59
  /**
58
60
  * Build session context from tree path entries (for LLM)
59
61
  */
@@ -62,7 +64,13 @@ function buildSessionContext(pathEntries) {
62
64
  let model = null;
63
65
  let compaction = null;
64
66
 
65
- for (const entry of pathEntries) {
67
+ // Guard against corrupted files with excessive entries
68
+ let entries = pathEntries;
69
+ if (pathEntries.length > MAX_SESSION_ENTRIES) {
70
+ entries = pathEntries.slice(-MAX_SESSION_ENTRIES);
71
+ }
72
+
73
+ for (const entry of entries) {
66
74
  if (entry.type === EntryTypes.THINKING_LEVEL_CHANGE) {
67
75
  thinkingLevel = entry.thinkingLevel;
68
76
  } else if (entry.type === EntryTypes.MODEL_CHANGE) {
@@ -87,18 +95,18 @@ function buildSessionContext(pathEntries) {
87
95
 
88
96
  if (compaction) {
89
97
  messages.push(createCompactionSummaryMessage(compaction.summary, compaction.tokensBefore, compaction.timestamp));
90
- const compactionIdx = pathEntries.findIndex(e => e.type === EntryTypes.COMPACTION && e.id === compaction.id);
98
+ const compactionIdx = entries.findIndex(e => e.type === EntryTypes.COMPACTION && e.id === compaction.id);
91
99
  let foundFirstKept = false;
92
100
  for (let i = 0; i < compactionIdx; i++) {
93
- const entry = pathEntries[i];
101
+ const entry = entries[i];
94
102
  if (entry.id === compaction.firstKeptEntryId) foundFirstKept = true;
95
103
  if (foundFirstKept) appendMessage(entry);
96
104
  }
97
- for (let i = compactionIdx + 1; i < pathEntries.length; i++) {
98
- appendMessage(pathEntries[i]);
105
+ for (let i = compactionIdx + 1; i < entries.length; i++) {
106
+ appendMessage(entries[i]);
99
107
  }
100
108
  } else {
101
- for (const entry of pathEntries) {
109
+ for (const entry of entries) {
102
110
  appendMessage(entry);
103
111
  }
104
112
  }
@@ -125,11 +125,18 @@ class SessionManager {
125
125
  const content = fs.readFileSync(filePath, 'utf8');
126
126
  const entries = [];
127
127
  const lines = content.trim().split('\n');
128
+ const seenIds = new Set();
128
129
 
129
130
  for (const line of lines) {
130
131
  if (!line.trim()) continue;
131
132
  try {
132
- entries.push(JSON.parse(line));
133
+ const entry = JSON.parse(line);
134
+ // Skip malformed entries
135
+ if (!entry || typeof entry !== 'object') continue;
136
+ // Skip duplicate entries (same id = corrupted file)
137
+ if (entry.id && seenIds.has(entry.id)) continue;
138
+ if (entry.id) seenIds.add(entry.id);
139
+ entries.push(entry);
133
140
  } catch {
134
141
  // Skip malformed lines
135
142
  }
@@ -409,9 +416,14 @@ class SessionManager {
409
416
 
410
417
  /**
411
418
  * Get messages (alias for buildSessionContext().messages)
419
+ * @param {number} [limit] - Optional limit to only return the last N messages
412
420
  */
413
- getMessages() {
414
- return this.buildSessionContext().messages;
421
+ getMessages(limit) {
422
+ const ctx = this.buildSessionContext();
423
+ if (limit && limit > 0) {
424
+ return ctx.messages.slice(-limit);
425
+ }
426
+ return ctx.messages;
415
427
  }
416
428
 
417
429
  /**
@@ -90,7 +90,7 @@ class MCPClientWrapper {
90
90
  }
91
91
 
92
92
  this.connected = true;
93
- log.info(` Connected to ${this.serverName} with ${this.tools.length} tools`);
93
+ // log.info(` Connected to ${this.serverName} with ${this.tools.length} tools`);
94
94
  } catch (err) {
95
95
  if (controller.signal.aborted) {
96
96
  log.error(` Connection timeout (${timeoutMs}ms) for ${this.serverName}`);
@@ -233,7 +233,7 @@ class MCPExecutorPlugin extends Plugin {
233
233
  if (this._config.servers) {
234
234
  for (const serverConfig of this._config.servers) {
235
235
  if (serverConfig.enabled === false) {
236
- log.info(` Skipping disabled server: ${serverConfig.name}`);
236
+ // log.info(` Skipping disabled server: ${serverConfig.name}`);
237
237
  // 保存完整配置,以便后续动态启用
238
238
  this._serverConfigs.set(serverConfig.name, { ...serverConfig });
239
239
  continue;
@@ -347,7 +347,7 @@ class MCPExecutorPlugin extends Plugin {
347
347
  }),
348
348
  execute: async (args) => {
349
349
  const { server, tool, args_json } = args;
350
- log.info(` mcp_call: server=${server}, tool=${tool}, args_json=${args_json}`);
350
+ // log.info(` mcp_call: server=${server}, tool=${tool}, args_json=${args_json}`);
351
351
 
352
352
  const clientInfo = this._clients.get(server);
353
353
  if (!clientInfo) {
@@ -464,23 +464,23 @@ class MCPExecutorPlugin extends Plugin {
464
464
  '重新加载 MCP 服务器配置。当配置文件 .foliko/mcp_config.json 修改后使用此工具重载配置',
465
465
  inputSchema: z.object({}),
466
466
  execute: async () => {
467
- log.info(' mcp_reload called');
467
+ // log.info(' mcp_reload called');
468
468
  try {
469
469
  const fs = require('fs');
470
470
  const path = require('path');
471
471
  const configPath = path.resolve('.foliko/mcp_config.json');
472
472
 
473
- log.info(' Reading config from:', configPath);
473
+ // log.info(' Reading config from:', configPath);
474
474
  if (!fs.existsSync(configPath)) {
475
475
  return { success: false, error: `配置文件不存在: ${configPath}` };
476
476
  }
477
477
 
478
478
  const configContent = fs.readFileSync(configPath, 'utf8');
479
479
  const config = JSON.parse(configContent);
480
- log.info(' Config loaded, reloading...');
480
+ // log.info(' Config loaded, reloading...');
481
481
 
482
482
  await this.reloadConfig(config);
483
- log.info(' Reload complete');
483
+ // log.info(' Reload complete');
484
484
 
485
485
  return {
486
486
  success: true,
@@ -518,13 +518,11 @@ class MCPExecutorPlugin extends Plugin {
518
518
  if (!clientInfo && serverConfig && serverConfig.enabled === false) {
519
519
  // 服务器是被禁用的,可以尝试启用
520
520
  }
521
- log.info(
522
- `[MCP] Enabling server: ${server}, clientInfo=${!!clientInfo}, serverConfig.enabled=${serverConfig?.enabled}`
523
- );
521
+ // log.info(`[MCP] Enabling server: ${server}, clientInfo=${!!clientInfo}, serverConfig.enabled=${serverConfig?.enabled}`);
524
522
  try {
525
523
  if (serverConfig) {
526
524
  const result = await this.addServer({ ...serverConfig, enabled: true });
527
- log.info(`[MCP] addServer result:`, JSON.stringify(result));
525
+ // log.info(`[MCP] addServer result:`, JSON.stringify(result));
528
526
  if (!result || result.success === false) {
529
527
  this._refreshAllAgentsMCPPrompt(this._framework);
530
528
  return result;
@@ -545,7 +543,7 @@ class MCPExecutorPlugin extends Plugin {
545
543
  if (!clientInfo) {
546
544
  return { success: false, error: `MCP server '${server}' not found` };
547
545
  }
548
- log.info(` Disabling MCP server: ${server}`);
546
+ // log.info(` Disabling MCP server: ${server}`);
549
547
  try {
550
548
  clientInfo.client.close?.();
551
549
  } catch (e) {}
@@ -1042,9 +1040,7 @@ class MCPExecutorPlugin extends Plugin {
1042
1040
  authProvider,
1043
1041
  enabled,
1044
1042
  } = config;
1045
- log.info(
1046
- `[MCP] addServer called: ${name}, enabled=${enabled}, hasClient=${this._clients.has(name)}`
1047
- );
1043
+ log.debug(`[MCP] addServer called: ${name}, enabled=${enabled}, hasClient=${this._clients.has(name)}`);
1048
1044
 
1049
1045
  if (this._clients.has(name)) {
1050
1046
  log.warn(` Server '${name}' already exists, skipping`);
@@ -1053,7 +1049,7 @@ class MCPExecutorPlugin extends Plugin {
1053
1049
 
1054
1050
  // 如果 enabled === false,跳过连接(用于 mcp_set_enabled 禁用后再开启的场景)
1055
1051
  if (enabled === false) {
1056
- log.info(` Server '${name}' is disabled, skipping connection`);
1052
+ // log.info(` Server '${name}' is disabled, skipping connection`);
1057
1053
  return { success: false, error: `Server '${name}' is disabled` };
1058
1054
  }
1059
1055
 
@@ -1069,7 +1065,7 @@ class MCPExecutorPlugin extends Plugin {
1069
1065
  authProvider,
1070
1066
  enabled,
1071
1067
  });
1072
- log.info(` Connecting to ${name}...`);
1068
+ // log.info(` Connecting to ${name}...`);
1073
1069
  let client;
1074
1070
  try {
1075
1071
  if (['sse', 'http'].includes(type)) {
@@ -1154,7 +1150,7 @@ class MCPExecutorPlugin extends Plugin {
1154
1150
  enabled: config.enabled !== false,
1155
1151
  });
1156
1152
 
1157
- log.info(
1153
+ log.debug(
1158
1154
  ` Added server '${name}' with ${toolsInfo.length} tools (ext_call names: ${Object.keys(
1159
1155
  this.tools
1160
1156
  )
@@ -1206,7 +1202,7 @@ class MCPExecutorPlugin extends Plugin {
1206
1202
  }
1207
1203
 
1208
1204
  reload(framework) {
1209
- log.info(' Reloading...');
1205
+ // log.info(' Reloading...');
1210
1206
  this._framework = framework;
1211
1207
  }
1212
1208
 
@@ -1215,11 +1211,11 @@ class MCPExecutorPlugin extends Plugin {
1215
1211
  * @param {Object} config - 新的配置对象,包含 mcpServers
1216
1212
  */
1217
1213
  async reloadConfig(config) {
1218
- log.info(' reloadConfig start');
1214
+ // log.info(' reloadConfig start');
1219
1215
  const newServers = config?.mcpServers || {};
1220
1216
 
1221
1217
  // 1. 先快速清理所有旧服务器(不等待 close 完成)
1222
- log.info(' Clearing old servers...');
1218
+ // log.info(' Clearing old servers...');
1223
1219
  for (const [name, clientInfo] of this._clients) {
1224
1220
  try {
1225
1221
  // 不等待 close,直接删除
@@ -1231,10 +1227,10 @@ class MCPExecutorPlugin extends Plugin {
1231
1227
  this._serverConfigs.clear();
1232
1228
 
1233
1229
  // 2. 并行添加新服务器
1234
- log.info(' Adding new servers...');
1230
+ // log.info(' Adding new servers...');
1235
1231
  const addPromises = Object.entries(newServers).map(async ([name, serverConfig]) => {
1236
1232
  if (serverConfig.enabled === false) {
1237
- log.info(` Skipping disabled server: ${name}`);
1233
+ // log.info(` Skipping disabled server: ${name}`);
1238
1234
  // 仍保存配置,以便后续动态启用
1239
1235
  this._serverConfigs.set(name, { name, ...serverConfig });
1240
1236
  return;
@@ -1254,7 +1250,7 @@ class MCPExecutorPlugin extends Plugin {
1254
1250
  });
1255
1251
 
1256
1252
  await Promise.all(addPromises);
1257
- log.info(' reloadConfig complete');
1253
+ // log.info(' reloadConfig complete');
1258
1254
 
1259
1255
  // 3. 刷新所有 agent 的 MCP 提示词
1260
1256
  if (this._framework) {
@@ -1286,7 +1282,7 @@ class MCPExecutorPlugin extends Plugin {
1286
1282
 
1287
1283
  config.mcpServers[serverName].enabled = enabled;
1288
1284
  fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8');
1289
- log.info(` Saved enabled=${enabled} for server '${serverName}' to config`);
1285
+ // log.info(` Saved enabled=${enabled} for server '${serverName}' to config`);
1290
1286
  return true;
1291
1287
  } catch (err) {
1292
1288
  log.error(` Failed to save MCP config:`, err.message);
@@ -157,7 +157,7 @@ class DataSplitter {
157
157
  const results = [];
158
158
  const errors = [];
159
159
 
160
- logger.info(
160
+ logger.debug(
161
161
  `[DataSplitter] 开始分拆处理: ${totalChunks} 块, 任务="${taskDescription.slice(0, 50)}..."`
162
162
  );
163
163
 
@@ -246,7 +246,7 @@ ${chunk.content}
246
246
  // 生成汇总摘要
247
247
  const summary = this._buildSummary(results, errors, taskDescription);
248
248
 
249
- logger.info(
249
+ logger.debug(
250
250
  `[DataSplitter] 分拆处理完成: ` +
251
251
  `${results.filter((r) => r.success).length}/${totalChunks} 块成功, ` +
252
252
  `${errors.length} 个错误`
@@ -277,7 +277,7 @@ ${chunk.content}
277
277
  const stats = this.getContentStats(content);
278
278
  const chunkSize = options.chunkSize || this.chunkSize;
279
279
 
280
- logger.info(
280
+ logger.debug(
281
281
  `[DataSplitter] 自动分拆: ${stats.chars} 字符, ` +
282
282
  `约 ${stats.estimatedTokens} tokens, ` +
283
283
  `分 ${stats.chunks} 块处理`
@@ -152,7 +152,7 @@ function validateToolCalls(messages, options = {}) {
152
152
  }
153
153
 
154
154
  if (shouldLog && fixedCount > 0) {
155
- logger.info(`[validateToolCalls] Fixed ${fixedCount} incomplete tool calls/results`);
155
+ // logger.info(`[validateToolCalls] Fixed ${fixedCount} incomplete tool calls/results`);
156
156
  }
157
157
 
158
158
  return fixedCount;
@@ -1,8 +1,8 @@
1
- /* Foliko v2 - Animations */
2
- @keyframes fadeInUp { from { opacity: 0; transform: translateY(30px); } to { opacity: 1; transform: translateY(0); } }
3
- @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
4
- @keyframes glow { 0%, 100% { opacity: 0.4; transform: translateX(-50%) scale(1); } 50% { opacity: 0.7; transform: translateX(-50%) scale(1.1); } }
5
- @keyframes pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.5; transform: scale(1.2); } }
6
- .reveal { opacity: 0; transform: translateY(30px); transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1); }
7
- .reveal.visible { opacity: 1; transform: translateY(0); }
1
+ /* Foliko v2 - Animations */
2
+ @keyframes fadeInUp { from { opacity: 0; transform: translateY(30px); } to { opacity: 1; transform: translateY(0); } }
3
+ @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
4
+ @keyframes glow { 0%, 100% { opacity: 0.4; transform: translateX(-50%) scale(1); } 50% { opacity: 0.7; transform: translateX(-50%) scale(1.1); } }
5
+ @keyframes pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.5; transform: scale(1.2); } }
6
+ .reveal { opacity: 0; transform: translateY(30px); transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1); }
7
+ .reveal.visible { opacity: 1; transform: translateY(0); }
8
8