foliko 1.1.67 → 1.1.69
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/.claude/settings.local.json +19 -10
- package/.dockerignore +45 -45
- package/.env.example +56 -56
- package/CLAUDE.md +2 -2
- package/README.md +13 -13
- package/SPEC.md +3 -3
- package/cli/src/commands/chat.js +2 -20
- package/cli/src/commands/list.js +7 -6
- package/cli/src/commands/plugin.js +3 -2
- package/cli/src/daemon.js +2 -2
- package/cli/src/ui/chat-ui-old.js +15 -4
- package/cli/src/ui/chat-ui.js +236 -203
- package/cli/src/ui/footer-bar.js +20 -46
- package/cli/src/ui/message-bubble.js +24 -2
- package/cli/src/ui/status-bar.js +177 -0
- package/cli/src/utils/config.js +29 -0
- package/cli/src/utils/plugin-config.js +1 -1
- package/docker-compose.yml +33 -33
- package/docs/features.md +120 -120
- package/docs/quick-reference.md +160 -160
- package/docs/user-manual.md +1391 -1391
- package/examples/ambient-example.js +2 -2
- package/examples/bootstrap.js +3 -3
- package/examples/test-chat.js +1 -1
- package/examples/test-reload.js +1 -1
- package/examples/test-telegram.js +1 -1
- package/examples/test-tg-bot.js +1 -1
- package/examples/test-tg-simple.js +2 -2
- package/examples/test-tg.js +1 -1
- package/examples/test-think.js +1 -1
- package/examples/test-weixin-feishu.js +3 -3
- package/package.json +3 -1
- package/plugins/ambient-agent/index.js +1 -1
- package/plugins/audit-plugin.js +84 -29
- package/plugins/coordinator-plugin.js +14 -12
- package/plugins/data-splitter-plugin.js +323 -0
- package/plugins/default-plugins.js +23 -12
- package/plugins/email/index.js +1 -1
- package/plugins/extension-executor-plugin.js +87 -9
- package/plugins/feishu-plugin.js +118 -16
- package/plugins/file-system-plugin.js +68 -50
- package/plugins/gate-trading.js +10 -10
- package/plugins/install-plugin.js +7 -7
- package/plugins/memory-plugin.js +9 -12
- package/plugins/plugin-manager-plugin.js +12 -14
- package/plugins/python-executor-plugin.js +1 -1
- package/plugins/python-plugin-loader.js +1 -1
- package/plugins/qq-plugin.js +151 -24
- package/plugins/rules-plugin.js +8 -8
- package/plugins/scheduler-plugin.js +24 -20
- package/plugins/session-plugin.js +313 -397
- package/plugins/storage-plugin.js +235 -175
- package/plugins/subagent-plugin.js +17 -13
- package/plugins/telegram-plugin.js +116 -17
- package/plugins/think-plugin.js +64 -60
- package/plugins/tools-plugin.js +8 -8
- package/plugins/web-plugin.js +2 -2
- package/plugins/weixin-plugin.js +107 -24
- package/skills/find-skills/AGENTS.md +2 -2
- package/skills/find-skills/SKILL.md +133 -133
- package/skills/foliko-dev/AGENTS.md +236 -236
- package/skills/foliko-dev/SKILL.md +19 -19
- package/skills/mcp-usage/SKILL.md +200 -200
- package/skills/plugin-guide/SKILL.md +4 -4
- package/skills/python-plugin-dev/SKILL.md +5 -5
- package/skills/skill-guide/SKILL.md +104 -6
- package/skills/subagent-guide/SKILL.md +237 -237
- package/skills/workflow-guide/SKILL.md +646 -646
- package/src/capabilities/skill-manager.js +124 -17
- package/src/capabilities/workflow-engine.js +3 -3
- package/src/core/agent-chat.js +72 -26
- package/src/core/agent.js +17 -27
- package/src/core/branch-summary-auto.js +206 -0
- package/src/core/chat-session.js +45 -169
- package/src/core/command-registry.js +200 -0
- package/src/core/constants.js +198 -0
- package/src/core/context-compressor.js +702 -326
- package/src/core/context-manager.js +0 -1
- package/src/core/enhanced-context-compressor.js +210 -0
- package/src/core/framework.js +260 -84
- package/src/core/jsonl-storage.js +253 -0
- package/src/core/plugin-base.js +7 -5
- package/src/core/plugin-manager.js +15 -10
- package/src/core/provider-registry.js +159 -0
- package/src/core/provider.js +2 -0
- package/src/core/session-entry.js +225 -0
- package/src/core/session-manager.js +701 -0
- package/src/core/storage-manager.js +494 -0
- package/src/core/sub-agent-config.js +1 -1
- package/src/core/subagent.js +16 -135
- package/src/core/token-counter.js +177 -58
- package/src/core/tool-executor.js +2 -70
- package/src/core/ui-extension-context.js +174 -0
- package/src/executors/mcp-executor.js +27 -16
- package/src/utils/chat-queue.js +11 -22
- package/src/utils/data-splitter.js +345 -0
- package/src/utils/logger.js +152 -180
- package/src/utils/message-validator.js +283 -0
- package/src/utils/plugin-helpers.js +2 -2
- package/src/utils/retry.js +168 -22
- package/website_v2/docs/api.html +1 -1
- package/website_v2/docs/configuration.html +2 -2
- package/website_v2/docs/plugin-development.html +4 -4
- package/website_v2/docs/project-structure.html +2 -2
- package/website_v2/docs/skill-development.html +2 -2
- package/website_v2/index.html +1 -1
- package/website_v2/styles/animations.css +7 -7
- package/.agent/agents/backend-dev.md +0 -102
- package/.agent/agents/data-analyst.md +0 -117
- package/.agent/agents/devops.md +0 -115
- package/.agent/agents/frontend-dev.md +0 -94
- package/.agent/agents/network-requester.md +0 -44
- package/.agent/agents/poster-designer.md +0 -52
- package/.agent/agents/product-manager.md +0 -85
- package/.agent/agents/qa-engineer.md +0 -100
- package/.agent/agents/security-engineer.md +0 -99
- package/.agent/agents/team-lead.md +0 -137
- package/.agent/agents/ui-designer.md +0 -116
- package/.agent/data/default.json +0 -58
- package/.agent/data/email/processed-emails.json +0 -1
- package/.agent/data/plugins-state.json +0 -199
- package/.agent/data/scheduler/tasks.json +0 -1
- package/.agent/data/web/web-config.json +0 -5
- package/.agent/data/weixin/images/file_1776188148383jpg +0 -0
- package/.agent/data/weixin/images/file_1776188458326.jpg +0 -0
- package/.agent/data/weixin/images/file_1776188689423.jpg +0 -0
- package/.agent/data/weixin/images/file_1776188813604.jpg +0 -0
- package/.agent/data/weixin/images/file_1776189097450.jpg +0 -0
- package/.agent/data/weixin/videos/file_1776188318431.mp4 +0 -0
- package/.agent/data/weixin.json +0 -6
- package/.agent/mcp_config.json +0 -14
- package/.agent/memory/user/mof6gk94-kneeuh.md +0 -9
- package/.agent/package.json +0 -8
- package/.agent/plugins/marknative/README.md +0 -134
- package/.agent/plugins/marknative/fonts/SegoeUI Emoji.ttf +0 -0
- package/.agent/plugins/marknative/fonts.zip +0 -0
- package/.agent/plugins/marknative/index.js +0 -256
- package/.agent/plugins/marknative/package.json +0 -12
- package/.agent/plugins/test-plugin.py +0 -99
- package/.agent/plugins.json +0 -14
- package/.agent/python-scripts/test_sample.py +0 -24
- package/.agent/sessions/cli_default.json +0 -247
- package/.agent/skills/agent-browser/SKILL.md +0 -311
- package/.agent/skills/agent-browser/TEST_PLAN.md +0 -200
- package/.agent/skills/sysinfo/SKILL.md +0 -38
- package/.agent/skills/sysinfo/system-info.sh +0 -130
- package/.agent/skills/workflow/SKILL.md +0 -324
- package/.agent/test-agent.js +0 -35
- package/.agent/weixin.json +0 -6
- package/.agent/workflows/email-digest.json +0 -50
- package/.agent/workflows/file-backup.json +0 -21
- package/.agent/workflows/get-ip-notify.json +0 -32
- package/.agent/workflows/news-aggregator.json +0 -93
- package/.agent/workflows/news-dashboard-v2.json +0 -94
- package/.agent/workflows/notification-batch.json +0 -32
- package/src/core/session-context.js +0 -346
- package/src/core/session-storage.js +0 -295
package/plugins/feishu-plugin.js
CHANGED
|
@@ -188,18 +188,28 @@ class FeishuPlugin extends Plugin {
|
|
|
188
188
|
const command = parts[0].substring(1)
|
|
189
189
|
const args = parts.slice(1).join(' ')
|
|
190
190
|
|
|
191
|
+
// 检查 skill 命令 (格式: skillname:cmdname)
|
|
192
|
+
if (command.includes(':')) {
|
|
193
|
+
const result = await this._executeSkillCommand(command, args)
|
|
194
|
+
if (result) {
|
|
195
|
+
await this._sendMessage(openId, `✅ ${result.data || result}`, originalMsg)
|
|
196
|
+
return
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
191
200
|
switch (command.toLowerCase()) {
|
|
192
201
|
case 'start':
|
|
193
202
|
case 'help':
|
|
194
|
-
await this.
|
|
195
|
-
'👋 欢迎使用 AI 助手!\n\n直接发送消息即可与我对话。\n\n可用命令:\n/start - 显示帮助\n/clean - 清除对话上下文\n/history - 查看历史消息数',
|
|
196
|
-
originalMsg)
|
|
203
|
+
await this._sendMessageHelp(openId, originalMsg)
|
|
197
204
|
break
|
|
198
205
|
case 'clear':
|
|
199
206
|
case 'clean':
|
|
200
207
|
await this._clearSessionContext(openId)
|
|
201
208
|
await this._sendMessage(openId, '✅ 对话上下文已清除', originalMsg)
|
|
202
209
|
break
|
|
210
|
+
case 'compress':
|
|
211
|
+
await this._compressSessionContext(openId)
|
|
212
|
+
break
|
|
203
213
|
case 'history':
|
|
204
214
|
if (this._sessionPlugin) {
|
|
205
215
|
const session = this._sessionPlugin.getSession(`feishu_${openId}`)
|
|
@@ -212,6 +222,26 @@ class FeishuPlugin extends Plugin {
|
|
|
212
222
|
}
|
|
213
223
|
break
|
|
214
224
|
default:
|
|
225
|
+
// 检查是否是 skill 命令 (格式: skillname:cmdname)
|
|
226
|
+
if (text.startsWith('/')) {
|
|
227
|
+
const cmdParts = command.split(':')
|
|
228
|
+
if (cmdParts.length === 2) {
|
|
229
|
+
const skillCmd = `${cmdParts[0]}:${cmdParts[1]}`
|
|
230
|
+
try {
|
|
231
|
+
const result = await this._framework.executeTool('ext_call', {
|
|
232
|
+
plugin: 'skill',
|
|
233
|
+
tool: skillCmd,
|
|
234
|
+
args: { args }
|
|
235
|
+
})
|
|
236
|
+
if (result.success !== false) {
|
|
237
|
+
await this._sendMessage(openId, `✅ ${result.data || result}`, originalMsg)
|
|
238
|
+
return
|
|
239
|
+
}
|
|
240
|
+
} catch (err) {
|
|
241
|
+
log.warn('Skill command failed:', err.message)
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
215
245
|
await this._processChat(openId, text, originalMsg)
|
|
216
246
|
}
|
|
217
247
|
}
|
|
@@ -444,7 +474,7 @@ class FeishuPlugin extends Plugin {
|
|
|
444
474
|
}
|
|
445
475
|
|
|
446
476
|
/**
|
|
447
|
-
*
|
|
477
|
+
* 清除会话上下文(清除消息历史)
|
|
448
478
|
*/
|
|
449
479
|
async _clearSessionContext(openId) {
|
|
450
480
|
const sessionId = `feishu_${openId}`
|
|
@@ -457,21 +487,93 @@ class FeishuPlugin extends Plugin {
|
|
|
457
487
|
agent._chatHandler.clearHistory(sessionId)
|
|
458
488
|
}
|
|
459
489
|
|
|
460
|
-
// 清除
|
|
490
|
+
// 清除 SessionManager 的消息
|
|
461
491
|
if (this._framework) {
|
|
462
|
-
const
|
|
463
|
-
if (
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
492
|
+
const manager = this._framework.getSessionContext(sessionId)
|
|
493
|
+
if (manager) {
|
|
494
|
+
manager.clearMessages()
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* 检查并执行 skill 命令
|
|
501
|
+
*/
|
|
502
|
+
async _executeSkillCommand(command, args) {
|
|
503
|
+
const extExecutor = this._framework?.pluginManager?.get('extension-executor')
|
|
504
|
+
if (!extExecutor || typeof extExecutor.executeSkillCommand !== 'function') return null
|
|
505
|
+
return await extExecutor.executeSkillCommand(command, args)
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* 发送帮助信息
|
|
510
|
+
*/
|
|
511
|
+
async _sendMessageHelp(openId, originalMsg) {
|
|
512
|
+
const extExecutor = this._framework?.pluginManager?.get('extension-executor')
|
|
513
|
+
const skillHelp = extExecutor?.getSkillCommandsHelp?.() || ''
|
|
514
|
+
|
|
515
|
+
let helpText = '👋 欢迎使用 AI 助手!\n\n直接发送消息即可与我对话。\n\n可用命令:\n/start - 显示帮助\n/clean - 清除对话上下文\n/compress - 压缩上下文\n/history - 查看历史消息数'
|
|
516
|
+
|
|
517
|
+
if (skillHelp) {
|
|
518
|
+
helpText += '\n\n【技能命令】\n' + skillHelp.split('\n').map(line => line.replace(/^\//, '/')).join('\n')
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
await this._sendMessage(openId, helpText, originalMsg)
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* 压缩会话上下文
|
|
526
|
+
*/
|
|
527
|
+
async _compressSessionContext(openId) {
|
|
528
|
+
const sessionId = `feishu_${openId}`
|
|
529
|
+
|
|
530
|
+
// 获取 sessionAgent
|
|
531
|
+
const { agent } = this._getSessionAgent(openId)
|
|
532
|
+
|
|
533
|
+
if (agent._chatHandler) {
|
|
534
|
+
const chatHandler = agent._chatHandler
|
|
535
|
+
|
|
536
|
+
// 先确保从 SessionContext 加载历史(强制重新加载)
|
|
537
|
+
const messageStore = chatHandler._chatSession.getSessionMessageStore(sessionId)
|
|
538
|
+
messageStore.historyLoaded = false
|
|
539
|
+
chatHandler._chatSession.loadHistory(sessionId)
|
|
540
|
+
|
|
541
|
+
let messages = messageStore.messages
|
|
542
|
+
|
|
543
|
+
// 如果 messageStore.messages 为空,尝试从 SessionContext 获取
|
|
544
|
+
if (!messages || messages.length === 0) {
|
|
545
|
+
if (this._framework) {
|
|
546
|
+
const sessionCtx = this._framework.getSessionContext(sessionId)
|
|
547
|
+
if (sessionCtx) {
|
|
548
|
+
messages = sessionCtx.getMessages()
|
|
549
|
+
messageStore.messages = messages
|
|
550
|
+
}
|
|
551
|
+
}
|
|
467
552
|
}
|
|
468
|
-
|
|
469
|
-
const
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
553
|
+
|
|
554
|
+
const beforeCount = messages ? messages.length : 0
|
|
555
|
+
await this._sendMessage(openId, `📦 开始压缩上下文,当前 ${beforeCount} 条消息...`, null)
|
|
556
|
+
|
|
557
|
+
if (messages && messages.length > 0) {
|
|
558
|
+
if (chatHandler._contextCompressor) {
|
|
559
|
+
await chatHandler._contextCompressor.compress(sessionId, messages, messageStore)
|
|
560
|
+
const afterCount = messages.length
|
|
561
|
+
// 同步回 SessionContext
|
|
562
|
+
if (this._framework) {
|
|
563
|
+
const sessionCtx = this._framework.getSessionContext(sessionId)
|
|
564
|
+
if (sessionCtx) {
|
|
565
|
+
sessionCtx.replaceMessages(messages)
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
await this._sendMessage(openId, `✅ 压缩完成:${beforeCount} → ${afterCount} 条(保留 ${chatHandler._contextCompressor._keepRecentMessages} 条)`, null)
|
|
569
|
+
} else {
|
|
570
|
+
await this._sendMessage(openId, '❌ 压缩器不可用', null)
|
|
571
|
+
}
|
|
572
|
+
} else {
|
|
573
|
+
await this._sendMessage(openId, '❌ 没有消息需要压缩', null)
|
|
474
574
|
}
|
|
575
|
+
} else {
|
|
576
|
+
await this._sendMessage(openId, '❌ ChatHandler 不可用', null)
|
|
475
577
|
}
|
|
476
578
|
}
|
|
477
579
|
|
|
@@ -76,7 +76,7 @@ class FileSystemPlugin extends Plugin {
|
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
78
|
readDir(dirPath)
|
|
79
|
-
return { success: true,
|
|
79
|
+
return { success: true, data: items.slice(0, 100), metadata: { dirPath, total: items.length } }
|
|
80
80
|
} catch (error) {
|
|
81
81
|
return { success: false, error: error.message }
|
|
82
82
|
}
|
|
@@ -95,7 +95,7 @@ class FileSystemPlugin extends Plugin {
|
|
|
95
95
|
const dirPath = args.path || args.dirPath
|
|
96
96
|
try {
|
|
97
97
|
fs.mkdirSync(dirPath, { recursive: true })
|
|
98
|
-
return { success: true,
|
|
98
|
+
return { success: true, data: `目录已创建: ${dirPath}` }
|
|
99
99
|
} catch (error) {
|
|
100
100
|
return { success: false, error: error.message }
|
|
101
101
|
}
|
|
@@ -140,10 +140,12 @@ class FileSystemPlugin extends Plugin {
|
|
|
140
140
|
}
|
|
141
141
|
return {
|
|
142
142
|
success: true,
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
143
|
+
data: content,
|
|
144
|
+
metadata: {
|
|
145
|
+
filePath: pathCheck.resolved,
|
|
146
|
+
size: stat.size,
|
|
147
|
+
lines: lines ? null : content.split('\n').length
|
|
148
|
+
}
|
|
147
149
|
}
|
|
148
150
|
} catch (error) {
|
|
149
151
|
return { success: false, error: error.message }
|
|
@@ -210,10 +212,12 @@ class FileSystemPlugin extends Plugin {
|
|
|
210
212
|
if (err) reject(err)
|
|
211
213
|
else resolve({
|
|
212
214
|
success: true,
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
215
|
+
data: `文件已${mode === 'append' ? '追加' : '写入'}: ${pathCheck.resolved}`,
|
|
216
|
+
metadata: {
|
|
217
|
+
filePath: pathCheck.resolved,
|
|
218
|
+
size: content.length,
|
|
219
|
+
mode
|
|
220
|
+
}
|
|
217
221
|
})
|
|
218
222
|
})
|
|
219
223
|
})
|
|
@@ -254,9 +258,11 @@ class FileSystemPlugin extends Plugin {
|
|
|
254
258
|
fs.appendFileSync(pathCheck.resolved, content, 'utf8')
|
|
255
259
|
return {
|
|
256
260
|
success: true,
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
261
|
+
data: `已追加内容到: ${pathCheck.resolved}`,
|
|
262
|
+
metadata: {
|
|
263
|
+
filePath: pathCheck.resolved,
|
|
264
|
+
appendedSize: content.length
|
|
265
|
+
}
|
|
260
266
|
}
|
|
261
267
|
} catch (error) {
|
|
262
268
|
return { success: false, error: error.message }
|
|
@@ -297,7 +303,7 @@ class FileSystemPlugin extends Plugin {
|
|
|
297
303
|
} else {
|
|
298
304
|
fs.unlinkSync(pathCheck.resolved)
|
|
299
305
|
}
|
|
300
|
-
return { success: true,
|
|
306
|
+
return { success: true, data: `已删除: ${pathCheck.resolved}` }
|
|
301
307
|
} catch (error) {
|
|
302
308
|
return { success: false, error: error.message }
|
|
303
309
|
}
|
|
@@ -660,13 +666,15 @@ edits 数组可以包含多个不重叠的替换操作,每个操作通过 oldT
|
|
|
660
666
|
|
|
661
667
|
return {
|
|
662
668
|
success: true,
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
669
|
+
data: results.slice(0, maxResults),
|
|
670
|
+
metadata: {
|
|
671
|
+
pattern,
|
|
672
|
+
total: results.length,
|
|
673
|
+
stats: {
|
|
674
|
+
filesWithMatches,
|
|
675
|
+
totalMatches,
|
|
676
|
+
searchPath: targetFile || dirPath
|
|
677
|
+
}
|
|
670
678
|
}
|
|
671
679
|
}
|
|
672
680
|
} catch (error) {
|
|
@@ -817,19 +825,23 @@ edits 数组可以包含多个不重叠的替换操作,每个操作通过 oldT
|
|
|
817
825
|
if (error) {
|
|
818
826
|
resolve({
|
|
819
827
|
success: false,
|
|
820
|
-
command,
|
|
821
828
|
error: error.message,
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
829
|
+
metadata: {
|
|
830
|
+
command,
|
|
831
|
+
stderr: stderr.substring(0, 2000),
|
|
832
|
+
stdout: stdout.substring(0, 2000),
|
|
833
|
+
duration
|
|
834
|
+
}
|
|
825
835
|
})
|
|
826
836
|
} else {
|
|
827
837
|
resolve({
|
|
828
838
|
success: true,
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
839
|
+
data: stdout.substring(0, 10000),
|
|
840
|
+
metadata: {
|
|
841
|
+
command,
|
|
842
|
+
stderr: stderr.substring(0, 1000),
|
|
843
|
+
duration
|
|
844
|
+
}
|
|
833
845
|
})
|
|
834
846
|
}
|
|
835
847
|
}
|
|
@@ -848,16 +860,18 @@ edits 数组可以包含多个不重叠的替换操作,每个操作通过 oldT
|
|
|
848
860
|
const beijingTime = new Date(now.getTime() + (8 * 60 * 60 * 1000))
|
|
849
861
|
return {
|
|
850
862
|
success: true,
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
863
|
+
data: beijingTime.toISOString().replace('T', ' ').substring(0, 19),
|
|
864
|
+
metadata: {
|
|
865
|
+
timestamp: now.getTime(),
|
|
866
|
+
timezone: 'Asia/Shanghai (UTC+8)',
|
|
867
|
+
formatted: {
|
|
868
|
+
year: beijingTime.getUTCFullYear(),
|
|
869
|
+
month: String(beijingTime.getUTCMonth() + 1).padStart(2, '0'),
|
|
870
|
+
day: String(beijingTime.getUTCDate()).padStart(2, '0'),
|
|
871
|
+
hour: String(beijingTime.getUTCHours()).padStart(2, '0'),
|
|
872
|
+
minute: String(beijingTime.getUTCMinutes()).padStart(2, '0'),
|
|
873
|
+
second: String(beijingTime.getUTCMinutes()).padStart(2, '0')
|
|
874
|
+
}
|
|
861
875
|
}
|
|
862
876
|
}
|
|
863
877
|
}
|
|
@@ -983,21 +997,25 @@ edits 数组可以包含多个不重叠的替换操作,每个操作通过 oldT
|
|
|
983
997
|
: data
|
|
984
998
|
return {
|
|
985
999
|
success: true,
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
1000
|
+
data: truncatedData,
|
|
1001
|
+
metadata: {
|
|
1002
|
+
status: response.status,
|
|
1003
|
+
statusText: response.statusText,
|
|
1004
|
+
headers: Object.fromEntries(response.headers.entries()),
|
|
1005
|
+
usedProxy: proxy,
|
|
1006
|
+
originalLength: typeof data === 'string' ? data.length : null,
|
|
1007
|
+
truncated: maxLength && typeof data === 'string' && data.length > maxLength
|
|
1008
|
+
}
|
|
993
1009
|
}
|
|
994
1010
|
} catch (error) {
|
|
995
1011
|
return {
|
|
996
1012
|
success: false,
|
|
997
1013
|
error: error.message,
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1014
|
+
metadata: {
|
|
1015
|
+
url,
|
|
1016
|
+
method,
|
|
1017
|
+
hint: '如果访问失败,可尝试设置 proxy: true'
|
|
1018
|
+
}
|
|
1001
1019
|
}
|
|
1002
1020
|
}
|
|
1003
1021
|
}
|
|
@@ -1026,7 +1044,7 @@ edits 数组可以包含多个不重叠的替换操作,每个操作通过 oldT
|
|
|
1026
1044
|
sessionId,
|
|
1027
1045
|
timestamp: new Date().toISOString()
|
|
1028
1046
|
})
|
|
1029
|
-
return { success: true,
|
|
1047
|
+
return { success: true, data: '通知已发送' }
|
|
1030
1048
|
} catch (error) {
|
|
1031
1049
|
return { success: false, error: error.message }
|
|
1032
1050
|
}
|
package/plugins/gate-trading.js
CHANGED
|
@@ -64,7 +64,7 @@ class GateTradingPlugin extends Plugin {
|
|
|
64
64
|
this.secretKey = args.secret;
|
|
65
65
|
const fs = require('fs');
|
|
66
66
|
fs.writeFileSync(__dirname + '/.env', `GATE_API_KEY=${args.api_key}\nGATE_SECRET_KEY=${args.secret}\n`);
|
|
67
|
-
return { success: true,
|
|
67
|
+
return { success: true, data: 'Gate API 密钥已成功配置' };
|
|
68
68
|
},
|
|
69
69
|
});
|
|
70
70
|
|
|
@@ -86,7 +86,7 @@ class GateTradingPlugin extends Plugin {
|
|
|
86
86
|
this.apiKey = '';
|
|
87
87
|
this.secretKey = '';
|
|
88
88
|
try { require('fs').unlinkSync(__dirname + '/.env'); } catch (e) {}
|
|
89
|
-
return { success: true,
|
|
89
|
+
return { success: true, data: 'API 配置已清除' };
|
|
90
90
|
},
|
|
91
91
|
});
|
|
92
92
|
|
|
@@ -99,7 +99,7 @@ class GateTradingPlugin extends Plugin {
|
|
|
99
99
|
this._checkAuth();
|
|
100
100
|
const spotApi = this._createSpotApi();
|
|
101
101
|
const currencies = await spotApi.listCurrencies();
|
|
102
|
-
return { success: true,
|
|
102
|
+
return { success: true, data: 'API 连接成功,密钥有效', metadata: { currencyCount: currencies.body.length } };
|
|
103
103
|
} catch (error) { return { success: false, error: error.message }; }
|
|
104
104
|
},
|
|
105
105
|
});
|
|
@@ -118,18 +118,18 @@ class GateTradingPlugin extends Plugin {
|
|
|
118
118
|
const { currency_pair, info_type } = args;
|
|
119
119
|
if (info_type === 'book' || !info_type) {
|
|
120
120
|
const book = await spotApi.listOrderBook(currency_pair, { limit: 10 });
|
|
121
|
-
return { success: true,
|
|
121
|
+
return { success: true, data: { bids: book.body.bids, asks: book.body.asks }, metadata: { type: 'order_book', currency_pair } };
|
|
122
122
|
} else if (info_type === 'tickers') {
|
|
123
123
|
const tickers = await spotApi.listTickers(currency_pair);
|
|
124
124
|
const t = tickers.body.find(x => x.currencyPair === currency_pair) || tickers.body[0];
|
|
125
125
|
return {
|
|
126
|
-
success: true, type: 'ticker', currency_pair: t.currencyPair,
|
|
126
|
+
success: true, data: { type: 'ticker', currency_pair: t.currencyPair,
|
|
127
127
|
last: t.last, high_24h: t.high24h, low_24h: t.low24h,
|
|
128
|
-
volume_24h: t.baseVolume, quote_volume_24h: t.quoteVolume, change_percentage_24h: t.changePercentage,
|
|
128
|
+
volume_24h: t.baseVolume, quote_volume_24h: t.quoteVolume, change_percentage_24h: t.changePercentage },
|
|
129
129
|
};
|
|
130
130
|
} else if (info_type === 'trades') {
|
|
131
131
|
const trades = await spotApi.listTrades(currency_pair);
|
|
132
|
-
return { success: true,
|
|
132
|
+
return { success: true, data: trades.body.slice(0, 20), metadata: { type: 'trades', currency_pair } };
|
|
133
133
|
}
|
|
134
134
|
return { success: false, error: '未知的信息类型' };
|
|
135
135
|
} catch (error) { return { success: false, error: error.message }; }
|
|
@@ -152,7 +152,7 @@ class GateTradingPlugin extends Plugin {
|
|
|
152
152
|
const nonZero = balances.filter(b => parseFloat(b.available) > 0 || parseFloat(b.locked) > 0);
|
|
153
153
|
return {
|
|
154
154
|
success: true,
|
|
155
|
-
|
|
155
|
+
data: nonZero.map(b => ({
|
|
156
156
|
currency: b.currency, available: b.available, locked: b.locked,
|
|
157
157
|
total: parseFloat(b.available) + parseFloat(b.locked),
|
|
158
158
|
})),
|
|
@@ -180,9 +180,9 @@ class GateTradingPlugin extends Plugin {
|
|
|
180
180
|
const result = await spotApi.createOrder(order);
|
|
181
181
|
const r = result.body;
|
|
182
182
|
return {
|
|
183
|
-
success: true, order_id: r.id, currency_pair: r.currency_pair,
|
|
183
|
+
success: true, data: { order_id: r.id, currency_pair: r.currency_pair,
|
|
184
184
|
type: r.type, side: r.side, amount: r.amount,
|
|
185
|
-
price: r.price, status: r.status, create_time: r.create_time,
|
|
185
|
+
price: r.price, status: r.status, create_time: r.create_time },
|
|
186
186
|
};
|
|
187
187
|
} catch (error) { return { success: false, error: error.message }; }
|
|
188
188
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* InstallPlugin - npm 包安装工具
|
|
3
|
-
* 自动安装缺少的 node 模块到 .
|
|
3
|
+
* 自动安装缺少的 node 模块到 .foliko 目录或指定目录
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
const { execSync } = require('child_process')
|
|
@@ -18,7 +18,7 @@ class InstallPlugin extends Plugin {
|
|
|
18
18
|
this.version = '1.0.0'
|
|
19
19
|
this.description = '自动安装 npm 包到指定目录'
|
|
20
20
|
|
|
21
|
-
this._agentDir = config.agentDir || '.
|
|
21
|
+
this._agentDir = config.agentDir || '.foliko' // 默认安装到 .foliko 目录
|
|
22
22
|
this._nodeModulesDir = null
|
|
23
23
|
this.system = true
|
|
24
24
|
}
|
|
@@ -41,7 +41,7 @@ class InstallPlugin extends Plugin {
|
|
|
41
41
|
description: '安装 npm 包到指定目录',
|
|
42
42
|
inputSchema: z.object({
|
|
43
43
|
package: z.string().optional().describe('包名,如 lodash、lodash@4.17.21 或 @scope/package'),
|
|
44
|
-
path: z.string().optional().describe('安装目标目录,如 .
|
|
44
|
+
path: z.string().optional().describe('安装目标目录,如 .foliko/plugins/my-plugin(默认为 .foliko)'),
|
|
45
45
|
file: z.string().optional().describe('本地 package.json 路径,从该文件安装所有依赖')
|
|
46
46
|
}),
|
|
47
47
|
execute: async (args) => {
|
|
@@ -79,7 +79,7 @@ class InstallPlugin extends Plugin {
|
|
|
79
79
|
/**
|
|
80
80
|
* 安装单个包到指定目录
|
|
81
81
|
* @param {string} packageName - 包名
|
|
82
|
-
* @param {string|null} targetPath - 目标目录,默认为 .
|
|
82
|
+
* @param {string|null} targetPath - 目标目录,默认为 .foliko
|
|
83
83
|
*/
|
|
84
84
|
_installPackage(packageName, targetPath = null) {
|
|
85
85
|
try {
|
|
@@ -104,7 +104,7 @@ class InstallPlugin extends Plugin {
|
|
|
104
104
|
|
|
105
105
|
return {
|
|
106
106
|
success: true,
|
|
107
|
-
|
|
107
|
+
data: `Successfully installed ${packageName} to ${installPath}`
|
|
108
108
|
}
|
|
109
109
|
} catch (err) {
|
|
110
110
|
return {
|
|
@@ -141,7 +141,7 @@ class InstallPlugin extends Plugin {
|
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
if (packages.length === 0) {
|
|
144
|
-
return { success: true,
|
|
144
|
+
return { success: true, data: 'No dependencies to install' }
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
// 确保目标目录存在
|
|
@@ -159,7 +159,7 @@ class InstallPlugin extends Plugin {
|
|
|
159
159
|
|
|
160
160
|
return {
|
|
161
161
|
success: true,
|
|
162
|
-
|
|
162
|
+
data: `Successfully installed ${packages.length} dependencies to ${installPath}`
|
|
163
163
|
}
|
|
164
164
|
} catch (err) {
|
|
165
165
|
return {
|
package/plugins/memory-plugin.js
CHANGED
|
@@ -24,7 +24,7 @@ const MEMORY_TYPES = {
|
|
|
24
24
|
/**
|
|
25
25
|
* 记忆存储路径
|
|
26
26
|
*/
|
|
27
|
-
const MEMORY_BASE_DIR = '.
|
|
27
|
+
const MEMORY_BASE_DIR = '.foliko/memory'
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
30
|
* 解析 YAML frontmatter(从 skill-manager 复用)
|
|
@@ -625,8 +625,7 @@ class MemoryPlugin extends Plugin {
|
|
|
625
625
|
|
|
626
626
|
return {
|
|
627
627
|
success: true,
|
|
628
|
-
|
|
629
|
-
memories: results.map(m => ({
|
|
628
|
+
data: results.map(m => ({
|
|
630
629
|
id: m.id,
|
|
631
630
|
name: m.name,
|
|
632
631
|
type: m.type,
|
|
@@ -665,8 +664,8 @@ class MemoryPlugin extends Plugin {
|
|
|
665
664
|
|
|
666
665
|
return {
|
|
667
666
|
success: true,
|
|
668
|
-
|
|
669
|
-
|
|
667
|
+
data: `Memory created: ${memory.id}`,
|
|
668
|
+
metadata: { id: memory.id }
|
|
670
669
|
}
|
|
671
670
|
} catch (err) {
|
|
672
671
|
return { success: false, error: err.message }
|
|
@@ -694,8 +693,7 @@ class MemoryPlugin extends Plugin {
|
|
|
694
693
|
|
|
695
694
|
return {
|
|
696
695
|
success: true,
|
|
697
|
-
|
|
698
|
-
memories: memories.map(m => ({
|
|
696
|
+
data: memories.map(m => ({
|
|
699
697
|
id: m.id,
|
|
700
698
|
name: m.name,
|
|
701
699
|
type: m.type,
|
|
@@ -752,8 +750,8 @@ class MemoryPlugin extends Plugin {
|
|
|
752
750
|
const memory = this._store.update(args.id, updates)
|
|
753
751
|
return {
|
|
754
752
|
success: true,
|
|
755
|
-
|
|
756
|
-
|
|
753
|
+
data: `Memory updated: ${memory.id}`,
|
|
754
|
+
metadata: { id: memory.id }
|
|
757
755
|
}
|
|
758
756
|
} catch (err) {
|
|
759
757
|
return { success: false, error: err.message }
|
|
@@ -776,7 +774,7 @@ class MemoryPlugin extends Plugin {
|
|
|
776
774
|
}
|
|
777
775
|
return {
|
|
778
776
|
success: true,
|
|
779
|
-
|
|
777
|
+
data: {
|
|
780
778
|
id: memory.id,
|
|
781
779
|
name: memory.name,
|
|
782
780
|
type: memory.type,
|
|
@@ -803,8 +801,7 @@ class MemoryPlugin extends Plugin {
|
|
|
803
801
|
const projects = this._store.getProjects()
|
|
804
802
|
return {
|
|
805
803
|
success: true,
|
|
806
|
-
stats,
|
|
807
|
-
projects
|
|
804
|
+
data: { stats, projects }
|
|
808
805
|
}
|
|
809
806
|
} catch (err) {
|
|
810
807
|
return { success: false, error: err.message }
|
|
@@ -119,7 +119,7 @@ class PluginManagerPlugin extends Plugin {
|
|
|
119
119
|
// 3. plugin_install - 从远程仓库安装插件到本地
|
|
120
120
|
framework.registerTool({
|
|
121
121
|
name: 'plugin_install',
|
|
122
|
-
description: '从远程 Git 仓库安装插件到本地 .
|
|
122
|
+
description: '从远程 Git 仓库安装插件到本地 .foliko/plugins 目录',
|
|
123
123
|
inputSchema: z.object({
|
|
124
124
|
name: z.string().describe('插件名称,如 puppeteer-plugin'),
|
|
125
125
|
repo: z.string().optional().describe('插件仓库 URL'),
|
|
@@ -160,7 +160,7 @@ class PluginManagerPlugin extends Plugin {
|
|
|
160
160
|
const contents = await response.json();
|
|
161
161
|
|
|
162
162
|
if (!Array.isArray(contents) || contents.length === 0) {
|
|
163
|
-
return { success: true,
|
|
163
|
+
return { success: true, data: [], metadata: { message: 'No plugins found in repository' } };
|
|
164
164
|
}
|
|
165
165
|
|
|
166
166
|
const plugins = [];
|
|
@@ -198,9 +198,8 @@ class PluginManagerPlugin extends Plugin {
|
|
|
198
198
|
|
|
199
199
|
return {
|
|
200
200
|
success: true,
|
|
201
|
-
plugins,
|
|
202
|
-
repo,
|
|
203
|
-
count: plugins.length,
|
|
201
|
+
data: plugins,
|
|
202
|
+
metadata: { repo, count: plugins.length },
|
|
204
203
|
};
|
|
205
204
|
|
|
206
205
|
} catch (err) {
|
|
@@ -213,7 +212,7 @@ class PluginManagerPlugin extends Plugin {
|
|
|
213
212
|
* 发布插件到远程仓库
|
|
214
213
|
*/
|
|
215
214
|
async _publishPlugin(pluginName, repo) {
|
|
216
|
-
const pluginsDir = path.resolve(process.cwd(), '.
|
|
215
|
+
const pluginsDir = path.resolve(process.cwd(), '.foliko', 'plugins');
|
|
217
216
|
const localPluginsDir = path.resolve(process.cwd(), 'plugins');
|
|
218
217
|
|
|
219
218
|
// 确定插件目录
|
|
@@ -303,8 +302,8 @@ class PluginManagerPlugin extends Plugin {
|
|
|
303
302
|
if (!status.trim()) {
|
|
304
303
|
return {
|
|
305
304
|
success: true,
|
|
306
|
-
|
|
307
|
-
repo,
|
|
305
|
+
data: `No changes to commit for plugin "${pluginName}"`,
|
|
306
|
+
metadata: { repo },
|
|
308
307
|
};
|
|
309
308
|
}
|
|
310
309
|
|
|
@@ -315,9 +314,8 @@ class PluginManagerPlugin extends Plugin {
|
|
|
315
314
|
|
|
316
315
|
return {
|
|
317
316
|
success: true,
|
|
318
|
-
|
|
319
|
-
repo,
|
|
320
|
-
path: `${pluginName}/${pluginName}.js`,
|
|
317
|
+
data: `Plugin "${pluginName}" published successfully`,
|
|
318
|
+
metadata: { repo, path: `${pluginName}/${pluginName}.js` },
|
|
321
319
|
};
|
|
322
320
|
|
|
323
321
|
} catch (err) {
|
|
@@ -332,7 +330,7 @@ class PluginManagerPlugin extends Plugin {
|
|
|
332
330
|
* 从远程仓库安装插件
|
|
333
331
|
*/
|
|
334
332
|
async _installPlugin(pluginName, repo) {
|
|
335
|
-
const localPluginsDir = path.resolve(process.cwd(), '.
|
|
333
|
+
const localPluginsDir = path.resolve(process.cwd(), '.foliko', 'plugins');
|
|
336
334
|
const tmpDir = path.join(require('os').tmpdir(), `foliko-plugin-install-${Date.now()}`);
|
|
337
335
|
|
|
338
336
|
try {
|
|
@@ -387,8 +385,8 @@ class PluginManagerPlugin extends Plugin {
|
|
|
387
385
|
|
|
388
386
|
return {
|
|
389
387
|
success: true,
|
|
390
|
-
|
|
391
|
-
path: targetDir,
|
|
388
|
+
data: `Plugin "${pluginName}" installed successfully`,
|
|
389
|
+
metadata: { path: targetDir },
|
|
392
390
|
};
|
|
393
391
|
|
|
394
392
|
} catch (err) {
|
|
@@ -23,7 +23,7 @@ class PythonExecutorPlugin extends Plugin {
|
|
|
23
23
|
this.config = {
|
|
24
24
|
pythonPath: config.pythonPath || 'python', // python 或 python3
|
|
25
25
|
timeout: config.timeout || 120000, // 2分钟超时
|
|
26
|
-
baseDir: config.baseDir || '.
|
|
26
|
+
baseDir: config.baseDir || '.foliko/python-scripts',
|
|
27
27
|
pipPath: config.pipPath || null // 可选,自定义 pip 路径
|
|
28
28
|
}
|
|
29
29
|
|