foliko 1.1.39 → 1.1.41
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/sessions/cli_default.json +42 -0
- package/.agent/sessions/qq_c2c_D960F12877541624D7B2C836110B3D0F.json +77 -0
- package/.claude/settings.local.json +4 -1
- package/cli/src/commands/daemon.js +140 -0
- package/cli/src/index.js +13 -2
- package/examples/daemon.js +51 -0
- package/package.json +1 -1
- package/plugins/qq-plugin.js +0 -7
- package/temp_img.md +0 -1
|
@@ -2943,6 +2943,48 @@
|
|
|
2943
2943
|
"text": "<think>QQ插件已成功启用。我需要告诉用户这个结果。\n</think>\n\n已成功开启 QQ 插件 ✓\n\n```\n名称: qq\n版本: 1.0.0\n状态: registered → enabled\n```\n\n现在 QQ 插件已经启用了。如果需要配置 QQ 机器人(比如登录、设置群聊等),请告诉我具体需求!"
|
|
2944
2944
|
}
|
|
2945
2945
|
]
|
|
2946
|
+
},
|
|
2947
|
+
{
|
|
2948
|
+
"role": "user",
|
|
2949
|
+
"content": "开启qq插件"
|
|
2950
|
+
},
|
|
2951
|
+
{
|
|
2952
|
+
"role": "assistant",
|
|
2953
|
+
"content": [
|
|
2954
|
+
{
|
|
2955
|
+
"type": "text",
|
|
2956
|
+
"text": "<think>用户再次要求开启qq插件,说明可能是命令没有生效或者有其他问题。让我检查一下qq插件的当前状态,然后再次尝试启用。\n</think>\n\n\n"
|
|
2957
|
+
},
|
|
2958
|
+
{
|
|
2959
|
+
"type": "tool-call",
|
|
2960
|
+
"toolCallId": "call_function_ejd5bg9jrzov_1",
|
|
2961
|
+
"toolName": "list_plugins",
|
|
2962
|
+
"input": {}
|
|
2963
|
+
}
|
|
2964
|
+
]
|
|
2965
|
+
},
|
|
2966
|
+
{
|
|
2967
|
+
"role": "tool",
|
|
2968
|
+
"content": [
|
|
2969
|
+
{
|
|
2970
|
+
"type": "tool-result",
|
|
2971
|
+
"toolCallId": "call_function_ejd5bg9jrzov_1",
|
|
2972
|
+
"toolName": "list_plugins",
|
|
2973
|
+
"output": {
|
|
2974
|
+
"type": "text",
|
|
2975
|
+
"value": "{\"success\":true,\"plugins\":[{\"name\":\"defaults\",\"status\":\"loaded\",\"enabled\":true,\"version\":\"1.0.0\",\"system\":true},{\"name\":\"install\",\"status\":\"loaded\",\"enabled\":true,\"version\":\"1.0.0\",\"system\":true},{\"name\":\"ai\",\"status\":\"loaded\",\"enabled\":true,\"version\":\"1.0.0\",\"system\":true},{\"name\":\"skill-manager\",\"status\":\"loaded\",\"enabled\":true,\"version\":\"1.0.0\",\"system\":true},{\"name\":\"mcp\",\"status\":\"loaded\",\"enabled\":true,\"version\":\"1.0.0\",\"system\":true},{\"name\":\"python-plugin-loader\",\"status\":\"loaded\",\"enabled\":true,\"version\":\"1.0.0\",\"system\":true},{\"name\":\"subagent-manager\",\"status\":\"loaded\",\"enabled\":true,\"version\":\"1.0.0\",\"system\":false},{\"name\":\"marknative\",\"status\":\"loaded\",\"enabled\":true,\"version\":\"1.0.1\",\"system\":false},{\"name\":\"poster\",\"status\":\"loaded\",\"enabled\":true,\"version\":\"1.2.2\",\"system\":false},{\"name\":\"ambient\",\"status\":\"loaded\",\"enabled\":true,\"version\":\"1.0.0\",\"system\":true},{\"name\":\"audit\",\"status\":\"loaded\",\"enabled\":true,\"version\":\"1.0.0\",\"system\":true},{\"name\":\"coordinator\",\"status\":\"registered\",\"enabled\":false,\"version\":\"1.0.0\",\"system\":false},{\"name\":\"email\",\"status\":\"registered\",\"enabled\":false,\"version\":\"1.1.0\",\"system\":false},{\"name\":\"extension-executor\",\"status\":\"loaded\",\"enabled\":true,\"version\":\"1.0.0\",\"system\":true},{\"name\":\"feishu\",\"status\":\"registered\",\"enabled\":false,\"version\":\"1.1.0\",\"system\":false},{\"name\":\"file-system\",\"status\":\"loaded\",\"enabled\":true,\"version\":\"1.0.0\",\"system\":true},{\"name\":\"gate-trading\",\"status\":\"loaded\",\"enabled\":true,\"version\":\"1.1.0\",\"system\":false},{\"name\":\"memory\",\"status\":\"loaded\",\"enabled\":true,\"version\":\"1.0.0\",\"system\":true},{\"name\":\"plugin_manager\",\"status\":\"loaded\",\"enabled\":true,\"version\":\"1.0.0\",\"system\":true},{\"name\":\"python-executor\",\"status\":\"loaded\",\"enabled\":true,\"version\":\"1.0.0\",\"system\":true},{\"name\":\"qq\",\"status\":\"loaded\",\"enabled\":true,\"version\":\"1.0.0\",\"system\":false},{\"name\":\"rules\",\"status\":\"loaded\",\"enabled\":true,\"version\":\"1.0.0\",\"system\":true},{\"name\":\"scheduler\",\"status\":\"loaded\",\"enabled\":true,\"version\":\"1.0.0\",\"system\":true},{\"name\":\"session\",\"status\":\"loaded\",\"enabled\":true,\"version\":\"1.0.0\",\"system\":true},{\"name\":\"shell-executor\",\"status\":\"loaded\",\"enabled\":true,\"version\":\"1.0.0\",\"system\":true},{\"name\":\"storage\",\"status\":\"loaded\",\"enabled\":true,\"version\":\"1.0.0\",\"system\":true},{\"name\":\"telegram\",\"status\":\"registered\",\"enabled\":false,\"version\":\"2.1.0\",\"system\":false},{\"name\":\"think\",\"status\":\"loaded\",\"enabled\":true,\"version\":\"1.0.0\",\"system\":false},{\"name\":\"tools\",\"status\":\"loaded\",\"enabled\":true,\"version\":\"1.0.0\",\"system\":true},{\"name\":\"web\",\"status\":\"loaded\",\"enabled\":true,\"version\":\"3.1.0\",\"system\":true},{\"name\":\"weixin\",\"status\":\"registered\",\"enabled\":false,\"version\":\"1.0.0\",\"system\":false}]}"
|
|
2976
|
+
}
|
|
2977
|
+
}
|
|
2978
|
+
]
|
|
2979
|
+
},
|
|
2980
|
+
{
|
|
2981
|
+
"role": "assistant",
|
|
2982
|
+
"content": [
|
|
2983
|
+
{
|
|
2984
|
+
"type": "text",
|
|
2985
|
+
"text": "<think>QQ 插件已经是 loaded 和 enabled 状态了,说明之前已经成功开启了。用户可能不知道或者重复发送了请求。告诉用户当前状态即可。\n</think>\n\nQQ 插件已经在运行中 ✓\n\n```\n名称: qq\n版本: 1.0.0\n状态: 已加载并启用\n```\n\n插件已正常开启,有需要可以随时使用!"
|
|
2986
|
+
}
|
|
2987
|
+
]
|
|
2946
2988
|
}
|
|
2947
2989
|
],
|
|
2948
2990
|
"variables": {},
|
|
@@ -13,6 +13,83 @@
|
|
|
13
13
|
"text": "<think>用户问有什么好玩的,这是一个比较开放的问题。我可以从以下几个角度回答:\n\n1. 推荐一些有趣的活动或项目\n2. 展示我可以帮助做的事情\n3. 提供一些娱乐建议\n\n让我思考一下有什么可以分享的。我可以展示一下这个 Agent 系统的一些有趣功能,比如:\n- 海报制作\n- AI 对话\n- 定时提醒\n- 网络请求获取信息\n- 编程辅助\n\n或者我可以问用户具体想要什么类型的\"好玩\",是想要:\n- 技术相关的项目\n- 游戏或娱乐\n- 实用工具\n- 学习新东西\n\n我觉得可以简单介绍一些有趣的功能,然后问用户具体偏好什么。\n</think>\n\n我可以帮你做很多有趣的事情!以下是一些推荐:\n\n## 🎮 技术类好玩的事\n\n1. **制作海报** - 用 poster 插件设计精美的海报、卡片\n2. **AI 绘图提示词** - 生成 Midjourney/Stable Diffusion 提示词\n3. **自动化脚本** - 用 Python 写个小游戏或工具\n4. **网页抓取** - 获取某个网站的信息做分析\n\n## 🌐 实用有趣的事\n\n1. **定时提醒** - 设置一些有趣的定时任务\n2. **记忆系统** - 让我记住你的偏好,下次更懂你\n3. **子 Agent** - 可以帮我处理更复杂的任务,比如写代码、做设计\n\n## 💡 随机推荐\n\n- \"帮我查下今天有什么新闻\"\n- \"画一个好看的海报模板\"\n- \"写一个随机笑话生成器\"\n- \"帮我分析一下某支股票\"\n\n---\n\n**你更想玩哪个方向?** 比如:\n- 🎨 创意设计(海报、绘图)\n- 💻 技术折腾(代码、自动化)\n- 📊 信息获取(查资料、分析)\n- 🎲 随机整活"
|
|
14
14
|
}
|
|
15
15
|
]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"role": "user",
|
|
19
|
+
"content": "你好"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"role": "assistant",
|
|
23
|
+
"content": [
|
|
24
|
+
{
|
|
25
|
+
"type": "text",
|
|
26
|
+
"text": "<think>用户只是简单打了个招呼\"你好\",这是一个很常见的对话开场。我不需要调用任何工具,直接回应即可。\n\n根据响应规范,我应该直接给出结论或结果,不说\"我需要...\"、\"我建议...\"等铺垫话术。\n\n我可以简短友好地回应,并延续之前的对话氛围。\n</think>\n\n你好!👋\n\n有什么我可以帮你的吗?"
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"role": "user",
|
|
32
|
+
"content": "你好"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"role": "assistant",
|
|
36
|
+
"content": [
|
|
37
|
+
{
|
|
38
|
+
"type": "text",
|
|
39
|
+
"text": "你好!😊\n\n有什么想聊的或者需要帮忙的吗?"
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"role": "user",
|
|
45
|
+
"content": "不错,今天星期几"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"role": "assistant",
|
|
49
|
+
"content": [
|
|
50
|
+
{
|
|
51
|
+
"type": "tool-call",
|
|
52
|
+
"toolCallId": "call_00_2sNBKE3ShNicmGLtewi1hfQS",
|
|
53
|
+
"toolName": "get_time",
|
|
54
|
+
"input": {}
|
|
55
|
+
}
|
|
56
|
+
]
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"role": "tool",
|
|
60
|
+
"content": [
|
|
61
|
+
{
|
|
62
|
+
"type": "tool-result",
|
|
63
|
+
"toolCallId": "call_00_2sNBKE3ShNicmGLtewi1hfQS",
|
|
64
|
+
"toolName": "get_time",
|
|
65
|
+
"output": {
|
|
66
|
+
"type": "text",
|
|
67
|
+
"value": "{\"success\":true,\"beijingTime\":\"2026-05-02 09:58:07\",\"timestamp\":1777687087755,\"timezone\":\"Asia/Shanghai (UTC+8)\",\"formatted\":{\"year\":2026,\"month\":\"05\",\"day\":\"02\",\"hour\":\"09\",\"minute\":\"58\",\"second\":\"58\"}}"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"role": "assistant",
|
|
74
|
+
"content": [
|
|
75
|
+
{
|
|
76
|
+
"type": "text",
|
|
77
|
+
"text": "今天是 **2026年5月2日,星期六** 🎉\n\n正好是周末,有什么好玩的计划吗?😄"
|
|
78
|
+
}
|
|
79
|
+
]
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"role": "user",
|
|
83
|
+
"content": "你都会些什么"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"role": "assistant",
|
|
87
|
+
"content": [
|
|
88
|
+
{
|
|
89
|
+
"type": "text",
|
|
90
|
+
"text": "好问题!让我给你列一下我能做的事情:\n\n## 🛠️ 核心能力\n\n### 💬 对话聊天\n- 日常聊天、回答问题、提供建议\n\n### 📝 文件操作\n- 读写文件、搜索内容、创建目录、修改文件\n\n### 🌐 网络请求\n- 抓取网页、调用 API、获取远程数据\n\n### 🐍 编程执行\n- 执行 Python 代码、安装 Python 包\n- 执行 Shell 命令、运行脚本\n\n### 🎨 创意设计\n- **制作海报** - 用 poster 插件生成精美海报/卡片\n- **Markdown 转图片** - 把文档渲染成图片\n\n### ⏰ 定时任务\n- 设置提醒、定时执行任务、Cron 表达式\n\n### 🧠 记忆系统\n- 记住你的偏好、项目信息、参考资料\n\n### 🔌 扩展插件\n- **加密货币交易** - Gate.io 现货/合约交易\n- **QQ 消息** - 发送 QQ 私聊/群聊消息\n- **Web 服务** - 启动 HTTP 服务、注册 Webhook\n\n### 🤖 子 Agent 专家团队\n- **前端开发** - 写 React/Vue/HTML/CSS\n- **后端开发** - API、数据库、微服务\n- **UI 设计** - 界面设计、交互设计\n- **数据分析** - 统计、可视化、报表\n- **DevOps** - 部署、Docker、K8s\n- **测试/安全** - 自动化测试、代码审计\n- **产品经理** - 需求分析、PRD\n\n### 🎯 技能系统\n- 浏览器自动化、工作流引擎、主动思考等\n\n---\n\n**想试试哪个?** 比如我马上可以:\n- 给你画张海报 🎨\n- 写个小程序 💻\n- 查个有趣的信息 🌐\n- 设置个定时提醒 ⏰"
|
|
91
|
+
}
|
|
92
|
+
]
|
|
16
93
|
}
|
|
17
94
|
],
|
|
18
95
|
"variables": {},
|
|
@@ -207,7 +207,10 @@
|
|
|
207
207
|
"Bash(npm test:*)",
|
|
208
208
|
"Bash(node -e \"require\\('./src/index.js'\\); console.log\\('Module loaded successfully'\\)\")",
|
|
209
209
|
"Bash(node examples/basic.js 2>&1)",
|
|
210
|
-
"Bash(node -c plugins/qq-plugin.js 2>&1)"
|
|
210
|
+
"Bash(node -c plugins/qq-plugin.js 2>&1)",
|
|
211
|
+
"Bash(node -c cli/src/commands/daemon.js 2>&1 && node -c cli/src/index.js 2>&1)",
|
|
212
|
+
"Bash(node -c examples/daemon.js 2>&1)",
|
|
213
|
+
"Bash(node -c cli/src/commands/daemon.js 2>&1)"
|
|
211
214
|
]
|
|
212
215
|
}
|
|
213
216
|
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Foliko Daemon 命令
|
|
3
|
+
* Usage: foliko start | stop | status
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const { spawn } = require('child_process');
|
|
9
|
+
|
|
10
|
+
// 使用 project root 的绝对路径
|
|
11
|
+
const PROJECT_ROOT = path.join(__dirname, '../../../');
|
|
12
|
+
const DAEMON_SCRIPT = path.join(PROJECT_ROOT, 'examples', 'daemon.js');
|
|
13
|
+
const PID_FILE = path.join(PROJECT_ROOT, '.foliko.pid');
|
|
14
|
+
const LOG_FILE = path.join(PROJECT_ROOT, '.foliko.log');
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 获取 PID 文件中的进程 ID
|
|
18
|
+
*/
|
|
19
|
+
function getPid() {
|
|
20
|
+
if (fs.existsSync(PID_FILE)) {
|
|
21
|
+
return parseInt(fs.readFileSync(PID_FILE, 'utf8').trim(), 10);
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 检查进程是否在运行
|
|
28
|
+
*/
|
|
29
|
+
function isRunning(pid) {
|
|
30
|
+
if (!pid) return false;
|
|
31
|
+
try {
|
|
32
|
+
process.kill(pid, 0);
|
|
33
|
+
return true;
|
|
34
|
+
} catch {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 启动守护进程
|
|
41
|
+
*/
|
|
42
|
+
async function startDaemon() {
|
|
43
|
+
const existingPid = getPid();
|
|
44
|
+
|
|
45
|
+
if (existingPid && isRunning(existingPid)) {
|
|
46
|
+
console.log(`Foliko 已在运行 (PID: ${existingPid})`);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// 启动子进程
|
|
51
|
+
const child = spawn(process.execPath, [DAEMON_SCRIPT], {
|
|
52
|
+
detached: true,
|
|
53
|
+
stdio: 'ignore',
|
|
54
|
+
cwd: PROJECT_ROOT,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// 重定向输出到日志文件
|
|
58
|
+
const outFd = fs.openSync(LOG_FILE, 'a');
|
|
59
|
+
fs.writeSync(outFd, `\n=== Foliko started at ${new Date().toISOString()} ===\n`);
|
|
60
|
+
|
|
61
|
+
// 保存 PID
|
|
62
|
+
fs.writeFileSync(PID_FILE, child.pid.toString());
|
|
63
|
+
|
|
64
|
+
// 脱离父进程(在 pipe 之前调用)
|
|
65
|
+
child.unref();
|
|
66
|
+
|
|
67
|
+
console.log(`Foliko 已启动 (PID: ${child.pid})`);
|
|
68
|
+
console.log(`日志文件: ${LOG_FILE}`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* 停止守护进程
|
|
73
|
+
*/
|
|
74
|
+
async function stopDaemon() {
|
|
75
|
+
const pid = getPid();
|
|
76
|
+
|
|
77
|
+
if (!pid || !isRunning(pid)) {
|
|
78
|
+
console.log('Foliko 未在运行');
|
|
79
|
+
if (fs.existsSync(PID_FILE)) {
|
|
80
|
+
fs.unlinkSync(PID_FILE);
|
|
81
|
+
}
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
process.kill(pid, 'SIGTERM');
|
|
87
|
+
console.log(`正在停止 Foliko (PID: ${pid})...`);
|
|
88
|
+
|
|
89
|
+
// 等待进程结束
|
|
90
|
+
setTimeout(() => {
|
|
91
|
+
if (fs.existsSync(PID_FILE)) {
|
|
92
|
+
fs.unlinkSync(PID_FILE);
|
|
93
|
+
}
|
|
94
|
+
console.log('Foliko 已停止');
|
|
95
|
+
}, 2000);
|
|
96
|
+
} catch (err) {
|
|
97
|
+
console.error(`停止失败: ${err.message}`);
|
|
98
|
+
if (fs.existsSync(PID_FILE)) {
|
|
99
|
+
fs.unlinkSync(PID_FILE);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* 查看状态
|
|
106
|
+
*/
|
|
107
|
+
async function statusDaemon() {
|
|
108
|
+
const pid = getPid();
|
|
109
|
+
|
|
110
|
+
if (!pid || !isRunning(pid)) {
|
|
111
|
+
console.log('Foliko 未在运行');
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
console.log(`Foliko 正在运行 (PID: ${pid})`);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Daemon 命令入口
|
|
120
|
+
* @param {string[]} fullArgs - 完整参数 [command, subCommand]
|
|
121
|
+
*/
|
|
122
|
+
async function daemonCommand(fullArgs) {
|
|
123
|
+
const command = fullArgs[0] || 'start';
|
|
124
|
+
|
|
125
|
+
switch (command) {
|
|
126
|
+
case 'start':
|
|
127
|
+
await startDaemon();
|
|
128
|
+
break;
|
|
129
|
+
case 'stop':
|
|
130
|
+
await stopDaemon();
|
|
131
|
+
break;
|
|
132
|
+
case 'status':
|
|
133
|
+
await statusDaemon();
|
|
134
|
+
break;
|
|
135
|
+
default:
|
|
136
|
+
console.log('用法: foliko start | stop | status');
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
module.exports = { daemonCommand };
|
package/cli/src/index.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
const { chatCommand } = require('./commands/chat');
|
|
6
6
|
const { listCommand } = require('./commands/list');
|
|
7
7
|
const { pluginCommand } = require('./commands/plugin');
|
|
8
|
+
const { daemonCommand } = require('./commands/daemon');
|
|
8
9
|
const fs = require('fs');
|
|
9
10
|
const path = require('path');
|
|
10
11
|
/**
|
|
@@ -39,6 +40,12 @@ async function cli() {
|
|
|
39
40
|
await pluginCommand(args.slice(1));
|
|
40
41
|
break;
|
|
41
42
|
|
|
43
|
+
case 'start':
|
|
44
|
+
case 'stop':
|
|
45
|
+
case 'status':
|
|
46
|
+
await daemonCommand([command, ...args.slice(1)]);
|
|
47
|
+
break;
|
|
48
|
+
|
|
42
49
|
case 'help':
|
|
43
50
|
case '--help':
|
|
44
51
|
case '-h':
|
|
@@ -72,6 +79,9 @@ Commands:
|
|
|
72
79
|
chat 启动持续对话聊天
|
|
73
80
|
list 列出所有子Agent配置
|
|
74
81
|
plugin 插件管理 (publish/install/list)
|
|
82
|
+
start 启动守护进程(后台运行)
|
|
83
|
+
stop 停止守护进程
|
|
84
|
+
status 查看守护进程状态
|
|
75
85
|
help 显示帮助信息
|
|
76
86
|
version 显示版本号
|
|
77
87
|
|
|
@@ -83,8 +93,9 @@ Chat Options:
|
|
|
83
93
|
Examples:
|
|
84
94
|
foliko chat
|
|
85
95
|
foliko chat --model MiniMax-M2.7
|
|
86
|
-
foliko
|
|
87
|
-
foliko
|
|
96
|
+
foliko start
|
|
97
|
+
foliko stop
|
|
98
|
+
foliko status
|
|
88
99
|
`);
|
|
89
100
|
}
|
|
90
101
|
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Foliko 后台服务入口
|
|
3
|
+
* 使用 framework.bootstrap() 自动加载 .agent/ 目录配置
|
|
4
|
+
* 持续运行,不退出
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { Framework } = require('../src');
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
// 重定向输出到日志文件
|
|
12
|
+
const LOG_FILE = path.join(process.cwd(), '.foliko.log');
|
|
13
|
+
const outFd = fs.openSync(LOG_FILE, 'a');
|
|
14
|
+
function log(...args) {
|
|
15
|
+
const msg = `[${new Date().toISOString()}] ` + args.join(' ') + '\n';
|
|
16
|
+
fs.writeSync(outFd, msg);
|
|
17
|
+
}
|
|
18
|
+
process.stdout.write = (chunk) => { log(chunk.toString()); return true; };
|
|
19
|
+
process.stderr.write = (chunk) => { log(chunk.toString()); return true; };
|
|
20
|
+
|
|
21
|
+
async function main() {
|
|
22
|
+
log('[Foliko] 启动后台服务...');
|
|
23
|
+
|
|
24
|
+
// 创建框架
|
|
25
|
+
const framework = new Framework({ debug: false });
|
|
26
|
+
|
|
27
|
+
// 使用 bootstrap 自动加载所有默认插件
|
|
28
|
+
await framework.bootstrap({
|
|
29
|
+
agentDir: './.agent',
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
log('[Foliko] 框架已就绪');
|
|
33
|
+
log('[Foliko] 已加载插件:', framework.pluginManager.getAll().map((p) => p.name));
|
|
34
|
+
log('[Foliko] 后台服务运行中 (PID: ' + process.pid + ')');
|
|
35
|
+
|
|
36
|
+
// 优雅退出
|
|
37
|
+
const shutdown = async () => {
|
|
38
|
+
log('[Foliko] 正在关闭...');
|
|
39
|
+
await framework.destroy();
|
|
40
|
+
log('[Foliko] 已关闭');
|
|
41
|
+
process.exit(0);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
process.on('SIGINT', shutdown);
|
|
45
|
+
process.on('SIGTERM', shutdown);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
main().catch((err) => {
|
|
49
|
+
log('[Foliko] 启动失败:', err.message);
|
|
50
|
+
process.exit(1);
|
|
51
|
+
});
|
package/package.json
CHANGED
package/plugins/qq-plugin.js
CHANGED
|
@@ -569,9 +569,6 @@ class QQPlugin extends Plugin {
|
|
|
569
569
|
})
|
|
570
570
|
|
|
571
571
|
sessionScope.on('message:complete', async ({ content }) => {
|
|
572
|
-
// 清理定时器
|
|
573
|
-
this.stopTypingInterval?.()
|
|
574
|
-
|
|
575
572
|
const streamSession = streamSessionMap.get(sessionId)
|
|
576
573
|
if (streamSession) {
|
|
577
574
|
try {
|
|
@@ -592,9 +589,6 @@ class QQPlugin extends Plugin {
|
|
|
592
589
|
})
|
|
593
590
|
|
|
594
591
|
sessionScope.on('queue:failed', async ({ error }) => {
|
|
595
|
-
// 清理定时器
|
|
596
|
-
this.stopTypingInterval?.()
|
|
597
|
-
|
|
598
592
|
// 清理流式会话
|
|
599
593
|
const streamSession = streamSessionMap.get(sessionId)
|
|
600
594
|
if (streamSession) {
|
|
@@ -645,7 +639,6 @@ class QQPlugin extends Plugin {
|
|
|
645
639
|
await this._sendMessage(identifier, `发生错误:${err.message}`)
|
|
646
640
|
}
|
|
647
641
|
} finally {
|
|
648
|
-
this.stopTypingInterval?.()
|
|
649
642
|
}
|
|
650
643
|
}
|
|
651
644
|
|
package/temp_img.md
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-

|