foliko 2.0.17 → 2.0.19
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 +1 -3
- package/.editorconfig +56 -56
- package/.lintstagedrc +7 -7
- package/.prettierignore +29 -29
- package/.prettierrc +11 -11
- package/Dockerfile +63 -63
- package/install.ps1 +129 -129
- package/install.sh +121 -121
- package/package.json +1 -1
- package/plugins/ambient/ExplorerLoop.js +10 -10
- package/plugins/core/scheduler/index.js +1 -1
- package/plugins/core/session/index.js +1 -0
- package/plugins/core/workflow/context.js +941 -941
- package/plugins/core/workflow/engine.js +66 -66
- package/plugins/core/workflow/js-runner.js +318 -318
- package/plugins/core/workflow/json-runner.js +323 -323
- package/plugins/core/workflow/stages/choice.js +74 -74
- package/plugins/core/workflow/stages/each.js +123 -123
- package/plugins/core/workflow/stages/parallel.js +69 -69
- package/plugins/messaging/feishu/index.js +5 -5
- package/plugins/messaging/qq/index.js +3 -3
- package/plugins/messaging/telegram/index.js +3 -3
- package/plugins/messaging/weixin/index.js +5 -5
- package/skills/find-skills/SKILL.md +133 -133
- package/src/agent/chat.js +124 -15
- package/src/session/session.js +2 -1
- package/weixin_o9cq80zgZqKPA2-s59PN43GdDy1w@im.wechat.jsonl +36 -0
package/install.sh
CHANGED
|
@@ -1,121 +1,121 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# Foliko Installer
|
|
3
|
-
|
|
4
|
-
set -e
|
|
5
|
-
|
|
6
|
-
echo -e "\033[36mFoliko Installer\033[0m"
|
|
7
|
-
echo -e "\033[36m=================\033[0m"
|
|
8
|
-
echo ""
|
|
9
|
-
|
|
10
|
-
# Detect OS
|
|
11
|
-
detect_os() {
|
|
12
|
-
if [[ "$OSTYPE" == "darwin"* ]]; then
|
|
13
|
-
echo "macOS"
|
|
14
|
-
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
|
15
|
-
echo "Linux"
|
|
16
|
-
else
|
|
17
|
-
echo "unknown"
|
|
18
|
-
fi
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
OS=$(detect_os)
|
|
22
|
-
|
|
23
|
-
# ============ Check/Install Node.js ============
|
|
24
|
-
echo -e "\033[36mChecking Node.js...\033[0m"
|
|
25
|
-
if command -v node &> /dev/null; then
|
|
26
|
-
echo -e "\033[32mNode.js installed: $(node --version)\033[0m"
|
|
27
|
-
else
|
|
28
|
-
echo -e "\033[33mNode.js not found, installing...\033[0m"
|
|
29
|
-
|
|
30
|
-
if [[ "$OS" == "macOS" ]]; then
|
|
31
|
-
if command -v brew &> /dev/null; then
|
|
32
|
-
brew install node
|
|
33
|
-
else
|
|
34
|
-
echo -e "\033[31mHomebrew not found. Install it first:\033[0m"
|
|
35
|
-
echo "/bin/bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\""
|
|
36
|
-
exit 1
|
|
37
|
-
fi
|
|
38
|
-
elif [[ "$OS" == "Linux" ]]; then
|
|
39
|
-
if command -v apt-get &> /dev/null; then
|
|
40
|
-
sudo apt-get update && sudo apt-get install -y nodejs npm
|
|
41
|
-
elif command -v yum &> /dev/null; then
|
|
42
|
-
sudo yum install -y nodejs npm
|
|
43
|
-
elif command -v pacman &> /dev/null; then
|
|
44
|
-
sudo pacman -S nodejs npm
|
|
45
|
-
else
|
|
46
|
-
echo -e "\033[31mNo package manager found. Install Node.js manually: https://nodejs.org/\033[0m"
|
|
47
|
-
exit 1
|
|
48
|
-
fi
|
|
49
|
-
fi
|
|
50
|
-
|
|
51
|
-
if command -v node &> /dev/null; then
|
|
52
|
-
echo -e "\033[32mNode.js installed: $(node --version)\033[0m"
|
|
53
|
-
else
|
|
54
|
-
echo -e "\033[31mNode.js installation failed\033[0m"
|
|
55
|
-
exit 1
|
|
56
|
-
fi
|
|
57
|
-
fi
|
|
58
|
-
echo ""
|
|
59
|
-
|
|
60
|
-
# ============ Check/Install Python ============
|
|
61
|
-
echo -e "\033[36mChecking Python...\033[0m"
|
|
62
|
-
if command -v python3 &> /dev/null; then
|
|
63
|
-
echo -e "\033[32mPython installed: $(python3 --version)\033[0m"
|
|
64
|
-
else
|
|
65
|
-
echo -e "\033[33mPython not found, installing...\033[0m"
|
|
66
|
-
|
|
67
|
-
if [[ "$OS" == "macOS" ]]; then
|
|
68
|
-
if command -v brew &> /dev/null; then
|
|
69
|
-
brew install python3
|
|
70
|
-
fi
|
|
71
|
-
elif [[ "$OS" == "Linux" ]]; then
|
|
72
|
-
if command -v apt-get &> /dev/null; then
|
|
73
|
-
sudo apt-get update && sudo apt-get install -y python3 python3-venv python3-pip
|
|
74
|
-
elif command -v yum &> /dev/null; then
|
|
75
|
-
sudo yum install -y python3
|
|
76
|
-
elif command -v pacman &> /dev/null; then
|
|
77
|
-
sudo pacman -S python python-pip
|
|
78
|
-
fi
|
|
79
|
-
fi
|
|
80
|
-
|
|
81
|
-
if command -v python3 &> /dev/null; then
|
|
82
|
-
echo -e "\033[32mPython installed: $(python3 --version)\033[0m"
|
|
83
|
-
else
|
|
84
|
-
echo -e "\033[33mPython installation failed (optional)\033[0m"
|
|
85
|
-
fi
|
|
86
|
-
fi
|
|
87
|
-
echo ""
|
|
88
|
-
|
|
89
|
-
# ============ Check/Install uv ============
|
|
90
|
-
echo -e "\033[36mChecking uv...\033[0m"
|
|
91
|
-
if command -v uv &> /dev/null; then
|
|
92
|
-
echo -e "\033[32muv installed: $(uv --version)\033[0m"
|
|
93
|
-
else
|
|
94
|
-
echo -e "\033[33muv not found, installing...\033[0m"
|
|
95
|
-
|
|
96
|
-
if [[ "$OS" == "macOS" ]] || [[ "$OS" == "Linux" ]]; then
|
|
97
|
-
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
98
|
-
source $HOME/.local/bin/env 2>/dev/null || true
|
|
99
|
-
|
|
100
|
-
if command -v uv &> /dev/null; then
|
|
101
|
-
echo -e "\033[32muv installed: $(uv --version)\033[0m"
|
|
102
|
-
else
|
|
103
|
-
echo -e "\033[33muv installation failed (optional)\033[0m"
|
|
104
|
-
fi
|
|
105
|
-
fi
|
|
106
|
-
fi
|
|
107
|
-
echo ""
|
|
108
|
-
|
|
109
|
-
# ============ Install Foliko ============
|
|
110
|
-
echo -e "\033[36mInstalling Foliko...\033[0m"
|
|
111
|
-
npm install -g foliko
|
|
112
|
-
|
|
113
|
-
if command -v foliko &> /dev/null; then
|
|
114
|
-
echo ""
|
|
115
|
-
echo -e "\033[32mInstallation complete!\033[0m"
|
|
116
|
-
echo "Run: foliko chat"
|
|
117
|
-
else
|
|
118
|
-
echo ""
|
|
119
|
-
echo -e "\033[31mInstallation failed. Try manually: npm install -g foliko\033[0m"
|
|
120
|
-
exit 1
|
|
121
|
-
fi
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Foliko Installer
|
|
3
|
+
|
|
4
|
+
set -e
|
|
5
|
+
|
|
6
|
+
echo -e "\033[36mFoliko Installer\033[0m"
|
|
7
|
+
echo -e "\033[36m=================\033[0m"
|
|
8
|
+
echo ""
|
|
9
|
+
|
|
10
|
+
# Detect OS
|
|
11
|
+
detect_os() {
|
|
12
|
+
if [[ "$OSTYPE" == "darwin"* ]]; then
|
|
13
|
+
echo "macOS"
|
|
14
|
+
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
|
15
|
+
echo "Linux"
|
|
16
|
+
else
|
|
17
|
+
echo "unknown"
|
|
18
|
+
fi
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
OS=$(detect_os)
|
|
22
|
+
|
|
23
|
+
# ============ Check/Install Node.js ============
|
|
24
|
+
echo -e "\033[36mChecking Node.js...\033[0m"
|
|
25
|
+
if command -v node &> /dev/null; then
|
|
26
|
+
echo -e "\033[32mNode.js installed: $(node --version)\033[0m"
|
|
27
|
+
else
|
|
28
|
+
echo -e "\033[33mNode.js not found, installing...\033[0m"
|
|
29
|
+
|
|
30
|
+
if [[ "$OS" == "macOS" ]]; then
|
|
31
|
+
if command -v brew &> /dev/null; then
|
|
32
|
+
brew install node
|
|
33
|
+
else
|
|
34
|
+
echo -e "\033[31mHomebrew not found. Install it first:\033[0m"
|
|
35
|
+
echo "/bin/bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\""
|
|
36
|
+
exit 1
|
|
37
|
+
fi
|
|
38
|
+
elif [[ "$OS" == "Linux" ]]; then
|
|
39
|
+
if command -v apt-get &> /dev/null; then
|
|
40
|
+
sudo apt-get update && sudo apt-get install -y nodejs npm
|
|
41
|
+
elif command -v yum &> /dev/null; then
|
|
42
|
+
sudo yum install -y nodejs npm
|
|
43
|
+
elif command -v pacman &> /dev/null; then
|
|
44
|
+
sudo pacman -S nodejs npm
|
|
45
|
+
else
|
|
46
|
+
echo -e "\033[31mNo package manager found. Install Node.js manually: https://nodejs.org/\033[0m"
|
|
47
|
+
exit 1
|
|
48
|
+
fi
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
if command -v node &> /dev/null; then
|
|
52
|
+
echo -e "\033[32mNode.js installed: $(node --version)\033[0m"
|
|
53
|
+
else
|
|
54
|
+
echo -e "\033[31mNode.js installation failed\033[0m"
|
|
55
|
+
exit 1
|
|
56
|
+
fi
|
|
57
|
+
fi
|
|
58
|
+
echo ""
|
|
59
|
+
|
|
60
|
+
# ============ Check/Install Python ============
|
|
61
|
+
echo -e "\033[36mChecking Python...\033[0m"
|
|
62
|
+
if command -v python3 &> /dev/null; then
|
|
63
|
+
echo -e "\033[32mPython installed: $(python3 --version)\033[0m"
|
|
64
|
+
else
|
|
65
|
+
echo -e "\033[33mPython not found, installing...\033[0m"
|
|
66
|
+
|
|
67
|
+
if [[ "$OS" == "macOS" ]]; then
|
|
68
|
+
if command -v brew &> /dev/null; then
|
|
69
|
+
brew install python3
|
|
70
|
+
fi
|
|
71
|
+
elif [[ "$OS" == "Linux" ]]; then
|
|
72
|
+
if command -v apt-get &> /dev/null; then
|
|
73
|
+
sudo apt-get update && sudo apt-get install -y python3 python3-venv python3-pip
|
|
74
|
+
elif command -v yum &> /dev/null; then
|
|
75
|
+
sudo yum install -y python3
|
|
76
|
+
elif command -v pacman &> /dev/null; then
|
|
77
|
+
sudo pacman -S python python-pip
|
|
78
|
+
fi
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
if command -v python3 &> /dev/null; then
|
|
82
|
+
echo -e "\033[32mPython installed: $(python3 --version)\033[0m"
|
|
83
|
+
else
|
|
84
|
+
echo -e "\033[33mPython installation failed (optional)\033[0m"
|
|
85
|
+
fi
|
|
86
|
+
fi
|
|
87
|
+
echo ""
|
|
88
|
+
|
|
89
|
+
# ============ Check/Install uv ============
|
|
90
|
+
echo -e "\033[36mChecking uv...\033[0m"
|
|
91
|
+
if command -v uv &> /dev/null; then
|
|
92
|
+
echo -e "\033[32muv installed: $(uv --version)\033[0m"
|
|
93
|
+
else
|
|
94
|
+
echo -e "\033[33muv not found, installing...\033[0m"
|
|
95
|
+
|
|
96
|
+
if [[ "$OS" == "macOS" ]] || [[ "$OS" == "Linux" ]]; then
|
|
97
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
98
|
+
source $HOME/.local/bin/env 2>/dev/null || true
|
|
99
|
+
|
|
100
|
+
if command -v uv &> /dev/null; then
|
|
101
|
+
echo -e "\033[32muv installed: $(uv --version)\033[0m"
|
|
102
|
+
else
|
|
103
|
+
echo -e "\033[33muv installation failed (optional)\033[0m"
|
|
104
|
+
fi
|
|
105
|
+
fi
|
|
106
|
+
fi
|
|
107
|
+
echo ""
|
|
108
|
+
|
|
109
|
+
# ============ Install Foliko ============
|
|
110
|
+
echo -e "\033[36mInstalling Foliko...\033[0m"
|
|
111
|
+
npm install -g foliko
|
|
112
|
+
|
|
113
|
+
if command -v foliko &> /dev/null; then
|
|
114
|
+
echo ""
|
|
115
|
+
echo -e "\033[32mInstallation complete!\033[0m"
|
|
116
|
+
echo "Run: foliko chat"
|
|
117
|
+
else
|
|
118
|
+
echo ""
|
|
119
|
+
echo -e "\033[31mInstallation failed. Try manually: npm install -g foliko\033[0m"
|
|
120
|
+
exit 1
|
|
121
|
+
fi
|
package/package.json
CHANGED
|
@@ -234,12 +234,12 @@ class ExplorerLoop {
|
|
|
234
234
|
// 非事件驱动目标可以完成
|
|
235
235
|
this._goalManager.completeGoal(goal.id)
|
|
236
236
|
this._addActivity('goal_completed', { goalId: goal.id, attempts: goal.attempts })
|
|
237
|
-
this._notifyUser('目标完成', `目标 "${goal.title}" 已完成(尝试次数:${goal.attempts})`, 'success')
|
|
237
|
+
await this._notifyUser('目标完成', `目标 "${goal.title}" 已完成(尝试次数:${goal.attempts})`, 'success')
|
|
238
238
|
} else if (!outcome.shouldContinue && !isEventDriven) {
|
|
239
239
|
// 非事件驱动目标可以失败
|
|
240
240
|
this._goalManager.failGoal(goal.id, '达到最大尝试次数')
|
|
241
241
|
this._addActivity('goal_failed', { goalId: goal.id, reason: '达到最大尝试次数' })
|
|
242
|
-
this._notifyUser('目标失败', `目标 "${goal.title}" 失败:达到最大尝试次数`, 'error')
|
|
242
|
+
await this._notifyUser('目标失败', `目标 "${goal.title}" 失败:达到最大尝试次数`, 'error')
|
|
243
243
|
} else {
|
|
244
244
|
// 事件驱动目标:不论结果如何,都重置并继续等待下一事件
|
|
245
245
|
this._addActivity('actions_completed', { goalId: goal.id, actionCount: results.length })
|
|
@@ -250,7 +250,7 @@ class ExplorerLoop {
|
|
|
250
250
|
// 一次性目标:所有 actions 完成后直接完成
|
|
251
251
|
this._goalManager.completeGoal(goal.id)
|
|
252
252
|
this._addActivity('goal_completed', { goalId: goal.id, reason: '一次性任务执行完成' })
|
|
253
|
-
this._notifyUser('目标完成', `目标 "${goal.title}" 已完成`, 'success')
|
|
253
|
+
await this._notifyUser('目标完成', `目标 "${goal.title}" 已完成`, 'success')
|
|
254
254
|
} else if (hasNewEvents) {
|
|
255
255
|
// 持久化目标且有新事件,重置 actions
|
|
256
256
|
this._resetGoalForNextEvent(goal)
|
|
@@ -269,7 +269,7 @@ class ExplorerLoop {
|
|
|
269
269
|
// 一次性目标:所有 actions 完成后直接完成
|
|
270
270
|
this._goalManager.completeGoal(goal.id)
|
|
271
271
|
this._addActivity('goal_completed', { goalId: goal.id, reason: '一次性任务执行完成' })
|
|
272
|
-
this._notifyUser('目标完成', `目标 "${goal.title}" 已完成`, 'success')
|
|
272
|
+
await this._notifyUser('目标完成', `目标 "${goal.title}" 已完成`, 'success')
|
|
273
273
|
} else {
|
|
274
274
|
// 持久化目标:等待下一事件
|
|
275
275
|
this._resetGoalForNextEvent(goal)
|
|
@@ -281,7 +281,7 @@ class ExplorerLoop {
|
|
|
281
281
|
if (!hasNewEvents && this._reflector.checkLoopDetection(goal, action.id)) {
|
|
282
282
|
this._addActivity('goal_failed', { goalId: goal.id, reason: '检测到循环' })
|
|
283
283
|
// 通知用户目标失败
|
|
284
|
-
this._notifyUser('目标失败', `目标 "${goal.title}" 失败:检测到循环(同一操作连续重复)`, 'error')
|
|
284
|
+
await this._notifyUser('目标失败', `目标 "${goal.title}" 失败:检测到循环(同一操作连续重复)`, 'error')
|
|
285
285
|
continue
|
|
286
286
|
}
|
|
287
287
|
|
|
@@ -298,12 +298,12 @@ class ExplorerLoop {
|
|
|
298
298
|
this._goalManager.completeGoal(goal.id)
|
|
299
299
|
this._addActivity('goal_completed', { goalId: goal.id, attempts: goal.attempts })
|
|
300
300
|
// 通知用户目标完成
|
|
301
|
-
this._notifyUser('目标完成', `目标 "${goal.title}" 已完成(尝试次数:${goal.attempts})`, 'success')
|
|
301
|
+
await this._notifyUser('目标完成', `目标 "${goal.title}" 已完成(尝试次数:${goal.attempts})`, 'success')
|
|
302
302
|
} else if (!outcome.shouldContinue) {
|
|
303
303
|
this._goalManager.failGoal(goal.id, '达到最大尝试次数')
|
|
304
304
|
this._addActivity('goal_failed', { goalId: goal.id, reason: '达到最大尝试次数' })
|
|
305
305
|
// 通知用户目标失败
|
|
306
|
-
this._notifyUser('目标失败', `目标 "${goal.title}" 失败:达到最大尝试次数`, 'error')
|
|
306
|
+
await this._notifyUser('目标失败', `目标 "${goal.title}" 失败:达到最大尝试次数`, 'error')
|
|
307
307
|
} else {
|
|
308
308
|
this._addActivity('action_executed', { goalId: goal.id, action: action.id, hasEvents: hasNewEvents })
|
|
309
309
|
|
|
@@ -313,7 +313,7 @@ class ExplorerLoop {
|
|
|
313
313
|
// 一次性目标:所有 actions 完成后直接完成
|
|
314
314
|
this._goalManager.completeGoal(goal.id)
|
|
315
315
|
this._addActivity('goal_completed', { goalId: goal.id, reason: '一次性任务执行完成' })
|
|
316
|
-
this._notifyUser('目标完成', `目标 "${goal.title}" 已完成`, 'success')
|
|
316
|
+
await this._notifyUser('目标完成', `目标 "${goal.title}" 已完成`, 'success')
|
|
317
317
|
} else if (hasNewEvents) {
|
|
318
318
|
// 持久化目标且有新事件,重置 actions
|
|
319
319
|
this._resetGoalForNextEvent(goal)
|
|
@@ -1019,14 +1019,14 @@ ${lastResultStr}
|
|
|
1019
1019
|
/**
|
|
1020
1020
|
* 通知用户(通过事件发送给消息插件)
|
|
1021
1021
|
*/
|
|
1022
|
-
_notifyUser(title, message, level = 'info') {
|
|
1022
|
+
async _notifyUser(title, message, level = 'info') {
|
|
1023
1023
|
if (!this._framework) return
|
|
1024
1024
|
|
|
1025
1025
|
// 获取目标相关的sessionId(如果有)
|
|
1026
1026
|
let sessionId = null
|
|
1027
1027
|
const sessionPlugin = this._framework.pluginManager.get('session')
|
|
1028
1028
|
if (sessionPlugin) {
|
|
1029
|
-
const sessions = sessionPlugin.listSessions()
|
|
1029
|
+
const sessions = await sessionPlugin.listSessions()
|
|
1030
1030
|
if (sessions.length > 0) {
|
|
1031
1031
|
// 取最新的会话
|
|
1032
1032
|
sessions.sort((a, b) => new Date(b.lastActive).getTime() - new Date(a.lastActive).getTime())
|
|
@@ -391,7 +391,7 @@ class SchedulerPlugin extends Plugin {
|
|
|
391
391
|
if (!targetSessionId) {
|
|
392
392
|
const sessionPlugin = this._framework?.pluginManager?.get('session');
|
|
393
393
|
if (sessionPlugin) {
|
|
394
|
-
const sessions = sessionPlugin.listSessions();
|
|
394
|
+
const sessions = await sessionPlugin.listSessions();
|
|
395
395
|
if (sessions.length > 0) {
|
|
396
396
|
sessions.sort((a, b) => {
|
|
397
397
|
const aTime = a.lastActive ? new Date(a.lastActive).getTime() : 0;
|
|
@@ -84,6 +84,7 @@ class SessionPlugin extends Plugin {
|
|
|
84
84
|
try {
|
|
85
85
|
const manager = SessionManager.open(filePath, sessionDir, cwd);
|
|
86
86
|
sessions.push({
|
|
87
|
+
id:path.basename(filePath, path.extname(filePath)),
|
|
87
88
|
sessionId: manager.getSessionId(),
|
|
88
89
|
sessionFile: manager.getSessionFile(),
|
|
89
90
|
messageCount: manager.getEntries().length,
|