foliko 1.0.80 → 1.0.81

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 (235) hide show
  1. package/.agent/agents/code-assistant.json +14 -0
  2. package/.agent/agents/email-assistant.json +14 -0
  3. package/.agent/agents/file-assistant.json +15 -0
  4. package/.agent/agents/system-assistant.json +15 -0
  5. package/.agent/agents/web-assistant.json +12 -0
  6. package/.agent/data/ambient/goals.json +50 -0
  7. package/.agent/data/ambient/memories.json +7 -0
  8. package/.agent/data/default.json +15 -31894
  9. package/.agent/data/plugins-state.json +146 -181
  10. package/.agent/data/scheduler/tasks.json +1 -0
  11. package/.agent/mcp_config.json +1 -0
  12. package/.agent/package.json +8 -0
  13. package/.agent/plugins/__pycache__/test_plugin.cpython-312.pyc +0 -0
  14. package/.agent/plugins/system-info/index.js +387 -0
  15. package/.agent/plugins/system-info/package.json +4 -0
  16. package/.agent/plugins/system-info/test.js +40 -0
  17. package/.agent/plugins/test_plugin.py +304 -0
  18. package/.agent/plugins.json +14 -5
  19. package/.agent/python-scripts/test_sample.py +24 -0
  20. package/.agent/skills/sysinfo/SKILL.md +38 -0
  21. package/.agent/skills/sysinfo/system-info.sh +130 -0
  22. package/.agent/skills/workflow/SKILL.md +324 -0
  23. package/.agent/workflows/email-digest.json +50 -0
  24. package/.agent/workflows/file-backup.json +21 -0
  25. package/.agent/workflows/get-ip-notify.json +32 -0
  26. package/.agent/workflows/news-aggregator.json +93 -0
  27. package/.agent/workflows/news-dashboard-v2.json +94 -0
  28. package/.agent/workflows/notification-batch.json +32 -0
  29. package/.claude/settings.local.json +171 -171
  30. package/.env.example +56 -56
  31. package/cli/bin/foliko.js +12 -12
  32. package/cli/src/commands/chat.js +143 -143
  33. package/cli/src/commands/list.js +93 -93
  34. package/cli/src/index.js +75 -75
  35. package/cli/src/ui/chat-ui.js +201 -201
  36. package/cli/src/utils/ansi.js +40 -40
  37. package/cli/src/utils/markdown.js +292 -292
  38. package/examples/ambient-example.js +194 -194
  39. package/examples/basic.js +115 -115
  40. package/examples/bootstrap.js +121 -121
  41. package/examples/mcp-example.js +56 -56
  42. package/examples/skill-example.js +49 -49
  43. package/examples/test-chat.js +137 -137
  44. package/examples/test-mcp.js +85 -85
  45. package/examples/test-reload.js +59 -59
  46. package/examples/test-telegram.js +50 -50
  47. package/examples/test-tg-bot.js +45 -45
  48. package/examples/test-tg-simple.js +47 -47
  49. package/examples/test-tg.js +62 -62
  50. package/examples/test-think.js +43 -43
  51. package/examples/test-web-plugin.js +103 -103
  52. package/examples/test-weixin-feishu.js +103 -103
  53. package/examples/workflow.js +158 -158
  54. package/package.json +83 -83
  55. package/plugins/ai-plugin.js +102 -102
  56. package/plugins/ambient-agent/EventWatcher.js +113 -113
  57. package/plugins/ambient-agent/ExplorerLoop.js +640 -640
  58. package/plugins/ambient-agent/GoalManager.js +197 -197
  59. package/plugins/ambient-agent/Reflector.js +95 -95
  60. package/plugins/ambient-agent/StateStore.js +90 -90
  61. package/plugins/ambient-agent/constants.js +101 -101
  62. package/plugins/ambient-agent/index.js +579 -579
  63. package/plugins/audit-plugin.js +187 -187
  64. package/plugins/default-plugins.js +548 -548
  65. package/plugins/email/constants.js +64 -64
  66. package/plugins/email/handlers.js +461 -461
  67. package/plugins/email/index.js +278 -278
  68. package/plugins/email/monitor.js +269 -269
  69. package/plugins/email/parser.js +138 -138
  70. package/plugins/email/reply.js +151 -151
  71. package/plugins/email/utils.js +124 -124
  72. package/plugins/extension-executor-plugin.js +326 -326
  73. package/plugins/feishu-plugin.js +481 -481
  74. package/plugins/file-system-plugin.js +920 -877
  75. package/plugins/gate-trading.js +747 -747
  76. package/plugins/install-plugin.js +199 -199
  77. package/plugins/python-executor-plugin.js +367 -367
  78. package/plugins/python-plugin-loader.js +651 -651
  79. package/plugins/rules-plugin.js +294 -294
  80. package/plugins/scheduler-plugin.js +691 -691
  81. package/plugins/session-plugin.js +494 -494
  82. package/plugins/shell-executor-plugin.js +197 -197
  83. package/plugins/storage-plugin.js +263 -263
  84. package/plugins/subagent-plugin.js +845 -845
  85. package/plugins/telegram-plugin.js +482 -482
  86. package/plugins/think-plugin.js +345 -345
  87. package/plugins/tools-plugin.js +196 -196
  88. package/plugins/web-plugin.js +637 -637
  89. package/plugins/weixin-plugin.js +545 -545
  90. package/skills/find-skills/AGENTS.md +162 -162
  91. package/skills/find-skills/SKILL.md +133 -133
  92. package/skills/foliko-dev/SKILL.md +563 -583
  93. package/skills/python-plugin-dev/SKILL.md +238 -238
  94. package/src/capabilities/index.js +11 -11
  95. package/src/capabilities/skill-manager.js +609 -609
  96. package/src/capabilities/workflow-engine.js +1109 -1109
  97. package/src/core/agent-chat.js +141 -134
  98. package/src/core/agent.js +958 -958
  99. package/src/core/framework.js +465 -465
  100. package/src/core/index.js +19 -19
  101. package/src/core/plugin-base.js +262 -262
  102. package/src/core/plugin-manager.js +863 -863
  103. package/src/core/provider.js +114 -114
  104. package/src/core/sub-agent-config.js +264 -264
  105. package/src/core/system-prompt-builder.js +120 -120
  106. package/src/core/tool-registry.js +517 -517
  107. package/src/core/tool-router.js +297 -297
  108. package/src/executors/executor-base.js +58 -58
  109. package/src/executors/mcp-executor.js +845 -845
  110. package/src/index.js +25 -25
  111. package/src/utils/circuit-breaker.js +301 -301
  112. package/src/utils/error-boundary.js +363 -363
  113. package/src/utils/error.js +374 -374
  114. package/src/utils/event-emitter.js +97 -97
  115. package/src/utils/id.js +133 -133
  116. package/src/utils/index.js +217 -217
  117. package/src/utils/logger.js +181 -181
  118. package/src/utils/plugin-helpers.js +90 -90
  119. package/src/utils/retry.js +122 -122
  120. package/src/utils/sandbox.js +292 -292
  121. package/test/tool-registry-validation.test.js +218 -218
  122. package/website/script.js +136 -136
  123. package/.agent/.shared/ui-ux-pro-max/data/charts.csv +0 -26
  124. package/.agent/.shared/ui-ux-pro-max/data/colors.csv +0 -97
  125. package/.agent/.shared/ui-ux-pro-max/data/icons.csv +0 -101
  126. package/.agent/.shared/ui-ux-pro-max/data/landing.csv +0 -31
  127. package/.agent/.shared/ui-ux-pro-max/data/products.csv +0 -97
  128. package/.agent/.shared/ui-ux-pro-max/data/prompts.csv +0 -24
  129. package/.agent/.shared/ui-ux-pro-max/data/react-performance.csv +0 -45
  130. package/.agent/.shared/ui-ux-pro-max/data/stacks/flutter.csv +0 -53
  131. package/.agent/.shared/ui-ux-pro-max/data/stacks/html-tailwind.csv +0 -56
  132. package/.agent/.shared/ui-ux-pro-max/data/stacks/jetpack-compose.csv +0 -53
  133. package/.agent/.shared/ui-ux-pro-max/data/stacks/nextjs.csv +0 -53
  134. package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxt-ui.csv +0 -51
  135. package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxtjs.csv +0 -59
  136. package/.agent/.shared/ui-ux-pro-max/data/stacks/react-native.csv +0 -52
  137. package/.agent/.shared/ui-ux-pro-max/data/stacks/react.csv +0 -54
  138. package/.agent/.shared/ui-ux-pro-max/data/stacks/shadcn.csv +0 -61
  139. package/.agent/.shared/ui-ux-pro-max/data/stacks/svelte.csv +0 -54
  140. package/.agent/.shared/ui-ux-pro-max/data/stacks/swiftui.csv +0 -51
  141. package/.agent/.shared/ui-ux-pro-max/data/stacks/vue.csv +0 -50
  142. package/.agent/.shared/ui-ux-pro-max/data/styles.csv +0 -59
  143. package/.agent/.shared/ui-ux-pro-max/data/typography.csv +0 -58
  144. package/.agent/.shared/ui-ux-pro-max/data/ui-reasoning.csv +0 -101
  145. package/.agent/.shared/ui-ux-pro-max/data/ux-guidelines.csv +0 -100
  146. package/.agent/.shared/ui-ux-pro-max/data/web-interface.csv +0 -31
  147. package/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/core.cpython-313.pyc +0 -0
  148. package/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-313.pyc +0 -0
  149. package/.agent/.shared/ui-ux-pro-max/scripts/core.py +0 -258
  150. package/.agent/.shared/ui-ux-pro-max/scripts/design_system.py +0 -1067
  151. package/.agent/.shared/ui-ux-pro-max/scripts/search.py +0 -106
  152. package/.agent/ARCHITECTURE.md +0 -288
  153. package/.agent/agents/ambient-agent.md +0 -57
  154. package/.agent/agents/debugger.md +0 -55
  155. package/.agent/agents/email-assistant.md +0 -49
  156. package/.agent/agents/file-manager.md +0 -42
  157. package/.agent/agents/python-developer.md +0 -60
  158. package/.agent/agents/scheduler.md +0 -59
  159. package/.agent/agents/web-developer.md +0 -45
  160. package/.agent/mcp_config_updated.json +0 -12
  161. package/.agent/rules/GEMINI.md +0 -273
  162. package/.agent/rules/allow-rule.md +0 -77
  163. package/.agent/rules/log-rule.md +0 -83
  164. package/.agent/rules/security-rule.md +0 -93
  165. package/.agent/scripts/auto_preview.py +0 -148
  166. package/.agent/scripts/checklist.py +0 -217
  167. package/.agent/scripts/session_manager.py +0 -120
  168. package/.agent/scripts/verify_all.py +0 -327
  169. package/.agent/skills/api-patterns/SKILL.md +0 -81
  170. package/.agent/skills/api-patterns/api-style.md +0 -42
  171. package/.agent/skills/api-patterns/auth.md +0 -24
  172. package/.agent/skills/api-patterns/documentation.md +0 -26
  173. package/.agent/skills/api-patterns/graphql.md +0 -41
  174. package/.agent/skills/api-patterns/rate-limiting.md +0 -31
  175. package/.agent/skills/api-patterns/response.md +0 -37
  176. package/.agent/skills/api-patterns/rest.md +0 -40
  177. package/.agent/skills/api-patterns/scripts/api_validator.py +0 -211
  178. package/.agent/skills/api-patterns/security-testing.md +0 -122
  179. package/.agent/skills/api-patterns/trpc.md +0 -41
  180. package/.agent/skills/api-patterns/versioning.md +0 -22
  181. package/.agent/skills/app-builder/SKILL.md +0 -75
  182. package/.agent/skills/app-builder/agent-coordination.md +0 -71
  183. package/.agent/skills/app-builder/feature-building.md +0 -53
  184. package/.agent/skills/app-builder/project-detection.md +0 -34
  185. package/.agent/skills/app-builder/scaffolding.md +0 -118
  186. package/.agent/skills/app-builder/tech-stack.md +0 -40
  187. package/.agent/skills/app-builder/templates/SKILL.md +0 -39
  188. package/.agent/skills/app-builder/templates/astro-static/TEMPLATE.md +0 -76
  189. package/.agent/skills/app-builder/templates/chrome-extension/TEMPLATE.md +0 -92
  190. package/.agent/skills/app-builder/templates/cli-tool/TEMPLATE.md +0 -88
  191. package/.agent/skills/app-builder/templates/electron-desktop/TEMPLATE.md +0 -88
  192. package/.agent/skills/app-builder/templates/express-api/TEMPLATE.md +0 -83
  193. package/.agent/skills/app-builder/templates/flutter-app/TEMPLATE.md +0 -90
  194. package/.agent/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +0 -90
  195. package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +0 -122
  196. package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +0 -122
  197. package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +0 -169
  198. package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +0 -134
  199. package/.agent/skills/app-builder/templates/python-fastapi/TEMPLATE.md +0 -83
  200. package/.agent/skills/app-builder/templates/react-native-app/TEMPLATE.md +0 -119
  201. package/.agent/skills/architecture/SKILL.md +0 -55
  202. package/.agent/skills/architecture/context-discovery.md +0 -43
  203. package/.agent/skills/architecture/examples.md +0 -94
  204. package/.agent/skills/architecture/pattern-selection.md +0 -68
  205. package/.agent/skills/architecture/patterns-reference.md +0 -50
  206. package/.agent/skills/architecture/trade-off-analysis.md +0 -77
  207. package/.agent/skills/clean-code/SKILL.md +0 -201
  208. package/.agent/skills/doc.md +0 -177
  209. package/.agent/skills/frontend-design/SKILL.md +0 -418
  210. package/.agent/skills/frontend-design/animation-guide.md +0 -331
  211. package/.agent/skills/frontend-design/color-system.md +0 -311
  212. package/.agent/skills/frontend-design/decision-trees.md +0 -418
  213. package/.agent/skills/frontend-design/motion-graphics.md +0 -306
  214. package/.agent/skills/frontend-design/scripts/accessibility_checker.py +0 -183
  215. package/.agent/skills/frontend-design/scripts/ux_audit.py +0 -722
  216. package/.agent/skills/frontend-design/typography-system.md +0 -345
  217. package/.agent/skills/frontend-design/ux-psychology.md +0 -1116
  218. package/.agent/skills/frontend-design/visual-effects.md +0 -383
  219. package/.agent/skills/i18n-localization/SKILL.md +0 -154
  220. package/.agent/skills/i18n-localization/scripts/i18n_checker.py +0 -241
  221. package/.agent/skills/mcp-builder/SKILL.md +0 -176
  222. package/.agent/skills/web-design-guidelines/SKILL.md +0 -57
  223. package/.agent/workflows/brainstorm.md +0 -113
  224. package/.agent/workflows/create.md +0 -59
  225. package/.agent/workflows/debug.md +0 -103
  226. package/.agent/workflows/deploy.md +0 -176
  227. package/.agent/workflows/enhance.md +0 -63
  228. package/.agent/workflows/orchestrate.md +0 -237
  229. package/.agent/workflows/plan.md +0 -89
  230. package/.agent/workflows/preview.md +0 -81
  231. package/.agent/workflows/simple-test.md +0 -42
  232. package/.agent/workflows/status.md +0 -86
  233. package/.agent/workflows/structured-orchestrate.md +0 -180
  234. package/.agent/workflows/test.md +0 -144
  235. package/.agent/workflows/ui-ux-pro-max.md +0 -296
@@ -1,548 +1,548 @@
1
- /**
2
- * 默认插件配置加载器
3
- * 检测 .agent/ 目录下的配置,提供给 bootstrap() 使用
4
- */
5
-
6
- const fs = require('fs')
7
- const path = require('path')
8
- const { Plugin } = require('../src/core/plugin-base')
9
- const { logger } = require('../src/utils/logger')
10
- const log = logger.child('AgentConfig')
11
- const bootstrapLog = logger.child('Bootstrap')
12
-
13
- /**
14
- * 加载 .agent 目录下的配置
15
- * 返回配置对象,可用于手动加载插件
16
- */
17
- function loadAgentConfig(agentDir = '.agent') {
18
- const config = {
19
- agentDir,
20
- ai: {},
21
- mcpServers: {},
22
- plugins: [],
23
- skillsDirs: [],
24
- agentsDir: null // 子Agent配置目录
25
- }
26
- const cmdDir=path.resolve(process.cwd())
27
- const resolvedDir = path.resolve(process.cwd(), agentDir)
28
-
29
- if (!fs.existsSync(resolvedDir)) {
30
- log.info(` .agent directory not found: ${resolvedDir}`)
31
- return config
32
- }
33
-
34
- log.info(` Loading config from: ${resolvedDir}`)
35
-
36
- // 添加 agents 目录(如果存在)
37
- const agentsDir = path.join(resolvedDir, 'agents')
38
- if (fs.existsSync(agentsDir)) {
39
- config.agentsDir = agentsDir
40
- log.info(` Found agents directory: ${agentsDir}`)
41
- }
42
-
43
- // 加载 config 文件(key=value 格式)
44
- const configFile = path.join(resolvedDir, 'config')
45
- if (fs.existsSync(configFile)) {
46
- try {
47
- const lines = fs.readFileSync(configFile, 'utf-8').split('\n')
48
- for (const line of lines) {
49
- const trimmed = line.trim()
50
- if (!trimmed || trimmed.startsWith('#')) continue
51
-
52
- const colonIndex = trimmed.indexOf(':')
53
- if (colonIndex === -1) continue
54
-
55
- const key = trimmed.substring(0, colonIndex).trim()
56
- const value = trimmed.substring(colonIndex + 1).trim()
57
-
58
- if (key === 'ai_key' || key === 'api_key') {
59
- config.ai.apiKey = value
60
- } else if (key === 'ai_model' || key === 'model') {
61
- config.ai.model = value
62
- } else if (key === 'ai_provider' || key === 'provider') {
63
- config.ai.provider = value
64
- } else if (key === 'ai_base_url' || key === 'baseURL') {
65
- config.ai.baseURL = value
66
- }
67
- }
68
- } catch (err) {
69
- log.error(` Failed to load config:`, err.message)
70
- }
71
- }
72
-
73
- // 加载 ai.json
74
- const aiFile = path.join(resolvedDir, 'ai.json')
75
- if (fs.existsSync(aiFile)) {
76
- try {
77
- const content = fs.readFileSync(aiFile, 'utf-8')
78
- const aiConfig = JSON.parse(content)
79
- config.ai = { ...config.ai, ...aiConfig }
80
- } catch (err) {
81
- log.error(` Failed to load ai.json:`, err.message)
82
- }
83
- }
84
-
85
- // 加载 plugins.json (支持 telegram, weixin, email 等插件配置)
86
- const pluginsFile = path.join(resolvedDir, 'plugins.json')
87
- if (fs.existsSync(pluginsFile)) {
88
- try {
89
- const content = fs.readFileSync(pluginsFile, 'utf-8')
90
- const pluginsConfig = JSON.parse(content)
91
- // telegram 配置
92
- if (pluginsConfig.telegram) {
93
- config.telegram = pluginsConfig.telegram
94
- }
95
- // weixin 配置
96
- if (pluginsConfig.weixin) {
97
- config.weixin = pluginsConfig.weixin
98
- }
99
- // email 配置
100
- if (pluginsConfig.email) {
101
- config.email = pluginsConfig.email
102
- }
103
- } catch (err) {
104
- log.error(` Failed to load plugins.json:`, err.message)
105
- }
106
- }
107
-
108
- // 加载 weixin.json (如果存在)
109
- const weixinFile = path.join(resolvedDir, 'weixin.json')
110
- if (fs.existsSync(weixinFile)) {
111
- try {
112
- const content = fs.readFileSync(weixinFile, 'utf-8')
113
- config.weixin = { ...config.weixin, ...JSON.parse(content) }
114
- } catch (err) {
115
- log.error(` Failed to load weixin.json:`, err.message)
116
- }
117
- }
118
-
119
- // 加载 mcp_config.json
120
- const mcpFile = path.join(resolvedDir, 'mcp_config.json')
121
- if (fs.existsSync(mcpFile)) {
122
- try {
123
- const content = fs.readFileSync(mcpFile, 'utf-8')
124
- const mcpConfig = JSON.parse(content)
125
- config.mcpServers = mcpConfig.mcpServers || {}
126
- } catch (err) {
127
- log.error(` Failed to load mcp_config.json:`, err.message)
128
- }
129
- }
130
-
131
- // 添加 .agent/skills 目录(不存在则创建)
132
- const skillsDir = path.join(resolvedDir, 'skills')
133
- if (fs.existsSync(resolvedDir) && !fs.existsSync(skillsDir)) {
134
- fs.mkdirSync(skillsDir, { recursive: true })
135
- log.info(` Created skills directory: ${skillsDir}`)
136
- }
137
- if (fs.existsSync(skillsDir)) {
138
- config.skillsDirs.push(skillsDir)
139
- }
140
-
141
- // 添加 .agent/skills 目录(不存在则创建)
142
- const cmdskillsDir = path.join(cmdDir, 'skills')
143
- if (fs.existsSync(resolvedDir) && !fs.existsSync(cmdskillsDir)) {
144
- fs.mkdirSync(cmdskillsDir, { recursive: true })
145
- log.info(` Created skills directory: ${cmdskillsDir}`)
146
- }
147
- if (fs.existsSync(cmdskillsDir)) {
148
- config.skillsDirs.push(cmdskillsDir)
149
- }
150
-
151
- // 添加 agentDir 父目录的 skills/ 目录
152
- const parentDir = path.dirname(__dirname)
153
- const rootSkillsDir = path.join(parentDir, 'skills')
154
- if (fs.existsSync(rootSkillsDir)) {
155
- config.skillsDirs.push(rootSkillsDir)
156
- }
157
-
158
- // const defaultSkillsDir = path.join(process.cwd(), 'defaultSkills')
159
- // if (fs.existsSync(defaultSkillsDir)) {
160
- // config.skillsDirs.push(defaultSkillsDir)
161
- // }
162
-
163
- return config
164
- }
165
-
166
- /**
167
- * DefaultPlugins - 默认插件配置加载器
168
- */
169
- class DefaultPlugins extends Plugin {
170
- constructor(config = {}) {
171
- super()
172
- this.name = 'defaults'
173
- this.version = '1.0.0'
174
- this.description = '默认插件配置加载器'
175
- this.priority = 0 // 最先加载
176
- this.system = true
177
-
178
- this._framework = null
179
- this._agentDir = config.agentDir || '.agent'
180
- this._config = null
181
- }
182
-
183
- install(framework) {
184
- this._framework = framework
185
- return this
186
- }
187
-
188
- start(framework) {
189
- // 加载配置
190
- this._config = loadAgentConfig(this._agentDir)
191
- return this
192
- }
193
-
194
- /**
195
- * 获取加载的配置
196
- */
197
- getConfig() {
198
- return this._config || loadAgentConfig(this._agentDir)
199
- }
200
-
201
- reload(framework) {
202
- this._framework = framework
203
- this._config = loadAgentConfig(this._agentDir)
204
- }
205
-
206
- uninstall(framework) {
207
- this._framework = null
208
- this._config = null
209
- }
210
- }
211
-
212
- /**
213
- * Bootstrap 辅助函数
214
- * 根据配置加载所有默认插件
215
- */
216
- async function bootstrapDefaults(framework, config = {}) {
217
- // 如果已经有配置,使用现有配置;否则加载
218
- const agentConfig = config._config
219
- if (!agentConfig) {
220
- bootstrapLog.error(' No config provided, skipping plugin loading')
221
- return
222
- }
223
- // 设置 bootstrap 模式,避免重复启动
224
- framework.pluginManager.setBootstrapping(true)
225
-
226
- // 合并 AI 配置
227
- const aiConfig = { ...agentConfig.ai, ...config.aiConfig }
228
-
229
- // 核心插件列表(不能禁用,必须加载)
230
- const CORE_PLUGINS = new Set([
231
- 'install', 'ai', 'storage', 'tools', 'workflow', 'skill-manager',
232
- 'mcp-executor', 'extension-executor', 'shell-executor', 'python-executor', 'session', 'web',
233
- 'audit', 'rules', 'scheduler', 'file-system', 'think', 'ambient',
234
- 'python-plugin-loader', 'telegram', 'weixin', 'subagent-manager'
235
- ])
236
-
237
- // 辅助函数:检查插件是否应该加载
238
- // 传入插件名称(字符串)、已创建的实例,或插件类
239
- const shouldLoad = (plugin) => {
240
- const name = typeof plugin === 'string' ? plugin : (plugin.name || plugin.prototype?.name)
241
- if (framework.pluginManager.has(name)) {
242
- framework._debug&&bootstrapLog.debug(` ${name} Plugin already loaded, skipping`)
243
- return false
244
- }
245
- // 系统插件(system: true)不能禁用
246
- let isSystem = false
247
- if (typeof plugin === 'function') {
248
- isSystem = plugin.prototype?.system === true
249
- } else if (typeof plugin === 'object') {
250
- isSystem = plugin.system === true
251
- }
252
- if (isSystem && framework.pluginManager.isEnabled(name) === false) {
253
- framework._debug&&bootstrapLog.debug(` ${name} is a system plugin, cannot be disabled`)
254
- }
255
- return true
256
- }
257
-
258
- // 0. Install 工具插件(最先加载,让其他插件能用到它的 node_modules)
259
- if (shouldLoad('install')) {
260
- const InstallPlugin = require('./install-plugin')
261
- await framework.loadPlugin(new InstallPlugin({ agentDir: agentConfig.agentDir }))
262
- framework._debug&&bootstrapLog.debug(' Install Plugin loaded')
263
- }
264
-
265
- // 合并 skillsDirs 配置(bootstrap 传入的优先)
266
- const skillsDirs = [
267
- ...(config.skillsDirs || []),
268
- ...(agentConfig.skillsDirs || [])
269
- ]
270
-
271
- framework._debug&&bootstrapLog.debug(' Loading default plugins...')
272
- // AI 插件(如果已禁用则跳过)
273
- if (!shouldLoad('ai') || !(aiConfig.provider || aiConfig.model || aiConfig.apiKey)) {
274
- // 跳过或已禁用
275
- } else {
276
- const AIPlugin = require('./ai-plugin')
277
- // 根据 provider 获取对应的 API key
278
- const upperProvider = (aiConfig.provider || 'deepseek').toUpperCase().replace(/-/g, '_')
279
- const envApiKey = process.env[`${upperProvider}_API_KEY`] || process.env.FOLIKO_API_KEY
280
- const aiPlugin = new AIPlugin({
281
- provider: aiConfig.provider || 'deepseek',
282
- model: aiConfig.model || 'deepseek-chat',
283
- apiKey: aiConfig.apiKey || envApiKey,
284
- baseURL: aiConfig.baseURL
285
- })
286
- await framework.loadPlugin(aiPlugin)
287
- framework._debug&&bootstrapLog.debug(' AI Plugin loaded')
288
- }
289
-
290
- // 1.5 创建主 Agent(供 Telegram 等需要绑定 Agent 的插件使用)
291
- if (!framework._mainAgent && aiConfig.provider) {
292
- const { Agent } = require('../src/core/agent')
293
- const aiPlugin = framework.pluginManager.get('ai')
294
- const aiClient = aiPlugin ? aiPlugin.getAIClient() : null
295
- framework._debug&&bootstrapLog.debug(' Creating Main Agent - aiClient:', !!aiClient)
296
-
297
- framework._mainAgent = framework.createAgent({
298
- name: 'MainAgent',
299
- systemPrompt: '你是一个智能助手。当用户提出问题或任务时,你会主动分析需求,选择合适的工具来获取信息或执行操作。你善于将复杂任务拆解为多个步骤,通过工具协作完成。',
300
- model: aiConfig.model,
301
- provider: aiConfig.provider,
302
- apiKey: aiConfig.apiKey,
303
- baseURL: aiConfig.baseURL
304
- })
305
- framework._agents.push(framework._mainAgent)
306
- framework._debug&&bootstrapLog.debug(' Main Agent created, has _chatHandler:', !!framework._mainAgent._chatHandler)
307
- }
308
-
309
- // 2. Skill 管理器插件(需要 skillsDirs 配置)
310
- if (shouldLoad('skill-manager') && skillsDirs.length > 0) {
311
- const { SkillManagerPlugin } = require('../src/capabilities/skill-manager')
312
- await framework.loadPlugin(new SkillManagerPlugin({ skillsDirs }))
313
- framework._debug&&bootstrapLog.debug(' Skill Manager loaded')
314
- }
315
-
316
- // 3. MCP 执行器插件(需要转换 mcpServers 格式)
317
- if (shouldLoad('mcp-executor')) {
318
- const mcpServers = Object.entries(agentConfig.mcpServers || {})
319
- const servers = mcpServers.map(([name, cfg]) => ({
320
- ...cfg,
321
- name,
322
- command: cfg.command,
323
- args: cfg.args || [],
324
- env: cfg.env || {},
325
- url: cfg.url,
326
- headers: cfg.headers
327
- }))
328
- const { MCPExecutorPlugin } = require('../src/executors/mcp-executor')
329
- await framework.loadPlugin(new MCPExecutorPlugin({ servers }))
330
- framework._debug&&bootstrapLog.debug(` MCP Executor loaded${servers.length > 0 ? ` (${servers.length} servers)` : ' (no servers)'}`)
331
- }
332
-
333
- // 4. Python 插件加载器(需要 agentDir)
334
- if (shouldLoad('python-plugin-loader')) {
335
- const PythonPluginLoader = require('./python-plugin-loader')
336
- await framework.loadPlugin(new PythonPluginLoader({ agentDir: agentConfig.agentDir }))
337
- framework._debug&&bootstrapLog.debug(' Python Plugin Loader loaded')
338
- }
339
-
340
- // 5. SubAgent 管理器(需要特殊初始化 SubAgentConfigManager)
341
- if (shouldLoad('subagent-manager')) {
342
- try {
343
- const { SubAgentConfigManager } = require('../src/core/sub-agent-config')
344
- const subAgentConfigManager = new SubAgentConfigManager(agentConfig.agentsDir)
345
- subAgentConfigManager.loadAll()
346
- framework._subAgentConfigManager = subAgentConfigManager
347
-
348
- const { SubAgentManagerPlugin } = require('./subagent-plugin')
349
- await framework.loadPlugin(new SubAgentManagerPlugin({ agentsDir: agentConfig.agentsDir }))
350
- framework._debug&&bootstrapLog.debug(' SubAgent Manager loaded')
351
- } catch (err) {
352
- bootstrapLog.warn(' SubAgent Manager failed:', err.message)
353
- }
354
- }
355
-
356
- // 6. 自动加载 plugins/ 目录下的所有插件
357
- await loadCustomPlugins(framework, agentConfig)
358
-
359
- framework._debug&&bootstrapLog.debug(' All plugins loaded')
360
-
361
- // 统一启动所有插件(避免重复启动)
362
- await framework.pluginManager.startAll()
363
-
364
- // 清除 bootstrap 模式
365
- framework.pluginManager.setBootstrapping(false)
366
-
367
- framework._debug&&bootstrapLog.debug(' Loaded plugins ', framework.pluginManager.getAll().length)
368
- framework._debug&&bootstrapLog.debug(' Loaded tools ', framework.getTools().length)
369
- }
370
-
371
- /**
372
- * 解析插件路径
373
- * 支持两种结构:
374
- * 1. 文件夹结构: .agent/plugins/my-plugin/index.js
375
- * 2. 单文件结构: .agent/plugins/my-plugin.js
376
- * @param {string} pluginsDir - 插件目录
377
- * @param {string} name - 插件名称
378
- * @returns {{path: string, type: 'folder'|'file'}|null} 插件路径和类型
379
- */
380
- function resolvePluginPath(pluginsDir, name) {
381
- const folderPath = path.join(pluginsDir, name)
382
- const filePath = path.join(pluginsDir, `${name}.js`)
383
-
384
- // 文件夹优先
385
- if (fs.existsSync(folderPath) && fs.statSync(folderPath).isDirectory()) {
386
- const pkgPath = path.join(folderPath, 'package.json')
387
- if (fs.existsSync(pkgPath)) {
388
- try {
389
- const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))
390
- const main = pkg.main || 'index.js'
391
- const mainPath = path.join(folderPath, main)
392
- if (fs.existsSync(mainPath)) {
393
- return { path: mainPath, type: 'folder' }
394
- }
395
- } catch (err) {
396
- log.warn(` Failed to parse package.json for ${name}:`, err.message)
397
- }
398
- }
399
- // 默认加载 index.js
400
- const indexPath = path.join(folderPath, 'index.js')
401
- if (fs.existsSync(indexPath)) {
402
- return { path: indexPath, type: 'folder' }
403
- }
404
- //log.warn(` No entry point found for plugin folder: ${name}`)
405
- return null
406
- }
407
-
408
- // 单文件回退
409
- if (fs.existsSync(filePath)) {
410
- return { path: filePath, type: 'file' }
411
- }
412
-
413
- return null
414
- }
415
-
416
- /**
417
- * 扫描插件目录,返回所有插件名称
418
- * @param {string} pluginsDir - 插件目录
419
- * @returns {string[]} 插件名称列表
420
- */
421
- function scanPluginNames(pluginsDir) {
422
- if (!fs.existsSync(pluginsDir)) {
423
- return []
424
- }
425
-
426
- const names = new Set()
427
- const entries = fs.readdirSync(pluginsDir, { withFileTypes: true })
428
-
429
- for (const entry of entries) {
430
- if (entry.isDirectory()) {
431
- // 文件夹插件
432
- names.add(entry.name)
433
- } else if (entry.isFile() && entry.name.endsWith('.js')) {
434
- // 单文件插件(排除与文件夹同名的)
435
- const baseName = entry.name.replace(/\.js$/, '')
436
- if (!names.has(baseName)) {
437
- names.add(baseName)
438
- }
439
- }
440
- }
441
-
442
- return Array.from(names)
443
- }
444
-
445
- async function loadCustomPlugins(framework, agentConfig) {
446
- const { Plugin } = require('../src/core/plugin-base')
447
-
448
- // 加载两个目录下的自定义插件:
449
- // 1. .agent/plugins/ - 用户自定义插件(强制启用)
450
- // 2. plugins/ - 项目内置插件(自动加载)
451
- const dirs = [
452
- { dir: path.resolve(process.cwd(), '.agent', 'plugins'), forceEnabled: true },
453
- { dir: path.resolve(process.cwd(), 'plugins'), forceEnabled: false },
454
- { dir: path.resolve(__dirname, '..', 'plugins'), forceEnabled: false }
455
- // 项目下的 plugins 目录(兼容旧版本)
456
-
457
- ]
458
-
459
- for (const { dir, forceEnabled } of dirs) {
460
- if (!fs.existsSync(dir)) {
461
- continue
462
- }
463
-
464
- // 扫描所有插件名称(支持文件夹和单文件)
465
- const pluginNames = scanPluginNames(dir)
466
-
467
- for (const pluginName of pluginNames) {
468
- try {
469
- const resolved = resolvePluginPath(dir, pluginName)
470
- if (!resolved) {
471
- continue
472
- }
473
-
474
- const { path: pluginPath, type } = resolved
475
-
476
- // 清除缓存
477
- delete require.cache[require.resolve(pluginPath)]
478
- const pluginModule = require(pluginPath)
479
-
480
- let plugin
481
- if (typeof pluginModule === 'function') {
482
- plugin = pluginModule
483
- } else if (pluginModule.default) {
484
- plugin = pluginModule.default
485
- } else {
486
- // 支持具名导出 { PluginClass } 或 { PluginClass, Other }
487
- // 找到第一个是 Plugin 子类的导出
488
- const keys = Object.keys(pluginModule)
489
- let foundPlugin = null
490
- for (const key of keys) {
491
- const exp = pluginModule[key]
492
- if (typeof exp === 'function' && exp.prototype instanceof Plugin) {
493
- foundPlugin = exp
494
- break
495
- }
496
- }
497
- plugin = foundPlugin || pluginModule
498
- }
499
-
500
- // 获取插件名称(参考 plugin-manager 的逻辑)
501
- let resolvedPluginName = pluginName
502
- if (typeof plugin === 'function' && plugin.prototype instanceof Plugin) {
503
- // Plugin 子类:实例化获取名称
504
- const instance = new plugin()
505
- resolvedPluginName = instance.name || pluginName
506
- } else if (typeof plugin === 'function') {
507
- // 工厂函数
508
- const result = plugin(Plugin)
509
- resolvedPluginName = result?.name || pluginName
510
- } else {
511
- resolvedPluginName = plugin?.name || pluginName
512
- }
513
-
514
- // 如果插件已加载且已启动,跳过
515
- if (framework.pluginManager.has(resolvedPluginName) &&
516
- framework.pluginManager.get(resolvedPluginName)?._started) {
517
- continue
518
- }
519
-
520
- bootstrapLog.debug(` Loading plugin: ${resolvedPluginName} (${type})`)
521
-
522
- // 从 agentConfig 获取插件配置
523
- const pluginConfig = agentConfig[resolvedPluginName] || {}
524
-
525
- // 实例化插件并传入配置
526
- let pluginInstance
527
- if (typeof plugin === 'function' && plugin.prototype instanceof Plugin) {
528
- pluginInstance = new plugin(pluginConfig)
529
- } else {
530
- pluginInstance = plugin
531
- }
532
-
533
- await framework.pluginManager.load(pluginInstance, { forceEnabled })
534
- } catch (err) {
535
- log.error(` Failed to load plugin ${pluginName}:`, err.message)
536
- }
537
- }
538
- }
539
- }
540
-
541
- module.exports = {
542
- DefaultPlugins,
543
- loadAgentConfig,
544
- bootstrapDefaults,
545
- loadCustomPlugins,
546
- resolvePluginPath,
547
- scanPluginNames
548
- }
1
+ /**
2
+ * 默认插件配置加载器
3
+ * 检测 .agent/ 目录下的配置,提供给 bootstrap() 使用
4
+ */
5
+
6
+ const fs = require('fs')
7
+ const path = require('path')
8
+ const { Plugin } = require('../src/core/plugin-base')
9
+ const { logger } = require('../src/utils/logger')
10
+ const log = logger.child('AgentConfig')
11
+ const bootstrapLog = logger.child('Bootstrap')
12
+
13
+ /**
14
+ * 加载 .agent 目录下的配置
15
+ * 返回配置对象,可用于手动加载插件
16
+ */
17
+ function loadAgentConfig(agentDir = '.agent') {
18
+ const config = {
19
+ agentDir,
20
+ ai: {},
21
+ mcpServers: {},
22
+ plugins: [],
23
+ skillsDirs: [],
24
+ agentsDir: null // 子Agent配置目录
25
+ }
26
+ const cmdDir=path.resolve(process.cwd())
27
+ const resolvedDir = path.resolve(process.cwd(), agentDir)
28
+
29
+ if (!fs.existsSync(resolvedDir)) {
30
+ log.info(` .agent directory not found: ${resolvedDir}`)
31
+ return config
32
+ }
33
+
34
+ log.info(` Loading config from: ${resolvedDir}`)
35
+
36
+ // 添加 agents 目录(如果存在)
37
+ const agentsDir = path.join(resolvedDir, 'agents')
38
+ if (fs.existsSync(agentsDir)) {
39
+ config.agentsDir = agentsDir
40
+ log.info(` Found agents directory: ${agentsDir}`)
41
+ }
42
+
43
+ // 加载 config 文件(key=value 格式)
44
+ const configFile = path.join(resolvedDir, 'config')
45
+ if (fs.existsSync(configFile)) {
46
+ try {
47
+ const lines = fs.readFileSync(configFile, 'utf-8').split('\n')
48
+ for (const line of lines) {
49
+ const trimmed = line.trim()
50
+ if (!trimmed || trimmed.startsWith('#')) continue
51
+
52
+ const colonIndex = trimmed.indexOf(':')
53
+ if (colonIndex === -1) continue
54
+
55
+ const key = trimmed.substring(0, colonIndex).trim()
56
+ const value = trimmed.substring(colonIndex + 1).trim()
57
+
58
+ if (key === 'ai_key' || key === 'api_key') {
59
+ config.ai.apiKey = value
60
+ } else if (key === 'ai_model' || key === 'model') {
61
+ config.ai.model = value
62
+ } else if (key === 'ai_provider' || key === 'provider') {
63
+ config.ai.provider = value
64
+ } else if (key === 'ai_base_url' || key === 'baseURL') {
65
+ config.ai.baseURL = value
66
+ }
67
+ }
68
+ } catch (err) {
69
+ log.error(` Failed to load config:`, err.message)
70
+ }
71
+ }
72
+
73
+ // 加载 ai.json
74
+ const aiFile = path.join(resolvedDir, 'ai.json')
75
+ if (fs.existsSync(aiFile)) {
76
+ try {
77
+ const content = fs.readFileSync(aiFile, 'utf-8')
78
+ const aiConfig = JSON.parse(content)
79
+ config.ai = { ...config.ai, ...aiConfig }
80
+ } catch (err) {
81
+ log.error(` Failed to load ai.json:`, err.message)
82
+ }
83
+ }
84
+
85
+ // 加载 plugins.json (支持 telegram, weixin, email 等插件配置)
86
+ const pluginsFile = path.join(resolvedDir, 'plugins.json')
87
+ if (fs.existsSync(pluginsFile)) {
88
+ try {
89
+ const content = fs.readFileSync(pluginsFile, 'utf-8')
90
+ const pluginsConfig = JSON.parse(content)
91
+ // telegram 配置
92
+ if (pluginsConfig.telegram) {
93
+ config.telegram = pluginsConfig.telegram
94
+ }
95
+ // weixin 配置
96
+ if (pluginsConfig.weixin) {
97
+ config.weixin = pluginsConfig.weixin
98
+ }
99
+ // email 配置
100
+ if (pluginsConfig.email) {
101
+ config.email = pluginsConfig.email
102
+ }
103
+ } catch (err) {
104
+ log.error(` Failed to load plugins.json:`, err.message)
105
+ }
106
+ }
107
+
108
+ // 加载 weixin.json (如果存在)
109
+ const weixinFile = path.join(resolvedDir, 'weixin.json')
110
+ if (fs.existsSync(weixinFile)) {
111
+ try {
112
+ const content = fs.readFileSync(weixinFile, 'utf-8')
113
+ config.weixin = { ...config.weixin, ...JSON.parse(content) }
114
+ } catch (err) {
115
+ log.error(` Failed to load weixin.json:`, err.message)
116
+ }
117
+ }
118
+
119
+ // 加载 mcp_config.json
120
+ const mcpFile = path.join(resolvedDir, 'mcp_config.json')
121
+ if (fs.existsSync(mcpFile)) {
122
+ try {
123
+ const content = fs.readFileSync(mcpFile, 'utf-8')
124
+ const mcpConfig = JSON.parse(content)
125
+ config.mcpServers = mcpConfig.mcpServers || {}
126
+ } catch (err) {
127
+ log.error(` Failed to load mcp_config.json:`, err.message)
128
+ }
129
+ }
130
+
131
+ // 添加 .agent/skills 目录(不存在则创建)
132
+ const skillsDir = path.join(resolvedDir, 'skills')
133
+ if (fs.existsSync(resolvedDir) && !fs.existsSync(skillsDir)) {
134
+ fs.mkdirSync(skillsDir, { recursive: true })
135
+ log.info(` Created skills directory: ${skillsDir}`)
136
+ }
137
+ if (fs.existsSync(skillsDir)) {
138
+ config.skillsDirs.push(skillsDir)
139
+ }
140
+
141
+ // 添加 .agent/skills 目录(不存在则创建)
142
+ const cmdskillsDir = path.join(cmdDir, 'skills')
143
+ if (fs.existsSync(resolvedDir) && !fs.existsSync(cmdskillsDir)) {
144
+ fs.mkdirSync(cmdskillsDir, { recursive: true })
145
+ log.info(` Created skills directory: ${cmdskillsDir}`)
146
+ }
147
+ if (fs.existsSync(cmdskillsDir)) {
148
+ config.skillsDirs.push(cmdskillsDir)
149
+ }
150
+
151
+ // 添加 agentDir 父目录的 skills/ 目录
152
+ const parentDir = path.dirname(__dirname)
153
+ const rootSkillsDir = path.join(parentDir, 'skills')
154
+ if (fs.existsSync(rootSkillsDir)) {
155
+ config.skillsDirs.push(rootSkillsDir)
156
+ }
157
+
158
+ // const defaultSkillsDir = path.join(process.cwd(), 'defaultSkills')
159
+ // if (fs.existsSync(defaultSkillsDir)) {
160
+ // config.skillsDirs.push(defaultSkillsDir)
161
+ // }
162
+
163
+ return config
164
+ }
165
+
166
+ /**
167
+ * DefaultPlugins - 默认插件配置加载器
168
+ */
169
+ class DefaultPlugins extends Plugin {
170
+ constructor(config = {}) {
171
+ super()
172
+ this.name = 'defaults'
173
+ this.version = '1.0.0'
174
+ this.description = '默认插件配置加载器'
175
+ this.priority = 0 // 最先加载
176
+ this.system = true
177
+
178
+ this._framework = null
179
+ this._agentDir = config.agentDir || '.agent'
180
+ this._config = null
181
+ }
182
+
183
+ install(framework) {
184
+ this._framework = framework
185
+ return this
186
+ }
187
+
188
+ start(framework) {
189
+ // 加载配置
190
+ this._config = loadAgentConfig(this._agentDir)
191
+ return this
192
+ }
193
+
194
+ /**
195
+ * 获取加载的配置
196
+ */
197
+ getConfig() {
198
+ return this._config || loadAgentConfig(this._agentDir)
199
+ }
200
+
201
+ reload(framework) {
202
+ this._framework = framework
203
+ this._config = loadAgentConfig(this._agentDir)
204
+ }
205
+
206
+ uninstall(framework) {
207
+ this._framework = null
208
+ this._config = null
209
+ }
210
+ }
211
+
212
+ /**
213
+ * Bootstrap 辅助函数
214
+ * 根据配置加载所有默认插件
215
+ */
216
+ async function bootstrapDefaults(framework, config = {}) {
217
+ // 如果已经有配置,使用现有配置;否则加载
218
+ const agentConfig = config._config
219
+ if (!agentConfig) {
220
+ bootstrapLog.error(' No config provided, skipping plugin loading')
221
+ return
222
+ }
223
+ // 设置 bootstrap 模式,避免重复启动
224
+ framework.pluginManager.setBootstrapping(true)
225
+
226
+ // 合并 AI 配置
227
+ const aiConfig = { ...agentConfig.ai, ...config.aiConfig }
228
+
229
+ // 核心插件列表(不能禁用,必须加载)
230
+ const CORE_PLUGINS = new Set([
231
+ 'install', 'ai', 'storage', 'tools', 'workflow', 'skill-manager',
232
+ 'mcp-executor', 'extension-executor', 'shell-executor', 'python-executor', 'session', 'web',
233
+ 'audit', 'rules', 'scheduler', 'file-system', 'think', 'ambient',
234
+ 'python-plugin-loader', 'telegram', 'weixin', 'subagent-manager'
235
+ ])
236
+
237
+ // 辅助函数:检查插件是否应该加载
238
+ // 传入插件名称(字符串)、已创建的实例,或插件类
239
+ const shouldLoad = (plugin) => {
240
+ const name = typeof plugin === 'string' ? plugin : (plugin.name || plugin.prototype?.name)
241
+ if (framework.pluginManager.has(name)) {
242
+ framework._debug&&bootstrapLog.debug(` ${name} Plugin already loaded, skipping`)
243
+ return false
244
+ }
245
+ // 系统插件(system: true)不能禁用
246
+ let isSystem = false
247
+ if (typeof plugin === 'function') {
248
+ isSystem = plugin.prototype?.system === true
249
+ } else if (typeof plugin === 'object') {
250
+ isSystem = plugin.system === true
251
+ }
252
+ if (isSystem && framework.pluginManager.isEnabled(name) === false) {
253
+ framework._debug&&bootstrapLog.debug(` ${name} is a system plugin, cannot be disabled`)
254
+ }
255
+ return true
256
+ }
257
+
258
+ // 0. Install 工具插件(最先加载,让其他插件能用到它的 node_modules)
259
+ if (shouldLoad('install')) {
260
+ const InstallPlugin = require('./install-plugin')
261
+ await framework.loadPlugin(new InstallPlugin({ agentDir: agentConfig.agentDir }))
262
+ framework._debug&&bootstrapLog.debug(' Install Plugin loaded')
263
+ }
264
+
265
+ // 合并 skillsDirs 配置(bootstrap 传入的优先)
266
+ const skillsDirs = [
267
+ ...(config.skillsDirs || []),
268
+ ...(agentConfig.skillsDirs || [])
269
+ ]
270
+
271
+ framework._debug&&bootstrapLog.debug(' Loading default plugins...')
272
+ // AI 插件(如果已禁用则跳过)
273
+ if (!shouldLoad('ai') || !(aiConfig.provider || aiConfig.model || aiConfig.apiKey)) {
274
+ // 跳过或已禁用
275
+ } else {
276
+ const AIPlugin = require('./ai-plugin')
277
+ // 根据 provider 获取对应的 API key
278
+ const upperProvider = (aiConfig.provider || 'deepseek').toUpperCase().replace(/-/g, '_')
279
+ const envApiKey = process.env[`${upperProvider}_API_KEY`] || process.env.FOLIKO_API_KEY
280
+ const aiPlugin = new AIPlugin({
281
+ provider: aiConfig.provider || 'deepseek',
282
+ model: aiConfig.model || 'deepseek-chat',
283
+ apiKey: aiConfig.apiKey || envApiKey,
284
+ baseURL: aiConfig.baseURL
285
+ })
286
+ await framework.loadPlugin(aiPlugin)
287
+ framework._debug&&bootstrapLog.debug(' AI Plugin loaded')
288
+ }
289
+
290
+ // 1.5 创建主 Agent(供 Telegram 等需要绑定 Agent 的插件使用)
291
+ if (!framework._mainAgent && aiConfig.provider) {
292
+ const { Agent } = require('../src/core/agent')
293
+ const aiPlugin = framework.pluginManager.get('ai')
294
+ const aiClient = aiPlugin ? aiPlugin.getAIClient() : null
295
+ framework._debug&&bootstrapLog.debug(' Creating Main Agent - aiClient:', !!aiClient)
296
+
297
+ framework._mainAgent = framework.createAgent({
298
+ name: 'MainAgent',
299
+ systemPrompt: '你是一个智能助手。当用户提出问题或任务时,你会主动分析需求,选择合适的工具来获取信息或执行操作。你善于将复杂任务拆解为多个步骤,通过工具协作完成。',
300
+ model: aiConfig.model,
301
+ provider: aiConfig.provider,
302
+ apiKey: aiConfig.apiKey,
303
+ baseURL: aiConfig.baseURL
304
+ })
305
+ framework._agents.push(framework._mainAgent)
306
+ framework._debug&&bootstrapLog.debug(' Main Agent created, has _chatHandler:', !!framework._mainAgent._chatHandler)
307
+ }
308
+
309
+ // 2. Skill 管理器插件(需要 skillsDirs 配置)
310
+ if (shouldLoad('skill-manager') && skillsDirs.length > 0) {
311
+ const { SkillManagerPlugin } = require('../src/capabilities/skill-manager')
312
+ await framework.loadPlugin(new SkillManagerPlugin({ skillsDirs }))
313
+ framework._debug&&bootstrapLog.debug(' Skill Manager loaded')
314
+ }
315
+
316
+ // 3. MCP 执行器插件(需要转换 mcpServers 格式)
317
+ if (shouldLoad('mcp-executor')) {
318
+ const mcpServers = Object.entries(agentConfig.mcpServers || {})
319
+ const servers = mcpServers.map(([name, cfg]) => ({
320
+ ...cfg,
321
+ name,
322
+ command: cfg.command,
323
+ args: cfg.args || [],
324
+ env: cfg.env || {},
325
+ url: cfg.url,
326
+ headers: cfg.headers
327
+ }))
328
+ const { MCPExecutorPlugin } = require('../src/executors/mcp-executor')
329
+ await framework.loadPlugin(new MCPExecutorPlugin({ servers }))
330
+ framework._debug&&bootstrapLog.debug(` MCP Executor loaded${servers.length > 0 ? ` (${servers.length} servers)` : ' (no servers)'}`)
331
+ }
332
+
333
+ // 4. Python 插件加载器(需要 agentDir)
334
+ if (shouldLoad('python-plugin-loader')) {
335
+ const PythonPluginLoader = require('./python-plugin-loader')
336
+ await framework.loadPlugin(new PythonPluginLoader({ agentDir: agentConfig.agentDir }))
337
+ framework._debug&&bootstrapLog.debug(' Python Plugin Loader loaded')
338
+ }
339
+
340
+ // 5. SubAgent 管理器(需要特殊初始化 SubAgentConfigManager)
341
+ if (shouldLoad('subagent-manager')) {
342
+ try {
343
+ const { SubAgentConfigManager } = require('../src/core/sub-agent-config')
344
+ const subAgentConfigManager = new SubAgentConfigManager(agentConfig.agentsDir)
345
+ subAgentConfigManager.loadAll()
346
+ framework._subAgentConfigManager = subAgentConfigManager
347
+
348
+ const { SubAgentManagerPlugin } = require('./subagent-plugin')
349
+ await framework.loadPlugin(new SubAgentManagerPlugin({ agentsDir: agentConfig.agentsDir }))
350
+ framework._debug&&bootstrapLog.debug(' SubAgent Manager loaded')
351
+ } catch (err) {
352
+ bootstrapLog.warn(' SubAgent Manager failed:', err.message)
353
+ }
354
+ }
355
+
356
+ // 6. 自动加载 plugins/ 目录下的所有插件
357
+ await loadCustomPlugins(framework, agentConfig)
358
+
359
+ framework._debug&&bootstrapLog.debug(' All plugins loaded')
360
+
361
+ // 统一启动所有插件(避免重复启动)
362
+ await framework.pluginManager.startAll()
363
+
364
+ // 清除 bootstrap 模式
365
+ framework.pluginManager.setBootstrapping(false)
366
+
367
+ framework._debug&&bootstrapLog.debug(' Loaded plugins ', framework.pluginManager.getAll().length)
368
+ framework._debug&&bootstrapLog.debug(' Loaded tools ', framework.getTools().length)
369
+ }
370
+
371
+ /**
372
+ * 解析插件路径
373
+ * 支持两种结构:
374
+ * 1. 文件夹结构: .agent/plugins/my-plugin/index.js
375
+ * 2. 单文件结构: .agent/plugins/my-plugin.js
376
+ * @param {string} pluginsDir - 插件目录
377
+ * @param {string} name - 插件名称
378
+ * @returns {{path: string, type: 'folder'|'file'}|null} 插件路径和类型
379
+ */
380
+ function resolvePluginPath(pluginsDir, name) {
381
+ const folderPath = path.join(pluginsDir, name)
382
+ const filePath = path.join(pluginsDir, `${name}.js`)
383
+
384
+ // 文件夹优先
385
+ if (fs.existsSync(folderPath) && fs.statSync(folderPath).isDirectory()) {
386
+ const pkgPath = path.join(folderPath, 'package.json')
387
+ if (fs.existsSync(pkgPath)) {
388
+ try {
389
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))
390
+ const main = pkg.main || 'index.js'
391
+ const mainPath = path.join(folderPath, main)
392
+ if (fs.existsSync(mainPath)) {
393
+ return { path: mainPath, type: 'folder' }
394
+ }
395
+ } catch (err) {
396
+ log.warn(` Failed to parse package.json for ${name}:`, err.message)
397
+ }
398
+ }
399
+ // 默认加载 index.js
400
+ const indexPath = path.join(folderPath, 'index.js')
401
+ if (fs.existsSync(indexPath)) {
402
+ return { path: indexPath, type: 'folder' }
403
+ }
404
+ //log.warn(` No entry point found for plugin folder: ${name}`)
405
+ return null
406
+ }
407
+
408
+ // 单文件回退
409
+ if (fs.existsSync(filePath)) {
410
+ return { path: filePath, type: 'file' }
411
+ }
412
+
413
+ return null
414
+ }
415
+
416
+ /**
417
+ * 扫描插件目录,返回所有插件名称
418
+ * @param {string} pluginsDir - 插件目录
419
+ * @returns {string[]} 插件名称列表
420
+ */
421
+ function scanPluginNames(pluginsDir) {
422
+ if (!fs.existsSync(pluginsDir)) {
423
+ return []
424
+ }
425
+
426
+ const names = new Set()
427
+ const entries = fs.readdirSync(pluginsDir, { withFileTypes: true })
428
+
429
+ for (const entry of entries) {
430
+ if (entry.isDirectory()) {
431
+ // 文件夹插件
432
+ names.add(entry.name)
433
+ } else if (entry.isFile() && entry.name.endsWith('.js')) {
434
+ // 单文件插件(排除与文件夹同名的)
435
+ const baseName = entry.name.replace(/\.js$/, '')
436
+ if (!names.has(baseName)) {
437
+ names.add(baseName)
438
+ }
439
+ }
440
+ }
441
+
442
+ return Array.from(names)
443
+ }
444
+
445
+ async function loadCustomPlugins(framework, agentConfig) {
446
+ const { Plugin } = require('../src/core/plugin-base')
447
+
448
+ // 加载两个目录下的自定义插件:
449
+ // 1. .agent/plugins/ - 用户自定义插件(强制启用)
450
+ // 2. plugins/ - 项目内置插件(自动加载)
451
+ const dirs = [
452
+ { dir: path.resolve(process.cwd(), '.agent', 'plugins'), forceEnabled: true },
453
+ { dir: path.resolve(process.cwd(), 'plugins'), forceEnabled: false },
454
+ { dir: path.resolve(__dirname, '..', 'plugins'), forceEnabled: false }
455
+ // 项目下的 plugins 目录(兼容旧版本)
456
+
457
+ ]
458
+
459
+ for (const { dir, forceEnabled } of dirs) {
460
+ if (!fs.existsSync(dir)) {
461
+ continue
462
+ }
463
+
464
+ // 扫描所有插件名称(支持文件夹和单文件)
465
+ const pluginNames = scanPluginNames(dir)
466
+
467
+ for (const pluginName of pluginNames) {
468
+ try {
469
+ const resolved = resolvePluginPath(dir, pluginName)
470
+ if (!resolved) {
471
+ continue
472
+ }
473
+
474
+ const { path: pluginPath, type } = resolved
475
+
476
+ // 清除缓存
477
+ delete require.cache[require.resolve(pluginPath)]
478
+ const pluginModule = require(pluginPath)
479
+
480
+ let plugin
481
+ if (typeof pluginModule === 'function') {
482
+ plugin = pluginModule
483
+ } else if (pluginModule.default) {
484
+ plugin = pluginModule.default
485
+ } else {
486
+ // 支持具名导出 { PluginClass } 或 { PluginClass, Other }
487
+ // 找到第一个是 Plugin 子类的导出
488
+ const keys = Object.keys(pluginModule)
489
+ let foundPlugin = null
490
+ for (const key of keys) {
491
+ const exp = pluginModule[key]
492
+ if (typeof exp === 'function' && exp.prototype instanceof Plugin) {
493
+ foundPlugin = exp
494
+ break
495
+ }
496
+ }
497
+ plugin = foundPlugin || pluginModule
498
+ }
499
+
500
+ // 获取插件名称(参考 plugin-manager 的逻辑)
501
+ let resolvedPluginName = pluginName
502
+ if (typeof plugin === 'function' && plugin.prototype instanceof Plugin) {
503
+ // Plugin 子类:实例化获取名称
504
+ const instance = new plugin()
505
+ resolvedPluginName = instance.name || pluginName
506
+ } else if (typeof plugin === 'function') {
507
+ // 工厂函数
508
+ const result = plugin(Plugin)
509
+ resolvedPluginName = result?.name || pluginName
510
+ } else {
511
+ resolvedPluginName = plugin?.name || pluginName
512
+ }
513
+
514
+ // 如果插件已加载且已启动,跳过
515
+ if (framework.pluginManager.has(resolvedPluginName) &&
516
+ framework.pluginManager.get(resolvedPluginName)?._started) {
517
+ continue
518
+ }
519
+
520
+ bootstrapLog.debug(` Loading plugin: ${resolvedPluginName} (${type})`)
521
+
522
+ // 从 agentConfig 获取插件配置
523
+ const pluginConfig = agentConfig[resolvedPluginName] || {}
524
+
525
+ // 实例化插件并传入配置
526
+ let pluginInstance
527
+ if (typeof plugin === 'function' && plugin.prototype instanceof Plugin) {
528
+ pluginInstance = new plugin(pluginConfig)
529
+ } else {
530
+ pluginInstance = plugin
531
+ }
532
+
533
+ await framework.pluginManager.load(pluginInstance, { forceEnabled })
534
+ } catch (err) {
535
+ log.error(` Failed to load plugin ${pluginName}:`, err.message)
536
+ }
537
+ }
538
+ }
539
+ }
540
+
541
+ module.exports = {
542
+ DefaultPlugins,
543
+ loadAgentConfig,
544
+ bootstrapDefaults,
545
+ loadCustomPlugins,
546
+ resolvePluginPath,
547
+ scanPluginNames
548
+ }