foliko 1.0.41 → 1.0.44

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=8088
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:20-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 pip3 install uv
18
+
19
+ # 设置工作目录
20
+ WORKDIR /app
21
+
22
+ # 全局安装 foliko CLI
23
+ RUN npm install -g foliko
24
+
25
+ # 暴露端口
26
+ # 8088: Web 服务端口
27
+ EXPOSE 8088
28
+
29
+ # 环境变量(可以在 docker-compose 或运行时覆盖)
30
+ ENV NODE_ENV=production
31
+ ENV WEB_PORT=8088
32
+ ENV WEB_HOST=127.0.0.1
33
+
34
+ # 默认命令:运行聊天界面
35
+ CMD ["foliko", "chat"]
@@ -101,11 +101,11 @@ async function chatCommand(args) {
101
101
  const agent = framework.createAgent({
102
102
  name: 'FolikoAgent',
103
103
  systemPrompt: `你是一个有帮助的助手,擅长回答问题和执行任务。
104
- **注意事项:**
105
- 1、遇到npx skills add,npx skills remove, npx skills list 命令时:
106
- --添加"-a openclaw","-y"参数
107
- --不要加-g 参数
108
- `,
104
+
105
+ **命令执行规范:**
106
+ - 执行 npx skills add / npx skills remove / npx skills list 命令时,必须自动添加参数:-a openclaw -y
107
+ - 禁止添加 -g 参数
108
+ - 例如:npx skills add xxx 应该执行为 npx skills add xxx -a openclaw -y`,
109
109
  sharedPrompt: `工作目录: {{WORK_DIR}}`,
110
110
  metadata: {
111
111
  WORK_DIR: process.cwd() // 覆盖内置的 WORK_DIR
@@ -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.41",
3
+ "version": "1.0.44",
4
4
  "description": "简约的插件化 Agent 框架",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -18,7 +18,12 @@ class FeishuPlugin extends Plugin {
18
18
  this.description = '飞书对话插件,使用 WebSocket 长连接接收消息'
19
19
  this.priority = 80
20
20
  this.enabled = false
21
- this.systemPrompt = '你是一个飞书助手。回复内容不要使用markdown格式文本。'
21
+ this.systemPrompt = `你是一个飞书助手。回复内容不要使用markdown格式文本。
22
+
23
+ **命令执行规范:**
24
+ - 执行 npx skills add / npx skills remove / npx skills list 命令时,必须自动添加参数:-a openclaw -y
25
+ - 禁止添加 -g 参数
26
+ - 例如:npx skills add xxx 应该执行为 npx skills add xxx -a openclaw -y`
22
27
 
23
28
  this.config = {
24
29
  appId: config.appId || process.env.FEISHU_APP_ID,
@@ -100,6 +105,11 @@ class FeishuPlugin extends Plugin {
100
105
  this._framework.on('scheduler:reminder', async (data) => {
101
106
  await this._handleScheduledReminder(data)
102
107
  })
108
+
109
+ // 监听 webhook 事件
110
+ this._framework.on('webhook:received', async (data) => {
111
+ await this._handleWebhookNotification(data)
112
+ })
103
113
  }
104
114
 
105
115
  console.log('[Feishu] WebSocket client started')
@@ -195,7 +205,9 @@ class FeishuPlugin extends Plugin {
195
205
  }
196
206
 
197
207
  const agent = this._framework.createSessionAgent(`feishu_${openId}`, {
198
- systemPrompt: this.systemPrompt
208
+ systemPrompt: this.systemPrompt,
209
+ sharedPrompt: `工作目录: {{WORK_DIR}}`,
210
+ metadata: { WORK_DIR: process.cwd() }
199
211
  })
200
212
  this._sessionAgents.set(openId, agent)
201
213
 
@@ -238,6 +250,27 @@ class FeishuPlugin extends Plugin {
238
250
  }
239
251
  }
240
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
+
241
274
  async _processChat(openId, text, originalMsg) {
242
275
  const sessionInfo = this._getSessionAgent(openId)
243
276
  if (!sessionInfo) return
@@ -26,7 +26,12 @@ class TelegramPlugin extends Plugin {
26
26
  this.description = 'Telegram 对话插件,绑定主Agent进行持续对话'
27
27
  this.priority = 80
28
28
  this.enabled = false
29
- this.systemPrompt = '你是一个有帮助的AI助手。回复内容不要使用markdown格式文本。'
29
+ this.systemPrompt = `你是一个有帮助的AI助手。回复内容不要使用markdown格式文本。
30
+
31
+ **命令执行规范:**
32
+ - 执行 npx skills add / npx skills remove / npx skills list 命令时,必须自动添加参数:-a openclaw -y
33
+ - 禁止添加 -g 参数
34
+ - 例如:npx skills add xxx 应该执行为 npx skills add xxx -a openclaw -y`
30
35
 
31
36
  this.config = {
32
37
  botToken: config.botToken || process.env.TELEGRAM_BOT_TOKEN,
@@ -97,6 +102,11 @@ class TelegramPlugin extends Plugin {
97
102
  this._framework.on('scheduler:reminder', async (data) => {
98
103
  await this._handleScheduledReminder(data)
99
104
  })
105
+
106
+ // 监听 webhook 事件
107
+ this._framework.on('webhook:received', async (data) => {
108
+ await this._handleWebhookNotification(data)
109
+ })
100
110
  }
101
111
  } catch (err) {
102
112
  console.error('[Telegram] Failed to initialize bot:', err.message)
@@ -135,6 +145,27 @@ class TelegramPlugin extends Plugin {
135
145
  }
136
146
  }
137
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
+
138
169
  _getMainAgent() {
139
170
  if (this._framework._mainAgent) return this._framework._mainAgent
140
171
  const agents = this._framework._agents || []
@@ -147,7 +178,9 @@ class TelegramPlugin extends Plugin {
147
178
  }
148
179
 
149
180
  const agent = this._framework.createSessionAgent(`telegram_${chatId}`, {
150
- systemPrompt: this.systemPrompt
181
+ systemPrompt: this.systemPrompt,
182
+ sharedPrompt: `工作目录: {{WORK_DIR}}`,
183
+ metadata: { WORK_DIR: process.cwd() }
151
184
  })
152
185
  this._sessionAgents.set(chatId, agent)
153
186
 
@@ -202,7 +202,22 @@ class WebPlugin extends Plugin {
202
202
 
203
203
  // 1. 静态文件
204
204
  const staticResult = this._serveStatic(pathname)
205
- if (staticResult) return staticResult
205
+ if (staticResult) {
206
+ if (staticResult.type === 'file') {
207
+ return c.newResponse(staticResult.content, {
208
+ headers: { 'Content-Type': staticResult.contentType }
209
+ })
210
+ }
211
+ if (staticResult.type === 'notFound') {
212
+ return c.json({ error: 'Not Found' }, 404)
213
+ }
214
+ if (staticResult.type === 'forbidden') {
215
+ return c.json({ error: 'Forbidden' }, 403)
216
+ }
217
+ if (staticResult.type === 'error') {
218
+ return c.json({ error: staticResult.message }, 500)
219
+ }
220
+ }
206
221
 
207
222
  // 2. Webhook(精确匹配)
208
223
  const webhook = this._webhooks.get(pathname)
@@ -261,7 +276,7 @@ class WebPlugin extends Plugin {
261
276
  const finalSessionId = sessionId || `web_${Date.now()}`
262
277
 
263
278
  // 触发 webhook 接收事件
264
- this._framework.emit('webhook:received', { webhook, data: webhookData })
279
+ this._framework.emit('webhook:received', { webhook, data: webhookData, sessionId: finalSessionId })
265
280
 
266
281
  if (!webhook.awaitResponse) {
267
282
  // 不等待,立即返回
@@ -281,7 +296,7 @@ class WebPlugin extends Plugin {
281
296
  }
282
297
 
283
298
  // 触发 webhook 处理完成事件
284
- this._framework.emit('webhook:received', { webhook, data: webhookData, response: responseText })
299
+ this._framework.emit('webhook:received', { webhook, data: webhookData, response: responseText, sessionId: finalSessionId })
285
300
  }).catch(err => {
286
301
  console.error('[Web] Webhook error:', err.message)
287
302
  })
@@ -307,7 +322,7 @@ class WebPlugin extends Plugin {
307
322
  }
308
323
 
309
324
  // 触发 webhook 处理完成事件
310
- this._framework.emit('webhook:received', { webhook, data: webhookData, response: responseText })
325
+ this._framework.emit('webhook:received', { webhook, data: webhookData, response: responseText, sessionId: finalSessionId })
311
326
 
312
327
  return { success: true, message: 'Webhook processed', response: responseText }
313
328
  } catch (err) {
@@ -21,7 +21,12 @@ class WeixinPlugin extends Plugin {
21
21
  // 默认不启用,需要在 plugins.json 中设置 enabled: true
22
22
  this.enabled = false
23
23
  this.path=`.agent/data`
24
- this.systemPrompt='你是一个微信助手。回复内容不要使用markdown格式文本'
24
+ this.systemPrompt=`你是一个微信助手。回复内容不要使用markdown格式文本
25
+
26
+ **命令执行规范:**
27
+ - 执行 npx skills add / npx skills remove / npx skills list 命令时,必须自动添加参数:-a openclaw -y
28
+ - 禁止添加 -g 参数
29
+ - 例如:npx skills add xxx 应该执行为 npx skills add xxx -a openclaw -y`
25
30
 
26
31
  this.config = {
27
32
  forceLogin: config.forceLogin || process.env.WEIXIN_FORCE_LOGIN === 'true',
@@ -69,6 +74,12 @@ class WeixinPlugin extends Plugin {
69
74
  console.log('[WeChat] Received scheduler reminder:', data)
70
75
  await this._handleScheduledReminder(data)
71
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
+ })
72
83
  }
73
84
 
74
85
  // 异步初始化 Bot
@@ -160,7 +171,9 @@ class WeixinPlugin extends Plugin {
160
171
 
161
172
  // 创建新 agent
162
173
  const agent = this._framework.createSessionAgent(`weixin_${userId}`, {
163
- systemPrompt: this.systemPrompt
174
+ systemPrompt: this.systemPrompt,
175
+ sharedPrompt: `工作目录: {{WORK_DIR}}`,
176
+ metadata: { WORK_DIR: process.cwd() }
164
177
  })
165
178
  this._sessionAgents.set(userId, agent)
166
179
  console.log('[WeChat] Created new session agent for userId:', userId)
@@ -327,6 +340,33 @@ class WeixinPlugin extends Plugin {
327
340
  }
328
341
  }
329
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
+
330
370
  /**
331
371
  * 获取插件状态
332
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