foliko 1.1.93 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (212) hide show
  1. package/.claude/settings.local.json +2 -1
  2. package/CLAUDE.md +56 -30
  3. package/REFACTORING_PLAN.md +645 -0
  4. package/docs/architecture.md +131 -0
  5. package/docs/migration.md +57 -0
  6. package/docs/public-api.md +138 -0
  7. package/docs/usage.md +385 -0
  8. package/examples/ambient-example.js +20 -137
  9. package/examples/basic.js +21 -48
  10. package/examples/bootstrap.js +16 -74
  11. package/examples/mcp-example.js +6 -29
  12. package/examples/skill-example.js +6 -19
  13. package/examples/workflow.js +8 -56
  14. package/package.json +8 -4
  15. package/plugins/README.md +49 -0
  16. package/plugins/{ambient-agent → ambient}/EventWatcher.js +1 -1
  17. package/plugins/{ambient-agent → ambient}/ExplorerLoop.js +3 -3
  18. package/plugins/{ambient-agent → ambient}/GoalManager.js +2 -2
  19. package/plugins/ambient/README.md +14 -0
  20. package/plugins/{ambient-agent → ambient}/Reflector.js +1 -1
  21. package/plugins/{ambient-agent → ambient}/StateStore.js +1 -1
  22. package/plugins/{ambient-agent → ambient}/index.js +2 -2
  23. package/plugins/{ai-plugin.js → core/ai/index.js} +14 -30
  24. package/plugins/{audit-plugin.js → core/audit/index.js} +3 -30
  25. package/plugins/{coordinator-plugin.js → core/coordinator/index.js} +3 -35
  26. package/plugins/core/default/bootstrap.js +224 -0
  27. package/plugins/core/default/config.js +222 -0
  28. package/plugins/core/default/index.js +58 -0
  29. package/plugins/core/mcp/index.js +1 -0
  30. package/plugins/{python-plugin-loader.js → core/python-loader/index.js} +7 -187
  31. package/plugins/{rules-plugin.js → core/rules/index.js} +121 -64
  32. package/plugins/{scheduler-plugin.js → core/scheduler/index.js} +12 -114
  33. package/plugins/{session-plugin.js → core/session/index.js} +9 -73
  34. package/{src/capabilities/skill-manager.js → plugins/core/skill-manager/index.js} +64 -18
  35. package/plugins/{storage-plugin.js → core/storage/index.js} +5 -29
  36. package/plugins/{subagent-plugin.js → core/sub-agent/index.js} +10 -171
  37. package/plugins/{think-plugin.js → core/think/index.js} +24 -91
  38. package/{src/capabilities/workflow-engine.js → plugins/core/workflow/index.js} +87 -85
  39. package/plugins/default-plugins.js +6 -720
  40. package/plugins/{data-splitter-plugin.js → executors/data-splitter/index.js} +9 -83
  41. package/plugins/{extension-executor-plugin.js → executors/extension/index.js} +13 -97
  42. package/plugins/{python-executor-plugin.js → executors/python/index.js} +6 -31
  43. package/plugins/{shell-executor-plugin.js → executors/shell/index.js} +2 -5
  44. package/plugins/install/README.md +9 -0
  45. package/plugins/{install-plugin.js → install/index.js} +3 -3
  46. package/plugins/{file-system-plugin.js → io/file-system/index.js} +34 -236
  47. package/plugins/{web-plugin.js → io/web/index.js} +11 -113
  48. package/plugins/memory/README.md +13 -0
  49. package/plugins/{memory-plugin.js → memory/index.js} +4 -18
  50. package/plugins/messaging/email/README.md +19 -0
  51. package/plugins/{email → messaging/email}/index.js +3 -3
  52. package/plugins/{feishu-plugin.js → messaging/feishu/index.js} +4 -4
  53. package/plugins/{qq-plugin.js → messaging/qq/index.js} +6 -17
  54. package/plugins/{telegram-plugin.js → messaging/telegram/index.js} +4 -4
  55. package/plugins/{weixin-plugin.js → messaging/weixin/index.js} +16 -16
  56. package/plugins/{plugin-manager-plugin.js → plugin-manager/index.js} +36 -180
  57. package/plugins/{tools-plugin.js → tools/index.js} +68 -116
  58. package/plugins/trading/README.md +15 -0
  59. package/plugins/{gate-trading.js → trading/index.js} +8 -8
  60. package/{examples → sandbox}/test-concurrent-chat.js +2 -2
  61. package/{examples → sandbox}/test-long-chat.js +2 -2
  62. package/{examples → sandbox}/test-session-chat.js +2 -2
  63. package/{examples → sandbox}/test-web-plugin.js +1 -1
  64. package/{examples → sandbox}/test-weixin-feishu.js +2 -2
  65. package/src/agent/base.js +56 -0
  66. package/src/{core/agent-chat.js → agent/chat.js} +11 -11
  67. package/src/{core/coordinator-manager.js → agent/coordinator.js} +3 -3
  68. package/src/agent/index.js +111 -0
  69. package/src/agent/main.js +337 -0
  70. package/src/agent/prompt.js +78 -0
  71. package/src/agent/sub.js +198 -0
  72. package/src/agent/worker.js +104 -0
  73. package/{cli/bin/foliko.js → src/cli/bin.js} +1 -1
  74. package/{cli/src → src/cli}/commands/chat.js +25 -21
  75. package/{cli/src → src/cli}/index.js +1 -0
  76. package/{cli/src → src/cli}/ui/chat-ui-old.js +40 -178
  77. package/{cli/src → src/cli}/ui/chat-ui.js +3 -3
  78. package/{cli/src → src/cli}/ui/components/footer-bar.js +1 -1
  79. package/src/common/errors.js +402 -0
  80. package/src/{utils → common}/logger.js +33 -0
  81. package/src/{utils/chat-queue.js → common/queue.js} +2 -2
  82. package/src/config/plugin-config.js +50 -0
  83. package/src/context/agent.js +32 -0
  84. package/src/context/compaction-prompts.js +170 -0
  85. package/src/context/compaction-utils.js +191 -0
  86. package/src/context/compressor.js +413 -0
  87. package/src/context/index.js +9 -0
  88. package/src/{core/context-manager.js → context/manager.js} +1 -1
  89. package/src/context/request.js +50 -0
  90. package/src/context/session.js +33 -0
  91. package/src/context/storage.js +30 -0
  92. package/src/executors/mcp-client.js +153 -0
  93. package/src/executors/mcp-desc.js +236 -0
  94. package/src/executors/mcp-executor.js +91 -956
  95. package/src/{core → framework}/command-registry.js +1 -1
  96. package/src/framework/framework.js +300 -0
  97. package/src/framework/index.js +18 -0
  98. package/src/framework/lifecycle.js +203 -0
  99. package/src/framework/loader.js +78 -0
  100. package/src/framework/registry.js +86 -0
  101. package/src/{core/ui-extension-context.js → framework/ui-extension.js} +1 -1
  102. package/src/index.js +130 -15
  103. package/src/llm/index.js +26 -0
  104. package/src/llm/provider.js +212 -0
  105. package/src/llm/registry.js +11 -0
  106. package/src/{core/token-counter.js → llm/tokens.js} +4 -37
  107. package/src/{core/plugin-base.js → plugin/base.js} +10 -136
  108. package/src/plugin/index.js +14 -0
  109. package/src/plugin/loader.js +101 -0
  110. package/src/plugin/manager.js +484 -0
  111. package/src/{core → session}/branch-summary-auto.js +2 -2
  112. package/src/{core/chat-session.js → session/chat.js} +2 -2
  113. package/src/session/index.js +7 -0
  114. package/src/{core/session-manager.js → session/session.js} +2 -2
  115. package/src/session/ttl.js +92 -0
  116. package/src/{core/jsonl-storage.js → storage/jsonl.js} +1 -1
  117. package/src/tool/executor.js +85 -0
  118. package/src/tool/index.js +15 -0
  119. package/src/tool/registry.js +143 -0
  120. package/src/{core/tool-router.js → tool/router.js} +17 -124
  121. package/src/tool/schema.js +108 -0
  122. package/src/utils/data-splitter.js +1 -1
  123. package/src/utils/download.js +1 -1
  124. package/src/utils/index.js +6 -6
  125. package/src/utils/message-validator.js +1 -1
  126. package/tests/core/context-storage.test.js +46 -0
  127. package/tests/core/llm.test.js +54 -0
  128. package/tests/core/plugin.test.js +42 -0
  129. package/tests/core/tool.test.js +60 -0
  130. package/tests/setup.js +10 -0
  131. package/tests/smoke.test.js +58 -0
  132. package/vitest.config.js +9 -0
  133. package/cli/src/daemon.js +0 -149
  134. package/docs/CONTEXT_DESIGN.md +0 -1596
  135. package/docs/ai-sdk-optimization.md +0 -655
  136. package/docs/features.md +0 -120
  137. package/docs/qq-bot.md +0 -976
  138. package/docs/quick-reference.md +0 -160
  139. package/docs/user-manual.md +0 -1391
  140. package/images/geometric_shapes.jpg +0 -0
  141. package/images/sunset_mountain_lake.jpg +0 -0
  142. package/skills/poster-guide/SKILL.md +0 -792
  143. package/src/capabilities/index.js +0 -11
  144. package/src/core/agent.js +0 -808
  145. package/src/core/context-compressor.js +0 -959
  146. package/src/core/enhanced-context-compressor.js +0 -210
  147. package/src/core/framework.js +0 -1422
  148. package/src/core/index.js +0 -30
  149. package/src/core/plugin-manager.js +0 -961
  150. package/src/core/provider-registry.js +0 -159
  151. package/src/core/provider.js +0 -156
  152. package/src/core/request-context.js +0 -98
  153. package/src/core/subagent.js +0 -442
  154. package/src/core/system-prompt-builder.js +0 -120
  155. package/src/core/tool-executor.js +0 -202
  156. package/src/core/tool-registry.js +0 -517
  157. package/src/core/worker-agent.js +0 -192
  158. package/src/executors/executor-base.js +0 -58
  159. package/src/utils/error-boundary.js +0 -363
  160. package/src/utils/error.js +0 -374
  161. package/system.md +0 -1645
  162. package/website_v2/README.md +0 -57
  163. package/website_v2/SPEC.md +0 -1
  164. package/website_v2/docs/api.html +0 -128
  165. package/website_v2/docs/configuration.html +0 -147
  166. package/website_v2/docs/plugin-development.html +0 -129
  167. package/website_v2/docs/project-structure.html +0 -89
  168. package/website_v2/docs/skill-development.html +0 -85
  169. package/website_v2/index.html +0 -489
  170. package/website_v2/scripts/main.js +0 -93
  171. package/website_v2/styles/animations.css +0 -8
  172. package/website_v2/styles/docs.css +0 -83
  173. package/website_v2/styles/main.css +0 -417
  174. package/xhs_auth.json +0 -268
  175. package//346/265/267/346/212/245/346/217/222/344/273/266.md +0 -621
  176. /package/plugins/{ambient-agent → ambient}/constants.js +0 -0
  177. /package/plugins/{email → messaging/email}/constants.js +0 -0
  178. /package/plugins/{email → messaging/email}/handlers.js +0 -0
  179. /package/plugins/{email → messaging/email}/monitor.js +0 -0
  180. /package/plugins/{email → messaging/email}/parser.js +0 -0
  181. /package/plugins/{email → messaging/email}/reply.js +0 -0
  182. /package/plugins/{email → messaging/email}/utils.js +0 -0
  183. /package/{examples → sandbox}/test-chat.js +0 -0
  184. /package/{examples → sandbox}/test-mcp.js +0 -0
  185. /package/{examples → sandbox}/test-reload.js +0 -0
  186. /package/{examples → sandbox}/test-telegram.js +0 -0
  187. /package/{examples → sandbox}/test-tg-bot.js +0 -0
  188. /package/{examples → sandbox}/test-tg-simple.js +0 -0
  189. /package/{examples → sandbox}/test-tg.js +0 -0
  190. /package/{examples → sandbox}/test-think.js +0 -0
  191. /package/src/{core/sub-agent-config.js → agent/sub-config.js} +0 -0
  192. /package/{cli/src → src/cli}/commands/daemon.js +0 -0
  193. /package/{cli/src → src/cli}/commands/list.js +0 -0
  194. /package/{cli/src → src/cli}/commands/plugin.js +0 -0
  195. /package/{cli/src → src/cli}/ui/components/agent-mention-provider.js +0 -0
  196. /package/{cli/src → src/cli}/ui/components/chained-autocomplete-provider.js +0 -0
  197. /package/{cli/src → src/cli}/ui/components/message-bubble.js +0 -0
  198. /package/{cli/src → src/cli}/ui/components/status-bar.js +0 -0
  199. /package/{cli/src → src/cli}/utils/ansi.js +0 -0
  200. /package/{cli/src → src/cli}/utils/config.js +0 -0
  201. /package/{cli/src → src/cli}/utils/markdown.js +0 -0
  202. /package/{cli/src → src/cli}/utils/plugin-config.js +0 -0
  203. /package/{cli/src → src/cli}/utils/render-diff.js +0 -0
  204. /package/src/{utils/circuit-breaker.js → common/circuit.js} +0 -0
  205. /package/src/{core → common}/constants.js +0 -0
  206. /package/src/{utils/edit-diff.js → common/diff.js} +0 -0
  207. /package/src/{utils/event-emitter.js → common/events.js} +0 -0
  208. /package/src/{utils → common}/id.js +0 -0
  209. /package/src/{utils → common}/retry.js +0 -0
  210. /package/src/{core/notification-manager.js → notification/manager.js} +0 -0
  211. /package/src/{core/session-entry.js → session/entry.js} +0 -0
  212. /package/src/{core/storage-manager.js → storage/manager.js} +0 -0
@@ -3,9 +3,9 @@
3
3
  * 支持 HTTP 服务、路由注册、Webhook(自动生成 /webhook/{id} 链接)
4
4
  */
5
5
 
6
- const { Plugin } = require('../src/core/plugin-base')
7
- const { logger } = require('../src/utils/logger')
8
- const { runInSandbox } = require('../src/utils/sandbox')
6
+ const { Plugin } = require('../../../src/plugin/base')
7
+ const { logger } = require('../../../src/common/logger')
8
+ const { runInSandbox } = require('../../../src/utils/sandbox')
9
9
  const log = logger.child('Web')
10
10
  const { z } = require('zod')
11
11
  const { serve } = require('@hono/node-server')
@@ -13,9 +13,6 @@ const { Hono } = require('hono')
13
13
  const fs = require('fs')
14
14
  const path = require('path')
15
15
 
16
- // ============================================================================
17
- // WebStore - 持久化 Web 配置到 .foliko/data/web/
18
- // ============================================================================
19
16
  class WebStore {
20
17
  constructor(persistencePath) {
21
18
  this._persistencePath = persistencePath
@@ -61,43 +58,34 @@ class WebPlugin extends Plugin {
61
58
  this.description = 'Web 服务插件,支持 HTTP 服务、路由注册、Webhook'
62
59
  this.priority = 50
63
60
 
64
- this.system = true
61
+ this.system = true
65
62
 
66
- // 服务器配置
67
63
  this._port = process.env.WEB_PORT || 3000
68
64
  this._host = process.env.WEB_HOST || '127.0.0.1'
69
- this._baseUrl = process.env.WEB_BASE_URL || null // 公网可访问的域名
65
+ this._baseUrl = process.env.WEB_BASE_URL || null
70
66
 
71
- // 运行时状态
72
67
  this._server = null
73
68
  this._app = null
74
69
  this._framework = null
75
70
 
76
71
  this.tools = {}
77
72
 
78
- // 数据存储(始终保持原始类型)
79
- this._routes = [] // 路由列表
80
- this._webhooks = new Map() // webhook Map: id -> {id, path, prompt, sessionId}
81
- this._statics = [] // 静态文件夹列表
73
+ this._routes = []
74
+ this._webhooks = new Map()
75
+ this._statics = []
82
76
 
83
- // 持久化存储
84
77
  this._webStore = null
85
78
  this._persistencePath = config.persistencePath || '.foliko/data/web'
86
79
  }
87
80
 
88
- // ==================== 生命周期 ====================
89
-
90
81
  install(framework) {
91
82
  this._framework = framework
92
83
  this._registerTools()
93
84
 
94
- // 初始化持久化存储
95
85
  this._webStore = new WebStore(this._persistencePath)
96
86
 
97
- // 加载已保存的配置
98
87
  this._loadPersistedConfig()
99
88
 
100
- // 将 WEB_BASE_URL 注入到 framework 的元数据,供所有 agent 使用
101
89
  if (this._baseUrl && framework._mainAgent) {
102
90
  framework._mainAgent.setMetadata('WEB_BASE_URL', this._baseUrl)
103
91
  }
@@ -112,28 +100,20 @@ class WebPlugin extends Plugin {
112
100
  reload(framework) {
113
101
  this._framework = framework
114
102
 
115
- // 重新初始化存储并加载配置
116
103
  this._webStore = new WebStore(this._persistencePath)
117
104
  this._loadPersistedConfig()
118
105
 
119
- // 重新注入 WEB_BASE_URL
120
106
  if (this._baseUrl && framework._mainAgent) {
121
107
  framework._mainAgent.setMetadata('WEB_BASE_URL', this._baseUrl)
122
108
  }
123
109
  }
124
110
 
125
- /**
126
- * 加载持久化的配置并恢复路由/webhook/静态资源
127
- */
128
111
  _loadPersistedConfig() {
129
112
  if (!this._webStore) return
130
113
 
131
114
  const config = this._webStore.loadConfig()
132
115
  if (!config) return
133
116
 
134
- // log.info(` 加载 Web 配置...`)
135
-
136
- // 恢复前先清空,避免 install -> reload 重复加载导致数据翻倍
137
117
  this._routes = []
138
118
  this._webhooks = new Map()
139
119
  this._statics = []
@@ -142,7 +122,6 @@ class WebPlugin extends Plugin {
142
122
  let hasWebhooks = false
143
123
  let hasStatics = false
144
124
 
145
- // 恢复路由
146
125
  if (config.routes && Array.isArray(config.routes)) {
147
126
  for (const route of config.routes) {
148
127
  if (route.method && route.path && route.handler) {
@@ -153,12 +132,10 @@ class WebPlugin extends Plugin {
153
132
  description: route.description || ''
154
133
  })
155
134
  hasRoutes = true
156
- // log.info(` 恢复路由: ${route.method} ${route.path}`)
157
135
  }
158
136
  }
159
137
  }
160
138
 
161
- // 恢复 Webhooks
162
139
  if (config.webhooks && Array.isArray(config.webhooks)) {
163
140
  for (const webhook of config.webhooks) {
164
141
  if (webhook.id && webhook.path) {
@@ -169,12 +146,10 @@ class WebPlugin extends Plugin {
169
146
  awaitResponse: webhook.awaitResponse || false
170
147
  })
171
148
  hasWebhooks = true
172
- // log.info(` 恢复 Webhook: ${webhook.path}`)
173
149
  }
174
150
  }
175
151
  }
176
152
 
177
- // 恢复静态资源
178
153
  if (config.statics && Array.isArray(config.statics)) {
179
154
  for (const staticItem of config.statics) {
180
155
  if (staticItem.urlPath && staticItem.folder) {
@@ -184,23 +159,17 @@ class WebPlugin extends Plugin {
184
159
  options: staticItem.options || { dotfiles: 'ignore', index: 'index.html' }
185
160
  })
186
161
  hasStatics = true
187
- // log.info(` 恢复静态资源: ${staticItem.urlPath} -> ${staticItem.folder}`)
188
162
  }
189
163
  }
190
164
  }
191
165
 
192
- // 如果有恢复的路由/webhook/静态资源,自动启动服务器
193
166
  if ((hasRoutes || hasWebhooks || hasStatics) && !this._server) {
194
- // log.info(` 恢复的 Web 配置需要启动服务器...`)
195
167
  this._startServer().catch(err => {
196
168
  log.error(` 自动启动服务器失败:`, err.message)
197
169
  })
198
170
  }
199
171
  }
200
172
 
201
- /**
202
- * 保存当前配置到持久化存储
203
- */
204
173
  _saveConfig() {
205
174
  if (!this._webStore) return
206
175
 
@@ -232,10 +201,7 @@ class WebPlugin extends Plugin {
232
201
  this._framework = null
233
202
  }
234
203
 
235
- // ==================== 工具注册 ====================
236
-
237
204
  _registerTools() {
238
- // 启动 Web 服务
239
205
  this.tools.web_start = {
240
206
  name: 'web_start',
241
207
  description: '启动 Web 服务',
@@ -246,7 +212,6 @@ class WebPlugin extends Plugin {
246
212
  execute: async (args) => this._startServer(args.port, args.host)
247
213
  }
248
214
 
249
- // 停止 Web 服务
250
215
  this.tools.web_stop = {
251
216
  name: 'web_stop',
252
217
  description: '停止 Web 服务',
@@ -254,7 +219,6 @@ class WebPlugin extends Plugin {
254
219
  execute: async () => this._stopServer()
255
220
  }
256
221
 
257
- // 注册 HTTP 路由
258
222
  this.tools.web_register_route = {
259
223
  name: 'web_register_route',
260
224
  description: '注册 HTTP 路由',
@@ -272,7 +236,6 @@ class WebPlugin extends Plugin {
272
236
  execute: async (args) => this._registerRoute(args.method, args.path, args.handler, args.description)
273
237
  }
274
238
 
275
- // 注册 Webhook(自动生成 /webhook/{id} 链接)
276
239
  this.tools.web_register_webhook = {
277
240
  name: 'web_register_webhook',
278
241
  description: '注册 Webhook,接收的数据会交给 LLM 处理。自动生成唯一 URL',
@@ -283,7 +246,6 @@ class WebPlugin extends Plugin {
283
246
  execute: async (args) => this._registerWebhook(args.prompt, args.awaitResponse)
284
247
  }
285
248
 
286
- // 注册静态资源
287
249
  this.tools.web_register_static = {
288
250
  name: 'web_register_static',
289
251
  description: '注册静态资源文件夹',
@@ -298,7 +260,6 @@ class WebPlugin extends Plugin {
298
260
  execute: async (args) => this._registerStatic(args.urlPath, args.folder, args.options)
299
261
  }
300
262
 
301
- // 列出所有路由
302
263
  this.tools.web_list_routes = {
303
264
  name: 'web_list_routes',
304
265
  description: '列出所有已注册的路由和 Webhook',
@@ -306,7 +267,6 @@ class WebPlugin extends Plugin {
306
267
  execute: async () => this._listRoutes()
307
268
  }
308
269
 
309
- // 删除路由
310
270
  this.tools.web_delete_route = {
311
271
  name: 'web_delete_route',
312
272
  description: '删除已注册的 HTTP 路由',
@@ -317,7 +277,6 @@ class WebPlugin extends Plugin {
317
277
  execute: async (args) => this._deleteRoute(args.method, args.path)
318
278
  }
319
279
 
320
- // 删除 Webhook
321
280
  this.tools.web_delete_webhook = {
322
281
  name: 'web_delete_webhook',
323
282
  description: '删除已注册的 Webhook',
@@ -327,7 +286,6 @@ class WebPlugin extends Plugin {
327
286
  execute: async (args) => this._deleteWebhook(args.id)
328
287
  }
329
288
 
330
- // 删除静态资源
331
289
  this.tools.web_delete_static = {
332
290
  name: 'web_delete_static',
333
291
  description: '删除已注册的静态资源文件夹',
@@ -337,7 +295,6 @@ class WebPlugin extends Plugin {
337
295
  execute: async (args) => this._deleteStatic(args.urlPath)
338
296
  }
339
297
 
340
- // 发送 HTTP 请求
341
298
  this.tools.web_request = {
342
299
  name: 'web_request',
343
300
  description: '发送 HTTP 请求',
@@ -351,8 +308,6 @@ class WebPlugin extends Plugin {
351
308
  }
352
309
  }
353
310
 
354
- // ==================== 服务器控制 ====================
355
-
356
311
  async _startServer(port, host) {
357
312
  if (this._server) {
358
313
  return { success: true, message: 'Server already running', port: this._port }
@@ -371,14 +326,11 @@ class WebPlugin extends Plugin {
371
326
  hostname: this._host
372
327
  })
373
328
  const serverUrl = this._getUrl()
374
- // log.info(` Server started on ${serverUrl}`)
375
329
  return {
376
330
  success: true,
377
331
  message: `Server started on ${serverUrl}`,
378
- // port: this._port,
379
- // host: this._host,
380
332
  host: serverUrl,
381
- url:serverUrl,
333
+ url: serverUrl,
382
334
  }
383
335
  } catch (err) {
384
336
  this._server = null
@@ -397,17 +349,13 @@ class WebPlugin extends Plugin {
397
349
  this._server.close()
398
350
  this._server = null
399
351
  this._app = null
400
- // log.info(' Server stopped')
401
352
  return { success: true, message: 'Server stopped' }
402
353
  }
403
354
 
404
- // ==================== 中间件 ====================
405
-
406
355
  _setupMiddleware() {
407
356
  this._app.use('*', async (c) => {
408
357
  const pathname = c.req.path
409
358
 
410
- // CORS 预检
411
359
  if (c.req.method === 'OPTIONS') {
412
360
  return c.text('', 200, {
413
361
  'Access-Control-Allow-Origin': '*',
@@ -416,7 +364,6 @@ class WebPlugin extends Plugin {
416
364
  })
417
365
  }
418
366
 
419
- // 1. 静态文件
420
367
  const staticResult = this._serveStatic(pathname)
421
368
  if (staticResult) {
422
369
  if (staticResult.type === 'file') {
@@ -435,7 +382,6 @@ class WebPlugin extends Plugin {
435
382
  }
436
383
  }
437
384
 
438
- // 2. Webhook(仅接受 POST)
439
385
  const webhook = this._webhooks.get(pathname)
440
386
  if (webhook) {
441
387
  if (c.req.method !== 'POST') {
@@ -445,20 +391,16 @@ class WebPlugin extends Plugin {
445
391
  return c.json(result)
446
392
  }
447
393
 
448
- // 3. 路由(支持参数)
449
394
  for (const route of this._routes) {
450
395
  if (route.method === c.req.method && this._matchPath(route.path, pathname)) {
451
396
  return await this._handleRoute(c, route, pathname)
452
397
  }
453
398
  }
454
399
 
455
- // 404
456
400
  return c.json({ success: false, error: 'Not Found', path: pathname }, 404)
457
401
  })
458
402
  }
459
403
 
460
- // ==================== 请求处理 ====================
461
-
462
404
  async _handleRoute(c, route, pathname) {
463
405
  const params = this._extractParams(route.path, pathname)
464
406
  const query = this._parseQuery(c)
@@ -466,13 +408,10 @@ class WebPlugin extends Plugin {
466
408
 
467
409
  const context = { params, query, body }
468
410
 
469
- // 构建 tools 代理对象,允许 handler 以函数方式直接调用工具
470
- // 例如: const user = await tools.get_user({ id: 1 })
471
411
  const registry = this._framework.toolRegistry
472
412
  const tools = new Proxy({}, {
473
413
  get: (_, name) => {
474
414
  if (name === 'call') {
475
- // 保留 call 方式作为后备
476
415
  return async (toolName, args) => registry.execute(toolName, args || {}, this._framework)
477
416
  }
478
417
  return async (args) => registry.execute(name, args || {}, this._framework)
@@ -494,11 +433,9 @@ class WebPlugin extends Plugin {
494
433
  timestamp: new Date().toISOString()
495
434
  }
496
435
 
497
- // 从执行上下文获取 sessionId
498
436
  const ctx = this._framework.getExecutionContext()
499
437
  const sessionId = ctx?.sessionId || null
500
438
 
501
- // 获取 Agent
502
439
  const agent = this._getAgent(sessionId)
503
440
  if (!agent) {
504
441
  log.error(' No agent available')
@@ -508,7 +445,6 @@ class WebPlugin extends Plugin {
508
445
  const prompt = webhook.prompt || '处理以下 webhook 数据,返回适当的响应:'
509
446
  const finalSessionId = sessionId || `web_${Date.now()}`
510
447
 
511
- // 触发 webhook 接收事件(扁平化结构)
512
448
  this._framework.emit('webhook:received', {
513
449
  path: webhook.path,
514
450
  method: c.req.method,
@@ -517,19 +453,15 @@ class WebPlugin extends Plugin {
517
453
  timestamp: webhookData.timestamp
518
454
  })
519
455
 
520
- // 使用子Agent处理 webhook
521
456
  const webhookAgent = this._framework.createSubAgent({
522
457
  name: 'webhook_handler',
523
458
  role: 'Webhook处理助手,专注于处理webhook数据并生成适当响应'
524
459
  })
525
460
 
526
461
  if (!webhook.awaitResponse) {
527
- // 不等待,立即返回
528
462
  webhookAgent.chat(`${prompt}\n\n数据:\n${JSON.stringify(webhookData, null, 2)}`).then(result => {
529
463
  const responseText = result.message || ''
530
- // log.info(` Webhook processed (${webhook.path}), LLM response (${responseText.length} chars)`)
531
464
 
532
- // 添加到 session 历史
533
465
  if (sessionId) {
534
466
  const sessionPlugin = this._framework.pluginManager.get('session')
535
467
  if (sessionPlugin) {
@@ -538,7 +470,6 @@ class WebPlugin extends Plugin {
538
470
  }
539
471
  }
540
472
 
541
- // 触发 webhook 处理完成事件
542
473
  this._framework.emit('webhook:processed', {
543
474
  path: webhook.path,
544
475
  method: c.req.method,
@@ -554,13 +485,10 @@ class WebPlugin extends Plugin {
554
485
  return { success: true, message: 'Webhook received, processing in background' }
555
486
  }
556
487
 
557
- // 等待 LLM 处理完成
558
488
  try {
559
489
  const result = await webhookAgent.chat(`${prompt}\n\n数据:\n${JSON.stringify(webhookData, null, 2)}`)
560
490
  const responseText = result.message || result.text || ''
561
- // log.info(` Webhook processed (${webhook.path}), LLM response (${responseText.length} chars)`)
562
491
 
563
- // 添加到 session 历史
564
492
  if (sessionId) {
565
493
  const sessionPlugin = this._framework.pluginManager.get('session')
566
494
  if (sessionPlugin) {
@@ -569,7 +497,6 @@ class WebPlugin extends Plugin {
569
497
  }
570
498
  }
571
499
 
572
- // 触发 webhook 处理完成事件
573
500
  this._framework.emit('webhook:processed', {
574
501
  path: webhook.path,
575
502
  method: c.req.method,
@@ -586,8 +513,6 @@ class WebPlugin extends Plugin {
586
513
  }
587
514
  }
588
515
 
589
- // ==================== 路由注册 ====================
590
-
591
516
  async _registerRoute(method, path, handler, description) {
592
517
  if (!path.startsWith('/') || path.length < 2) {
593
518
  return { success: false, error: 'Invalid path format' }
@@ -605,10 +530,8 @@ class WebPlugin extends Plugin {
605
530
  this._routes.push(route)
606
531
  }
607
532
 
608
- // 持久化保存
609
533
  this._saveConfig()
610
534
 
611
- // log.info(` Route registered: ${method} ${path}`)
612
535
  return { success: true, message: `Route ${method} ${path} registered`, url: this._getUrl(path), route: { method, path, description } }
613
536
  }
614
537
 
@@ -617,7 +540,6 @@ class WebPlugin extends Plugin {
617
540
  await this._startServer()
618
541
  }
619
542
 
620
- // 生成唯一 ID 和路径:/webhook/{id}
621
543
  const id = this._generateId()
622
544
  const webhookPath = `/webhook/${id}`
623
545
 
@@ -628,10 +550,8 @@ class WebPlugin extends Plugin {
628
550
  awaitResponse
629
551
  })
630
552
 
631
- // 持久化保存
632
553
  this._saveConfig()
633
554
 
634
- // log.info(` Webhook registered: ${webhookPath}`)
635
555
  return {
636
556
  success: true,
637
557
  message: `Webhook registered`,
@@ -658,10 +578,8 @@ class WebPlugin extends Plugin {
658
578
  }
659
579
  })
660
580
 
661
- // 持久化保存
662
581
  this._saveConfig()
663
582
 
664
- // log.info(` Static registered: ${normalizedPath} -> ${folder}`)
665
583
  return {
666
584
  success: true,
667
585
  message: `Static folder registered`,
@@ -689,7 +607,6 @@ class WebPlugin extends Plugin {
689
607
 
690
608
  this._routes.splice(index, 1)
691
609
  this._saveConfig()
692
- // log.info(` Route deleted: ${method} ${path}`)
693
610
  return { success: true, message: `Route deleted: ${method} ${path}` }
694
611
  }
695
612
 
@@ -708,7 +625,6 @@ class WebPlugin extends Plugin {
708
625
 
709
626
  this._webhooks.delete(found)
710
627
  this._saveConfig()
711
- // log.info(` Webhook deleted: ${found}`)
712
628
  return { success: true, message: `Webhook deleted: ${found}` }
713
629
  }
714
630
 
@@ -721,12 +637,9 @@ class WebPlugin extends Plugin {
721
637
 
722
638
  this._statics.splice(index, 1)
723
639
  this._saveConfig()
724
- // log.info(` Static deleted: ${normalizedPath}`)
725
640
  return { success: true, message: `Static folder deleted: ${normalizedPath}` }
726
641
  }
727
642
 
728
- // ==================== HTTP 客户端 ====================
729
-
730
643
  async _sendRequest(method, urlPath, body, headers) {
731
644
  if (!this._server) {
732
645
  return { success: false, error: 'Server not started' }
@@ -747,7 +660,7 @@ class WebPlugin extends Plugin {
747
660
  const response = await fetch(url, options)
748
661
  const text = await response.text()
749
662
  let parsed = text
750
- try { parsed = JSON.parse(text) } catch { /* not JSON */ }
663
+ try { parsed = JSON.parse(text) } catch {}
751
664
 
752
665
  return { success: true, status: response.status, headers: Object.fromEntries(response.headers.entries()), body: parsed }
753
666
  } catch (err) {
@@ -755,8 +668,6 @@ class WebPlugin extends Plugin {
755
668
  }
756
669
  }
757
670
 
758
- // ==================== 工具方法 ====================
759
-
760
671
  _matchPath(routePath, reqPath) {
761
672
  const routeParts = routePath.split('/').filter(Boolean)
762
673
  const reqParts = reqPath.split('/').filter(Boolean)
@@ -788,7 +699,6 @@ class WebPlugin extends Plugin {
788
699
  async _parseBody(c) {
789
700
  try {
790
701
  const rawText = await c.req.text()
791
- // log.info(rawText)
792
702
  if (!rawText) return {}
793
703
  return JSON.parse(rawText)
794
704
  } catch (e) {
@@ -805,32 +715,23 @@ class WebPlugin extends Plugin {
805
715
 
806
716
  async _executeHandler(handlerCode, context, tools) {
807
717
  try {
808
- // 辅助函数
809
718
  const helpers = {
810
- // 基础工具
811
719
  echo: (val) => val,
812
720
  json: (val) => JSON.stringify(val),
813
721
  JSON: JSON,
814
- // 日期时间
815
722
  Date: Date,
816
723
  now: () => Date.now(),
817
- // 字符串
818
724
  Str: String,
819
- // 编码
820
725
  btoa: (str) => Buffer.from(str).toString('base64'),
821
726
  atob: (str) => Buffer.from(str, 'base64').toString(),
822
- // 格式化
823
727
  template: (str, vars) => str.replace(/\{\{(\w+)\}\}/g, (_, k) => vars[k] ?? `{{${k}}}`),
824
- // 随机
825
728
  uuid: () => Math.random().toString(36).substring(2) + Date.now().toString(36),
826
- // HTTP 请求(通过 fetch)
827
729
  fetch: async (url, options = {}) => {
828
730
  const { method = 'GET', headers = {}, body } = options
829
731
  const res = await fetch(url, { method, headers, body })
830
732
  return { status: res.status, headers: Object.fromEntries(res.headers), body: await res.text() }
831
733
  }
832
734
  }
833
- // 使用沙箱执行用户代码,防止恶意代码执行
834
735
  return await runInSandbox(handlerCode, { context, tools, ...helpers }, { timeout: 10000 })
835
736
  } catch (err) {
836
737
  return { success: false, error: `Handler error: ${err.message}` }
@@ -843,7 +744,6 @@ class WebPlugin extends Plugin {
843
744
  const relativePath = pathname.substring(staticFolder.urlPath.length) || staticFolder.options.index
844
745
  const filePath = path.join(staticFolder.folder, relativePath)
845
746
 
846
- // 安全检查
847
747
  if (!filePath.startsWith(staticFolder.folder)) {
848
748
  return { type: 'forbidden' }
849
749
  }
@@ -880,7 +780,6 @@ class WebPlugin extends Plugin {
880
780
  _getAgent(sessionId) {
881
781
  const finalSessionId = sessionId || `web_${Date.now()}`
882
782
 
883
- // 尝试从对应平台插件获取 Agent
884
783
  const platformPrefixes = ['weixin_', 'telegram_', 'feishu_']
885
784
  for (const prefix of platformPrefixes) {
886
785
  if (finalSessionId.startsWith(prefix)) {
@@ -893,9 +792,8 @@ class WebPlugin extends Plugin {
893
792
  }
894
793
  }
895
794
 
896
- // 返回主 Agent
897
795
  return this._framework._mainAgent || this._framework._agents?.[0]
898
796
  }
899
797
  }
900
798
 
901
- module.exports = WebPlugin
799
+ module.exports = WebPlugin
@@ -0,0 +1,13 @@
1
+ # Memory Plugin
2
+
3
+ 四层记忆系统:工作记忆、短期记忆、长期记忆、核心记忆。
4
+
5
+ ## 依赖
6
+
7
+ - core/storage (键值存储)
8
+
9
+ ## 能力
10
+
11
+ - 对话历史摘要与压缩
12
+ - 关键信息提取与持久化
13
+ - 上下文增强 (prepareStep 集成)
@@ -3,14 +3,14 @@
3
3
  * 四层记忆系统:user, feedback, project, reference
4
4
  */
5
5
 
6
- const { Plugin } = require('../src/core/plugin-base')
7
- const { logger } = require('../src/utils/logger')
6
+ const { Plugin } = require('../../src/plugin/base')
7
+ const { logger } = require('../../src/common/logger')
8
8
  const log = logger.child('Memory')
9
9
  const { z } = require('zod')
10
10
  const fs = require('fs')
11
11
  const path = require('path')
12
12
  const { EventEmitter } = require('events')
13
- const {cleanResponse} =require('../src/utils')
13
+ const {cleanResponse} =require('../../src/utils')
14
14
  /**
15
15
  * 记忆类型常量
16
16
  */
@@ -972,20 +972,6 @@ class MemoryPlugin extends Plugin {
972
972
  }
973
973
  }
974
974
  }
975
-
976
- // 批量处理错误
977
- // if (this._pendingErrors.length > 0) {
978
- // const errors = this._pendingErrors.splice(0, 10) // 每次最多处理 10 条
979
- // log.debug(`Processing ${errors.length} pending errors`)
980
-
981
- // for (const errorData of errors) {
982
- // try {
983
- // await this._extractErrorLesson(errorData)
984
- // } catch (err) {
985
- // log.warn('Failed to extract error lesson:', err.message)
986
- // }
987
- // }
988
- // }
989
975
  } finally {
990
976
  this._isExtracting = false
991
977
  }
@@ -1158,7 +1144,7 @@ ${prompt}`
1158
1144
  return parsed
1159
1145
  } catch (parseErr) {
1160
1146
  // JSON 解析失败,尝试清理不可见字符后重试
1161
- const cleaned = jsonStr.replace(/[\u0000-\u001F\u007F-\u009F\u200B-\u200F\u2028\u2029]/g, '')
1147
+ const cleaned = jsonStr.replace(/[\x00-\x1f\x7f-\x9f\u200b-\u200f\u2028-\u2029]/g, '')
1162
1148
  try {
1163
1149
  const parsed = JSON.parse(cleaned)
1164
1150
  return parsed
@@ -0,0 +1,19 @@
1
+ # Email Plugin
2
+
3
+ SMTP/IMAP 邮件集成插件。
4
+
5
+ ## 配置
6
+
7
+ 通过 `config.email` 在 plugins.json 中配置:
8
+ - `smtpHost` — SMTP 服务器地址
9
+ - `smtpPort` — SMTP 端口
10
+ - `imapHost` — IMAP 服务器地址
11
+ - `imapPort` — IMAP 端口
12
+ - `user` — 邮箱账号
13
+ - `pass` — 邮箱密码
14
+
15
+ ## 能力
16
+
17
+ - 发送邮件 (SMTP)
18
+ - 接收/监控邮件 (IMAP idle)
19
+ - 邮件回复、转发
@@ -3,8 +3,8 @@
3
3
  * 邮件收发插件 - 支持读取和发送电子邮件、监控新邮件
4
4
  */
5
5
 
6
- const { Plugin } = require('../../src/core/plugin-base')
7
- const { logger } = require('../../src/utils/logger')
6
+ const { Plugin } = require('../../../src/plugin/base')
7
+ const { logger } = require('../../../src/common/logger')
8
8
  const log = logger.child('Email')
9
9
  const { z } = require('zod')
10
10
  const fs = require('fs')
@@ -75,7 +75,7 @@ class EmailPlugin extends Plugin {
75
75
  - attachments.content: Base64内容
76
76
  - attachments.cid: 嵌入式图片CID(HTML中用 <img src="cid:xxx"> 引用)`
77
77
  this.priority = 50
78
- this.enabled = false
78
+ this.enabled = config.enabled === true
79
79
 
80
80
  this.tools={}
81
81
 
@@ -8,10 +8,10 @@
8
8
  * - allowedUsers: 允许的用户 openId 数组
9
9
  */
10
10
 
11
- const { Plugin } = require('../src/core/plugin-base')
12
- const { logger } = require('../src/utils/logger')
11
+ const { Plugin } = require('../../../src/plugin/base')
12
+ const { logger } = require('../../../src/common/logger')
13
13
  const log = logger.child('Feishu')
14
- const {cleanResponse} =require('../src/utils')
14
+ const {cleanResponse} =require('../../../src/utils')
15
15
  const removeMarkdown = require('remove-markdown');
16
16
  class FeishuPlugin extends Plugin {
17
17
  constructor(config = {}) {
@@ -20,7 +20,7 @@ class FeishuPlugin extends Plugin {
20
20
  this.version = '1.1.0'
21
21
  this.description = '飞书对话插件,使用 WebSocket 长连接接收消息'
22
22
  this.priority = 80
23
- this.enabled = false
23
+ this.enabled = config.enabled === true
24
24
  this.systemPrompt = `你是一个飞书助手。回复内容不要使用markdown格式文本。
25
25
 
26
26
  **重要:** 子Agent 匹配规则必须遵守: