foliko 1.1.7 → 1.1.9

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 (113) hide show
  1. package/.agent/agents/poster-expert.md +228 -0
  2. package/.agent/data/default.json +10 -0
  3. package/.agent/data/plugins-state.json +1 -1
  4. package/.agent/mcp_config.json +0 -6
  5. package/.agent/plugins/test-plugin.py +15 -0
  6. package/.agent/plugins/test_nested_plugin.py +85 -0
  7. package/.agent/sessions/cli_default.json +83 -803
  8. package/.agent/sessions/weixin_o9cq80zgZqKPA2-s59PN43GdDy1w@im.wechat.json +189 -0
  9. package/.claude/settings.local.json +8 -1
  10. package/cli/src/ui/chat-ui.js +32 -21
  11. package/foliko_poster.png +0 -0
  12. package/output/business_poster_final.png +0 -0
  13. package/output/emoji_test_v2.png +0 -0
  14. package/output/foliko-ai-launch-poster.png +0 -0
  15. package/output/foliko-poster.png +0 -0
  16. package/output/muji_style_poster.png +0 -0
  17. package/output/new_product_launch.png +0 -0
  18. package/output/news_poster_625yi_subsidy.png +0 -0
  19. package/output/tech_future_2026.png +0 -0
  20. package/output/tech_future_poster.png +0 -0
  21. package/package.json +2 -2
  22. package/plugins/default-plugins.js +60 -7
  23. package/plugins/extension-executor-plugin.js +32 -22
  24. package/plugins/feishu-plugin.js +2 -2
  25. package/plugins/python-plugin-loader.js +461 -40
  26. package/plugins/python-plugin-loader.js.bak +856 -0
  27. package/plugins/subagent-plugin.js +0 -121
  28. package/plugins/telegram-plugin.js +2 -2
  29. package/plugins/weixin-plugin.js +40 -31
  30. package/poster.png +0 -0
  31. package/skills/foliko-dev/SKILL.md +6 -0
  32. package/skills/python-plugin-dev/SKILL.md +124 -2
  33. package/src/core/agent-chat.js +220 -281
  34. package/src/core/agent.js +127 -29
  35. package/src/executors/mcp-executor.js +282 -26
  36. package/src/utils/plugin-helpers.js +22 -4
  37. package/system.md +362 -109
  38. package/test-scan.js +18 -0
  39. package/.agent/memory/feedback/mnt7jrlt-d67qs7.md +0 -15
  40. package/.agent/memory/feedback/mnt88ja3-al4fuy.md +0 -9
  41. package/.agent/plugins/poster-plugin/README.md +0 -304
  42. package/.agent/plugins/poster-plugin/emojis/rocket.png +0 -1
  43. package/.agent/plugins/poster-plugin/fonts/PatuaOne-Regular.ttf +0 -0
  44. package/.agent/plugins/poster-plugin/fonts/SegoeUI Emoji.ttf +0 -0
  45. package/.agent/plugins/poster-plugin/fonts//345/276/256/350/275/257/351/233/205/351/273/221.ttf +0 -0
  46. package/.agent/plugins/poster-plugin/fonts//345/276/256/350/275/257/351/233/205/351/273/221/347/262/227/344/275/223.ttf +0 -0
  47. package/.agent/plugins/poster-plugin/index.js +0 -13
  48. package/.agent/plugins/poster-plugin/package.json +0 -29
  49. package/.agent/plugins/poster-plugin/src/canvas.js +0 -224
  50. package/.agent/plugins/poster-plugin/src/components/arrow.js +0 -84
  51. package/.agent/plugins/poster-plugin/src/components/avatar.js +0 -71
  52. package/.agent/plugins/poster-plugin/src/components/badge.js +0 -85
  53. package/.agent/plugins/poster-plugin/src/components/barcode.js +0 -120
  54. package/.agent/plugins/poster-plugin/src/components/bubble.js +0 -153
  55. package/.agent/plugins/poster-plugin/src/components/button.js +0 -124
  56. package/.agent/plugins/poster-plugin/src/components/card.js +0 -88
  57. package/.agent/plugins/poster-plugin/src/components/chart.js +0 -127
  58. package/.agent/plugins/poster-plugin/src/components/chip.js +0 -88
  59. package/.agent/plugins/poster-plugin/src/components/columns.js +0 -107
  60. package/.agent/plugins/poster-plugin/src/components/cta.js +0 -87
  61. package/.agent/plugins/poster-plugin/src/components/divider.js +0 -55
  62. package/.agent/plugins/poster-plugin/src/components/feature.js +0 -85
  63. package/.agent/plugins/poster-plugin/src/components/featureGrid.js +0 -117
  64. package/.agent/plugins/poster-plugin/src/components/frame.js +0 -230
  65. package/.agent/plugins/poster-plugin/src/components/grid.js +0 -118
  66. package/.agent/plugins/poster-plugin/src/components/highlightText.js +0 -144
  67. package/.agent/plugins/poster-plugin/src/components/icon.js +0 -94
  68. package/.agent/plugins/poster-plugin/src/components/imageFrame.js +0 -155
  69. package/.agent/plugins/poster-plugin/src/components/index.js +0 -81
  70. package/.agent/plugins/poster-plugin/src/components/listItem.js +0 -147
  71. package/.agent/plugins/poster-plugin/src/components/notification.js +0 -123
  72. package/.agent/plugins/poster-plugin/src/components/progress.js +0 -79
  73. package/.agent/plugins/poster-plugin/src/components/progressCircle.js +0 -117
  74. package/.agent/plugins/poster-plugin/src/components/qrcode.js +0 -74
  75. package/.agent/plugins/poster-plugin/src/components/quote.js +0 -97
  76. package/.agent/plugins/poster-plugin/src/components/rating.js +0 -85
  77. package/.agent/plugins/poster-plugin/src/components/ribbon.js +0 -193
  78. package/.agent/plugins/poster-plugin/src/components/seal.js +0 -146
  79. package/.agent/plugins/poster-plugin/src/components/star.js +0 -70
  80. package/.agent/plugins/poster-plugin/src/components/statCard.js +0 -105
  81. package/.agent/plugins/poster-plugin/src/components/stepper.js +0 -118
  82. package/.agent/plugins/poster-plugin/src/components/table.js +0 -167
  83. package/.agent/plugins/poster-plugin/src/components/tagCloud.js +0 -85
  84. package/.agent/plugins/poster-plugin/src/components/timeline.js +0 -117
  85. package/.agent/plugins/poster-plugin/src/components/watermark.js +0 -52
  86. package/.agent/plugins/poster-plugin/src/composer.js +0 -2146
  87. package/.agent/plugins/poster-plugin/src/elements/artText.js +0 -60
  88. package/.agent/plugins/poster-plugin/src/elements/background.js +0 -84
  89. package/.agent/plugins/poster-plugin/src/elements/circle.js +0 -31
  90. package/.agent/plugins/poster-plugin/src/elements/image.js +0 -28
  91. package/.agent/plugins/poster-plugin/src/elements/index.js +0 -28
  92. package/.agent/plugins/poster-plugin/src/elements/line.js +0 -23
  93. package/.agent/plugins/poster-plugin/src/elements/polygon.js +0 -63
  94. package/.agent/plugins/poster-plugin/src/elements/rectangle.js +0 -32
  95. package/.agent/plugins/poster-plugin/src/elements/richText.js +0 -230
  96. package/.agent/plugins/poster-plugin/src/elements/svg.js +0 -108
  97. package/.agent/plugins/poster-plugin/src/elements/text.js +0 -109
  98. package/.agent/plugins/poster-plugin/src/fonts.js +0 -243
  99. package/.agent/plugins/poster-plugin/src/index.js +0 -2081
  100. package/.agent/plugins/poster-plugin/src/presets.js +0 -36
  101. package/.agent/plugins/poster-plugin/src/templates/business.js +0 -60
  102. package/.agent/plugins/poster-plugin/src/templates/gradient.js +0 -64
  103. package/.agent/plugins/poster-plugin/src/templates/index.js +0 -43
  104. package/.agent/plugins/poster-plugin/src/templates/modern.js +0 -69
  105. package/.agent/plugins/poster-plugin/src/templates/simple.js +0 -58
  106. package/.agent/plugins/poster-plugin/src/templates/social.js +0 -62
  107. package/.agent/plugins/poster-plugin/src/templates/tech.js +0 -84
  108. package/.agent/plugins/poster-plugin/src/utils/imageLoader.js +0 -84
  109. package/.agent/plugins/poster-plugin/test-background.svg +0 -1
  110. package/.agent/plugins/poster-plugin/test-full-poster.svg +0 -2
  111. package/.agent/plugins/poster-plugin/test-image.png +0 -0
  112. package/.agent/plugins/poster-plugin/yarn.lock +0 -1007
  113. package/output/zen_silence.png +0 -0
@@ -172,7 +172,14 @@
172
172
  "Bash(node -c D:/Code/vb-agent/src/utils/index.js && echo \"Syntax OK\")",
173
173
  "Bash(cd \"D:/Code/vb-agent\" && node -c src/core/agent-chat.js 2>&1)",
174
174
  "WebFetch(domain:ai-sdk.google.com)",
175
- "Bash(node test_debug.js)"
175
+ "Bash(cd \"D:/Code/foliko/.agent/plugins\" && rm -rf poster-plugin && ln -s \"D:/Code/foliko-plugins/poster-plugin\" poster-plugin)",
176
+ "Bash(cd \"D:/Code/foliko/.agent/plugins\" && rm -rf poster-plugin && cmd //c \"mklink /D poster-plugin D:\\\\\\\\Code\\\\\\\\foliko-plugins\\\\\\\\poster-plugin\" 2>&1 || echo \"Trying ln -s again\")",
177
+ "Bash(cd \"D:/Code/foliko\" && node -e \"\nconst { Framework } = require\\('./src'\\);\nconst PythonPluginLoader = require\\('./plugins/python-plugin-loader'\\);\nconst ext = require\\('./plugins/extension-executor-plugin'\\);\nconst AIPlugin = require\\('./plugins/ai-plugin'\\);\n\nasync function test\\(\\) {\n const fw = new Framework\\(\\);\n await fw.loadPlugin\\(new ext\\(\\)\\);\n await fw.loadPlugin\\(new PythonPluginLoader\\({ agentDir: '.agent' }\\)\\);\n await fw.loadPlugin\\(new AIPlugin\\({ apiKey: 'test' }\\)\\);\n \n console.log\\('Extensions:', fw.pluginManager.get\\('extension-executor'\\)?._extensions?.keys\\(\\)\\);\n console.log\\('Python plugins:', fw.pluginManager.get\\('python-plugin-loader'\\)?._pythonPlugins?.keys\\(\\)\\);\n}\n\ntest\\(\\).catch\\(console.error\\);\n\" 2>&1 | head -20)",
178
+ "Bash(cd \"D:/Code/foliko\" && node -e \"\nconst { Framework } = require\\('./src'\\);\nconst PythonPluginLoader = require\\('./plugins/python-plugin-loader'\\);\nconst ext = require\\('./plugins/extension-executor-plugin'\\);\nconst AIPlugin = require\\('./plugins/ai-plugin'\\);\n\nasync function test\\(\\) {\n const fw = new Framework\\(\\);\n await fw.loadPlugin\\(new ext\\(\\)\\);\n await fw.loadPlugin\\(new PythonPluginLoader\\({ agentDir: '.agent' }\\)\\);\n await fw.loadPlugin\\(new AIPlugin\\({ apiKey: 'test' }\\)\\);\n \n const executor = fw.pluginManager.get\\('extension-executor'\\);\n const extData = executor._extensions.get\\('python'\\);\n console.log\\('Python ext tools:', extData?.tools?.map\\(t => \\({ name: t.name, desc: t.description }\\)\\)\\);\n}\n\ntest\\(\\).catch\\(console.error\\);\n\" 2>&1 | grep -v \"^\\\\[2m\")",
179
+ "Bash(cd \"D:/Code/foliko\" && node test-python-ext.js 2>&1 | grep -v \"^\\\\[2m\")",
180
+ "Bash(cd \"D:/Code/foliko\" && node -e \"require\\('./plugins/extension-executor-plugin'\\); console.log\\('OK'\\)\")",
181
+ "Bash(cd D:/Code/foliko && timeout 8s node cli/bin/foliko.js chat 2>&1 || true)",
182
+ "Bash(cd /d/Code/foliko-plugins/poster-plugin && node -e \"\nconst LayoutManager = require\\('./src/layout-manager'\\);\nconsole.log\\('LayoutManager loaded successfully'\\);\nconsole.log\\('Methods:', Object.getOwnPropertyNames\\(LayoutManager.prototype\\).join\\(', '\\)\\);\n\")"
176
183
  ]
177
184
  }
178
185
  }
@@ -151,29 +151,40 @@ class ChatUI {
151
151
 
152
152
  let lineBuffer = '';
153
153
  await runWithContext({ sessionId }, async () => {
154
- for await (const chunk of this.agent.chatStream(message, { sessionId })) {
155
- if (interrupted) break;
156
-
157
- if (chunk.type === 'text') {
158
- fullResponse += chunk.text;
159
- lineBuffer += chunk.text;
160
-
161
- while (lineBuffer.includes('\n')) {
162
- if (interrupted) break;
163
-
164
- const nlIndex = lineBuffer.indexOf('\n');
165
- const line = lineBuffer.substring(0, nlIndex);
166
- lineBuffer = lineBuffer.substring(nlIndex + 1);
167
- if (line.trim()) {
168
- console.log(renderLine(line, renderState));
154
+ await this.agent.continue(message, sessionId, {
155
+ onChunk: (chunk) => {
156
+ if (interrupted) return;
157
+
158
+ if (chunk.type === 'text') {
159
+ fullResponse += chunk.text;
160
+ lineBuffer += chunk.text;
161
+
162
+ while (lineBuffer.includes('\n')) {
163
+ if (interrupted) break;
164
+
165
+ const nlIndex = lineBuffer.indexOf('\n');
166
+ const line = lineBuffer.substring(0, nlIndex);
167
+ lineBuffer = lineBuffer.substring(nlIndex + 1);
168
+ if (line.trim()) {
169
+ console.log(renderLine(line, renderState));
170
+ }
169
171
  }
172
+ } else if (chunk.type === 'tool-call') {
173
+ console.log(
174
+ `\n${colored('[工具调用]', YELLOW)} ${chunk.toolName}`,
175
+ JSON.stringify(chunk.input)
176
+ );
177
+ } else if (chunk.type === 'error') {
178
+ console.error(`\n${colored('[错误]', RED)} ${chunk.error}`);
170
179
  }
171
- } else if (chunk.type === 'tool-call') {
172
- console.log(`\n${colored('[工具调用]', YELLOW)} ${chunk.toolName}`);
173
- } else if (chunk.type === 'error') {
174
- console.error(`\n${colored('[错误]', RED)} ${chunk.error}`);
175
- }
176
- }
180
+ },
181
+ onComplete: async (full, ctx) => {
182
+ const response = cleanResponse(full);
183
+ if (!response) {
184
+ ctx.push('请继续完成任务', { sessionId });
185
+ }
186
+ },
187
+ });
177
188
  });
178
189
 
179
190
  if (lineBuffer.trim() && !interrupted) {
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foliko",
3
- "version": "1.1.7",
3
+ "version": "1.1.9",
4
4
  "description": "简约的插件化 Agent 框架",
5
5
  "main": "src/index.js",
6
6
  "type": "commonjs",
@@ -54,7 +54,7 @@
54
54
  "@ai-sdk/openai-compatible": "^2.0.35",
55
55
  "@anthropic-ai/sdk": "^0.39.0",
56
56
  "@chnak/weixin-bot": "^1.2.7",
57
- "@chnak/zod-to-markdown": "1.0.6",
57
+ "@chnak/zod-to-markdown": "1.0.7",
58
58
  "@hono/node-server": "^1.19.11",
59
59
  "@larksuiteoapi/node-sdk": "^1.59.0",
60
60
  "@modelcontextprotocol/sdk": "^1.27.1",
@@ -21,7 +21,8 @@ function loadAgentConfig(agentDir = '.agent') {
21
21
  mcpServers: {},
22
22
  plugins: [],
23
23
  skillsDirs: [],
24
- agentsDir: null // 子Agent配置目录
24
+ agentsDir: null, // 子Agent配置目录
25
+ pluginLinks: {} // 外部插件链接 { "插件名": "外部路径" }
25
26
  }
26
27
  const cmdDir=path.resolve(process.cwd())
27
28
  const resolvedDir = path.resolve(process.cwd(), agentDir)
@@ -100,6 +101,13 @@ function loadAgentConfig(agentDir = '.agent') {
100
101
  if (pluginsConfig.email) {
101
102
  config.email = pluginsConfig.email
102
103
  }
104
+ // 外部插件链接配置 (pluginLinks: { "poster": "/path/to/poster-plugin" })
105
+ if (pluginsConfig.pluginLinks) {
106
+ config.pluginLinks = pluginsConfig.pluginLinks
107
+ for (const [name, targetPath] of Object.entries(pluginsConfig.pluginLinks)) {
108
+ log.info(` Found plugin link: ${name} -> ${targetPath}`)
109
+ }
110
+ }
103
111
  } catch (err) {
104
112
  log.error(` Failed to load plugins.json:`, err.message)
105
113
  }
@@ -325,7 +333,8 @@ async function bootstrapDefaults(framework, config = {}) {
325
333
  args: cfg.args || [],
326
334
  env: cfg.env || {},
327
335
  url: cfg.url,
328
- headers: cfg.headers
336
+ headers: cfg.headers,
337
+ enabled: cfg.enabled !== false // 默认为 true
329
338
  }))
330
339
  const { MCPExecutorPlugin } = require('../src/executors/mcp-executor')
331
340
  await framework.loadPlugin(new MCPExecutorPlugin({ servers }))
@@ -375,6 +384,7 @@ async function bootstrapDefaults(framework, config = {}) {
375
384
  * 支持两种结构:
376
385
  * 1. 文件夹结构: .agent/plugins/my-plugin/index.js
377
386
  * 2. 单文件结构: .agent/plugins/my-plugin.js
387
+ * 支持符号链接
378
388
  * @param {string} pluginsDir - 插件目录
379
389
  * @param {string} name - 插件名称
380
390
  * @returns {{path: string, type: 'folder'|'file'}|null} 插件路径和类型
@@ -383,8 +393,28 @@ function resolvePluginPath(pluginsDir, name) {
383
393
  const folderPath = path.join(pluginsDir, name)
384
394
  const filePath = path.join(pluginsDir, `${name}.js`)
385
395
 
386
- // 文件夹优先
387
- if (fs.existsSync(folderPath) && fs.statSync(folderPath).isDirectory()) {
396
+ // 检查文件夹是否存在
397
+ if (!fs.existsSync(folderPath)) {
398
+ // 单文件回退
399
+ if (fs.existsSync(filePath)) {
400
+ return { path: filePath, type: 'file' }
401
+ }
402
+ return null
403
+ }
404
+
405
+ // 检查是否为目录(支持符号链接)
406
+ let isDir = false
407
+ try {
408
+ isDir = fs.statSync(folderPath).isDirectory()
409
+ } catch (err) {
410
+ // 无法访问,跳过
411
+ if (fs.existsSync(filePath)) {
412
+ return { path: filePath, type: 'file' }
413
+ }
414
+ return null
415
+ }
416
+
417
+ if (isDir) {
388
418
  const pkgPath = path.join(folderPath, 'package.json')
389
419
  if (fs.existsSync(pkgPath)) {
390
420
  try {
@@ -403,7 +433,6 @@ function resolvePluginPath(pluginsDir, name) {
403
433
  if (fs.existsSync(indexPath)) {
404
434
  return { path: indexPath, type: 'folder' }
405
435
  }
406
- //log.warn(` No entry point found for plugin folder: ${name}`)
407
436
  return null
408
437
  }
409
438
 
@@ -417,6 +446,7 @@ function resolvePluginPath(pluginsDir, name) {
417
446
 
418
447
  /**
419
448
  * 扫描插件目录,返回所有插件名称
449
+ * 支持符号链接
420
450
  * @param {string} pluginsDir - 插件目录
421
451
  * @returns {string[]} 插件名称列表
422
452
  */
@@ -429,8 +459,31 @@ function scanPluginNames(pluginsDir) {
429
459
  const entries = fs.readdirSync(pluginsDir, { withFileTypes: true })
430
460
 
431
461
  for (const entry of entries) {
432
- if (entry.isDirectory()) {
433
- // 文件夹插件
462
+ const fullPath = path.join(pluginsDir, entry.name)
463
+
464
+ // 检查是否为符号链接
465
+ let isSymlink = false
466
+ try {
467
+ const lstat = fs.lstatSync(fullPath)
468
+ isSymlink = lstat.isSymbolicLink()
469
+ } catch (err) {
470
+ // 无法获取信息,跳过
471
+ continue
472
+ }
473
+
474
+ // 获取实际类型(跟随符号链接)
475
+ let isDir = entry.isDirectory()
476
+ if (isSymlink) {
477
+ try {
478
+ isDir = fs.statSync(fullPath).isDirectory()
479
+ } catch (err) {
480
+ // 符号链接目标不存在,跳过
481
+ continue
482
+ }
483
+ }
484
+
485
+ if (isDir) {
486
+ // 文件夹插件(包括符号链接指向的目录)
434
487
  names.add(entry.name)
435
488
  } else if (entry.isFile() && entry.name.endsWith('.js')) {
436
489
  // 单文件插件(排除与文件夹同名的)
@@ -347,27 +347,14 @@ class ExtensionExecutorPlugin extends Plugin {
347
347
  const extDesc = this._buildExtensionsDescription();
348
348
  if (!extDesc) return;
349
349
 
350
- const existingPrompt = agent._originalPrompt || '';
351
-
352
- // 如果已有 [Extensions] 部分,替换它
353
- const extStartIdx = existingPrompt.indexOf('【Extensions】');
354
- if (extStartIdx !== -1) {
355
- const extEndMarker = '\n\n【';
356
- let extEndIdx = existingPrompt.indexOf(extEndMarker, extStartIdx);
357
- if (extEndIdx === -1) {
358
- // 尝试其他标记
359
- extEndIdx = existingPrompt.indexOf('\n\n---\n\n', extStartIdx);
360
- }
361
- if (extEndIdx === -1) {
362
- extEndIdx = existingPrompt.length;
363
- } else {
364
- extEndIdx += extEndMarker.length;
365
- }
366
- const newPrompt = existingPrompt.substring(0, extStartIdx) + extDesc + existingPrompt.substring(extEndIdx);
367
- agent.setSystemPrompt(newPrompt);
368
- } else {
369
- agent.setSystemPrompt(existingPrompt + '\n\n' + extDesc);
370
- }
350
+ let existingPrompt = agent._originalPrompt || '';
351
+
352
+ // 移除所有已存在的 ## 【Extensions 部分(防止重复累积)
353
+ const extRegex = /## 【Extensions】[\s\S]*?(?=\n## 【|$)/;
354
+ existingPrompt = existingPrompt.replace(extRegex, '').trim();
355
+
356
+ // 添加新的 Extensions 部分
357
+ agent.setSystemPrompt(existingPrompt + '\n\n' + extDesc);
371
358
  }
372
359
 
373
360
  _buildExtensionsDescription() {
@@ -550,7 +537,7 @@ class ExtensionExecutorPlugin extends Plugin {
550
537
  }));
551
538
  }
552
539
 
553
- reload(framework) {
540
+ async reload(framework) {
554
541
  this._framework = framework;
555
542
  // 重新扫描所有已加载插件的 tools
556
543
  this._extensions.clear();
@@ -562,6 +549,29 @@ class ExtensionExecutorPlugin extends Plugin {
562
549
  this._mcpExecutor = framework.pluginManager?.get('mcp') || null;
563
550
  // 刷新所有 Agent 的扩展提示词
564
551
  this._refreshAllAgentsExtPrompt(framework);
552
+
553
+ // 同时重载 MCP 配置
554
+ await this._reloadMCPConfig(framework);
555
+ }
556
+
557
+ // 重载 MCP 配置
558
+ async _reloadMCPConfig(framework) {
559
+ const fs = require('fs');
560
+ const path = require('path');
561
+ const mcpExecutor = framework.pluginManager?.get('mcp');
562
+ if (!mcpExecutor) return;
563
+
564
+ try {
565
+ const configPath = path.resolve('.agent/mcp_config.json');
566
+ if (fs.existsSync(configPath)) {
567
+ const configContent = fs.readFileSync(configPath, 'utf8');
568
+ const config = JSON.parse(configContent);
569
+ await mcpExecutor.reloadConfig(config);
570
+ logger.info(' MCP config reloaded via extension-executor');
571
+ }
572
+ } catch (err) {
573
+ logger.warn(' Failed to reload MCP config:', err.message);
574
+ }
565
575
  }
566
576
 
567
577
  async uninstall(framework) {
@@ -288,7 +288,7 @@ class FeishuPlugin extends Plugin {
288
288
  * 处理统一通知
289
289
  */
290
290
  async _handleNotification(data) {
291
- const { title, message, source, level, sessionId } = data
291
+ const { title, message, source = '系统消息', level, sessionId } = data
292
292
 
293
293
  // 确定 openId
294
294
  let openId = null
@@ -327,7 +327,7 @@ class FeishuPlugin extends Plugin {
327
327
  error: '❌'
328
328
  }
329
329
  const emoji = levelEmoji[level] || 'ℹ️'
330
- const notificationText = `${emoji} [${source}] ${title}\n\n${message}`
330
+ const notificationText = `${emoji} [${source}] ${title || '通知'}\n\n${message || ''}`
331
331
 
332
332
  try {
333
333
  await this._sendTextMessage(openId, notificationText)