foliko 1.0.43 → 1.0.46

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.
package/.dockerignore ADDED
@@ -0,0 +1,45 @@
1
+ # 依赖
2
+ node_modules
3
+ .agent/node_modules
4
+
5
+ # 日志
6
+ *.log
7
+ npm-debug.log*
8
+
9
+ # 环境变量(包含敏感信息)
10
+ .env
11
+ .env.local
12
+
13
+ # Git
14
+ .git
15
+ .gitignore
16
+
17
+ # IDE
18
+ .idea
19
+ .vscode
20
+ *.swp
21
+ *.swo
22
+
23
+ # 文档(可选保留)
24
+ *.md
25
+ !README.md
26
+
27
+ # 测试
28
+ test
29
+ tests
30
+ coverage
31
+
32
+ # 临时文件
33
+ tmp
34
+ temp
35
+ *.tmp
36
+
37
+ # Docker 相关(避免递归)
38
+ Dockerfile*
39
+ docker-compose*
40
+ .dockerignore
41
+
42
+ # CI/CD
43
+ .github
44
+ .gitlab-ci.yml
45
+ .travis.yml
package/.env.example CHANGED
@@ -38,3 +38,13 @@ FROM_EMAIL=your-email@gmail.com
38
38
 
39
39
  # ========== Telegram Bot (optional) ==========
40
40
  TELEGRAM_BOT_TOKEN=your-telegram-bot-token
41
+
42
+ # ========== Web Server (optional) ==========
43
+ # Web 服务端口,默认 8088
44
+ WEB_PORT=3000
45
+
46
+ # Web 服务主机,默认 127.0.0.1
47
+ WEB_HOST=127.0.0.1
48
+
49
+ # 公网访问的 base URL(用于生成 webhook URL 等),不设置则使用 host:port
50
+ WEB_BASE_URL=https://your-domain.com
package/Dockerfile ADDED
@@ -0,0 +1,35 @@
1
+ # ========== Foliko - 插件化 Agent 框架 ==========
2
+ # 基于 Node.js 20 LTS
3
+
4
+ FROM node:25-slim
5
+
6
+ # 安装 Python 和构建工具(部分 npm 包需要编译)
7
+ RUN apt-get update && apt-get install -y --no-install-recommends \
8
+ build-essential \
9
+ python3 \
10
+ python3-pip \
11
+ curl \
12
+ git \
13
+ && rm -rf /var/lib/apt/lists/* \
14
+ && ln -sf /usr/bin/python3 /usr/bin/python
15
+
16
+ # 安装 uv(快速的 Python 包管理器)
17
+ RUN curl -LsSf https://astral.sh/uv/install.sh | sh
18
+ ENV PATH="/root/.local/bin:$PATH"
19
+
20
+ # 设置工作目录
21
+ WORKDIR /app
22
+
23
+ # 全局安装 foliko CLI
24
+ RUN npm install -g foliko
25
+
26
+ # 暴露端口
27
+ # 8088: Web 服务端口
28
+ EXPOSE 3000
29
+
30
+ # 环境变量(可以在 docker-compose 或运行时覆盖)
31
+ ENV NODE_ENV=production
32
+
33
+
34
+ # 默认命令:运行聊天界面
35
+ CMD ["foliko", "chat"]
@@ -0,0 +1,33 @@
1
+ # ========== Foliko Docker Compose ==========
2
+ # 使用方式: docker-compose up -d
3
+
4
+ services:
5
+ foliko:
6
+ build: .
7
+ container_name: foliko-agent
8
+ restart: unless-stopped
9
+ ports:
10
+ - "8088:8088"
11
+ environment:
12
+ # AI 配置
13
+ - FOLIKO_PROVIDER=${FOLIKO_PROVIDER:-minimax}
14
+ - FOLIKO_MODEL=${FOLIKO_MODEL:-}
15
+ - FOLIKO_BASE_URL=${FOLIKO_BASE_URL:-}
16
+ - FOLIKO_API_KEY=${FOLIKO_API_KEY:-}
17
+ # Web 服务配置
18
+ - WEB_PORT=8088
19
+ - WEB_HOST=0.0.0.0
20
+ - WEB_BASE_URL=${WEB_BASE_URL:-}
21
+ # Telegram 配置(可选)
22
+ - TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN:-}
23
+ # 飞书配置(可选)
24
+ - FEISHU_APP_ID=${FEISHU_APP_ID:-}
25
+ - FEISHU_APP_SECRET=${FEISHU_APP_SECRET:-}
26
+ volumes:
27
+ # 持久化数据
28
+ - foliko-data:/app/.agent/data
29
+ tty: true
30
+ stdin_open: true
31
+
32
+ volumes:
33
+ foliko-data:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foliko",
3
- "version": "1.0.43",
3
+ "version": "1.0.46",
4
4
  "description": "简约的插件化 Agent 框架",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -105,6 +105,11 @@ class FeishuPlugin extends Plugin {
105
105
  this._framework.on('scheduler:reminder', async (data) => {
106
106
  await this._handleScheduledReminder(data)
107
107
  })
108
+
109
+ // 监听 webhook 事件
110
+ this._framework.on('webhook:received', async (data) => {
111
+ await this._handleWebhookNotification(data)
112
+ })
108
113
  }
109
114
 
110
115
  console.log('[Feishu] WebSocket client started')
@@ -245,6 +250,27 @@ class FeishuPlugin extends Plugin {
245
250
  }
246
251
  }
247
252
 
253
+ /**
254
+ * 处理 webhook 通知
255
+ */
256
+ async _handleWebhookNotification(data) {
257
+ const { data: webhookData, response, sessionId } = data
258
+
259
+ if (!sessionId || !sessionId.startsWith('feishu_')) {
260
+ return
261
+ }
262
+
263
+ const openId = sessionId.replace('feishu_', '')
264
+ const notificationText = `📥 [Webhook 接收]\n\n路径: ${webhookData.path}\n方法: ${webhookData.method}\n\n处理结果: ${response || '处理中...'}`
265
+
266
+ try {
267
+ await this._sendTextMessage(openId, notificationText)
268
+ console.log(`[Feishu] Webhook notification sent to ${openId}`)
269
+ } catch (err) {
270
+ console.error(`[Feishu] Failed to send webhook notification:`, err.message)
271
+ }
272
+ }
273
+
248
274
  async _processChat(openId, text, originalMsg) {
249
275
  const sessionInfo = this._getSessionAgent(openId)
250
276
  if (!sessionInfo) return
@@ -102,6 +102,11 @@ class TelegramPlugin extends Plugin {
102
102
  this._framework.on('scheduler:reminder', async (data) => {
103
103
  await this._handleScheduledReminder(data)
104
104
  })
105
+
106
+ // 监听 webhook 事件
107
+ this._framework.on('webhook:received', async (data) => {
108
+ await this._handleWebhookNotification(data)
109
+ })
105
110
  }
106
111
  } catch (err) {
107
112
  console.error('[Telegram] Failed to initialize bot:', err.message)
@@ -140,6 +145,27 @@ class TelegramPlugin extends Plugin {
140
145
  }
141
146
  }
142
147
 
148
+ /**
149
+ * 处理 webhook 通知
150
+ */
151
+ async _handleWebhookNotification(data) {
152
+ const { data: webhookData, response, sessionId } = data
153
+
154
+ if (!sessionId || !sessionId.startsWith('telegram_')) {
155
+ return
156
+ }
157
+
158
+ const chatId = sessionId.replace('telegram_', '')
159
+ const notificationText = `📥 [Webhook 接收]\n\n路径: ${webhookData.path}\n方法: ${webhookData.method}\n\n处理结果: ${response || '处理中...'}`
160
+
161
+ try {
162
+ await this._bot.sendMessage(chatId, notificationText)
163
+ console.log(`[Telegram] Webhook notification sent to chat ${chatId}`)
164
+ } catch (err) {
165
+ console.error(`[Telegram] Failed to send webhook notification:`, err.message)
166
+ }
167
+ }
168
+
143
169
  _getMainAgent() {
144
170
  if (this._framework._mainAgent) return this._framework._mainAgent
145
171
  const agents = this._framework._agents || []
@@ -19,9 +19,9 @@ class WebPlugin extends Plugin {
19
19
  this.priority = 50
20
20
 
21
21
  // 服务器配置
22
- this._port = config.port || process.env.WEB_PORT || 8088
23
- this._host = config.host || process.env.WEB_HOST || '127.0.0.1'
24
- this._baseUrl = config.baseUrl || process.env.WEB_BASE_URL || null // 公网可访问的域名
22
+ this._port = process.env.WEB_PORT || 3000
23
+ this._host = process.env.WEB_HOST || '127.0.0.1'
24
+ this._baseUrl = process.env.WEB_BASE_URL || null // 公网可访问的域名
25
25
 
26
26
  // 运行时状态
27
27
  this._server = null
@@ -157,12 +157,14 @@ class WebPlugin extends Plugin {
157
157
  port: this._port,
158
158
  hostname: this._host
159
159
  })
160
- console.log(`[Web] Server started on http://${this._host}:${this._port}`)
160
+ const serverUrl = this._getUrl()
161
+ console.log(`[Web] Server started on ${serverUrl}`)
161
162
  return {
162
163
  success: true,
163
- message: `Server started on http://${this._host}:${this._port}`,
164
+ message: `Server started on ${serverUrl}`,
164
165
  port: this._port,
165
- host: this._host
166
+ host: this._host,
167
+ url: serverUrl
166
168
  }
167
169
  } catch (err) {
168
170
  this._server = null
@@ -202,7 +204,22 @@ class WebPlugin extends Plugin {
202
204
 
203
205
  // 1. 静态文件
204
206
  const staticResult = this._serveStatic(pathname)
205
- if (staticResult) return staticResult
207
+ if (staticResult) {
208
+ if (staticResult.type === 'file') {
209
+ return c.newResponse(staticResult.content, {
210
+ headers: { 'Content-Type': staticResult.contentType }
211
+ })
212
+ }
213
+ if (staticResult.type === 'notFound') {
214
+ return c.json({ error: 'Not Found' }, 404)
215
+ }
216
+ if (staticResult.type === 'forbidden') {
217
+ return c.json({ error: 'Forbidden' }, 403)
218
+ }
219
+ if (staticResult.type === 'error') {
220
+ return c.json({ error: staticResult.message }, 500)
221
+ }
222
+ }
206
223
 
207
224
  // 2. Webhook(精确匹配)
208
225
  const webhook = this._webhooks.get(pathname)
@@ -261,7 +278,7 @@ class WebPlugin extends Plugin {
261
278
  const finalSessionId = sessionId || `web_${Date.now()}`
262
279
 
263
280
  // 触发 webhook 接收事件
264
- this._framework.emit('webhook:received', { webhook, data: webhookData })
281
+ this._framework.emit('webhook:received', { webhook, data: webhookData, sessionId: finalSessionId })
265
282
 
266
283
  if (!webhook.awaitResponse) {
267
284
  // 不等待,立即返回
@@ -281,7 +298,7 @@ class WebPlugin extends Plugin {
281
298
  }
282
299
 
283
300
  // 触发 webhook 处理完成事件
284
- this._framework.emit('webhook:received', { webhook, data: webhookData, response: responseText })
301
+ this._framework.emit('webhook:received', { webhook, data: webhookData, response: responseText, sessionId: finalSessionId })
285
302
  }).catch(err => {
286
303
  console.error('[Web] Webhook error:', err.message)
287
304
  })
@@ -307,7 +324,7 @@ class WebPlugin extends Plugin {
307
324
  }
308
325
 
309
326
  // 触发 webhook 处理完成事件
310
- this._framework.emit('webhook:received', { webhook, data: webhookData, response: responseText })
327
+ this._framework.emit('webhook:received', { webhook, data: webhookData, response: responseText, sessionId: finalSessionId })
311
328
 
312
329
  return { success: true, message: 'Webhook processed', response: responseText }
313
330
  } catch (err) {
@@ -391,7 +408,7 @@ class WebPlugin extends Plugin {
391
408
  }
392
409
 
393
410
  _listRoutes() {
394
- const baseUrl = this._getUrl('')
411
+ const baseUrl = this._getUrl()
395
412
 
396
413
  return {
397
414
  success: true,
@@ -462,7 +479,7 @@ class WebPlugin extends Plugin {
462
479
  return query
463
480
  }
464
481
 
465
- _getUrl(path) {
482
+ _getUrl(path='') {
466
483
  if (this._baseUrl) {
467
484
  return `${this._baseUrl}${path}`
468
485
  }
@@ -74,6 +74,12 @@ class WeixinPlugin extends Plugin {
74
74
  console.log('[WeChat] Received scheduler reminder:', data)
75
75
  await this._handleScheduledReminder(data)
76
76
  })
77
+
78
+ // 监听 webhook 事件
79
+ this._framework.on('webhook:received', async (data) => {
80
+ console.log('[WeChat] Received webhook event:', data)
81
+ await this._handleWebhookNotification(data)
82
+ })
77
83
  }
78
84
 
79
85
  // 异步初始化 Bot
@@ -334,6 +340,33 @@ class WeixinPlugin extends Plugin {
334
340
  }
335
341
  }
336
342
 
343
+ /**
344
+ * 处理 webhook 通知
345
+ */
346
+ async _handleWebhookNotification(data) {
347
+ const { data: webhookData, response, sessionId } = data
348
+
349
+ if (!this._bot) {
350
+ console.warn('[WeChat] Bot not ready, cannot send webhook notification')
351
+ return
352
+ }
353
+
354
+ // 只处理 weixin 相关的 session
355
+ if (!sessionId || !sessionId.startsWith('weixin_')) {
356
+ return
357
+ }
358
+
359
+ const userId = sessionId.replace('weixin_', '')
360
+ const notificationText = `📥 [Webhook 接收]\n\n路径: ${webhookData.path}\n方法: ${webhookData.method}\n\n处理结果: ${response || '处理中...'}`
361
+
362
+ try {
363
+ await this._bot.sendText(userId, notificationText)
364
+ console.log(`[WeChat] Webhook notification sent to user ${userId}`)
365
+ } catch (err) {
366
+ console.error(`[WeChat] Failed to send webhook notification:`, err.message)
367
+ }
368
+ }
369
+
337
370
  /**
338
371
  * 获取插件状态
339
372
  */
package/test.txt ADDED
@@ -0,0 +1,3 @@
1
+ Hello from static resource test!
2
+ This is a test file for verifying static resource serving.
3
+ Timestamp: 2026-03-24