foliko 1.1.93 → 2.0.1

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 (212) hide show
  1. package/.claude/settings.local.json +2 -1
  2. package/CLAUDE.md +56 -30
  3. package/REFACTORING_PLAN.md +645 -0
  4. package/docs/architecture.md +131 -0
  5. package/docs/migration.md +57 -0
  6. package/docs/public-api.md +138 -0
  7. package/docs/usage.md +385 -0
  8. package/examples/ambient-example.js +20 -137
  9. package/examples/basic.js +21 -48
  10. package/examples/bootstrap.js +16 -74
  11. package/examples/mcp-example.js +6 -29
  12. package/examples/skill-example.js +6 -19
  13. package/examples/workflow.js +8 -56
  14. package/package.json +8 -4
  15. package/plugins/README.md +49 -0
  16. package/plugins/{ambient-agent → ambient}/EventWatcher.js +1 -1
  17. package/plugins/{ambient-agent → ambient}/ExplorerLoop.js +3 -3
  18. package/plugins/{ambient-agent → ambient}/GoalManager.js +2 -2
  19. package/plugins/ambient/README.md +14 -0
  20. package/plugins/{ambient-agent → ambient}/Reflector.js +1 -1
  21. package/plugins/{ambient-agent → ambient}/StateStore.js +1 -1
  22. package/plugins/{ambient-agent → ambient}/index.js +2 -2
  23. package/plugins/{ai-plugin.js → core/ai/index.js} +14 -30
  24. package/plugins/{audit-plugin.js → core/audit/index.js} +3 -30
  25. package/plugins/{coordinator-plugin.js → core/coordinator/index.js} +3 -35
  26. package/plugins/core/default/bootstrap.js +224 -0
  27. package/plugins/core/default/config.js +222 -0
  28. package/plugins/core/default/index.js +58 -0
  29. package/plugins/core/mcp/index.js +1 -0
  30. package/plugins/{python-plugin-loader.js → core/python-loader/index.js} +7 -187
  31. package/plugins/{rules-plugin.js → core/rules/index.js} +121 -64
  32. package/plugins/{scheduler-plugin.js → core/scheduler/index.js} +12 -114
  33. package/plugins/{session-plugin.js → core/session/index.js} +9 -73
  34. package/{src/capabilities/skill-manager.js → plugins/core/skill-manager/index.js} +64 -18
  35. package/plugins/{storage-plugin.js → core/storage/index.js} +5 -29
  36. package/plugins/{subagent-plugin.js → core/sub-agent/index.js} +10 -171
  37. package/plugins/{think-plugin.js → core/think/index.js} +24 -91
  38. package/{src/capabilities/workflow-engine.js → plugins/core/workflow/index.js} +87 -85
  39. package/plugins/default-plugins.js +6 -720
  40. package/plugins/{data-splitter-plugin.js → executors/data-splitter/index.js} +9 -83
  41. package/plugins/{extension-executor-plugin.js → executors/extension/index.js} +13 -97
  42. package/plugins/{python-executor-plugin.js → executors/python/index.js} +6 -31
  43. package/plugins/{shell-executor-plugin.js → executors/shell/index.js} +2 -5
  44. package/plugins/install/README.md +9 -0
  45. package/plugins/{install-plugin.js → install/index.js} +3 -3
  46. package/plugins/{file-system-plugin.js → io/file-system/index.js} +34 -236
  47. package/plugins/{web-plugin.js → io/web/index.js} +11 -113
  48. package/plugins/memory/README.md +13 -0
  49. package/plugins/{memory-plugin.js → memory/index.js} +4 -18
  50. package/plugins/messaging/email/README.md +19 -0
  51. package/plugins/{email → messaging/email}/index.js +3 -3
  52. package/plugins/{feishu-plugin.js → messaging/feishu/index.js} +4 -4
  53. package/plugins/{qq-plugin.js → messaging/qq/index.js} +6 -17
  54. package/plugins/{telegram-plugin.js → messaging/telegram/index.js} +4 -4
  55. package/plugins/{weixin-plugin.js → messaging/weixin/index.js} +16 -16
  56. package/plugins/{plugin-manager-plugin.js → plugin-manager/index.js} +36 -180
  57. package/plugins/{tools-plugin.js → tools/index.js} +68 -116
  58. package/plugins/trading/README.md +15 -0
  59. package/plugins/{gate-trading.js → trading/index.js} +8 -8
  60. package/{examples → sandbox}/test-concurrent-chat.js +2 -2
  61. package/{examples → sandbox}/test-long-chat.js +2 -2
  62. package/{examples → sandbox}/test-session-chat.js +2 -2
  63. package/{examples → sandbox}/test-web-plugin.js +1 -1
  64. package/{examples → sandbox}/test-weixin-feishu.js +2 -2
  65. package/src/agent/base.js +56 -0
  66. package/src/{core/agent-chat.js → agent/chat.js} +11 -11
  67. package/src/{core/coordinator-manager.js → agent/coordinator.js} +3 -3
  68. package/src/agent/index.js +111 -0
  69. package/src/agent/main.js +337 -0
  70. package/src/agent/prompt.js +78 -0
  71. package/src/agent/sub.js +198 -0
  72. package/src/agent/worker.js +104 -0
  73. package/{cli/bin/foliko.js → src/cli/bin.js} +1 -1
  74. package/{cli/src → src/cli}/commands/chat.js +25 -21
  75. package/{cli/src → src/cli}/index.js +1 -0
  76. package/{cli/src → src/cli}/ui/chat-ui-old.js +40 -178
  77. package/{cli/src → src/cli}/ui/chat-ui.js +3 -3
  78. package/{cli/src → src/cli}/ui/components/footer-bar.js +1 -1
  79. package/src/common/errors.js +402 -0
  80. package/src/{utils → common}/logger.js +33 -0
  81. package/src/{utils/chat-queue.js → common/queue.js} +2 -2
  82. package/src/config/plugin-config.js +50 -0
  83. package/src/context/agent.js +32 -0
  84. package/src/context/compaction-prompts.js +170 -0
  85. package/src/context/compaction-utils.js +191 -0
  86. package/src/context/compressor.js +413 -0
  87. package/src/context/index.js +9 -0
  88. package/src/{core/context-manager.js → context/manager.js} +1 -1
  89. package/src/context/request.js +50 -0
  90. package/src/context/session.js +33 -0
  91. package/src/context/storage.js +30 -0
  92. package/src/executors/mcp-client.js +153 -0
  93. package/src/executors/mcp-desc.js +236 -0
  94. package/src/executors/mcp-executor.js +91 -956
  95. package/src/{core → framework}/command-registry.js +1 -1
  96. package/src/framework/framework.js +300 -0
  97. package/src/framework/index.js +18 -0
  98. package/src/framework/lifecycle.js +203 -0
  99. package/src/framework/loader.js +78 -0
  100. package/src/framework/registry.js +86 -0
  101. package/src/{core/ui-extension-context.js → framework/ui-extension.js} +1 -1
  102. package/src/index.js +130 -15
  103. package/src/llm/index.js +26 -0
  104. package/src/llm/provider.js +212 -0
  105. package/src/llm/registry.js +11 -0
  106. package/src/{core/token-counter.js → llm/tokens.js} +4 -37
  107. package/src/{core/plugin-base.js → plugin/base.js} +10 -136
  108. package/src/plugin/index.js +14 -0
  109. package/src/plugin/loader.js +101 -0
  110. package/src/plugin/manager.js +484 -0
  111. package/src/{core → session}/branch-summary-auto.js +2 -2
  112. package/src/{core/chat-session.js → session/chat.js} +2 -2
  113. package/src/session/index.js +7 -0
  114. package/src/{core/session-manager.js → session/session.js} +2 -2
  115. package/src/session/ttl.js +92 -0
  116. package/src/{core/jsonl-storage.js → storage/jsonl.js} +1 -1
  117. package/src/tool/executor.js +85 -0
  118. package/src/tool/index.js +15 -0
  119. package/src/tool/registry.js +143 -0
  120. package/src/{core/tool-router.js → tool/router.js} +17 -124
  121. package/src/tool/schema.js +108 -0
  122. package/src/utils/data-splitter.js +1 -1
  123. package/src/utils/download.js +1 -1
  124. package/src/utils/index.js +6 -6
  125. package/src/utils/message-validator.js +1 -1
  126. package/tests/core/context-storage.test.js +46 -0
  127. package/tests/core/llm.test.js +54 -0
  128. package/tests/core/plugin.test.js +42 -0
  129. package/tests/core/tool.test.js +60 -0
  130. package/tests/setup.js +10 -0
  131. package/tests/smoke.test.js +58 -0
  132. package/vitest.config.js +9 -0
  133. package/cli/src/daemon.js +0 -149
  134. package/docs/CONTEXT_DESIGN.md +0 -1596
  135. package/docs/ai-sdk-optimization.md +0 -655
  136. package/docs/features.md +0 -120
  137. package/docs/qq-bot.md +0 -976
  138. package/docs/quick-reference.md +0 -160
  139. package/docs/user-manual.md +0 -1391
  140. package/images/geometric_shapes.jpg +0 -0
  141. package/images/sunset_mountain_lake.jpg +0 -0
  142. package/skills/poster-guide/SKILL.md +0 -792
  143. package/src/capabilities/index.js +0 -11
  144. package/src/core/agent.js +0 -808
  145. package/src/core/context-compressor.js +0 -959
  146. package/src/core/enhanced-context-compressor.js +0 -210
  147. package/src/core/framework.js +0 -1422
  148. package/src/core/index.js +0 -30
  149. package/src/core/plugin-manager.js +0 -961
  150. package/src/core/provider-registry.js +0 -159
  151. package/src/core/provider.js +0 -156
  152. package/src/core/request-context.js +0 -98
  153. package/src/core/subagent.js +0 -442
  154. package/src/core/system-prompt-builder.js +0 -120
  155. package/src/core/tool-executor.js +0 -202
  156. package/src/core/tool-registry.js +0 -517
  157. package/src/core/worker-agent.js +0 -192
  158. package/src/executors/executor-base.js +0 -58
  159. package/src/utils/error-boundary.js +0 -363
  160. package/src/utils/error.js +0 -374
  161. package/system.md +0 -1645
  162. package/website_v2/README.md +0 -57
  163. package/website_v2/SPEC.md +0 -1
  164. package/website_v2/docs/api.html +0 -128
  165. package/website_v2/docs/configuration.html +0 -147
  166. package/website_v2/docs/plugin-development.html +0 -129
  167. package/website_v2/docs/project-structure.html +0 -89
  168. package/website_v2/docs/skill-development.html +0 -85
  169. package/website_v2/index.html +0 -489
  170. package/website_v2/scripts/main.js +0 -93
  171. package/website_v2/styles/animations.css +0 -8
  172. package/website_v2/styles/docs.css +0 -83
  173. package/website_v2/styles/main.css +0 -417
  174. package/xhs_auth.json +0 -268
  175. package//346/265/267/346/212/245/346/217/222/344/273/266.md +0 -621
  176. /package/plugins/{ambient-agent → ambient}/constants.js +0 -0
  177. /package/plugins/{email → messaging/email}/constants.js +0 -0
  178. /package/plugins/{email → messaging/email}/handlers.js +0 -0
  179. /package/plugins/{email → messaging/email}/monitor.js +0 -0
  180. /package/plugins/{email → messaging/email}/parser.js +0 -0
  181. /package/plugins/{email → messaging/email}/reply.js +0 -0
  182. /package/plugins/{email → messaging/email}/utils.js +0 -0
  183. /package/{examples → sandbox}/test-chat.js +0 -0
  184. /package/{examples → sandbox}/test-mcp.js +0 -0
  185. /package/{examples → sandbox}/test-reload.js +0 -0
  186. /package/{examples → sandbox}/test-telegram.js +0 -0
  187. /package/{examples → sandbox}/test-tg-bot.js +0 -0
  188. /package/{examples → sandbox}/test-tg-simple.js +0 -0
  189. /package/{examples → sandbox}/test-tg.js +0 -0
  190. /package/{examples → sandbox}/test-think.js +0 -0
  191. /package/src/{core/sub-agent-config.js → agent/sub-config.js} +0 -0
  192. /package/{cli/src → src/cli}/commands/daemon.js +0 -0
  193. /package/{cli/src → src/cli}/commands/list.js +0 -0
  194. /package/{cli/src → src/cli}/commands/plugin.js +0 -0
  195. /package/{cli/src → src/cli}/ui/components/agent-mention-provider.js +0 -0
  196. /package/{cli/src → src/cli}/ui/components/chained-autocomplete-provider.js +0 -0
  197. /package/{cli/src → src/cli}/ui/components/message-bubble.js +0 -0
  198. /package/{cli/src → src/cli}/ui/components/status-bar.js +0 -0
  199. /package/{cli/src → src/cli}/utils/ansi.js +0 -0
  200. /package/{cli/src → src/cli}/utils/config.js +0 -0
  201. /package/{cli/src → src/cli}/utils/markdown.js +0 -0
  202. /package/{cli/src → src/cli}/utils/plugin-config.js +0 -0
  203. /package/{cli/src → src/cli}/utils/render-diff.js +0 -0
  204. /package/src/{utils/circuit-breaker.js → common/circuit.js} +0 -0
  205. /package/src/{core → common}/constants.js +0 -0
  206. /package/src/{utils/edit-diff.js → common/diff.js} +0 -0
  207. /package/src/{utils/event-emitter.js → common/events.js} +0 -0
  208. /package/src/{utils → common}/id.js +0 -0
  209. /package/src/{utils → common}/retry.js +0 -0
  210. /package/src/{core/notification-manager.js → notification/manager.js} +0 -0
  211. /package/src/{core/session-entry.js → session/entry.js} +0 -0
  212. /package/src/{core/storage-manager.js → storage/manager.js} +0 -0
@@ -1,94 +1,42 @@
1
+ 'use strict';
2
+
1
3
  /**
2
4
  * Plugin 基类
3
5
  * 所有插件的基类
4
6
  */
5
7
 
8
+ const { logger } = require('../common/logger');
9
+ const log = logger.child('plugin');
10
+
6
11
  class Plugin {
7
- /**
8
- * 插件名称
9
- * @type {string}
10
- */
11
12
  name = 'unnamed-plugin';
12
-
13
- /**
14
- * 插件版本
15
- * @type {string}
16
- */
17
13
  version = '1.0.0';
18
-
19
- /**
20
- * 插件描述
21
- * @type {string}
22
- */
23
14
  description = '';
24
-
25
- /**
26
- * 插件优先级,数值越小越先加载
27
- * @type {number}
28
- */
29
15
  priority = 100;
30
16
 
31
- /**
32
- * 子Agent配置数组 - 配置后自动注册子Agent
33
- * 格式: [{ name: 'xxx', role: '角色', tools: {...}, parentTools: [...] }]
34
- * @type {Array}
35
- */
36
17
  agents = [];
37
-
38
- /**
39
- * 插件是否启用,默认为 true
40
- * 设置为 false 时插件不会被加载,但在列表中仍可见
41
- * @type {boolean}
42
- */
43
18
  enabled = true;
44
-
45
- /**
46
- * 是否为系统插件,默认为 false
47
- * 系统插件不能被禁用,始终启用
48
- * @type {boolean}
49
- */
50
19
  system = false;
51
20
 
52
21
  _framework = null;
53
22
  _subAgents = [];
54
- _promptParts = []; // 注册的提示词部分
55
- _deferredPromptParts = null; // 延迟注册的提示词部分(等待主 agent 创建)
56
-
57
- /**
58
- * 插件注册的工具集(供 ExtensionExecutor 自动加载)
59
- * 格式: { toolName: { name, description, inputSchema, execute } }
60
- * @type {Object}
61
- */
23
+ _promptParts = [];
24
+ _deferredPromptParts = null;
62
25
  tools = {};
63
26
 
64
- /**
65
- * 安装插件 - 注册工具/事件等
66
- * @param {Framework} framework - 框架实例
67
- */
68
27
  install(framework) {
69
28
  this._framework = framework;
70
29
  return this;
71
30
  }
72
31
 
73
- /**
74
- * 注册工具到扩展执行器(供 ExtensionExecutor 统一管理)
75
- * 支持三种调用方式:
76
- * this.registerTool('name', { description, inputSchema, execute })
77
- * this.registerTool({ name, description, inputSchema, execute })
78
- * this.registerTool({ name, description, inputSchema, execute, pluginName: 'xxx' })
79
- * @param {string|Object} name - 工具名称或工具定义对象
80
- * @param {Object} [def] - 工具定义 { description, inputSchema, execute }
81
- */
82
32
  registerTool(name, def) {
83
33
  if (!this._framework) return;
84
- // 支持 this.registerTool({ name, description, ... }) 形式
85
34
  if (typeof name === 'object' && name !== null) {
86
35
  def = name;
87
36
  name = def.name;
88
37
  }
89
38
  if (!name || !def) return;
90
39
 
91
- // 支持自定义插件名
92
40
  const pluginName = def.pluginName || this.name;
93
41
  delete def.pluginName;
94
42
 
@@ -106,39 +54,25 @@ class Plugin {
106
54
  }
107
55
  }
108
56
 
109
- /**
110
- * 启动插件 - 初始化完成后的启动
111
- * @param {Framework} framework - 框架实例
112
- */
113
57
  start(framework) {
114
- // 自动注册配置的子Agent
115
58
  this._autoRegisterSubAgents();
116
59
  return this;
117
60
  }
118
61
 
119
- /**
120
- * 自动注册子Agent(根据 this.agents 配置)
121
- * @private
122
- */
123
62
  _autoRegisterSubAgents() {
124
- // 确定要注册的agent配置
125
63
  const agentsToRegister = this._deferredSubAgents || this.agents;
126
64
  if (!agentsToRegister || !Array.isArray(agentsToRegister) || agentsToRegister.length === 0) {
127
65
  return;
128
66
  }
129
67
 
130
- // 获取父Agent
131
68
  const parentAgent = this._getParentAgent();
132
69
 
133
70
  if (!parentAgent) {
134
- // 没有父Agent,推迟到框架准备好时再注册
135
71
  if (!this._deferredSubAgents) {
136
72
  log.debug(` No parent agent found, deferring subagent registration`);
137
73
  this._deferredSubAgents = agentsToRegister;
138
- // 监听框架准备好事件
139
74
  if (this._framework) {
140
75
  this._framework.once('framework:ready', () => {
141
- // 延迟注册,确保主Agent已创建
142
76
  setTimeout(() => this._autoRegisterSubAgents(), 100);
143
77
  });
144
78
  }
@@ -146,7 +80,6 @@ class Plugin {
146
80
  return;
147
81
  }
148
82
 
149
- // 有父Agent了,清除延迟标记
150
83
  this._deferredSubAgents = null;
151
84
 
152
85
  for (const agentConfig of agentsToRegister) {
@@ -159,10 +92,6 @@ class Plugin {
159
92
  }
160
93
  }
161
94
 
162
- /**
163
- * 获取父Agent
164
- * @private
165
- */
166
95
  _getParentAgent() {
167
96
  if (!this._framework) return null;
168
97
  if (this._framework._mainAgent) return this._framework._mainAgent;
@@ -170,29 +99,17 @@ class Plugin {
170
99
  return agents.length > 0 ? agents[agents.length - 1] : null;
171
100
  }
172
101
 
173
- /**
174
- * 注册子Agent
175
- * @param {Object} config - 子Agent配置
176
- * @param {string} config.name - 子Agent名称
177
- * @param {string} config.role - 子Agent角色
178
- * @param {string} [config.description] - 子Agent描述
179
- * @param {Object} [config.tools] - 自定义工具 { name: toolDef }
180
- * @param {string[]} [config.parentTools] - 从父Agent继承的工具名称
181
- * @returns {Object} 注册的子Agent信息
182
- */
183
102
  registerSubAgent(config) {
184
103
  if (!this._framework) {
185
104
  throw new Error('Plugin not installed, call install(framework) first');
186
105
  }
187
106
 
188
- // 获取 subagent-manager 插件
189
107
  const subAgentManager = this._framework.pluginManager.get('subagent-manager');
190
108
 
191
109
  if (!subAgentManager) {
192
110
  throw new Error('subagent-manager plugin not found');
193
111
  }
194
112
 
195
- // 创建子Agent实例
196
113
  const agent = this._framework.createSubAgent({
197
114
  name: config.name,
198
115
  role: config.role,
@@ -201,7 +118,6 @@ class Plugin {
201
118
  parentTools: config.parentTools || [],
202
119
  });
203
120
 
204
- // 注册到 subagent-manager
205
121
  subAgentManager.registerPlugin({
206
122
  name: config.name,
207
123
  role: config.role,
@@ -210,28 +126,21 @@ class Plugin {
210
126
  tools: config.tools || {},
211
127
  });
212
128
 
213
- // 保存引用以便后续清理
214
129
  this._subAgents.push({
215
130
  name: config.name,
216
131
  agent,
217
- plugin: null, // 兼容旧代码
132
+ plugin: null,
218
133
  });
219
134
 
220
135
  log.debug(` Registered subagent: ${config.name}`);
221
136
  return { name: config.name, agent };
222
137
  }
223
138
 
224
- /**
225
- * 热重载插件 - 手动调用重载时执行
226
- * @param {Framework} framework - 框架实例
227
- */
228
139
  reload(framework) {
229
140
  this._framework = framework;
230
- // 清除之前的延迟注册
231
141
  this._deferredSubAgents = null;
232
142
  this._deferredPromptParts = null;
233
143
 
234
- // 重新注册提示词部分
235
144
  for (const part of this._promptParts) {
236
145
  try {
237
146
  framework._mainAgent?.registerPromptPart(part.name, part.priority, part.provider);
@@ -240,38 +149,24 @@ class Plugin {
240
149
  }
241
150
  }
242
151
 
243
- // 重新注册子Agent
244
152
  this._autoRegisterSubAgents();
245
153
  }
246
154
 
247
- /**
248
- * 工作目录变更钩子 — 框架级 cwd 切换时由 Framework.setCwd 调用
249
- * 子类可重写以重新加载 cwd 相关的资源(路径、文件句柄等)
250
- * @param {string} oldCwd
251
- * @param {string} newCwd
252
- * @param {Framework} framework
253
- */
254
155
  onCwdChanged(oldCwd, newCwd, framework) {
255
- // 默认 no-op
156
+ // default no-op
256
157
  }
257
158
 
258
- /**
259
- * 卸载插件 - 清理资源
260
- * @param {Framework} framework - 框架实例
261
- */
262
159
  uninstall(framework) {
263
- // 注销所有提示词部分
264
160
  for (const part of this._promptParts) {
265
161
  try {
266
162
  framework._mainAgent?.unregisterPromptPart(part.name);
267
163
  } catch (err) {
268
- // 忽略
164
+ // ignore
269
165
  }
270
166
  }
271
167
  this._promptParts = [];
272
168
  this._deferredPromptParts = null;
273
169
 
274
- // 销毁所有子Agent
275
170
  for (const plugin of this._subAgents) {
276
171
  try {
277
172
  plugin.uninstall(framework);
@@ -283,38 +178,25 @@ class Plugin {
283
178
  this._framework = null;
284
179
  }
285
180
 
286
- /**
287
- * 注册系统提示词部分
288
- * 插件可以在 install() 或 start() 中调用此方法注册自己的提示词
289
- * @param {string} name - 部分名称(唯一标识)
290
- * @param {number} [priority=100] - 优先级,数值越小越靠前
291
- * @param {Function} provider - 返回提示词内容的函数,签名: () => string
292
- */
293
181
  registerPromptPart(name, priority = 100, provider) {
294
182
  if (!this._framework) return;
295
183
 
296
- // 保存记录
297
184
  this._promptParts.push({ name, priority, provider });
298
185
 
299
- // 如果主 agent 已存在,直接注册
300
186
  const mainAgent = this._framework.getMainAgent();
301
187
  if (mainAgent) {
302
188
  mainAgent.registerPromptPart(name, priority, provider);
303
- // 同步到所有子Agent
304
189
  this._framework.syncPromptPartsToSubagents();
305
190
  return;
306
191
  }
307
192
 
308
- // 否则延迟注册,等待框架准备好
309
193
  if (!this._deferredPromptParts) {
310
194
  this._deferredPromptParts = [];
311
195
  }
312
196
  this._deferredPromptParts.push({ name, priority, provider });
313
197
 
314
- // 监听框架准备好事件
315
198
  const alreadyListening = this._framework._events?.['framework:ready']?.length > 0;
316
199
  this._framework.once('framework:ready', () => {
317
- // 延迟确保主 agent 已创建
318
200
  setTimeout(() => {
319
201
  if (this._deferredPromptParts) {
320
202
  for (const part of this._deferredPromptParts) {
@@ -326,17 +208,12 @@ class Plugin {
326
208
  }
327
209
  }
328
210
  this._deferredPromptParts = null;
329
- // 同步到所有子Agent
330
211
  this._framework.syncPromptPartsToSubagents();
331
212
  }
332
213
  }, 100);
333
214
  });
334
215
  }
335
216
 
336
- /**
337
- * 获取插件信息
338
- * @returns {Object}
339
- */
340
217
  getInfo() {
341
218
  return {
342
219
  name: this.name,
@@ -347,9 +224,6 @@ class Plugin {
347
224
  }
348
225
  }
349
226
 
350
- /**
351
- * 内置插件类型常量
352
- */
353
227
  const PluginType = {
354
228
  AI: 'ai',
355
229
  TOOLS: 'tools',
@@ -0,0 +1,14 @@
1
+ 'use strict';
2
+
3
+ const { Plugin, PluginType } = require('./base');
4
+ const { PluginManager } = require('./manager');
5
+ const { resolvePluginPath, scanPluginNames, loadPluginFromPath } = require('./loader');
6
+
7
+ module.exports = {
8
+ Plugin,
9
+ PluginType,
10
+ PluginManager,
11
+ resolvePluginPath,
12
+ scanPluginNames,
13
+ loadPluginFromPath,
14
+ };
@@ -0,0 +1,101 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Plugin Loader - 加载插件配置与路径解析
5
+ */
6
+
7
+ const path = require('path');
8
+ const fs = require('fs');
9
+ const { logger } = require('../common/logger');
10
+ const log = logger.child('plugin-loader');
11
+
12
+ /**
13
+ * Resolve plugin path from name
14
+ * @param {string} pluginName
15
+ * @param {Object} options
16
+ * @returns {string|null}
17
+ */
18
+ function resolvePluginPath(pluginName, options = {}) {
19
+ const { pluginDirs = [], searchPaths = [] } = options;
20
+
21
+ // Check explicit paths first
22
+ const allPaths = [...pluginDirs, ...searchPaths];
23
+ for (const dir of allPaths) {
24
+ const fullPath = path.resolve(dir, pluginName);
25
+ if (fs.existsSync(fullPath)) {
26
+ return fullPath;
27
+ }
28
+ const indexJs = path.join(fullPath, 'index.js');
29
+ if (fs.existsSync(indexJs)) {
30
+ return fullPath;
31
+ }
32
+ }
33
+
34
+ // Check node_modules
35
+ try {
36
+ const resolved = require.resolve(pluginName);
37
+ return resolved;
38
+ } catch {
39
+ return null;
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Scan directory for plugin names
45
+ * @param {string} dir
46
+ * @returns {string[]}
47
+ */
48
+ function scanPluginNames(dir) {
49
+ if (!fs.existsSync(dir)) return [];
50
+
51
+ try {
52
+ return fs.readdirSync(dir)
53
+ .filter(f => {
54
+ const fullPath = path.join(dir, f);
55
+ const stat = fs.statSync(fullPath);
56
+ if (stat.isDirectory()) {
57
+ return fs.existsSync(path.join(fullPath, 'index.js'));
58
+ }
59
+ return f.endsWith('.js');
60
+ })
61
+ .map(f => f.replace(/\.js$/, ''));
62
+ } catch (err) {
63
+ log.warn(`Failed to scan plugin directory ${dir}: ${err.message}`);
64
+ return [];
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Load a plugin from a file path
70
+ * @param {string} pluginPath
71
+ * @returns {Object|null} Plugin instance
72
+ */
73
+ function loadPluginFromPath(pluginPath) {
74
+ try {
75
+ const resolved = require.resolve(pluginPath);
76
+ const module = require(resolved);
77
+
78
+ // Handle both direct export and { Plugin } export
79
+ const PluginClass = module.Plugin || module.default || module;
80
+ if (typeof PluginClass === 'function') {
81
+ const instance = new PluginClass();
82
+ instance.sourcePath = resolved;
83
+ return instance;
84
+ }
85
+ // If already an instance
86
+ if (PluginClass.name && PluginClass.install) {
87
+ PluginClass.sourcePath = resolved;
88
+ return PluginClass;
89
+ }
90
+ return null;
91
+ } catch (err) {
92
+ log.warn(`Failed to load plugin from ${pluginPath}: ${err.message}`);
93
+ return null;
94
+ }
95
+ }
96
+
97
+ module.exports = {
98
+ resolvePluginPath,
99
+ scanPluginNames,
100
+ loadPluginFromPath,
101
+ };