foliko 1.0.74 → 1.0.76

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. package/.agent/.shared/ui-ux-pro-max/data/charts.csv +26 -0
  2. package/.agent/.shared/ui-ux-pro-max/data/colors.csv +97 -0
  3. package/.agent/.shared/ui-ux-pro-max/data/icons.csv +101 -0
  4. package/.agent/.shared/ui-ux-pro-max/data/landing.csv +31 -0
  5. package/.agent/.shared/ui-ux-pro-max/data/products.csv +97 -0
  6. package/.agent/.shared/ui-ux-pro-max/data/prompts.csv +24 -0
  7. package/.agent/.shared/ui-ux-pro-max/data/react-performance.csv +45 -0
  8. package/.agent/.shared/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  9. package/.agent/.shared/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  10. package/.agent/.shared/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
  11. package/.agent/.shared/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  12. package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  13. package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  14. package/.agent/.shared/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  15. package/.agent/.shared/ui-ux-pro-max/data/stacks/react.csv +54 -0
  16. package/.agent/.shared/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  17. package/.agent/.shared/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  18. package/.agent/.shared/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  19. package/.agent/.shared/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  20. package/.agent/.shared/ui-ux-pro-max/data/styles.csv +59 -0
  21. package/.agent/.shared/ui-ux-pro-max/data/typography.csv +58 -0
  22. package/.agent/.shared/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  23. package/.agent/.shared/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  24. package/.agent/.shared/ui-ux-pro-max/data/web-interface.csv +31 -0
  25. package/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/core.cpython-313.pyc +0 -0
  26. package/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-313.pyc +0 -0
  27. package/.agent/.shared/ui-ux-pro-max/scripts/core.py +258 -0
  28. package/.agent/.shared/ui-ux-pro-max/scripts/design_system.py +1067 -0
  29. package/.agent/.shared/ui-ux-pro-max/scripts/search.py +106 -0
  30. package/.agent/ARCHITECTURE.md +288 -0
  31. package/.agent/agents/ambient-agent.md +57 -0
  32. package/.agent/agents/debugger.md +55 -0
  33. package/.agent/agents/email-assistant.md +49 -0
  34. package/.agent/agents/file-manager.md +42 -0
  35. package/.agent/agents/python-developer.md +60 -0
  36. package/.agent/agents/scheduler.md +59 -0
  37. package/.agent/agents/web-developer.md +45 -0
  38. package/.agent/data/default.json +29 -0
  39. package/.agent/data/plugins-state.json +255 -0
  40. package/.agent/mcp_config.json +4 -0
  41. package/.agent/mcp_config_updated.json +12 -0
  42. package/.agent/plugins.json +5 -0
  43. package/.agent/rules/GEMINI.md +273 -0
  44. package/.agent/rules/allow-rule.md +77 -0
  45. package/.agent/rules/log-rule.md +83 -0
  46. package/.agent/rules/security-rule.md +93 -0
  47. package/.agent/scripts/auto_preview.py +148 -0
  48. package/.agent/scripts/checklist.py +217 -0
  49. package/.agent/scripts/session_manager.py +120 -0
  50. package/.agent/scripts/verify_all.py +327 -0
  51. package/.agent/skills/api-patterns/SKILL.md +81 -0
  52. package/.agent/skills/api-patterns/api-style.md +42 -0
  53. package/.agent/skills/api-patterns/auth.md +24 -0
  54. package/.agent/skills/api-patterns/documentation.md +26 -0
  55. package/.agent/skills/api-patterns/graphql.md +41 -0
  56. package/.agent/skills/api-patterns/rate-limiting.md +31 -0
  57. package/.agent/skills/api-patterns/response.md +37 -0
  58. package/.agent/skills/api-patterns/rest.md +40 -0
  59. package/.agent/skills/api-patterns/scripts/api_validator.py +211 -0
  60. package/.agent/skills/api-patterns/security-testing.md +122 -0
  61. package/.agent/skills/api-patterns/trpc.md +41 -0
  62. package/.agent/skills/api-patterns/versioning.md +22 -0
  63. package/.agent/skills/app-builder/SKILL.md +75 -0
  64. package/.agent/skills/app-builder/agent-coordination.md +71 -0
  65. package/.agent/skills/app-builder/feature-building.md +53 -0
  66. package/.agent/skills/app-builder/project-detection.md +34 -0
  67. package/.agent/skills/app-builder/scaffolding.md +118 -0
  68. package/.agent/skills/app-builder/tech-stack.md +40 -0
  69. package/.agent/skills/app-builder/templates/SKILL.md +39 -0
  70. package/.agent/skills/app-builder/templates/astro-static/TEMPLATE.md +76 -0
  71. package/.agent/skills/app-builder/templates/chrome-extension/TEMPLATE.md +92 -0
  72. package/.agent/skills/app-builder/templates/cli-tool/TEMPLATE.md +88 -0
  73. package/.agent/skills/app-builder/templates/electron-desktop/TEMPLATE.md +88 -0
  74. package/.agent/skills/app-builder/templates/express-api/TEMPLATE.md +83 -0
  75. package/.agent/skills/app-builder/templates/flutter-app/TEMPLATE.md +90 -0
  76. package/.agent/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +90 -0
  77. package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +122 -0
  78. package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +122 -0
  79. package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +169 -0
  80. package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +134 -0
  81. package/.agent/skills/app-builder/templates/python-fastapi/TEMPLATE.md +83 -0
  82. package/.agent/skills/app-builder/templates/react-native-app/TEMPLATE.md +119 -0
  83. package/.agent/skills/architecture/SKILL.md +55 -0
  84. package/.agent/skills/architecture/context-discovery.md +43 -0
  85. package/.agent/skills/architecture/examples.md +94 -0
  86. package/.agent/skills/architecture/pattern-selection.md +68 -0
  87. package/.agent/skills/architecture/patterns-reference.md +50 -0
  88. package/.agent/skills/architecture/trade-off-analysis.md +77 -0
  89. package/.agent/skills/clean-code/SKILL.md +201 -0
  90. package/.agent/skills/doc.md +177 -0
  91. package/.agent/skills/frontend-design/SKILL.md +418 -0
  92. package/.agent/skills/frontend-design/animation-guide.md +331 -0
  93. package/.agent/skills/frontend-design/color-system.md +311 -0
  94. package/.agent/skills/frontend-design/decision-trees.md +418 -0
  95. package/.agent/skills/frontend-design/motion-graphics.md +306 -0
  96. package/.agent/skills/frontend-design/scripts/accessibility_checker.py +183 -0
  97. package/.agent/skills/frontend-design/scripts/ux_audit.py +722 -0
  98. package/.agent/skills/frontend-design/typography-system.md +345 -0
  99. package/.agent/skills/frontend-design/ux-psychology.md +1116 -0
  100. package/.agent/skills/frontend-design/visual-effects.md +383 -0
  101. package/.agent/skills/i18n-localization/SKILL.md +154 -0
  102. package/.agent/skills/i18n-localization/scripts/i18n_checker.py +241 -0
  103. package/.agent/skills/mcp-builder/SKILL.md +176 -0
  104. package/.agent/skills/web-design-guidelines/SKILL.md +57 -0
  105. package/.agent/workflows/brainstorm.md +113 -0
  106. package/.agent/workflows/create.md +59 -0
  107. package/.agent/workflows/debug.md +103 -0
  108. package/.agent/workflows/deploy.md +176 -0
  109. package/.agent/workflows/enhance.md +63 -0
  110. package/.agent/workflows/orchestrate.md +237 -0
  111. package/.agent/workflows/plan.md +89 -0
  112. package/.agent/workflows/preview.md +81 -0
  113. package/.agent/workflows/simple-test.md +42 -0
  114. package/.agent/workflows/status.md +86 -0
  115. package/.agent/workflows/structured-orchestrate.md +180 -0
  116. package/.agent/workflows/test.md +144 -0
  117. package/.agent/workflows/ui-ux-pro-max.md +296 -0
  118. package/.claude/settings.local.json +11 -1
  119. package/.editorconfig +56 -0
  120. package/.husky/pre-commit +4 -0
  121. package/.lintstagedrc +7 -0
  122. package/.prettierignore +29 -0
  123. package/.prettierrc +11 -0
  124. package/CLAUDE.md +2 -0
  125. package/README.md +64 -55
  126. package/SPEC.md +102 -61
  127. package/cli/bin/foliko.js +11 -11
  128. package/cli/src/commands/chat.js +143 -141
  129. package/cli/src/commands/list.js +93 -90
  130. package/cli/src/index.js +75 -75
  131. package/cli/src/ui/chat-ui.js +201 -199
  132. package/cli/src/utils/ansi.js +40 -40
  133. package/cli/src/utils/markdown.js +292 -296
  134. package/docker-compose.yml +1 -1
  135. package/docs/ai-sdk-optimization.md +655 -643
  136. package/docs/features.md +80 -80
  137. package/docs/quick-reference.md +49 -46
  138. package/docs/user-manual.md +411 -380
  139. package/examples/ambient-example.js +194 -196
  140. package/examples/basic.js +50 -45
  141. package/examples/bootstrap.js +121 -112
  142. package/examples/mcp-example.js +19 -16
  143. package/examples/skill-example.js +20 -20
  144. package/examples/test-chat.js +137 -135
  145. package/examples/test-mcp.js +85 -79
  146. package/examples/test-reload.js +59 -61
  147. package/examples/test-telegram.js +50 -50
  148. package/examples/test-tg-bot.js +45 -42
  149. package/examples/test-tg-simple.js +47 -46
  150. package/examples/test-tg.js +62 -62
  151. package/examples/test-think.js +43 -37
  152. package/examples/test-web-plugin.js +103 -98
  153. package/examples/test-weixin-feishu.js +103 -100
  154. package/examples/workflow.js +158 -158
  155. package/package.json +37 -3
  156. package/plugins/ai-plugin.js +102 -100
  157. package/plugins/ambient-agent/EventWatcher.js +113 -0
  158. package/plugins/ambient-agent/ExplorerLoop.js +640 -0
  159. package/plugins/ambient-agent/GoalManager.js +197 -0
  160. package/plugins/ambient-agent/Reflector.js +95 -0
  161. package/plugins/ambient-agent/StateStore.js +90 -0
  162. package/plugins/ambient-agent/constants.js +101 -0
  163. package/plugins/ambient-agent/index.js +579 -0
  164. package/plugins/audit-plugin.js +187 -187
  165. package/plugins/default-plugins.js +662 -649
  166. package/plugins/email/constants.js +64 -0
  167. package/plugins/email/handlers.js +461 -0
  168. package/plugins/email/index.js +278 -0
  169. package/plugins/email/monitor.js +269 -0
  170. package/plugins/email/parser.js +138 -0
  171. package/plugins/email/reply.js +151 -0
  172. package/plugins/email/utils.js +124 -0
  173. package/plugins/feishu-plugin.js +481 -477
  174. package/plugins/file-system-plugin.js +826 -476
  175. package/plugins/install-plugin.js +199 -197
  176. package/plugins/python-executor-plugin.js +367 -365
  177. package/plugins/python-plugin-loader.js +481 -479
  178. package/plugins/rules-plugin.js +294 -292
  179. package/plugins/scheduler-plugin.js +691 -689
  180. package/plugins/session-plugin.js +369 -367
  181. package/plugins/shell-executor-plugin.js +197 -197
  182. package/plugins/storage-plugin.js +240 -238
  183. package/plugins/subagent-plugin.js +845 -785
  184. package/plugins/telegram-plugin.js +482 -475
  185. package/plugins/think-plugin.js +345 -343
  186. package/plugins/tools-plugin.js +196 -194
  187. package/plugins/web-plugin.js +606 -604
  188. package/plugins/weixin-plugin.js +545 -538
  189. package/reports/system-health-report-20260401.md +79 -0
  190. package/skills/ambient-agent/SKILL.md +49 -39
  191. package/skills/foliko-dev/AGENTS.md +64 -61
  192. package/skills/foliko-dev/SKILL.md +125 -119
  193. package/skills/mcp-usage/SKILL.md +19 -17
  194. package/skills/python-plugin-dev/SKILL.md +16 -15
  195. package/skills/skill-guide/SKILL.md +12 -12
  196. package/skills/subagent-guide/SKILL.md +237 -0
  197. package/skills/workflow-guide/SKILL.md +90 -45
  198. package/skills/workflow-troubleshooting/DEBUGGING.md +36 -21
  199. package/skills/workflow-troubleshooting/SKILL.md +156 -79
  200. package/src/capabilities/index.js +11 -11
  201. package/src/capabilities/skill-manager.js +609 -595
  202. package/src/capabilities/workflow-engine.js +1109 -1195
  203. package/src/core/agent-chat.js +882 -735
  204. package/src/core/agent.js +892 -688
  205. package/src/core/framework.js +465 -431
  206. package/src/core/index.js +19 -19
  207. package/src/core/plugin-base.js +219 -219
  208. package/src/core/plugin-manager.js +863 -767
  209. package/src/core/provider.js +114 -111
  210. package/src/core/sub-agent-config.js +264 -0
  211. package/src/core/system-prompt-builder.js +120 -0
  212. package/src/core/tool-registry.js +517 -134
  213. package/src/core/tool-router.js +297 -216
  214. package/src/executors/executor-base.js +12 -12
  215. package/src/executors/mcp-executor.js +741 -729
  216. package/src/index.js +25 -37
  217. package/src/utils/circuit-breaker.js +301 -0
  218. package/src/utils/error-boundary.js +363 -0
  219. package/src/utils/error.js +374 -0
  220. package/src/utils/event-emitter.js +97 -97
  221. package/src/utils/id.js +133 -0
  222. package/src/utils/index.js +217 -3
  223. package/src/utils/logger.js +181 -0
  224. package/src/utils/plugin-helpers.js +90 -0
  225. package/src/utils/retry.js +122 -0
  226. package/src/utils/sandbox.js +292 -0
  227. package/test/tool-registry-validation.test.js +218 -0
  228. package/test_report.md +70 -0
  229. package/website/docs/api.html +169 -107
  230. package/website/docs/configuration.html +296 -144
  231. package/website/docs/plugin-development.html +154 -85
  232. package/website/docs/project-structure.html +110 -109
  233. package/website/docs/skill-development.html +117 -61
  234. package/website/index.html +209 -205
  235. package/website/script.js +136 -133
  236. package/website/styles.css +1 -1
  237. package/plugins/ambient-agent-plugin.js +0 -1565
  238. package/plugins/email.js +0 -1142
@@ -1,649 +1,662 @@
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
-
10
- /**
11
- * 加载 .agent 目录下的配置
12
- * 返回配置对象,可用于手动加载插件
13
- */
14
- function loadAgentConfig(agentDir = '.agent') {
15
- const config = {
16
- agentDir,
17
- ai: {},
18
- mcpServers: {},
19
- plugins: [],
20
- skillsDirs: [],
21
- agentsDir: null // 子Agent配置目录
22
- }
23
- const cmdDir=path.resolve(process.cwd())
24
- const resolvedDir = path.resolve(process.cwd(), agentDir)
25
-
26
- if (!fs.existsSync(resolvedDir)) {
27
- console.log(`[AgentConfig] .agent directory not found: ${resolvedDir}`)
28
- return config
29
- }
30
-
31
- console.log(`[AgentConfig] Loading config from: ${resolvedDir}`)
32
-
33
- // 添加 agents 目录(如果存在)
34
- const agentsDir = path.join(resolvedDir, 'agents')
35
- if (fs.existsSync(agentsDir)) {
36
- config.agentsDir = agentsDir
37
- console.log(`[AgentConfig] Found agents directory: ${agentsDir}`)
38
- }
39
-
40
- // 加载 config 文件(key=value 格式)
41
- const configFile = path.join(resolvedDir, 'config')
42
- if (fs.existsSync(configFile)) {
43
- try {
44
- const lines = fs.readFileSync(configFile, 'utf-8').split('\n')
45
- for (const line of lines) {
46
- const trimmed = line.trim()
47
- if (!trimmed || trimmed.startsWith('#')) continue
48
-
49
- const colonIndex = trimmed.indexOf(':')
50
- if (colonIndex === -1) continue
51
-
52
- const key = trimmed.substring(0, colonIndex).trim()
53
- const value = trimmed.substring(colonIndex + 1).trim()
54
-
55
- if (key === 'ai_key' || key === 'api_key') {
56
- config.ai.apiKey = value
57
- } else if (key === 'ai_model' || key === 'model') {
58
- config.ai.model = value
59
- } else if (key === 'ai_provider' || key === 'provider') {
60
- config.ai.provider = value
61
- } else if (key === 'ai_base_url' || key === 'baseURL') {
62
- config.ai.baseURL = value
63
- }
64
- }
65
- } catch (err) {
66
- console.error(`[AgentConfig] Failed to load config:`, err.message)
67
- }
68
- }
69
-
70
- // 加载 ai.json
71
- const aiFile = path.join(resolvedDir, 'ai.json')
72
- if (fs.existsSync(aiFile)) {
73
- try {
74
- const content = fs.readFileSync(aiFile, 'utf-8')
75
- const aiConfig = JSON.parse(content)
76
- config.ai = { ...config.ai, ...aiConfig }
77
- } catch (err) {
78
- console.error(`[AgentConfig] Failed to load ai.json:`, err.message)
79
- }
80
- }
81
-
82
- // 加载 plugins.json (支持 telegram, weixin, email 等插件配置)
83
- const pluginsFile = path.join(resolvedDir, 'plugins.json')
84
- if (fs.existsSync(pluginsFile)) {
85
- try {
86
- const content = fs.readFileSync(pluginsFile, 'utf-8')
87
- const pluginsConfig = JSON.parse(content)
88
- // telegram 配置
89
- if (pluginsConfig.telegram) {
90
- config.telegram = pluginsConfig.telegram
91
- }
92
- // weixin 配置
93
- if (pluginsConfig.weixin) {
94
- config.weixin = pluginsConfig.weixin
95
- }
96
- // email 配置
97
- if (pluginsConfig.email) {
98
- config.email = pluginsConfig.email
99
- }
100
- } catch (err) {
101
- console.error(`[AgentConfig] Failed to load plugins.json:`, err.message)
102
- }
103
- }
104
-
105
- // 加载 weixin.json (如果存在)
106
- const weixinFile = path.join(resolvedDir, 'weixin.json')
107
- if (fs.existsSync(weixinFile)) {
108
- try {
109
- const content = fs.readFileSync(weixinFile, 'utf-8')
110
- config.weixin = { ...config.weixin, ...JSON.parse(content) }
111
- } catch (err) {
112
- console.error(`[AgentConfig] Failed to load weixin.json:`, err.message)
113
- }
114
- }
115
-
116
- // 加载 mcp_config.json
117
- const mcpFile = path.join(resolvedDir, 'mcp_config.json')
118
- if (fs.existsSync(mcpFile)) {
119
- try {
120
- const content = fs.readFileSync(mcpFile, 'utf-8')
121
- const mcpConfig = JSON.parse(content)
122
- config.mcpServers = mcpConfig.mcpServers || {}
123
- } catch (err) {
124
- console.error(`[AgentConfig] Failed to load mcp_config.json:`, err.message)
125
- }
126
- }
127
-
128
- // 添加 .agent/skills 目录(不存在则创建)
129
- const skillsDir = path.join(resolvedDir, 'skills')
130
- if (fs.existsSync(resolvedDir) && !fs.existsSync(skillsDir)) {
131
- fs.mkdirSync(skillsDir, { recursive: true })
132
- console.log(`[AgentConfig] Created skills directory: ${skillsDir}`)
133
- }
134
- if (fs.existsSync(skillsDir)) {
135
- config.skillsDirs.push(skillsDir)
136
- }
137
-
138
- // 添加 .agent/skills 目录(不存在则创建)
139
- const cmdskillsDir = path.join(cmdDir, 'skills')
140
- if (fs.existsSync(resolvedDir) && !fs.existsSync(cmdskillsDir)) {
141
- fs.mkdirSync(cmdskillsDir, { recursive: true })
142
- console.log(`[AgentConfig] Created skills directory: ${cmdskillsDir}`)
143
- }
144
- if (fs.existsSync(cmdskillsDir)) {
145
- config.skillsDirs.push(cmdskillsDir)
146
- }
147
-
148
- // 添加 agentDir 父目录的 skills/ 目录
149
- const parentDir = path.dirname(__dirname)
150
- const rootSkillsDir = path.join(parentDir, 'skills')
151
- if (fs.existsSync(rootSkillsDir)) {
152
- config.skillsDirs.push(rootSkillsDir)
153
- }
154
-
155
- // const defaultSkillsDir = path.join(process.cwd(), 'defaultSkills')
156
- // if (fs.existsSync(defaultSkillsDir)) {
157
- // config.skillsDirs.push(defaultSkillsDir)
158
- // }
159
-
160
- return config
161
- }
162
-
163
- /**
164
- * DefaultPlugins - 默认插件配置加载器
165
- */
166
- class DefaultPlugins extends Plugin {
167
- constructor(config = {}) {
168
- super()
169
- this.name = 'defaults'
170
- this.version = '1.0.0'
171
- this.description = '默认插件配置加载器'
172
- this.priority = 0 // 最先加载
173
- this.system = true
174
-
175
- this._framework = null
176
- this._agentDir = config.agentDir || '.agent'
177
- this._config = null
178
- }
179
-
180
- install(framework) {
181
- this._framework = framework
182
- return this
183
- }
184
-
185
- start(framework) {
186
- // 加载配置
187
- this._config = loadAgentConfig(this._agentDir)
188
- return this
189
- }
190
-
191
- /**
192
- * 获取加载的配置
193
- */
194
- getConfig() {
195
- return this._config || loadAgentConfig(this._agentDir)
196
- }
197
-
198
- reload(framework) {
199
- this._framework = framework
200
- this._config = loadAgentConfig(this._agentDir)
201
- }
202
-
203
- uninstall(framework) {
204
- this._framework = null
205
- this._config = null
206
- }
207
- }
208
-
209
- /**
210
- * Bootstrap 辅助函数
211
- * 根据配置加载所有默认插件
212
- */
213
- async function bootstrapDefaults(framework, config = {}) {
214
- // 如果已经有配置,使用现有配置;否则加载
215
- const agentConfig = config._config
216
- if (!agentConfig) {
217
- console.error('[Bootstrap] No config provided, skipping plugin loading')
218
- return
219
- }
220
- // 设置 bootstrap 模式,避免重复启动
221
- framework.pluginManager.setBootstrapping(true)
222
-
223
- // 合并 AI 配置
224
- const aiConfig = { ...agentConfig.ai, ...config.aiConfig }
225
-
226
- // 核心插件列表(不能禁用,必须加载)
227
- const CORE_PLUGINS = new Set([
228
- 'install', 'ai', 'storage', 'tools', 'workflow', 'skill-manager',
229
- 'mcp-executor', 'shell-executor', 'python-executor', 'session', 'web',
230
- 'audit', 'rules', 'scheduler', 'file-system', 'think', 'ambient',
231
- 'python-plugin-loader', 'telegram', 'weixin', 'subagent-manager'
232
- ])
233
-
234
- // 辅助函数:检查插件是否应该加载
235
- // 传入插件名称(字符串)、已创建的实例,或插件类
236
- const shouldLoad = (plugin) => {
237
- const name = typeof plugin === 'string' ? plugin : (plugin.name || plugin.prototype?.name)
238
- if (framework.pluginManager.has(name)) {
239
- framework._debug&&console.log(`[Bootstrap] ${name} Plugin already loaded, skipping`)
240
- return false
241
- }
242
- // 系统插件(system: true)不能禁用
243
- let isSystem = false
244
- if (typeof plugin === 'function') {
245
- isSystem = plugin.prototype?.system === true
246
- } else if (typeof plugin === 'object') {
247
- isSystem = plugin.system === true
248
- }
249
- if (isSystem && framework.pluginManager.isEnabled(name) === false) {
250
- framework._debug&&console.log(`[Bootstrap] ${name} is a system plugin, cannot be disabled`)
251
- }
252
- return true
253
- }
254
-
255
- // 0. Install 工具插件(最先加载,让其他插件能用到它的 node_modules)
256
- if (shouldLoad('install')) {
257
- const { InstallPlugin } = require('./install-plugin')
258
- await framework.loadPlugin(new InstallPlugin({ agentDir: agentConfig.agentDir }))
259
- framework._debug&&console.log('[Bootstrap] Install Plugin loaded')
260
- }
261
-
262
- // 合并 skillsDirs 配置(bootstrap 传入的优先)
263
- const skillsDirs = [
264
- ...(config.skillsDirs || []),
265
- ...(agentConfig.skillsDirs || [])
266
- ]
267
-
268
- framework._debug&&console.log('[Bootstrap] Loading default plugins...')
269
- // AI 插件(如果已禁用则跳过)
270
- if (!shouldLoad('ai') || !(aiConfig.provider || aiConfig.model || aiConfig.apiKey)) {
271
- // 跳过或已禁用
272
- } else {
273
- const { AIPlugin } = require('./ai-plugin')
274
- // 根据 provider 获取对应的 API key
275
- const upperProvider = (aiConfig.provider || 'deepseek').toUpperCase().replace(/-/g, '_')
276
- const envApiKey = process.env[`${upperProvider}_API_KEY`] || process.env.FOLIKO_API_KEY
277
- const aiPlugin = new AIPlugin({
278
- provider: aiConfig.provider || 'deepseek',
279
- model: aiConfig.model || 'deepseek-chat',
280
- apiKey: aiConfig.apiKey || envApiKey,
281
- baseURL: aiConfig.baseURL
282
- })
283
- await framework.loadPlugin(aiPlugin)
284
- framework._debug&&console.log('[Bootstrap] AI Plugin loaded')
285
- }
286
-
287
- // 1.5 创建主 Agent(供 Telegram 等需要绑定 Agent 的插件使用)
288
- if (!framework._mainAgent && aiConfig.provider) {
289
- const { Agent } = require('../src/core/agent')
290
- const aiPlugin = framework.pluginManager.get('ai')
291
- const aiClient = aiPlugin ? aiPlugin.getAIClient() : null
292
- framework._debug&&console.log('[Bootstrap] Creating Main Agent - aiClient:', !!aiClient)
293
-
294
- framework._mainAgent = new Agent(framework, {
295
- name: 'MainAgent',
296
- systemPrompt: '你是一个智能助手。当用户提出问题或任务时,你会主动分析需求,选择合适的工具来获取信息或执行操作。你善于将复杂任务拆解为多个步骤,通过工具协作完成。',
297
- model: aiConfig.model,
298
- provider: aiConfig.provider,
299
- apiKey: aiConfig.apiKey,
300
- baseURL: aiConfig.baseURL
301
- })
302
- framework._agents.push(framework._mainAgent)
303
- framework._debug&&console.log('[Bootstrap] Main Agent created, has _chatHandler:', !!framework._mainAgent._chatHandler)
304
- }
305
-
306
- // 2. Storage 存储插件
307
- if (shouldLoad('storage')) {
308
- const { StoragePlugin } = require('./storage-plugin')
309
- await framework.loadPlugin(new StoragePlugin())
310
- framework._debug&&console.log('[Bootstrap] Storage Plugin loaded')
311
- }
312
-
313
- // 3. 内置工具插件
314
- if (shouldLoad('tools')) {
315
- const { ToolsPlugin } = require('./tools-plugin')
316
- await framework.loadPlugin(new ToolsPlugin())
317
- framework._debug&&console.log('[Bootstrap] Tools Plugin loaded')
318
- }
319
-
320
- // 4. 工作流插件
321
- if (shouldLoad('workflow')) {
322
- const { WorkflowPlugin } = require('../src/capabilities/workflow-engine')
323
- await framework.loadPlugin(new WorkflowPlugin())
324
- framework._debug&&console.log('[Bootstrap] Workflow Plugin loaded')
325
- }
326
-
327
- // 5. Skill 管理器插件
328
- if (shouldLoad('skill-manager')) {
329
- if (skillsDirs.length > 0) {
330
- const { SkillManagerPlugin } = require('../src/capabilities/skill-manager')
331
- // 传递所有 skills 目录
332
- await framework.loadPlugin(new SkillManagerPlugin({ skillsDirs }))
333
- framework._debug&&console.log('[Bootstrap] Skill Manager loaded')
334
- }
335
- }
336
-
337
- // 6. MCP 执行器插件(始终加载,确保 mcp_reload 工具可用)
338
- if (shouldLoad('mcp-executor')) {
339
- const mcpServers = Object.entries(agentConfig.mcpServers || {})
340
- const servers = mcpServers.map(([name, cfg]) => ({
341
- ...cfg,
342
- name,
343
- command: cfg.command,
344
- args: cfg.args || [],
345
- env: cfg.env || {},
346
- url: cfg.url,
347
- headers: cfg.headers
348
- }))
349
- const { MCPExecutorPlugin } = require('../src/executors/mcp-executor')
350
- await framework.loadPlugin(new MCPExecutorPlugin({ servers }))
351
- framework._debug&&console.log(`[Bootstrap] MCP Executor loaded${servers.length > 0 ? ` (${servers.length} servers)` : ' (no servers)'}`)
352
- }
353
-
354
- // 7. Shell 执行器插件
355
- if (shouldLoad('shell-executor')) {
356
- const { ShellExecutorPlugin } = require('./shell-executor-plugin')
357
- await framework.loadPlugin(new ShellExecutorPlugin())
358
- framework._debug&&console.log('[Bootstrap] Shell Executor loaded')
359
- }
360
-
361
- // 8. Python 执行器插件
362
- if (shouldLoad('python-executor')) {
363
- const { PythonExecutorPlugin } = require('./python-executor-plugin')
364
- await framework.loadPlugin(new PythonExecutorPlugin())
365
- framework._debug&&console.log('[Bootstrap] Python Executor loaded')
366
- }
367
-
368
- // 8.5 Web Web服务插件
369
- if (shouldLoad('web')) {
370
- const { WebPlugin } = require('./web-plugin')
371
- await framework.loadPlugin(new WebPlugin())
372
- framework._debug&&console.log('[Bootstrap] Web Plugin loaded')
373
- }
374
-
375
- // 9. Session 会话管理插件
376
- if (shouldLoad('session')) {
377
- const { SessionPlugin } = require('./session-plugin')
378
- await framework.loadPlugin(new SessionPlugin())
379
- framework._debug&&console.log('[Bootstrap] Session Plugin loaded')
380
- }
381
-
382
- // 10. Audit 审计日志插件
383
- if (shouldLoad('audit')) {
384
- const { AuditPlugin } = require('./audit-plugin')
385
- await framework.loadPlugin(new AuditPlugin())
386
- framework._debug&&console.log('[Bootstrap] Audit Plugin loaded')
387
- }
388
-
389
- // 10. Rules 规则引擎插件
390
- if (shouldLoad('rules')) {
391
- const { RulesPlugin } = require('./rules-plugin')
392
- await framework.loadPlugin(new RulesPlugin())
393
- framework._debug&&console.log('[Bootstrap] Rules Plugin loaded')
394
- }
395
-
396
- // 11. Scheduler 定时任务插件
397
- if (shouldLoad('scheduler')) {
398
- const { SchedulerPlugin } = require('./scheduler-plugin')
399
- await framework.loadPlugin(new SchedulerPlugin())
400
- framework._debug&&console.log('[Bootstrap] Scheduler Plugin loaded')
401
- }
402
-
403
- // 11. FileSystem 文件系统插件
404
- if (shouldLoad('file-system')) {
405
- const { FileSystemPlugin } = require('./file-system-plugin')
406
- await framework.loadPlugin(new FileSystemPlugin())
407
- framework._debug&&console.log('[Bootstrap] FileSystem Plugin loaded')
408
- }
409
-
410
- // 12. Think 主动思考插件
411
- if (shouldLoad('think')) {
412
- const { ThinkPlugin } = require('./think-plugin')
413
- await framework.loadPlugin(new ThinkPlugin())
414
- framework._debug&&console.log('[Bootstrap] Think Plugin loaded')
415
- }
416
-
417
- // 12.1 Ambient Agent 插件
418
- if (shouldLoad('ambient')) {
419
- const { AmbientAgentPlugin } = require('./ambient-agent-plugin')
420
- await framework.loadPlugin(new AmbientAgentPlugin())
421
- framework._debug&&console.log('[Bootstrap] Ambient Agent Plugin loaded')
422
- }
423
-
424
- // 12.5 Python 插件加载器
425
- if (shouldLoad('python-plugin-loader')) {
426
- const { PythonPluginLoader } = require('./python-plugin-loader')
427
- await framework.loadPlugin(new PythonPluginLoader({ agentDir: agentConfig.agentDir }))
428
- framework._debug&&console.log('[Bootstrap] Python Plugin Loader loaded')
429
- }
430
-
431
- // 12.6 Telegram 插件(默认禁用,需要在 plugins.json 中设置 enabled: true)
432
- if (shouldLoad('telegram')) {
433
- const { TelegramPlugin } = require('./telegram-plugin')
434
- const telegramConfig = {
435
- botToken: process.env.TELEGRAM_BOT_TOKEN || agentConfig.telegram?.botToken
436
- }
437
- await framework.loadPlugin(new TelegramPlugin(telegramConfig))
438
- }
439
-
440
- // 12.7 WeChat 插件(默认禁用,需要在 plugins.json 中设置 enabled: true)
441
- if (shouldLoad('weixin')) {
442
- try {
443
- const { WeixinPlugin } = require('./weixin-plugin')
444
- const weixinConfig = {
445
- forceLogin: agentConfig.weixin?.forceLogin || false,
446
- qrcodeTerminal: agentConfig.weixin?.qrcodeTerminal !== false,
447
- allowedUsers: agentConfig.weixin?.allowedUsers || []
448
- }
449
- await framework.loadPlugin(new WeixinPlugin(weixinConfig))
450
- } catch (err) {
451
- console.warn('[Bootstrap] WeChat Plugin not available:', err.message)
452
- }
453
- }
454
-
455
- // 12.8 Email 插件(默认禁用,需要在 plugins.json 中设置 enabled: true)
456
- if (shouldLoad('email')) {
457
- try {
458
- const { Plugin } = require('../src/core/plugin-base')
459
- const { EmailPlugin } = require('./email')
460
- // 支持两种格式:email.smtp 或 email.config.smtp
461
- const emailData = agentConfig.email || {}
462
- const emailCfg = emailData.config || {}
463
- const emailConfig = {
464
- smtp: emailCfg.smtp || emailData.smtp || {},
465
- imap: emailCfg.imap || emailData.imap || {},
466
- clientId: emailCfg.clientId || emailData.clientId
467
- }
468
- await framework.loadPlugin(new EmailPlugin(emailConfig))
469
- } catch (err) {
470
- console.warn('[Bootstrap] Email Plugin not available:', err.message)
471
- }
472
- }
473
-
474
- // 12.9 Feishu 插件(默认禁用,需要在 plugins.json 中设置 enabled: true)
475
- if (shouldLoad('feishu')) {
476
- try {
477
- const { FeishuPlugin } = require('./feishu-plugin')
478
- const feishuConfig = {
479
- allowedUsers: agentConfig.feishu?.allowedUsers || []
480
- }
481
- await framework.loadPlugin(new FeishuPlugin(feishuConfig))
482
- } catch (err) {
483
- console.warn('[Bootstrap] Feishu Plugin not available:', err.message)
484
- }
485
- }
486
-
487
- // 12.10 SubAgent 管理器
488
- if (shouldLoad('subagent-manager')) {
489
- try {
490
- const { SubAgentManagerPlugin } = require('./subagent-plugin')
491
- await framework.loadPlugin(new SubAgentManagerPlugin({ agentsDir: agentConfig.agentsDir }))
492
- framework._debug&&console.log('[Bootstrap] SubAgent Manager loaded')
493
- } catch (err) {
494
- console.warn('[Bootstrap] SubAgent Manager failed:', err.message)
495
- }
496
- }
497
-
498
- // 13. 加载自定义插件
499
- await loadCustomPlugins(framework, agentConfig)
500
-
501
- framework._debug&&console.log('[Bootstrap] All plugins loaded')
502
-
503
- // 统一启动所有插件(避免重复启动)
504
- await framework.pluginManager.startAll()
505
-
506
- // 清除 bootstrap 模式
507
- framework.pluginManager.setBootstrapping(false)
508
-
509
- framework._debug&&console.log('[Bootstrap] Loaded plugins ', framework.pluginManager.getAll().length)
510
- framework._debug&&console.log('[Bootstrap] Loaded tools ', framework.getTools().length)
511
- }
512
-
513
- /**
514
- * 解析插件路径
515
- * 支持两种结构:
516
- * 1. 文件夹结构: .agent/plugins/my-plugin/index.js
517
- * 2. 单文件结构: .agent/plugins/my-plugin.js
518
- * @param {string} pluginsDir - 插件目录
519
- * @param {string} name - 插件名称
520
- * @returns {{path: string, type: 'folder'|'file'}|null} 插件路径和类型
521
- */
522
- function resolvePluginPath(pluginsDir, name) {
523
- const folderPath = path.join(pluginsDir, name)
524
- const filePath = path.join(pluginsDir, `${name}.js`)
525
-
526
- // 文件夹优先
527
- if (fs.existsSync(folderPath) && fs.statSync(folderPath).isDirectory()) {
528
- const pkgPath = path.join(folderPath, 'package.json')
529
- if (fs.existsSync(pkgPath)) {
530
- try {
531
- const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))
532
- const main = pkg.main || 'index.js'
533
- const mainPath = path.join(folderPath, main)
534
- if (fs.existsSync(mainPath)) {
535
- return { path: mainPath, type: 'folder' }
536
- }
537
- } catch (err) {
538
- console.warn(`[resolvePluginPath] Failed to parse package.json for ${name}:`, err.message)
539
- }
540
- }
541
- // 默认加载 index.js
542
- const indexPath = path.join(folderPath, 'index.js')
543
- if (fs.existsSync(indexPath)) {
544
- return { path: indexPath, type: 'folder' }
545
- }
546
- //console.warn(`[resolvePluginPath] No entry point found for plugin folder: ${name}`)
547
- return null
548
- }
549
-
550
- // 单文件回退
551
- if (fs.existsSync(filePath)) {
552
- return { path: filePath, type: 'file' }
553
- }
554
-
555
- return null
556
- }
557
-
558
- /**
559
- * 扫描插件目录,返回所有插件名称
560
- * @param {string} pluginsDir - 插件目录
561
- * @returns {string[]} 插件名称列表
562
- */
563
- function scanPluginNames(pluginsDir) {
564
- if (!fs.existsSync(pluginsDir)) {
565
- return []
566
- }
567
-
568
- const names = new Set()
569
- const entries = fs.readdirSync(pluginsDir, { withFileTypes: true })
570
-
571
- for (const entry of entries) {
572
- if (entry.isDirectory()) {
573
- // 文件夹插件
574
- names.add(entry.name)
575
- } else if (entry.isFile() && entry.name.endsWith('.js')) {
576
- // 单文件插件(排除与文件夹同名的)
577
- const baseName = entry.name.replace(/\.js$/, '')
578
- if (!names.has(baseName)) {
579
- names.add(baseName)
580
- }
581
- }
582
- }
583
-
584
- return Array.from(names)
585
- }
586
-
587
- async function loadCustomPlugins(framework, agentConfig) {
588
- // 加载 .agent/plugins 目录下的自定义插件
589
- const pluginsDir = path.resolve(process.cwd(), '.agent', 'plugins')
590
-
591
- if (!fs.existsSync(pluginsDir)) {
592
- return
593
- }
594
-
595
- // 扫描所有插件名称(支持文件夹和单文件)
596
- const pluginNames = scanPluginNames(pluginsDir)
597
-
598
- for (const pluginName of pluginNames) {
599
- try {
600
- const resolved = resolvePluginPath(pluginsDir, pluginName)
601
- if (!resolved) {
602
- //console.warn(`[Bootstrap] Cannot resolve plugin: ${pluginName}`)
603
- continue
604
- }
605
-
606
- const { path: pluginPath, type } = resolved
607
-
608
- // 清除缓存
609
- delete require.cache[require.resolve(pluginPath)]
610
- const pluginModule = require(pluginPath)
611
-
612
- let plugin
613
- if (typeof pluginModule === 'function') {
614
- // 免引入写法:直接传递函数,让 loadPlugin 内部处理
615
- plugin = pluginModule
616
- } else if (pluginModule.default) {
617
- plugin = pluginModule.default
618
- } else {
619
- plugin = pluginModule
620
- }
621
-
622
- // 获取插件名称
623
- const tempPlugin = typeof plugin === 'function' && plugin.prototype?.name
624
- ? new plugin() : plugin
625
- const resolvedPluginName = tempPlugin.name || pluginName
626
-
627
- // 如果插件已加载且已启动,跳过
628
- if (framework.pluginManager.has(resolvedPluginName) &&
629
- framework.pluginManager.get(resolvedPluginName)?._started) {
630
- continue
631
- }
632
-
633
- //console.log(`[Bootstrap] Loading custom plugin: ${pluginName} (${type})`)
634
- // .agent/plugins 目录下的插件强制启用,不受 state 文件 enabled: false 影响
635
- await framework.pluginManager.load(plugin, { forceEnabled: true })
636
- } catch (err) {
637
- console.error(`[Bootstrap] Failed to load plugin ${pluginName}:`, err.message)
638
- }
639
- }
640
- }
641
-
642
- module.exports = {
643
- DefaultPlugins,
644
- loadAgentConfig,
645
- bootstrapDefaults,
646
- loadCustomPlugins,
647
- resolvePluginPath,
648
- scanPluginNames
649
- }
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', '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. Storage 存储插件
310
+ if (shouldLoad('storage')) {
311
+ const { StoragePlugin } = require('./storage-plugin')
312
+ await framework.loadPlugin(new StoragePlugin())
313
+ framework._debug&&bootstrapLog.debug(' Storage Plugin loaded')
314
+ }
315
+
316
+ // 3. 内置工具插件
317
+ if (shouldLoad('tools')) {
318
+ const { ToolsPlugin } = require('./tools-plugin')
319
+ await framework.loadPlugin(new ToolsPlugin())
320
+ framework._debug&&bootstrapLog.debug(' Tools Plugin loaded')
321
+ }
322
+
323
+ // 4. 工作流插件
324
+ if (shouldLoad('workflow')) {
325
+ const { WorkflowPlugin } = require('../src/capabilities/workflow-engine')
326
+ await framework.loadPlugin(new WorkflowPlugin())
327
+ framework._debug&&bootstrapLog.debug(' Workflow Plugin loaded')
328
+ }
329
+
330
+ // 5. Skill 管理器插件
331
+ if (shouldLoad('skill-manager')) {
332
+ if (skillsDirs.length > 0) {
333
+ const { SkillManagerPlugin } = require('../src/capabilities/skill-manager')
334
+ // 传递所有 skills 目录
335
+ await framework.loadPlugin(new SkillManagerPlugin({ skillsDirs }))
336
+ framework._debug&&bootstrapLog.debug(' Skill Manager loaded')
337
+ }
338
+ }
339
+
340
+ // 6. MCP 执行器插件(始终加载,确保 mcp_reload 工具可用)
341
+ if (shouldLoad('mcp-executor')) {
342
+ const mcpServers = Object.entries(agentConfig.mcpServers || {})
343
+ const servers = mcpServers.map(([name, cfg]) => ({
344
+ ...cfg,
345
+ name,
346
+ command: cfg.command,
347
+ args: cfg.args || [],
348
+ env: cfg.env || {},
349
+ url: cfg.url,
350
+ headers: cfg.headers
351
+ }))
352
+ const { MCPExecutorPlugin } = require('../src/executors/mcp-executor')
353
+ await framework.loadPlugin(new MCPExecutorPlugin({ servers }))
354
+ framework._debug&&bootstrapLog.debug(` MCP Executor loaded${servers.length > 0 ? ` (${servers.length} servers)` : ' (no servers)'}`)
355
+ }
356
+
357
+ // 7. Shell 执行器插件
358
+ if (shouldLoad('shell-executor')) {
359
+ const { ShellExecutorPlugin } = require('./shell-executor-plugin')
360
+ await framework.loadPlugin(new ShellExecutorPlugin())
361
+ framework._debug&&bootstrapLog.debug(' Shell Executor loaded')
362
+ }
363
+
364
+ // 8. Python 执行器插件
365
+ if (shouldLoad('python-executor')) {
366
+ const { PythonExecutorPlugin } = require('./python-executor-plugin')
367
+ await framework.loadPlugin(new PythonExecutorPlugin())
368
+ framework._debug&&bootstrapLog.debug(' Python Executor loaded')
369
+ }
370
+
371
+ // 8.5 Web Web服务插件
372
+ if (shouldLoad('web')) {
373
+ const { WebPlugin } = require('./web-plugin')
374
+ await framework.loadPlugin(new WebPlugin())
375
+ framework._debug&&bootstrapLog.debug(' Web Plugin loaded')
376
+ }
377
+
378
+ // 9. Session 会话管理插件
379
+ if (shouldLoad('session')) {
380
+ const { SessionPlugin } = require('./session-plugin')
381
+ await framework.loadPlugin(new SessionPlugin())
382
+ framework._debug&&bootstrapLog.debug(' Session Plugin loaded')
383
+ }
384
+
385
+ // 10. Audit 审计日志插件
386
+ if (shouldLoad('audit')) {
387
+ const { AuditPlugin } = require('./audit-plugin')
388
+ await framework.loadPlugin(new AuditPlugin())
389
+ framework._debug&&bootstrapLog.debug(' Audit Plugin loaded')
390
+ }
391
+
392
+ // 10. Rules 规则引擎插件
393
+ if (shouldLoad('rules')) {
394
+ const { RulesPlugin } = require('./rules-plugin')
395
+ await framework.loadPlugin(new RulesPlugin())
396
+ framework._debug&&bootstrapLog.debug(' Rules Plugin loaded')
397
+ }
398
+
399
+ // 11. Scheduler 定时任务插件
400
+ if (shouldLoad('scheduler')) {
401
+ const { SchedulerPlugin } = require('./scheduler-plugin')
402
+ await framework.loadPlugin(new SchedulerPlugin())
403
+ framework._debug&&bootstrapLog.debug(' Scheduler Plugin loaded')
404
+ }
405
+
406
+ // 11. FileSystem 文件系统插件
407
+ if (shouldLoad('file-system')) {
408
+ const { FileSystemPlugin } = require('./file-system-plugin')
409
+ await framework.loadPlugin(new FileSystemPlugin())
410
+ framework._debug&&bootstrapLog.debug(' FileSystem Plugin loaded')
411
+ }
412
+
413
+ // 12. Think 主动思考插件
414
+ if (shouldLoad('think')) {
415
+ const { ThinkPlugin } = require('./think-plugin')
416
+ await framework.loadPlugin(new ThinkPlugin())
417
+ framework._debug&&bootstrapLog.debug(' Think Plugin loaded')
418
+ }
419
+
420
+ // 12.1 Ambient Agent 插件
421
+ if (shouldLoad('ambient')) {
422
+ const { AmbientAgentPlugin } = require('./ambient-agent')
423
+ await framework.loadPlugin(new AmbientAgentPlugin())
424
+ framework._debug&&bootstrapLog.debug(' Ambient Agent Plugin loaded')
425
+ }
426
+
427
+ // 12.5 Python 插件加载器
428
+ if (shouldLoad('python-plugin-loader')) {
429
+ const { PythonPluginLoader } = require('./python-plugin-loader')
430
+ await framework.loadPlugin(new PythonPluginLoader({ agentDir: agentConfig.agentDir }))
431
+ framework._debug&&bootstrapLog.debug(' Python Plugin Loader loaded')
432
+ }
433
+
434
+ // 12.6 Telegram 插件(默认禁用,需要在 plugins.json 中设置 enabled: true)
435
+ if (shouldLoad('telegram')) {
436
+ const { TelegramPlugin } = require('./telegram-plugin')
437
+ const telegramConfig = {
438
+ botToken: process.env.TELEGRAM_BOT_TOKEN || agentConfig.telegram?.botToken
439
+ }
440
+ await framework.loadPlugin(new TelegramPlugin(telegramConfig))
441
+ }
442
+
443
+ // 12.7 WeChat 插件(默认禁用,需要在 plugins.json 中设置 enabled: true)
444
+ if (shouldLoad('weixin')) {
445
+ try {
446
+ const { WeixinPlugin } = require('./weixin-plugin')
447
+ const weixinConfig = {
448
+ forceLogin: agentConfig.weixin?.forceLogin || false,
449
+ qrcodeTerminal: agentConfig.weixin?.qrcodeTerminal !== false,
450
+ allowedUsers: agentConfig.weixin?.allowedUsers || []
451
+ }
452
+ await framework.loadPlugin(new WeixinPlugin(weixinConfig))
453
+ } catch (err) {
454
+ bootstrapLog.warn(' WeChat Plugin not available:', err.message)
455
+ }
456
+ }
457
+
458
+ // 12.8 Email 插件(默认禁用,需要在 plugins.json 中设置 enabled: true)
459
+ if (shouldLoad('email')) {
460
+ try {
461
+ const { Plugin } = require('../src/core/plugin-base')
462
+ const { logger } = require('../src/utils/logger')
463
+ const log = logger.child('AgentConfig')
464
+ const bootstrapLog = logger.child('Bootstrap')
465
+ const { EmailPlugin } = require('./email')
466
+ // 支持两种格式:email.smtp email.config.smtp
467
+ const emailData = agentConfig.email || {}
468
+ const emailCfg = emailData.config || {}
469
+ const emailConfig = {
470
+ smtp: emailCfg.smtp || emailData.smtp || {},
471
+ imap: emailCfg.imap || emailData.imap || {},
472
+ clientId: emailCfg.clientId || emailData.clientId
473
+ }
474
+ await framework.loadPlugin(new EmailPlugin(emailConfig))
475
+ } catch (err) {
476
+ bootstrapLog.warn(' Email Plugin not available:', err.message)
477
+ }
478
+ }
479
+
480
+ // 12.9 Feishu 插件(默认禁用,需要在 plugins.json 中设置 enabled: true)
481
+ if (shouldLoad('feishu')) {
482
+ try {
483
+ const { FeishuPlugin } = require('./feishu-plugin')
484
+ const feishuConfig = {
485
+ allowedUsers: agentConfig.feishu?.allowedUsers || []
486
+ }
487
+ await framework.loadPlugin(new FeishuPlugin(feishuConfig))
488
+ } catch (err) {
489
+ bootstrapLog.warn(' Feishu Plugin not available:', err.message)
490
+ }
491
+ }
492
+
493
+ // 12.10 SubAgent 管理器
494
+ if (shouldLoad('subagent-manager')) {
495
+ try {
496
+ // 先初始化 SubAgentConfigManager 并加载所有配置
497
+ const { SubAgentConfigManager } = require('../src/core/sub-agent-config')
498
+ const subAgentConfigManager = new SubAgentConfigManager(agentConfig.agentsDir)
499
+ subAgentConfigManager.loadAll()
500
+ framework._subAgentConfigManager = subAgentConfigManager
501
+
502
+ // 然后加载 SubAgentManagerPlugin
503
+ const { SubAgentManagerPlugin } = require('./subagent-plugin')
504
+ await framework.loadPlugin(new SubAgentManagerPlugin({ agentsDir: agentConfig.agentsDir }))
505
+ framework._debug&&bootstrapLog.debug(' SubAgent Manager loaded')
506
+ } catch (err) {
507
+ bootstrapLog.warn(' SubAgent Manager failed:', err.message)
508
+ }
509
+ }
510
+
511
+ // 13. 加载自定义插件
512
+ await loadCustomPlugins(framework, agentConfig)
513
+
514
+ framework._debug&&bootstrapLog.debug(' All plugins loaded')
515
+
516
+ // 统一启动所有插件(避免重复启动)
517
+ await framework.pluginManager.startAll()
518
+
519
+ // 清除 bootstrap 模式
520
+ framework.pluginManager.setBootstrapping(false)
521
+
522
+ framework._debug&&bootstrapLog.debug(' Loaded plugins ', framework.pluginManager.getAll().length)
523
+ framework._debug&&bootstrapLog.debug(' Loaded tools ', framework.getTools().length)
524
+ }
525
+
526
+ /**
527
+ * 解析插件路径
528
+ * 支持两种结构:
529
+ * 1. 文件夹结构: .agent/plugins/my-plugin/index.js
530
+ * 2. 单文件结构: .agent/plugins/my-plugin.js
531
+ * @param {string} pluginsDir - 插件目录
532
+ * @param {string} name - 插件名称
533
+ * @returns {{path: string, type: 'folder'|'file'}|null} 插件路径和类型
534
+ */
535
+ function resolvePluginPath(pluginsDir, name) {
536
+ const folderPath = path.join(pluginsDir, name)
537
+ const filePath = path.join(pluginsDir, `${name}.js`)
538
+
539
+ // 文件夹优先
540
+ if (fs.existsSync(folderPath) && fs.statSync(folderPath).isDirectory()) {
541
+ const pkgPath = path.join(folderPath, 'package.json')
542
+ if (fs.existsSync(pkgPath)) {
543
+ try {
544
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))
545
+ const main = pkg.main || 'index.js'
546
+ const mainPath = path.join(folderPath, main)
547
+ if (fs.existsSync(mainPath)) {
548
+ return { path: mainPath, type: 'folder' }
549
+ }
550
+ } catch (err) {
551
+ log.warn(` Failed to parse package.json for ${name}:`, err.message)
552
+ }
553
+ }
554
+ // 默认加载 index.js
555
+ const indexPath = path.join(folderPath, 'index.js')
556
+ if (fs.existsSync(indexPath)) {
557
+ return { path: indexPath, type: 'folder' }
558
+ }
559
+ //log.warn(` No entry point found for plugin folder: ${name}`)
560
+ return null
561
+ }
562
+
563
+ // 单文件回退
564
+ if (fs.existsSync(filePath)) {
565
+ return { path: filePath, type: 'file' }
566
+ }
567
+
568
+ return null
569
+ }
570
+
571
+ /**
572
+ * 扫描插件目录,返回所有插件名称
573
+ * @param {string} pluginsDir - 插件目录
574
+ * @returns {string[]} 插件名称列表
575
+ */
576
+ function scanPluginNames(pluginsDir) {
577
+ if (!fs.existsSync(pluginsDir)) {
578
+ return []
579
+ }
580
+
581
+ const names = new Set()
582
+ const entries = fs.readdirSync(pluginsDir, { withFileTypes: true })
583
+
584
+ for (const entry of entries) {
585
+ if (entry.isDirectory()) {
586
+ // 文件夹插件
587
+ names.add(entry.name)
588
+ } else if (entry.isFile() && entry.name.endsWith('.js')) {
589
+ // 单文件插件(排除与文件夹同名的)
590
+ const baseName = entry.name.replace(/\.js$/, '')
591
+ if (!names.has(baseName)) {
592
+ names.add(baseName)
593
+ }
594
+ }
595
+ }
596
+
597
+ return Array.from(names)
598
+ }
599
+
600
+ async function loadCustomPlugins(framework, agentConfig) {
601
+ // 加载 .agent/plugins 目录下的自定义插件
602
+ const pluginsDir = path.resolve(process.cwd(), '.agent', 'plugins')
603
+
604
+ if (!fs.existsSync(pluginsDir)) {
605
+ return
606
+ }
607
+
608
+ // 扫描所有插件名称(支持文件夹和单文件)
609
+ const pluginNames = scanPluginNames(pluginsDir)
610
+
611
+ for (const pluginName of pluginNames) {
612
+ try {
613
+ const resolved = resolvePluginPath(pluginsDir, pluginName)
614
+ if (!resolved) {
615
+ //log.warn(` Cannot resolve plugin: ${pluginName}`)
616
+ continue
617
+ }
618
+
619
+ const { path: pluginPath, type } = resolved
620
+
621
+ // 清除缓存
622
+ delete require.cache[require.resolve(pluginPath)]
623
+ const pluginModule = require(pluginPath)
624
+
625
+ let plugin
626
+ if (typeof pluginModule === 'function') {
627
+ // 免引入写法:直接传递函数,让 loadPlugin 内部处理
628
+ plugin = pluginModule
629
+ } else if (pluginModule.default) {
630
+ plugin = pluginModule.default
631
+ } else {
632
+ plugin = pluginModule
633
+ }
634
+
635
+ // 获取插件名称
636
+ const tempPlugin = typeof plugin === 'function' && plugin.prototype?.name
637
+ ? new plugin() : plugin
638
+ const resolvedPluginName = tempPlugin.name || pluginName
639
+
640
+ // 如果插件已加载且已启动,跳过
641
+ if (framework.pluginManager.has(resolvedPluginName) &&
642
+ framework.pluginManager.get(resolvedPluginName)?._started) {
643
+ continue
644
+ }
645
+
646
+ //bootstrapLog.debug(` Loading custom plugin: ${pluginName} (${type})`)
647
+ // .agent/plugins 目录下的插件强制启用,不受 state 文件 enabled: false 影响
648
+ await framework.pluginManager.load(plugin, { forceEnabled: true })
649
+ } catch (err) {
650
+ log.error(` Failed to load plugin ${pluginName}:`, err.message)
651
+ }
652
+ }
653
+ }
654
+
655
+ module.exports = {
656
+ DefaultPlugins,
657
+ loadAgentConfig,
658
+ bootstrapDefaults,
659
+ loadCustomPlugins,
660
+ resolvePluginPath,
661
+ scanPluginNames
662
+ }