foliko 1.1.6 → 1.1.7
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/.agent/data/email/processed-emails.json +1 -0
- package/.agent/data/plugins-state.json +5 -1
- package/.agent/data/web/web-config.json +5 -0
- package/.agent/memory/feedback/mnt7jrlt-d67qs7.md +15 -0
- package/.agent/memory/feedback/mnt88ja3-al4fuy.md +9 -0
- package/.agent/plugins/test-plugin.py +108 -0
- package/.agent/sessions/cli_default.json +514 -5298
- package/.claude/settings.local.json +2 -1
- package/SPEC.md +735 -696
- package/output/zen_silence.png +0 -0
- package/package.json +2 -2
- package/plugins/ambient-agent/EventWatcher.js +33 -37
- package/plugins/ambient-agent/ExplorerLoop.js +338 -36
- package/plugins/ambient-agent/GoalManager.js +7 -3
- package/plugins/ambient-agent/StateStore.js +30 -1
- package/plugins/ambient-agent/constants.js +15 -1
- package/plugins/ambient-agent/index.js +26 -33
- package/plugins/coordinator-plugin.js +3 -3
- package/plugins/default-plugins.js +2 -2
- package/plugins/email/index.js +150 -36
- package/plugins/email/monitor.js +79 -5
- package/plugins/email/reply.js +15 -25
- package/plugins/extension-executor-plugin.js +160 -31
- package/plugins/file-system-plugin.js +57 -24
- package/plugins/memory-plugin.js +176 -64
- package/plugins/python-plugin-loader.js +79 -9
- package/plugins/scheduler-plugin.js +64 -24
- package/plugins/think-plugin.js +7 -2
- package/plugins/web-plugin.js +263 -4
- package/skills/ambient-agent/SKILL.md +342 -314
- package/src/core/agent-chat.js +64 -9
- package/src/core/agent.js +118 -59
- package/src/core/tool-registry.js +5 -5
- package/src/executors/mcp-executor.js +188 -26
- package/src/utils/id.js +5 -0
- package/system.md +3480 -0
- package/.agent/data/ambient/goals.json +0 -50
- package/.agent/data/ambient/memories.json +0 -7
- package/.agent/memory/core.md +0 -1
- package/.agent/memory/feedback/mnrsiuoc-e1ru74.md +0 -9
- package/.agent/memory/feedback/mnrt2mmz-98az6n.md +0 -9
- package/.agent/memory/feedback/mnrtqrhm-kxsicz.md +0 -9
- package/.agent/memory/feedback/mnrts8vg-i0ngzp.md +0 -15
- package/.agent/memory/feedback/mnrtt7jt-c0trb2.md +0 -9
- package/.agent/memory/feedback/mnruc2f0-5s52la.md +0 -16
- package/.agent/memory/feedback/mnrumbmx-63sa0v.md +0 -9
- package/.agent/memory/project/mnn93ogy-ypjn27.md +0 -9
- package/.agent/memory/project/mnn98fqy-5nhc1u.md +0 -25
- package/.agent/memory/project/mnrp7p5n-8enm2a.md +0 -31
- package/.agent/memory/project/mnrp9ifb-yynks0.md +0 -40
- package/.agent/memory/project/mnrpb3b8-f617s4.md +0 -25
- package/.agent/memory/project/mnrrmqgg-focprv.md +0 -9
- package/.agent/memory/project/mnrtykbh-6atsor.md +0 -9
- package/.agent/memory/project/mnru9jiu-kgau16.md +0 -35
- package/.agent/memory/reference/mnq3oenw-46haj6.md +0 -63
- package/.agent/memory/reference/mnq5qxm2-mjoooh.md +0 -116
- package/.agent/memory/reference/mnrnvpwo-rcqv9m.md +0 -52
- package/.agent/memory/reference/mnrovxvz-zy9xqm.md +0 -25
- package/.agent/memory/reference/mnroxabj-1b3930.md +0 -68
- package/.agent/memory/reference/mnrpjtlp-mnb9od.md +0 -35
- package/.agent/memory/reference/mnrps1x3-6b8xfm.md +0 -28
- package/.agent/memory/reference/mnrpt9ov-15er5w.md +0 -22
- package/.agent/memory/reference/mnrq82dn-y9tv9e.md +0 -50
- package/.agent/memory/reference/mnrqnr5v-v75drf.md +0 -34
- package/.agent/memory/reference/mnrrfzys-urudaf.md +0 -31
- package/.agent/memory/reference/mnrrocha-t0027n.md +0 -21
- package/.agent/memory/reference/mnrukklc-bxndsb.md +0 -35
- package/.agent/memory/user/mnm67t9m-x8rekk.md +0 -9
- package/.agent/memory/user/mnn5mmqh-w6aktx.md +0 -11
- package/.agent/memory/user/mnnbfhhn-dk1bd1.md +0 -22
- package/.agent/memory/user/mnrt39t8-8eosy0.md +0 -9
- package/foliko-cloud-rising.png +0 -0
- package/foliko-dawn-of-ai.png +0 -0
- package/foliko-mindful-observation.png +0 -0
- package/foliko-stellar-dreams.png +0 -0
- package/foliko-zen-jing.png +0 -0
- package/foliko-zen-kong.png +0 -0
- package/foliko-zen-wu.png +0 -0
- package/zen_karesansui.png +0 -0
package/plugins/web-plugin.js
CHANGED
|
@@ -13,6 +13,46 @@ const { Hono } = require('hono')
|
|
|
13
13
|
const fs = require('fs')
|
|
14
14
|
const path = require('path')
|
|
15
15
|
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// WebStore - 持久化 Web 配置到 .agent/data/web/
|
|
18
|
+
// ============================================================================
|
|
19
|
+
class WebStore {
|
|
20
|
+
constructor(persistencePath) {
|
|
21
|
+
this._persistencePath = persistencePath
|
|
22
|
+
this._ensureDir()
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
_ensureDir() {
|
|
26
|
+
if (!fs.existsSync(this._persistencePath)) {
|
|
27
|
+
fs.mkdirSync(this._persistencePath, { recursive: true })
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
_getConfigPath() {
|
|
32
|
+
return path.join(this._persistencePath, 'web-config.json')
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
saveConfig(data) {
|
|
36
|
+
try {
|
|
37
|
+
fs.writeFileSync(this._getConfigPath(), JSON.stringify(data, null, 2))
|
|
38
|
+
} catch (err) {
|
|
39
|
+
log.error(' 保存 Web 配置失败:', err.message)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
loadConfig() {
|
|
44
|
+
try {
|
|
45
|
+
const filePath = this._getConfigPath()
|
|
46
|
+
if (fs.existsSync(filePath)) {
|
|
47
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf-8'))
|
|
48
|
+
}
|
|
49
|
+
} catch (err) {
|
|
50
|
+
log.error(' 加载 Web 配置失败:', err.message)
|
|
51
|
+
}
|
|
52
|
+
return null
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
16
56
|
class WebPlugin extends Plugin {
|
|
17
57
|
constructor(config = {}) {
|
|
18
58
|
super()
|
|
@@ -39,6 +79,10 @@ class WebPlugin extends Plugin {
|
|
|
39
79
|
this._routes = [] // 路由列表
|
|
40
80
|
this._webhooks = new Map() // webhook Map: id -> {id, path, prompt, sessionId}
|
|
41
81
|
this._statics = [] // 静态文件夹列表
|
|
82
|
+
|
|
83
|
+
// 持久化存储
|
|
84
|
+
this._webStore = null
|
|
85
|
+
this._persistencePath = config.persistencePath || '.agent/data/web'
|
|
42
86
|
}
|
|
43
87
|
|
|
44
88
|
// ==================== 生命周期 ====================
|
|
@@ -47,6 +91,12 @@ class WebPlugin extends Plugin {
|
|
|
47
91
|
this._framework = framework
|
|
48
92
|
this._registerTools()
|
|
49
93
|
|
|
94
|
+
// 初始化持久化存储
|
|
95
|
+
this._webStore = new WebStore(this._persistencePath)
|
|
96
|
+
|
|
97
|
+
// 加载已保存的配置
|
|
98
|
+
this._loadPersistedConfig()
|
|
99
|
+
|
|
50
100
|
// 将 WEB_BASE_URL 注入到 framework 的元数据,供所有 agent 使用
|
|
51
101
|
if (this._baseUrl && framework._mainAgent) {
|
|
52
102
|
framework._mainAgent.setMetadata('WEB_BASE_URL', this._baseUrl)
|
|
@@ -61,12 +111,117 @@ class WebPlugin extends Plugin {
|
|
|
61
111
|
|
|
62
112
|
reload(framework) {
|
|
63
113
|
this._framework = framework
|
|
114
|
+
|
|
115
|
+
// 重新初始化存储并加载配置
|
|
116
|
+
this._webStore = new WebStore(this._persistencePath)
|
|
117
|
+
this._loadPersistedConfig()
|
|
118
|
+
|
|
64
119
|
// 重新注入 WEB_BASE_URL
|
|
65
120
|
if (this._baseUrl && framework._mainAgent) {
|
|
66
121
|
framework._mainAgent.setMetadata('WEB_BASE_URL', this._baseUrl)
|
|
67
122
|
}
|
|
68
123
|
}
|
|
69
124
|
|
|
125
|
+
/**
|
|
126
|
+
* 加载持久化的配置并恢复路由/webhook/静态资源
|
|
127
|
+
*/
|
|
128
|
+
_loadPersistedConfig() {
|
|
129
|
+
if (!this._webStore) return
|
|
130
|
+
|
|
131
|
+
const config = this._webStore.loadConfig()
|
|
132
|
+
if (!config) return
|
|
133
|
+
|
|
134
|
+
log.info(` 加载 Web 配置...`)
|
|
135
|
+
|
|
136
|
+
let hasRoutes = false
|
|
137
|
+
let hasWebhooks = false
|
|
138
|
+
let hasStatics = false
|
|
139
|
+
|
|
140
|
+
// 恢复路由
|
|
141
|
+
if (config.routes && Array.isArray(config.routes)) {
|
|
142
|
+
for (const route of config.routes) {
|
|
143
|
+
if (route.method && route.path && route.handler) {
|
|
144
|
+
this._routes.push({
|
|
145
|
+
method: route.method,
|
|
146
|
+
path: route.path,
|
|
147
|
+
handler: route.handler,
|
|
148
|
+
description: route.description || ''
|
|
149
|
+
})
|
|
150
|
+
hasRoutes = true
|
|
151
|
+
log.info(` 恢复路由: ${route.method} ${route.path}`)
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// 恢复 Webhooks
|
|
157
|
+
if (config.webhooks && Array.isArray(config.webhooks)) {
|
|
158
|
+
for (const webhook of config.webhooks) {
|
|
159
|
+
if (webhook.id && webhook.path) {
|
|
160
|
+
this._webhooks.set(webhook.path, {
|
|
161
|
+
id: webhook.id,
|
|
162
|
+
path: webhook.path,
|
|
163
|
+
prompt: webhook.prompt || '处理以下 webhook 数据,返回适当的响应:',
|
|
164
|
+
awaitResponse: webhook.awaitResponse || false
|
|
165
|
+
})
|
|
166
|
+
hasWebhooks = true
|
|
167
|
+
log.info(` 恢复 Webhook: ${webhook.path}`)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// 恢复静态资源
|
|
173
|
+
if (config.statics && Array.isArray(config.statics)) {
|
|
174
|
+
for (const staticItem of config.statics) {
|
|
175
|
+
if (staticItem.urlPath && staticItem.folder) {
|
|
176
|
+
this._statics.push({
|
|
177
|
+
urlPath: staticItem.urlPath,
|
|
178
|
+
folder: staticItem.folder,
|
|
179
|
+
options: staticItem.options || { dotfiles: 'ignore', index: 'index.html' }
|
|
180
|
+
})
|
|
181
|
+
hasStatics = true
|
|
182
|
+
log.info(` 恢复静态资源: ${staticItem.urlPath} -> ${staticItem.folder}`)
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// 如果有恢复的路由/webhook/静态资源,自动启动服务器
|
|
188
|
+
if ((hasRoutes || hasWebhooks || hasStatics) && !this._server) {
|
|
189
|
+
log.info(` 恢复的 Web 配置需要启动服务器...`)
|
|
190
|
+
this._startServer().catch(err => {
|
|
191
|
+
log.error(` 自动启动服务器失败:`, err.message)
|
|
192
|
+
})
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* 保存当前配置到持久化存储
|
|
198
|
+
*/
|
|
199
|
+
_saveConfig() {
|
|
200
|
+
if (!this._webStore) return
|
|
201
|
+
|
|
202
|
+
const config = {
|
|
203
|
+
routes: this._routes.map(r => ({
|
|
204
|
+
method: r.method,
|
|
205
|
+
path: r.path,
|
|
206
|
+
handler: r.handler,
|
|
207
|
+
description: r.description
|
|
208
|
+
})),
|
|
209
|
+
webhooks: Array.from(this._webhooks.values()).map(w => ({
|
|
210
|
+
id: w.id,
|
|
211
|
+
path: w.path,
|
|
212
|
+
prompt: w.prompt,
|
|
213
|
+
awaitResponse: w.awaitResponse
|
|
214
|
+
})),
|
|
215
|
+
statics: this._statics.map(s => ({
|
|
216
|
+
urlPath: s.urlPath,
|
|
217
|
+
folder: s.folder,
|
|
218
|
+
options: s.options
|
|
219
|
+
}))
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
this._webStore.saveConfig(config)
|
|
223
|
+
}
|
|
224
|
+
|
|
70
225
|
uninstall() {
|
|
71
226
|
this._stopServer()
|
|
72
227
|
this._framework = null
|
|
@@ -146,6 +301,37 @@ class WebPlugin extends Plugin {
|
|
|
146
301
|
execute: async () => this._listRoutes()
|
|
147
302
|
}
|
|
148
303
|
|
|
304
|
+
// 删除路由
|
|
305
|
+
this.tools.web_delete_route = {
|
|
306
|
+
name: 'web_delete_route',
|
|
307
|
+
description: '删除已注册的 HTTP 路由',
|
|
308
|
+
inputSchema: z.object({
|
|
309
|
+
method: z.enum(['GET', 'POST', 'PUT', 'DELETE', 'PATCH']).describe('HTTP 方法'),
|
|
310
|
+
path: z.string().describe('路由路径,如 /api/user')
|
|
311
|
+
}),
|
|
312
|
+
execute: async (args) => this._deleteRoute(args.method, args.path)
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// 删除 Webhook
|
|
316
|
+
this.tools.web_delete_webhook = {
|
|
317
|
+
name: 'web_delete_webhook',
|
|
318
|
+
description: '删除已注册的 Webhook',
|
|
319
|
+
inputSchema: z.object({
|
|
320
|
+
id: z.string().describe('Webhook ID')
|
|
321
|
+
}),
|
|
322
|
+
execute: async (args) => this._deleteWebhook(args.id)
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// 删除静态资源
|
|
326
|
+
this.tools.web_delete_static = {
|
|
327
|
+
name: 'web_delete_static',
|
|
328
|
+
description: '删除已注册的静态资源文件夹',
|
|
329
|
+
inputSchema: z.object({
|
|
330
|
+
urlPath: z.string().describe('URL 路径前缀,如 /public')
|
|
331
|
+
}),
|
|
332
|
+
execute: async (args) => this._deleteStatic(args.urlPath)
|
|
333
|
+
}
|
|
334
|
+
|
|
149
335
|
// 发送 HTTP 请求
|
|
150
336
|
this.tools.web_request = {
|
|
151
337
|
name: 'web_request',
|
|
@@ -317,8 +503,14 @@ class WebPlugin extends Plugin {
|
|
|
317
503
|
const prompt = webhook.prompt || '处理以下 webhook 数据,返回适当的响应:'
|
|
318
504
|
const finalSessionId = sessionId || `web_${Date.now()}`
|
|
319
505
|
|
|
320
|
-
// 触发 webhook
|
|
321
|
-
this._framework.emit('webhook:received', {
|
|
506
|
+
// 触发 webhook 接收事件(扁平化结构)
|
|
507
|
+
this._framework.emit('webhook:received', {
|
|
508
|
+
path: webhook.path,
|
|
509
|
+
method: c.req.method,
|
|
510
|
+
query,
|
|
511
|
+
body,
|
|
512
|
+
timestamp: webhookData.timestamp
|
|
513
|
+
})
|
|
322
514
|
|
|
323
515
|
// 使用子Agent处理 webhook
|
|
324
516
|
const webhookAgent = this._framework.createSubAgent({
|
|
@@ -342,7 +534,14 @@ class WebPlugin extends Plugin {
|
|
|
342
534
|
}
|
|
343
535
|
|
|
344
536
|
// 触发 webhook 处理完成事件
|
|
345
|
-
this._framework.emit('webhook:processed', {
|
|
537
|
+
this._framework.emit('webhook:processed', {
|
|
538
|
+
path: webhook.path,
|
|
539
|
+
method: c.req.method,
|
|
540
|
+
query,
|
|
541
|
+
body,
|
|
542
|
+
response: responseText,
|
|
543
|
+
timestamp: webhookData.timestamp
|
|
544
|
+
})
|
|
346
545
|
}).catch(err => {
|
|
347
546
|
log.error(' Webhook error:', err.message)
|
|
348
547
|
})
|
|
@@ -366,7 +565,14 @@ class WebPlugin extends Plugin {
|
|
|
366
565
|
}
|
|
367
566
|
|
|
368
567
|
// 触发 webhook 处理完成事件
|
|
369
|
-
this._framework.emit('webhook:
|
|
568
|
+
this._framework.emit('webhook:processed', {
|
|
569
|
+
path: webhook.path,
|
|
570
|
+
method: c.req.method,
|
|
571
|
+
query,
|
|
572
|
+
body,
|
|
573
|
+
response: responseText,
|
|
574
|
+
timestamp: webhookData.timestamp
|
|
575
|
+
})
|
|
370
576
|
|
|
371
577
|
return { success: true, message: 'Webhook processed', response: responseText }
|
|
372
578
|
} catch (err) {
|
|
@@ -394,6 +600,9 @@ class WebPlugin extends Plugin {
|
|
|
394
600
|
this._routes.push(route)
|
|
395
601
|
}
|
|
396
602
|
|
|
603
|
+
// 持久化保存
|
|
604
|
+
this._saveConfig()
|
|
605
|
+
|
|
397
606
|
log.info(` Route registered: ${method} ${path}`)
|
|
398
607
|
return { success: true, message: `Route ${method} ${path} registered`, url: this._getUrl(path), route: { method, path, description } }
|
|
399
608
|
}
|
|
@@ -414,6 +623,9 @@ class WebPlugin extends Plugin {
|
|
|
414
623
|
awaitResponse
|
|
415
624
|
})
|
|
416
625
|
|
|
626
|
+
// 持久化保存
|
|
627
|
+
this._saveConfig()
|
|
628
|
+
|
|
417
629
|
log.info(` Webhook registered: ${webhookPath}`)
|
|
418
630
|
return {
|
|
419
631
|
success: true,
|
|
@@ -441,6 +653,9 @@ class WebPlugin extends Plugin {
|
|
|
441
653
|
}
|
|
442
654
|
})
|
|
443
655
|
|
|
656
|
+
// 持久化保存
|
|
657
|
+
this._saveConfig()
|
|
658
|
+
|
|
444
659
|
log.info(` Static registered: ${normalizedPath} -> ${folder}`)
|
|
445
660
|
return {
|
|
446
661
|
success: true,
|
|
@@ -461,6 +676,50 @@ class WebPlugin extends Plugin {
|
|
|
461
676
|
}
|
|
462
677
|
}
|
|
463
678
|
|
|
679
|
+
async _deleteRoute(method, path) {
|
|
680
|
+
const index = this._routes.findIndex(r => r.method === method.toUpperCase() && r.path === path)
|
|
681
|
+
if (index < 0) {
|
|
682
|
+
return { success: false, error: `Route not found: ${method} ${path}` }
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
this._routes.splice(index, 1)
|
|
686
|
+
this._saveConfig()
|
|
687
|
+
log.info(` Route deleted: ${method} ${path}`)
|
|
688
|
+
return { success: true, message: `Route deleted: ${method} ${path}` }
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
async _deleteWebhook(id) {
|
|
692
|
+
let found = null
|
|
693
|
+
for (const [path, webhook] of this._webhooks.entries()) {
|
|
694
|
+
if (webhook.id === id) {
|
|
695
|
+
found = path
|
|
696
|
+
break
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
if (!found) {
|
|
701
|
+
return { success: false, error: `Webhook not found: ${id}` }
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
this._webhooks.delete(found)
|
|
705
|
+
this._saveConfig()
|
|
706
|
+
log.info(` Webhook deleted: ${found}`)
|
|
707
|
+
return { success: true, message: `Webhook deleted: ${found}` }
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
async _deleteStatic(urlPath) {
|
|
711
|
+
const normalizedPath = urlPath.endsWith('/') ? urlPath : urlPath + '/'
|
|
712
|
+
const index = this._statics.findIndex(s => s.urlPath === normalizedPath)
|
|
713
|
+
if (index < 0) {
|
|
714
|
+
return { success: false, error: `Static folder not found: ${urlPath}` }
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
this._statics.splice(index, 1)
|
|
718
|
+
this._saveConfig()
|
|
719
|
+
log.info(` Static deleted: ${normalizedPath}`)
|
|
720
|
+
return { success: true, message: `Static folder deleted: ${normalizedPath}` }
|
|
721
|
+
}
|
|
722
|
+
|
|
464
723
|
// ==================== HTTP 客户端 ====================
|
|
465
724
|
|
|
466
725
|
async _sendRequest(method, urlPath, body, headers) {
|