foliko 1.0.51 → 1.0.53

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.
@@ -1,126 +1,131 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Bash(grep -r \"dotenv\" \"D:/Code/vb-agent/\" --include=\"*.json\" 2>/dev/null | head -20)",
5
- "Bash(cd \"D:/Code/vb-agent\" && pnpm add dotenv)",
6
- "Bash(cd \"D:/Code/vb-agent\" && node -e \"const ai = require\\('ai'\\); console.log\\(Object.keys\\(ai\\).filter\\(k => k.toLowerCase\\(\\).includes\\('reason'\\) || k.toLowerCase\\(\\).includes\\('split'\\) || k.toLowerCase\\(\\).includes\\('think'\\)\\)\\)\")",
7
- "Bash(cd \"D:/Code/vb-agent\" && node -e \"const ai = require\\('ai'\\); console.log\\(typeof ai.extractReasoningMiddleware, ai.extractReasoningMiddleware.toString\\(\\).substring\\(0, 500\\)\\)\")",
8
- "Bash(cd \"D:/Code/vb-agent\" && node -e \"\nconst ai = require\\('ai'\\);\nconsole.log\\('=== extractReasoningMiddleware ==='\\);\nconsole.log\\(ai.extractReasoningMiddleware.toString\\(\\)\\);\nconsole.log\\('\\\\n=== isReasoningUIPart ==='\\);\nconsole.log\\(typeof ai.isReasoningUIPart\\);\n\")",
9
- "Bash(cd \"D:/Code/vb-agent\" && node -e \"const ai = require\\('ai'\\); console.log\\(Object.keys\\(ai\\).filter\\(k => k.toLowerCase\\(\\).includes\\('split'\\)\\)\\)\")",
10
- "Bash(cd \"D:/Code/vb-agent\" && pnpm add ink react)",
11
- "Bash(cd \"D:/Code/vb-agent\" && node cli/bin/foliko.js --help)",
12
- "Bash(cd \"D:/Code/vb-agent\" && timeout 2 node cli/bin/foliko.js chat 2>&1 || true)",
13
- "Bash(cd \"D:/Code/vb-agent\" && node -e \"const mt = require\\('marked-terminal'\\); console.log\\(typeof mt, Object.keys\\(mt\\)\\)\")",
14
- "Bash(cd \"D:/Code/vb-agent\" && timeout 3 node cli/bin/foliko.js chat 2>&1 || true)",
15
- "Bash(echo \"你好\" | node cli/bin/foliko.js chat 2>&1 | head -50)",
16
- "Bash(printf '思考一下1+1等于几\\\\n' | node cli/bin/foliko.js chat 2>&1 | head -100)",
17
- "Bash(printf '1+1等于几\\\\n' | node cli/bin/foliko.js chat 2>&1)",
18
- "Bash(node -e \"\nconst { renderLine } = require\\('./cli/src/utils/markdown'\\)\nconsole.log\\(renderLine\\('🎉 这是一个 emoji'\\)\\)\nconsole.log\\(renderLine\\('**粗体** 和 🎉'\\)\\)\n\")",
19
- "Bash(node -e \"\nconst { render } = require\\('./cli/src/utils/markdown'\\)\nconst text = '🎉 今天是个好日子\\\\n## 标题\\\\n- 列表项1\\\\n- 列表项2'\nconsole.log\\(render\\(text\\)\\)\n\")",
20
- "Bash(node -e \"\nconst { renderLine } = require\\('./cli/src/utils/markdown'\\)\n\n// 模拟emoji被截断的情况\nconst emoji = '🎉'\nconsole.log\\('完整的 emoji:', renderLine\\(emoji\\)\\)\n\n// 模拟截断 - emoji的UTF-8字节是 \\\\xF0\\\\x9F\\\\x8E\\\\x89\nconst partial = '\\\\xF0\\\\x9F' // 不完整的emoji\nconsole.log\\('截断的 emoji:', renderLine\\(partial\\)\\)\n\")",
21
- "Bash(node -e \"\nconst isIncompleteUTF8 = \\(str\\) => {\n if \\(!str || str.length === 0\\) return false\n const lastChar = str.charCodeAt\\(str.length - 1\\)\n if \\(lastChar >= 0x80 && lastChar < 0xC0\\) return true\n return false\n}\n\n// 测试各种emoji\nconst tests = ['🎉', '📁', '⚡', '🛠️', '🔑', '💾', '📝', '⏰', '🔌', '📋']\ntests.forEach\\(e => {\n console.log\\(e, '完整:', !isIncompleteUTF8\\(e\\)\\)\n}\\)\n\n// 测试被截断的emoji \\(只保留第一字节\\)\nconst broken = '🎉'.slice\\(0, 1\\)\nconsole.log\\('截断emoji:', broken, '检测:', isIncompleteUTF8\\(broken\\)\\)\n\")",
22
- "Bash(node -e \"\nconst { renderLine } = require\\('./cli/src/utils/markdown'\\)\nconsole.log\\('测试:', renderLine\\('📁 文件操作:读取、创建'\\)\\)\n\")",
23
- "Bash(node -e \"\nconst hasIncompleteSurrogate = \\(str\\) => {\n if \\(!str || str.length === 0\\) return false\n const lastChar = str.charCodeAt\\(str.length - 1\\)\n console.log\\('检查:', str, 'lastChar:', lastChar.toString\\(16\\), '范围:', \\(lastChar >= 0xD800 && lastChar <= 0xDBFF\\)\\)\n return lastChar >= 0xD800 && lastChar <= 0xDBFF\n}\n\nconst chunk1 = '\\\\xD83C'\nconsole.log\\('结果:', hasIncompleteSurrogate\\(chunk1\\)\\)\n\")",
24
- "Bash(cd D:/Code/vb-agent && node test-stream-emoji.js 2>&1)",
25
- "Read(//d/Date/20260321/app/**)",
26
- "Bash(node -e \":*)",
27
- "Bash(node -e \"\nconst { loadAgentConfig } = require\\('./plugins/default-plugins'\\);\nconst config = loadAgentConfig\\('D:/Date/20260321/app/.agent'\\);\nconsole.log\\('skillsDirs:', config.skillsDirs\\);\n\")",
28
- "Bash(cd D:/Code/vb-agent && pnpm install --shamefully-hoist 2>&1 | head -20)",
29
- "Bash(cd D:/Code/vb-agent && rm -rf node_modules && pnpm install)",
30
- "Bash(cd D:/Code/vb-agent && timeout 8 node test-tg.js 2>&1 || true)",
31
- "Bash(cd D:/Code/vb-agent && timeout 10 node test-tg.js 2>&1 || true)",
32
- "Bash(find /d/Code/vb-agent -name \"*email*\" -type f 2>/dev/null | grep -v node_modules | grep -v .git)",
33
- "Bash(find /d/Code/vb-agent -maxdepth 2 -name \"*.md\" -type f 2>/dev/null | grep -v node_modules)",
34
- "Bash(node -c plugins/default-plugins.js && node -c src/core/plugin-manager.js && echo \"Syntax OK\")",
35
- "Bash(node -c plugins/install-plugin.js && echo \"Syntax OK\")",
36
- "Bash(node -c cli/src/ui/chat-ui.js && echo \"Syntax OK\")",
37
- "Bash(node -c plugins/default-plugins.js && echo \"Syntax OK\")",
38
- "Bash(node -c plugins/scheduler-plugin.js && echo \"Syntax OK\")",
39
- "Bash(node -c plugins/telegram-plugin.js && node -c plugins/scheduler-plugin.js && echo \"Syntax OK\")",
40
- "Bash(node -c plugins/telegram-plugin.js && echo \"Syntax OK\")",
41
- "WebSearch",
42
- "Bash(npm ls:*)",
43
- "Bash(cd node_modules/@chnak/weixin-bot && npm run build 2>&1)",
44
- "Bash(cd node_modules/@chnak/weixin-bot && npx tsc 2>&1)",
45
- "Bash(npm install:*)",
46
- "Bash(cd node_modules/@chnak/weixin-bot && npx typescript --version && npx tsc 2>&1)",
47
- "Bash(npx tsc:*)",
48
- "Bash(node --check /d/Code/vb-agent/plugins/weixin-plugin.js 2>&1)",
49
- "Bash(node --check /d/Code/vb-agent/plugins/telegram-plugin.js && node --check /d/Code/vb-agent/plugins/weixin-plugin.js && echo \"OK\")",
50
- "Bash(node --check /d/Code/vb-agent/cli/src/ui/chat-ui.js && echo \"OK\")",
51
- "Bash(npm uninstall:*)",
52
- "Bash(rm -rf /tmp/weixin-bot && git clone https://github.com/chnak/weixin-bot.git /tmp/weixin-bot 2>&1)",
53
- "Bash(mkdir -p node_modules/@chnak/weixin-bot && cp -r /tmp/weixin-bot/nodejs/* node_modules/@chnak/weixin-bot/ && cd node_modules/@chnak/weixin-bot && npm install 2>&1)",
54
- "Bash(node --check /d/Code/vb-agent/plugins/weixin-plugin.js && echo \"OK\")",
55
- "Bash(node -e \"import\\('@chnak/weixin-bot'\\).then\\(m => console.log\\('OK:', Object.keys\\(m\\)\\)\\).catch\\(e => console.error\\('Error:', e.message\\)\\)\")",
56
- "Bash(npm run:*)",
57
- "Bash(node -e \"const { WeixinBot } = require\\('@chnak/weixin-bot'\\); console.log\\(typeof WeixinBot\\)\" 2>&1)",
58
- "Bash(node -e \"import\\('@chnak/weixin-bot'\\).then\\(m => console.log\\('OK:', typeof m.WeixinBot\\)\\).catch\\(e => console.error\\('Error:', e.message\\)\\)\" 2>&1)",
59
- "Bash(ls -la D:/code/vb-agent/cli/bin/ && cat D:/code/vb-agent/cli/bin/*.js 2>/dev/null | head -50)",
60
- "Bash(npm config:*)",
61
- "Bash(node -c plugins/subagent-plugin.js 2>&1)",
62
- "Bash(node -c plugins/default-plugins.js 2>&1)",
63
- "Bash(node -c plugins/default-plugins.js && node -c src/core/plugin-manager.js && node -c plugins/tools-plugin.js 2>&1)",
64
- "Bash(node -c src/core/plugin-base.js && node -c src/core/plugin-manager.js 2>&1)",
65
- "Bash(node -c plugins/telegram-plugin.js && node -c plugins/weixin-plugin.js 2>&1)",
66
- "Bash(node -c src/core/plugin-manager.js 2>&1)",
67
- "Bash(node -c src/core/plugin-manager.js && node -c src/core/plugin-base.js && node -c plugins/default-plugins.js && node -c plugins/telegram-plugin.js && node -c plugins/weixin-plugin.js 2>&1)",
68
- "Bash(node -e \"require\\('dotenv'\\).config\\(\\); console.log\\('PROVIDER:', process.env.FOLIKO_PROVIDER\\); console.log\\('MODEL:', process.env.FOLIKO_MODEL\\); console.log\\('KEY:', process.env.DEEPSEEK_API_KEY ? 'set' : 'not set'\\)\" 2>&1)",
69
- "Bash(node cli/src/index.js chat 2>&1 | head -30)",
70
- "Bash(node -e 'const { DEFAULT_PROVIDERS } = require\\(\"./src/core/provider\"\\); console.log\\(DEFAULT_PROVIDERS\\);')",
71
- "Bash(node -e \"const dotenv = require\\('dotenv'\\); const result = dotenv.config\\(\\); console.log\\('Result:', result\\); console.log\\('PROVIDER after dotenv:', process.env.FOLIKO_PROVIDER\\);\" 2>&1)",
72
- "Bash(node -c plugins/email.js && node -c plugins/default-plugins.js 2>&1)",
73
- "Bash(node -c plugins/email.js 2>&1)",
74
- "Bash(npm list:*)",
75
- "Bash(node -e \"const {EmailPlugin} = require\\('./plugins/email'\\); const p = new EmailPlugin\\(\\); console.log\\('email plugin loaded ok'\\); console.log\\('enabled:', p.enabled\\); console.log\\('version:', p.version\\);\" 2>&1)",
76
- "Bash(cd D:/Code/vb-agent && node -e \"console.log\\('IMAP_HOST:', process.env.IMAP_HOST\\); console.log\\('IMAP_USER:', process.env.IMAP_USER\\); console.log\\('IMAP_PORT:', process.env.IMAP_PORT\\);\")",
77
- "Bash(node -e \"const sdk = require\\('@larksuiteoapi/node-sdk'\\); console.log\\(Object.keys\\(sdk\\)\\);\")",
78
- "Bash(node -e \"const { WSClient } = require\\('@larksuiteoapi/node-sdk'\\); const sdk = new WSClient\\({}\\); console.log\\(Object.getOwnPropertyNames\\(Object.getPrototypeOf\\(sdk\\)\\)\\);\")",
79
- "Bash(node -c src/core/framework.js 2>&1)",
80
- "Bash(node -c plugins/telegram-plugin.js 2>&1)",
81
- "Bash(node -c src/capabilities/skill-manager.js 2>&1)",
82
- "Bash(node -c plugins/feishu-plugin.js 2>&1)",
83
- "Bash(node debug-skills.js)",
84
- "Bash(node -c src/capabilities/workflow-engine.js 2>&1)",
85
- "Bash(node -c skills/workflow-guide/SKILL.md 2>&1 || head -10 skills/workflow-guide/SKILL.md)",
86
- "Bash(ls plugins/*.js 2>&1)",
87
- "Bash(node -c plugins/web-plugin.js 2>&1)",
88
- "Bash(cd D:/code/vb-agent && node -e \"require\\('./plugins/web-plugin.js'\\)\" 2>&1)",
89
- "Bash(cd D:/code/vb-agent && node -e \"\nconst { WebPlugin } = require\\('./plugins/web-plugin.js'\\);\nconst p = new WebPlugin\\(\\);\nconsole.log\\('Plugin created:', p.name, p.version\\);\n\" 2>&1)",
90
- "Bash(cd D:/code/vb-agent && mkdir -p test-static && echo '<html><body>Hello Static</body></html>' > test-static/index.html)",
91
- "mcp__plugin_context7_context7__resolve-library-id",
92
- "mcp__plugin_context7_context7__query-docs",
93
- "Bash(cd D:/code/vb-agent && rm test-hono.js)",
94
- "Bash(curl -s http://localhost:3000/test 2>&1 || echo \"连接失败\")",
95
- "Bash(cd D:/code/vb-agent && timeout 15 node examples/test-web-plugin.js 2>&1)",
96
- "Bash(cd D:/code/vb-agent && timeout 60 node examples/test-chat.js 2>&1 | head -100)",
97
- "Bash(cd D:/code/vb-agent && timeout 120 node examples/test-chat.js 2>&1 | tail -80)",
98
- "Bash(cd D:/code/vb-agent && timeout 120 node examples/bootstrap.js 2>&1 | tail -100)",
99
- "Bash(cd D:/code/vb-agent && timeout 10 node examples/test-web-plugin.js 2>&1)",
100
- "Bash(curl -s -X POST http://localhost:3000/test-webhook \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"message\":\"test from curl\",\"sessionId\":\"web_test\"}')",
101
- "Bash(curl -s http://localhost:3000/test 2>&1 || echo \"Connection failed\")",
102
- "Bash(curl -s -X POST http://localhost:3000/webhook/test-webhook \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"message\":\"test from curl\",\"sessionId\":\"web_test\"}')",
103
- "Bash(curl -s http://localhost:3000/webui/status)",
104
- "Bash(curl -s http://localhost:3000/test)",
105
- "Bash(curl -s -v -X POST http://localhost:3000/test-webhook \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"message\":\"test\"}' 2>&1 | head -30)",
106
- "Bash(curl -s -X POST \"http://localhost:3000/webhook/test-webhook\" \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"message\":\"test\"}' 2>&1)",
107
- "Bash(curl -s http://localhost:3000/webui/ 2>&1)",
108
- "Bash(curl -s -X POST http://localhost:3000/webui/list-routes \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{}' 2>&1 || echo \"Endpoint not found\")",
109
- "Bash(curl -s http://localhost:3000/ 2>&1)",
110
- "Bash(curl -s -X POST \"http://localhost:3000/webhook/test-webhook\" \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"message\":\"test with prefix\"}')",
111
- "Bash(netstat -ano | grep :3000 | head -5)",
112
- "Bash(netstat -ano | grep :3000 | grep LISTENING)",
113
- "Bash(curl -s -X POST http://localhost:3000/test-webhook \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"message\":\"test\",\"sessionId\":\"web_test\"}')",
114
- "Bash(taskkill /F /IM node.exe 2>/dev/null; sleep 1; echo \"Node processes killed\")",
115
- "Bash(netstat -ano | grep :3000)",
116
- "Bash(taskkill //F //PID 19848)",
117
- "Bash(curl -s -X POST \"http://localhost:3000/webhook/075s5s2umn4smn4f\" \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"test\":\"data\"}' 2>&1)",
118
- "Bash(curl -s http://localhost:3000/api/hello 2>&1)",
119
- "Bash(curl -v -X POST \"http://localhost:3000/webhook/075s5s2umn4smn4f\" \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"test\":\"data\"}' 2>&1 | head -30)",
120
- "Bash(cd D:/code/vb-agent && timeout 30 node test-compression.js 2>&1)",
121
- "Bash(cd D:/code/vb-agent && node -c src/core/agent-chat.js 2>&1)",
122
- "Bash(cd D:/code/vb-agent && node -e \"require\\('./src/core/agent-chat.js'\\); console.log\\('模块加载成功'\\)\" 2>&1)",
123
- "Bash(cd D:/code/vb-agent && node -e \"require\\('./src/core/agent.js'\\); console.log\\('Agent 加载成功'\\)\" 2>&1)"
124
- ]
125
- }
126
- }
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(grep -r \"dotenv\" \"D:/Code/vb-agent/\" --include=\"*.json\" 2>/dev/null | head -20)",
5
+ "Bash(cd \"D:/Code/vb-agent\" && pnpm add dotenv)",
6
+ "Bash(cd \"D:/Code/vb-agent\" && node -e \"const ai = require\\('ai'\\); console.log\\(Object.keys\\(ai\\).filter\\(k => k.toLowerCase\\(\\).includes\\('reason'\\) || k.toLowerCase\\(\\).includes\\('split'\\) || k.toLowerCase\\(\\).includes\\('think'\\)\\)\\)\")",
7
+ "Bash(cd \"D:/Code/vb-agent\" && node -e \"const ai = require\\('ai'\\); console.log\\(typeof ai.extractReasoningMiddleware, ai.extractReasoningMiddleware.toString\\(\\).substring\\(0, 500\\)\\)\")",
8
+ "Bash(cd \"D:/Code/vb-agent\" && node -e \"\nconst ai = require\\('ai'\\);\nconsole.log\\('=== extractReasoningMiddleware ==='\\);\nconsole.log\\(ai.extractReasoningMiddleware.toString\\(\\)\\);\nconsole.log\\('\\\\n=== isReasoningUIPart ==='\\);\nconsole.log\\(typeof ai.isReasoningUIPart\\);\n\")",
9
+ "Bash(cd \"D:/Code/vb-agent\" && node -e \"const ai = require\\('ai'\\); console.log\\(Object.keys\\(ai\\).filter\\(k => k.toLowerCase\\(\\).includes\\('split'\\)\\)\\)\")",
10
+ "Bash(cd \"D:/Code/vb-agent\" && pnpm add ink react)",
11
+ "Bash(cd \"D:/Code/vb-agent\" && node cli/bin/foliko.js --help)",
12
+ "Bash(cd \"D:/Code/vb-agent\" && timeout 2 node cli/bin/foliko.js chat 2>&1 || true)",
13
+ "Bash(cd \"D:/Code/vb-agent\" && node -e \"const mt = require\\('marked-terminal'\\); console.log\\(typeof mt, Object.keys\\(mt\\)\\)\")",
14
+ "Bash(cd \"D:/Code/vb-agent\" && timeout 3 node cli/bin/foliko.js chat 2>&1 || true)",
15
+ "Bash(echo \"你好\" | node cli/bin/foliko.js chat 2>&1 | head -50)",
16
+ "Bash(printf '思考一下1+1等于几\\\\n' | node cli/bin/foliko.js chat 2>&1 | head -100)",
17
+ "Bash(printf '1+1等于几\\\\n' | node cli/bin/foliko.js chat 2>&1)",
18
+ "Bash(node -e \"\nconst { renderLine } = require\\('./cli/src/utils/markdown'\\)\nconsole.log\\(renderLine\\('🎉 这是一个 emoji'\\)\\)\nconsole.log\\(renderLine\\('**粗体** 和 🎉'\\)\\)\n\")",
19
+ "Bash(node -e \"\nconst { render } = require\\('./cli/src/utils/markdown'\\)\nconst text = '🎉 今天是个好日子\\\\n## 标题\\\\n- 列表项1\\\\n- 列表项2'\nconsole.log\\(render\\(text\\)\\)\n\")",
20
+ "Bash(node -e \"\nconst { renderLine } = require\\('./cli/src/utils/markdown'\\)\n\n// 模拟emoji被截断的情况\nconst emoji = '🎉'\nconsole.log\\('完整的 emoji:', renderLine\\(emoji\\)\\)\n\n// 模拟截断 - emoji的UTF-8字节是 \\\\xF0\\\\x9F\\\\x8E\\\\x89\nconst partial = '\\\\xF0\\\\x9F' // 不完整的emoji\nconsole.log\\('截断的 emoji:', renderLine\\(partial\\)\\)\n\")",
21
+ "Bash(node -e \"\nconst isIncompleteUTF8 = \\(str\\) => {\n if \\(!str || str.length === 0\\) return false\n const lastChar = str.charCodeAt\\(str.length - 1\\)\n if \\(lastChar >= 0x80 && lastChar < 0xC0\\) return true\n return false\n}\n\n// 测试各种emoji\nconst tests = ['🎉', '📁', '⚡', '🛠️', '🔑', '💾', '📝', '⏰', '🔌', '📋']\ntests.forEach\\(e => {\n console.log\\(e, '完整:', !isIncompleteUTF8\\(e\\)\\)\n}\\)\n\n// 测试被截断的emoji \\(只保留第一字节\\)\nconst broken = '🎉'.slice\\(0, 1\\)\nconsole.log\\('截断emoji:', broken, '检测:', isIncompleteUTF8\\(broken\\)\\)\n\")",
22
+ "Bash(node -e \"\nconst { renderLine } = require\\('./cli/src/utils/markdown'\\)\nconsole.log\\('测试:', renderLine\\('📁 文件操作:读取、创建'\\)\\)\n\")",
23
+ "Bash(node -e \"\nconst hasIncompleteSurrogate = \\(str\\) => {\n if \\(!str || str.length === 0\\) return false\n const lastChar = str.charCodeAt\\(str.length - 1\\)\n console.log\\('检查:', str, 'lastChar:', lastChar.toString\\(16\\), '范围:', \\(lastChar >= 0xD800 && lastChar <= 0xDBFF\\)\\)\n return lastChar >= 0xD800 && lastChar <= 0xDBFF\n}\n\nconst chunk1 = '\\\\xD83C'\nconsole.log\\('结果:', hasIncompleteSurrogate\\(chunk1\\)\\)\n\")",
24
+ "Bash(cd D:/Code/vb-agent && node test-stream-emoji.js 2>&1)",
25
+ "Read(//d/Date/20260321/app/**)",
26
+ "Bash(node -e \":*)",
27
+ "Bash(node -e \"\nconst { loadAgentConfig } = require\\('./plugins/default-plugins'\\);\nconst config = loadAgentConfig\\('D:/Date/20260321/app/.agent'\\);\nconsole.log\\('skillsDirs:', config.skillsDirs\\);\n\")",
28
+ "Bash(cd D:/Code/vb-agent && pnpm install --shamefully-hoist 2>&1 | head -20)",
29
+ "Bash(cd D:/Code/vb-agent && rm -rf node_modules && pnpm install)",
30
+ "Bash(cd D:/Code/vb-agent && timeout 8 node test-tg.js 2>&1 || true)",
31
+ "Bash(cd D:/Code/vb-agent && timeout 10 node test-tg.js 2>&1 || true)",
32
+ "Bash(find /d/Code/vb-agent -name \"*email*\" -type f 2>/dev/null | grep -v node_modules | grep -v .git)",
33
+ "Bash(find /d/Code/vb-agent -maxdepth 2 -name \"*.md\" -type f 2>/dev/null | grep -v node_modules)",
34
+ "Bash(node -c plugins/default-plugins.js && node -c src/core/plugin-manager.js && echo \"Syntax OK\")",
35
+ "Bash(node -c plugins/install-plugin.js && echo \"Syntax OK\")",
36
+ "Bash(node -c cli/src/ui/chat-ui.js && echo \"Syntax OK\")",
37
+ "Bash(node -c plugins/default-plugins.js && echo \"Syntax OK\")",
38
+ "Bash(node -c plugins/scheduler-plugin.js && echo \"Syntax OK\")",
39
+ "Bash(node -c plugins/telegram-plugin.js && node -c plugins/scheduler-plugin.js && echo \"Syntax OK\")",
40
+ "Bash(node -c plugins/telegram-plugin.js && echo \"Syntax OK\")",
41
+ "WebSearch",
42
+ "Bash(npm ls:*)",
43
+ "Bash(cd node_modules/@chnak/weixin-bot && npm run build 2>&1)",
44
+ "Bash(cd node_modules/@chnak/weixin-bot && npx tsc 2>&1)",
45
+ "Bash(npm install:*)",
46
+ "Bash(cd node_modules/@chnak/weixin-bot && npx typescript --version && npx tsc 2>&1)",
47
+ "Bash(npx tsc:*)",
48
+ "Bash(node --check /d/Code/vb-agent/plugins/weixin-plugin.js 2>&1)",
49
+ "Bash(node --check /d/Code/vb-agent/plugins/telegram-plugin.js && node --check /d/Code/vb-agent/plugins/weixin-plugin.js && echo \"OK\")",
50
+ "Bash(node --check /d/Code/vb-agent/cli/src/ui/chat-ui.js && echo \"OK\")",
51
+ "Bash(npm uninstall:*)",
52
+ "Bash(rm -rf /tmp/weixin-bot && git clone https://github.com/chnak/weixin-bot.git /tmp/weixin-bot 2>&1)",
53
+ "Bash(mkdir -p node_modules/@chnak/weixin-bot && cp -r /tmp/weixin-bot/nodejs/* node_modules/@chnak/weixin-bot/ && cd node_modules/@chnak/weixin-bot && npm install 2>&1)",
54
+ "Bash(node --check /d/Code/vb-agent/plugins/weixin-plugin.js && echo \"OK\")",
55
+ "Bash(node -e \"import\\('@chnak/weixin-bot'\\).then\\(m => console.log\\('OK:', Object.keys\\(m\\)\\)\\).catch\\(e => console.error\\('Error:', e.message\\)\\)\")",
56
+ "Bash(npm run:*)",
57
+ "Bash(node -e \"const { WeixinBot } = require\\('@chnak/weixin-bot'\\); console.log\\(typeof WeixinBot\\)\" 2>&1)",
58
+ "Bash(node -e \"import\\('@chnak/weixin-bot'\\).then\\(m => console.log\\('OK:', typeof m.WeixinBot\\)\\).catch\\(e => console.error\\('Error:', e.message\\)\\)\" 2>&1)",
59
+ "Bash(ls -la D:/code/vb-agent/cli/bin/ && cat D:/code/vb-agent/cli/bin/*.js 2>/dev/null | head -50)",
60
+ "Bash(npm config:*)",
61
+ "Bash(node -c plugins/subagent-plugin.js 2>&1)",
62
+ "Bash(node -c plugins/default-plugins.js 2>&1)",
63
+ "Bash(node -c plugins/default-plugins.js && node -c src/core/plugin-manager.js && node -c plugins/tools-plugin.js 2>&1)",
64
+ "Bash(node -c src/core/plugin-base.js && node -c src/core/plugin-manager.js 2>&1)",
65
+ "Bash(node -c plugins/telegram-plugin.js && node -c plugins/weixin-plugin.js 2>&1)",
66
+ "Bash(node -c src/core/plugin-manager.js 2>&1)",
67
+ "Bash(node -c src/core/plugin-manager.js && node -c src/core/plugin-base.js && node -c plugins/default-plugins.js && node -c plugins/telegram-plugin.js && node -c plugins/weixin-plugin.js 2>&1)",
68
+ "Bash(node -e \"require\\('dotenv'\\).config\\(\\); console.log\\('PROVIDER:', process.env.FOLIKO_PROVIDER\\); console.log\\('MODEL:', process.env.FOLIKO_MODEL\\); console.log\\('KEY:', process.env.DEEPSEEK_API_KEY ? 'set' : 'not set'\\)\" 2>&1)",
69
+ "Bash(node cli/src/index.js chat 2>&1 | head -30)",
70
+ "Bash(node -e 'const { DEFAULT_PROVIDERS } = require\\(\"./src/core/provider\"\\); console.log\\(DEFAULT_PROVIDERS\\);')",
71
+ "Bash(node -e \"const dotenv = require\\('dotenv'\\); const result = dotenv.config\\(\\); console.log\\('Result:', result\\); console.log\\('PROVIDER after dotenv:', process.env.FOLIKO_PROVIDER\\);\" 2>&1)",
72
+ "Bash(node -c plugins/email.js && node -c plugins/default-plugins.js 2>&1)",
73
+ "Bash(node -c plugins/email.js 2>&1)",
74
+ "Bash(npm list:*)",
75
+ "Bash(node -e \"const {EmailPlugin} = require\\('./plugins/email'\\); const p = new EmailPlugin\\(\\); console.log\\('email plugin loaded ok'\\); console.log\\('enabled:', p.enabled\\); console.log\\('version:', p.version\\);\" 2>&1)",
76
+ "Bash(cd D:/Code/vb-agent && node -e \"console.log\\('IMAP_HOST:', process.env.IMAP_HOST\\); console.log\\('IMAP_USER:', process.env.IMAP_USER\\); console.log\\('IMAP_PORT:', process.env.IMAP_PORT\\);\")",
77
+ "Bash(node -e \"const sdk = require\\('@larksuiteoapi/node-sdk'\\); console.log\\(Object.keys\\(sdk\\)\\);\")",
78
+ "Bash(node -e \"const { WSClient } = require\\('@larksuiteoapi/node-sdk'\\); const sdk = new WSClient\\({}\\); console.log\\(Object.getOwnPropertyNames\\(Object.getPrototypeOf\\(sdk\\)\\)\\);\")",
79
+ "Bash(node -c src/core/framework.js 2>&1)",
80
+ "Bash(node -c plugins/telegram-plugin.js 2>&1)",
81
+ "Bash(node -c src/capabilities/skill-manager.js 2>&1)",
82
+ "Bash(node -c plugins/feishu-plugin.js 2>&1)",
83
+ "Bash(node debug-skills.js)",
84
+ "Bash(node -c src/capabilities/workflow-engine.js 2>&1)",
85
+ "Bash(node -c skills/workflow-guide/SKILL.md 2>&1 || head -10 skills/workflow-guide/SKILL.md)",
86
+ "Bash(ls plugins/*.js 2>&1)",
87
+ "Bash(node -c plugins/web-plugin.js 2>&1)",
88
+ "Bash(cd D:/code/vb-agent && node -e \"require\\('./plugins/web-plugin.js'\\)\" 2>&1)",
89
+ "Bash(cd D:/code/vb-agent && node -e \"\nconst { WebPlugin } = require\\('./plugins/web-plugin.js'\\);\nconst p = new WebPlugin\\(\\);\nconsole.log\\('Plugin created:', p.name, p.version\\);\n\" 2>&1)",
90
+ "Bash(cd D:/code/vb-agent && mkdir -p test-static && echo '<html><body>Hello Static</body></html>' > test-static/index.html)",
91
+ "mcp__plugin_context7_context7__resolve-library-id",
92
+ "mcp__plugin_context7_context7__query-docs",
93
+ "Bash(cd D:/code/vb-agent && rm test-hono.js)",
94
+ "Bash(curl -s http://localhost:3000/test 2>&1 || echo \"连接失败\")",
95
+ "Bash(cd D:/code/vb-agent && timeout 15 node examples/test-web-plugin.js 2>&1)",
96
+ "Bash(cd D:/code/vb-agent && timeout 60 node examples/test-chat.js 2>&1 | head -100)",
97
+ "Bash(cd D:/code/vb-agent && timeout 120 node examples/test-chat.js 2>&1 | tail -80)",
98
+ "Bash(cd D:/code/vb-agent && timeout 120 node examples/bootstrap.js 2>&1 | tail -100)",
99
+ "Bash(cd D:/code/vb-agent && timeout 10 node examples/test-web-plugin.js 2>&1)",
100
+ "Bash(curl -s -X POST http://localhost:3000/test-webhook \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"message\":\"test from curl\",\"sessionId\":\"web_test\"}')",
101
+ "Bash(curl -s http://localhost:3000/test 2>&1 || echo \"Connection failed\")",
102
+ "Bash(curl -s -X POST http://localhost:3000/webhook/test-webhook \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"message\":\"test from curl\",\"sessionId\":\"web_test\"}')",
103
+ "Bash(curl -s http://localhost:3000/webui/status)",
104
+ "Bash(curl -s http://localhost:3000/test)",
105
+ "Bash(curl -s -v -X POST http://localhost:3000/test-webhook \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"message\":\"test\"}' 2>&1 | head -30)",
106
+ "Bash(curl -s -X POST \"http://localhost:3000/webhook/test-webhook\" \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"message\":\"test\"}' 2>&1)",
107
+ "Bash(curl -s http://localhost:3000/webui/ 2>&1)",
108
+ "Bash(curl -s -X POST http://localhost:3000/webui/list-routes \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{}' 2>&1 || echo \"Endpoint not found\")",
109
+ "Bash(curl -s http://localhost:3000/ 2>&1)",
110
+ "Bash(curl -s -X POST \"http://localhost:3000/webhook/test-webhook\" \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"message\":\"test with prefix\"}')",
111
+ "Bash(netstat -ano | grep :3000 | head -5)",
112
+ "Bash(netstat -ano | grep :3000 | grep LISTENING)",
113
+ "Bash(curl -s -X POST http://localhost:3000/test-webhook \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"message\":\"test\",\"sessionId\":\"web_test\"}')",
114
+ "Bash(taskkill /F /IM node.exe 2>/dev/null; sleep 1; echo \"Node processes killed\")",
115
+ "Bash(netstat -ano | grep :3000)",
116
+ "Bash(taskkill //F //PID 19848)",
117
+ "Bash(curl -s -X POST \"http://localhost:3000/webhook/075s5s2umn4smn4f\" \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"test\":\"data\"}' 2>&1)",
118
+ "Bash(curl -s http://localhost:3000/api/hello 2>&1)",
119
+ "Bash(curl -v -X POST \"http://localhost:3000/webhook/075s5s2umn4smn4f\" \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"test\":\"data\"}' 2>&1 | head -30)",
120
+ "Bash(cd D:/code/vb-agent && timeout 30 node test-compression.js 2>&1)",
121
+ "Bash(cd D:/code/vb-agent && node -c src/core/agent-chat.js 2>&1)",
122
+ "Bash(cd D:/code/vb-agent && node -e \"require\\('./src/core/agent-chat.js'\\); console.log\\('模块加载成功'\\)\" 2>&1)",
123
+ "Bash(cd D:/code/vb-agent && node -e \"require\\('./src/core/agent.js'\\); console.log\\('Agent 加载成功'\\)\" 2>&1)",
124
+ "Bash(node -c src/capabilities/skill-manager.js && node -c src/executors/mcp-executor.js && node -c src/capabilities/workflow-engine.js && node -c src/core/plugin-manager.js 2>&1)",
125
+ "Bash(node -c src/core/plugin-manager.js && node -c plugins/tools-plugin.js 2>&1)",
126
+ "Bash(node -c plugins/default-plugins.js && node -c cli/src/commands/chat.js 2>&1)",
127
+ "Bash(node -c plugins/telegram-plugin.js && node -c plugins/feishu-plugin.js && node -c plugins/weixin-plugin.js 2>&1)",
128
+ "Bash(node -c src/core/agent.js 2>&1)"
129
+ ]
130
+ }
131
+ }
package/Dockerfile CHANGED
@@ -3,15 +3,43 @@
3
3
 
4
4
  FROM node:25-slim
5
5
 
6
- # 安装 Python 和构建工具(部分 npm 包需要编译)
6
+ # 安装无头浏览器(Chromium)和构建工具
7
7
  RUN apt-get update && apt-get install -y --no-install-recommends \
8
8
  build-essential \
9
9
  python3 \
10
10
  python3-pip \
11
11
  curl \
12
12
  git \
13
+ wget \
14
+ gnupg \
15
+ # Chromium 及依赖
16
+ chromium \
17
+ chromium-sandbox \
18
+ libnss3 \
19
+ libatk1.0-0 \
20
+ libatk-bridge2.0-0 \
21
+ libcups2 \
22
+ libdrm2 \
23
+ libxkbcommon0 \
24
+ libxcomposite1 \
25
+ libxdamage1 \
26
+ libxfixes3 \
27
+ libxrandr2 \
28
+ libgbm1 \
29
+ libasound2 \
30
+ libpango-1.0-0 \
31
+ libpangocairo-1.0-0 \
32
+ libgtk-3-0 \
33
+ fonts-liberation \
34
+ xdg-utils \
13
35
  && rm -rf /var/lib/apt/lists/* \
14
- && ln -sf /usr/bin/python3 /usr/bin/python
36
+ && ln -sf /usr/bin/python3 /usr/bin/python \
37
+ && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
38
+
39
+ # 设置 Chromium 环境变量(无头模式运行)
40
+ ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
41
+ ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
42
+ ENV CHROME_BIN=/usr/bin/chromium
15
43
 
16
44
  # 安装 uv(快速的 Python 包管理器)
17
45
  RUN curl -LsSf https://astral.sh/uv/install.sh | sh
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foliko",
3
- "version": "1.0.51",
3
+ "version": "1.0.53",
4
4
  "description": "简约的插件化 Agent 框架",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -13,6 +13,7 @@ class AIPlugin extends Plugin {
13
13
  this.version = '1.0.0'
14
14
  this.description = 'AI 对话能力插件'
15
15
  this.priority = 1 // 最先加载
16
+ this.system = true
16
17
 
17
18
  this.config = {
18
19
  provider: config.provider || 'deepseek',
@@ -13,6 +13,7 @@ class AuditPlugin extends Plugin {
13
13
  this.version = '1.0.0'
14
14
  this.description = '审计日志插件,记录工具调用、技能执行、错误信息等操作历史'
15
15
  this.priority = 20
16
+ this.system = true
16
17
 
17
18
  this.config = {
18
19
  maxLogs: config.maxLogs || 1000,
@@ -170,6 +170,7 @@ class DefaultPlugins extends Plugin {
170
170
  this.version = '1.0.0'
171
171
  this.description = '默认插件配置加载器'
172
172
  this.priority = 0 // 最先加载
173
+ this.system = true
173
174
 
174
175
  this._framework = null
175
176
  this._agentDir = config.agentDir || '.agent'
@@ -231,15 +232,23 @@ async function bootstrapDefaults(framework, config = {}) {
231
232
  'python-plugin-loader', 'telegram', 'weixin', 'subagent-manager'
232
233
  ])
233
234
 
234
- // 辅助函数:检查插件是否应该加载(核心插件不能禁用)
235
- const shouldLoad = (name) => {
235
+ // 辅助函数:检查插件是否应该加载
236
+ // 传入插件名称(字符串)、已创建的实例,或插件类
237
+ const shouldLoad = (plugin) => {
238
+ const name = typeof plugin === 'string' ? plugin : (plugin.name || plugin.prototype?.name)
236
239
  if (framework.pluginManager.has(name)) {
237
240
  console.log(`[Bootstrap] ${name} Plugin already loaded, skipping`)
238
241
  return false
239
242
  }
240
- // 核心插件不能禁用
241
- if (CORE_PLUGINS.has(name) && framework.pluginManager.isEnabled(name) === false) {
242
- console.log(`[Bootstrap] ${name} is a core plugin, cannot be disabled`)
243
+ // 系统插件(system: true)不能禁用
244
+ let isSystem = false
245
+ if (typeof plugin === 'function') {
246
+ isSystem = plugin.prototype?.system === true
247
+ } else if (typeof plugin === 'object') {
248
+ isSystem = plugin.system === true
249
+ }
250
+ if (isSystem && framework.pluginManager.isEnabled(name) === false) {
251
+ console.log(`[Bootstrap] ${name} is a system plugin, cannot be disabled`)
243
252
  }
244
253
  return true
245
254
  }
@@ -615,14 +624,9 @@ async function loadCustomPlugins(framework, agentConfig) {
615
624
  continue
616
625
  }
617
626
 
618
- // 如果插件被禁用(在 state 文件中 enabled: false),跳过
619
- if (framework.pluginManager.isEnabled(resolvedPluginName) === false) {
620
- console.log(`[Bootstrap] Custom plugin '${resolvedPluginName}' is disabled, skipping`)
621
- continue
622
- }
623
-
624
627
  console.log(`[Bootstrap] Loading custom plugin: ${pluginName} (${type})`)
625
- await framework.loadPlugin(plugin)
628
+ // .agent/plugins 目录下的插件强制启用,不受 state 文件 enabled: false 影响
629
+ await framework.pluginManager.load(plugin, { forceEnabled: true })
626
630
  } catch (err) {
627
631
  console.error(`[Bootstrap] Failed to load plugin ${pluginName}:`, err.message)
628
632
  }
@@ -12,6 +12,7 @@ class FileSystemPlugin extends Plugin {
12
12
  this.version = '1.0.0'
13
13
  this.description = '文件系统工具插件'
14
14
  this.priority = 5
15
+ this.system = true
15
16
  }
16
17
 
17
18
  install(framework) {
@@ -18,6 +18,7 @@ class InstallPlugin extends Plugin {
18
18
 
19
19
  this._agentDir = config.agentDir || '.agent'
20
20
  this._nodeModulesDir = null
21
+ this.system = true
21
22
  }
22
23
 
23
24
  install(framework) {
@@ -25,6 +25,8 @@ class PythonExecutorPlugin extends Plugin {
25
25
  pipPath: config.pipPath || null // 可选,自定义 pip 路径
26
26
  }
27
27
 
28
+ this.system = true
29
+
28
30
  this._framework = null
29
31
  this._tempDir = null
30
32
  }
@@ -59,6 +59,7 @@ class PythonPluginLoader extends Plugin {
59
59
  this._agentDir = config.agentDir || '.agent'
60
60
  this._pythonPlugins = new Map()
61
61
  this._framework = null
62
+ this.system = true
62
63
  }
63
64
 
64
65
  install(framework) {
@@ -36,7 +36,8 @@ class RulesPlugin extends Plugin {
36
36
  this.version = '1.0.0'
37
37
  this.description = '规则引擎插件,用于控制工具调用权限、内容过滤、触发动作'
38
38
  this.priority = 25
39
-
39
+ this.system = true
40
+
40
41
  this.config = {
41
42
  rulesDir: config.rulesDir || '.agent/rules',
42
43
  autoLoad: config.autoLoad !== false
@@ -63,7 +63,7 @@ class SchedulerPlugin extends Plugin {
63
63
  this.version = '1.0.0'
64
64
  this.description = '定时任务调度插件,支持 Cron 表达式、绝对时间、相对时间'
65
65
  this.priority = 15
66
-
66
+ this.system = true
67
67
  this.config = {
68
68
  checkInterval: config.checkInterval || 1000 // 每秒检查一次
69
69
  }
@@ -29,6 +29,8 @@ class SessionPlugin extends Plugin {
29
29
  this.description = '会话管理插件,支持多会话隔离、历史记录、会话超时清理'
30
30
  this.priority = 5
31
31
 
32
+ this.system = true
33
+
32
34
  this.config = {
33
35
  sessionTTL: config.sessionTTL || 30 * 60 * 1000, // 30分钟
34
36
  maxSessions: config.maxSessions || 100,
@@ -15,6 +15,8 @@ class ShellExecutorPlugin extends Plugin {
15
15
  this.description = 'Shell 执行器,用于运行终端命令和脚本'
16
16
  this.priority = 15
17
17
 
18
+ this.system = true
19
+
18
20
  this.config = {
19
21
  timeout: config.timeout || 60000,
20
22
  workingDir: config.workingDir || process.cwd()
@@ -16,6 +16,8 @@ class StoragePlugin extends Plugin {
16
16
  this.description = '数据持久化存储插件,支持键值对存储'
17
17
  this.priority = 3
18
18
 
19
+ this.system = true
20
+
19
21
  this.config = {
20
22
  type: config.type || 'json', // json 或 memory
21
23
  path: config.path || '.agent/data',
@@ -17,6 +17,8 @@ class SubAgentPlugin extends Plugin {
17
17
  this.description = config.description || `子Agent: ${config.name}`
18
18
  this.priority = 10
19
19
 
20
+ this.system = true
21
+
20
22
  // 子Agent配置
21
23
  // tools: { toolName: toolFn } 自定义工具(只属于此子Agent)
22
24
  // parentTools: ['read_file'] 从父Agent继承的工具名称列表
@@ -13,6 +13,8 @@ class ToolsPlugin extends Plugin {
13
13
  this.version = '1.0.0'
14
14
  this.description = '内置工具插件,提供热重载和工具管理功能'
15
15
  this.priority = 10
16
+
17
+ this.system = true
16
18
 
17
19
  this._framework = null
18
20
  }
@@ -74,7 +76,8 @@ class ToolsPlugin extends Plugin {
74
76
  name: p.name,
75
77
  status: p.status,
76
78
  enabled: p.enabled,
77
- version: p.version
79
+ version: p.version,
80
+ system: p.system
78
81
  }))
79
82
  }
80
83
  }
@@ -18,6 +18,8 @@ class WebPlugin extends Plugin {
18
18
  this.description = 'Web 服务插件,支持 HTTP 服务、路由注册、Webhook'
19
19
  this.priority = 50
20
20
 
21
+ this.system = true
22
+
21
23
  // 服务器配置
22
24
  this._port = process.env.WEB_PORT || 3000
23
25
  this._host = process.env.WEB_HOST || '127.0.0.1'
@@ -94,7 +96,12 @@ class WebPlugin extends Plugin {
94
96
  inputSchema: z.object({
95
97
  method: z.enum(['GET', 'POST', 'PUT', 'DELETE', 'PATCH']).describe('HTTP 方法'),
96
98
  path: z.string().describe('路由路径,如 /api/user'),
97
- handler: z.string().describe('处理逻辑,JavaScript 代码字符串,必须用 return 返回内容。\n示例:\n return "hello"\n return { hello: "world" }\n return context.params.id\n return context.query\n return context.body\n可用变量:context.params、context.query、context.body'),
99
+ handler: z.string().describe(
100
+ '处理逻辑,JavaScript 代码字符串,必须用 return 返回内容。' +
101
+ '优先使用 tools.{toolName}(args) 调用工具获取真实数据。' +
102
+ '可用变量:context.params, context.query, context.body, tools。' +
103
+ '示例:return await tools.get_user({ id: context.params.id })'
104
+ ),
98
105
  description: z.string().optional().describe('路由描述')
99
106
  }),
100
107
  execute: async (args) => this._registerRoute(args.method, args.path, args.handler, args.description)
@@ -259,7 +266,21 @@ class WebPlugin extends Plugin {
259
266
  const body = await this._parseBody(c)
260
267
 
261
268
  const context = { params, query, body }
262
- const result = await this._executeHandler(route.handler, context)
269
+
270
+ // 构建 tools 代理对象,允许 handler 以函数方式直接调用工具
271
+ // 例如: const user = await tools.get_user({ id: 1 })
272
+ const registry = this._framework.toolRegistry
273
+ const tools = new Proxy({}, {
274
+ get: (_, name) => {
275
+ if (name === 'call') {
276
+ // 保留 call 方式作为后备
277
+ return async (toolName, args) => registry.execute(toolName, args || {}, this._framework)
278
+ }
279
+ return async (args) => registry.execute(name, args || {}, this._framework)
280
+ }
281
+ })
282
+
283
+ const result = await this._executeHandler(route.handler, context, tools)
263
284
  return c.json(result)
264
285
  }
265
286
 
@@ -508,10 +529,10 @@ class WebPlugin extends Plugin {
508
529
  return `http://${this._host}:${this._port}${path}`
509
530
  }
510
531
 
511
- async _executeHandler(handlerCode, context) {
532
+ async _executeHandler(handlerCode, context, tools) {
512
533
  try {
513
- const fn = new Function('context', `return (async () => { ${handlerCode} })()`)
514
- return await fn(context)
534
+ const fn = new Function('context', 'tools', `return (async () => { ${handlerCode} })()`)
535
+ return await fn(context, tools)
515
536
  } catch (err) {
516
537
  return { success: false, error: `Handler error: ${err.message}` }
517
538
  }
@@ -131,6 +131,7 @@ class SkillManagerPlugin extends Plugin {
131
131
  this.version = '1.0.0'
132
132
  this.description = '技能管理器,加载和管理 Skill'
133
133
  this.priority = 5
134
+ this.system = true
134
135
 
135
136
  this._framework = null
136
137
  this._skillsDirs = Array.isArray(config.skillsDirs) ? config.skillsDirs : [config.skillsDir || '.agent/skills', 'skills']
@@ -297,6 +297,7 @@ class WorkflowPlugin extends Plugin {
297
297
  this.version = '1.0.0'
298
298
  this.description = '工作流引擎,支持结构化工作流定义和执行'
299
299
  this.priority = 6
300
+ this.system = true
300
301
 
301
302
  this._framework = null
302
303
  this._engine = null
package/src/core/agent.js CHANGED
@@ -241,9 +241,36 @@ class Agent extends EventEmitter {
241
241
  parts.push(capabilitiesDesc)
242
242
  }
243
243
 
244
+ // 8. 工具调用核心规则(统一追加到所有 Agent)
245
+ const toolCoreRules = this._getToolCoreRules()
246
+ if (toolCoreRules) {
247
+ parts.push(toolCoreRules)
248
+ }
249
+
244
250
  return parts.join('\n\n')
245
251
  }
246
252
 
253
+ /**
254
+ * 获取工具调用核心规则
255
+ * @private
256
+ */
257
+ _getToolCoreRules() {
258
+ return `【工具调用核心规则】
259
+ 1. 当用户询问需要获取数据、信息或执行操作时,必须调用工具
260
+ 2. 不要编造、推测数据,必须调用工具获取真实信息
261
+ 3. 直接调用工具后,基于返回结果回答
262
+
263
+ 【工具使用】
264
+ - 可用工具会提供,格式为 toolName(toolArgs)
265
+ - 如果不确定用哪个工具,先调用可能相关的工具
266
+ - 工具调用会返回结果,基于结果回答用户
267
+
268
+ 【禁止事项】
269
+ - 不要回复"我需要..."、"我建议..."等模糊回答
270
+ - 不要在没有调用工具的情况下给出数据或答案
271
+ - 不要自己编造用户、订单、任务等任何数据`
272
+ }
273
+
247
274
  /**
248
275
  * 刷新上下文
249
276
  */
@@ -42,6 +42,13 @@ class Plugin {
42
42
  */
43
43
  enabled = true
44
44
 
45
+ /**
46
+ * 是否为系统插件,默认为 false
47
+ * 系统插件不能被禁用,始终启用
48
+ * @type {boolean}
49
+ */
50
+ system = false
51
+
45
52
  _framework = null
46
53
  _subAgents = []
47
54
 
@@ -36,19 +36,33 @@ class PluginManager {
36
36
  */
37
37
  _saveState() {
38
38
  try {
39
- const state = {}
39
+ const stateFile = this._getStateFile()
40
+ // 读取现有状态(如果存在),保留原有内容
41
+ let state = {}
42
+ if (fs.existsSync(stateFile)) {
43
+ try {
44
+ state = JSON.parse(fs.readFileSync(stateFile, 'utf-8'))
45
+ } catch (e) {
46
+ // 文件损坏,使用空对象
47
+ state = {}
48
+ }
49
+ }
50
+
51
+ // 合并新状态到现有状态
40
52
  for (const [name, entry] of this._plugins) {
41
53
  // AI 配置不保存,每次从环境变量和命令行获取
42
54
  if (name === 'ai') {
43
55
  state[name] = { enabled: entry.enabled }
44
56
  } else {
45
57
  state[name] = {
58
+ ...(state[name] || {}), // 保留现有配置
46
59
  enabled: entry.enabled,
47
60
  config: entry.instance?.config || {}
48
61
  }
49
62
  }
50
63
  }
51
- fs.writeFileSync(this._getStateFile(), JSON.stringify(state, null, 2))
64
+
65
+ fs.writeFileSync(stateFile, JSON.stringify(state, null, 2))
52
66
  } catch (err) {
53
67
  console.error('[PluginManager] Failed to save state:', err.message)
54
68
  }
@@ -75,7 +89,7 @@ class PluginManager {
75
89
  * 注册插件(不加载)
76
90
  * @param {Plugin|Object} plugin - 插件实例或定义
77
91
  */
78
- register(plugin) {
92
+ register(plugin, options = {}) {
79
93
  if (!plugin.name) {
80
94
  throw new Error('Plugin must have a name')
81
95
  }
@@ -96,13 +110,21 @@ class PluginManager {
96
110
  pluginInstance.config = { ...pluginInstance.config, ...savedConfig }
97
111
  }
98
112
 
99
- // 使用保存的状态,否则使用插件实例的 enabled,默认 true
100
- const finalEnabled = savedEnabled !== undefined ? savedEnabled : (pluginInstance.enabled !== undefined ? pluginInstance.enabled : true)
113
+ // 系统插件强制启用,不能禁用
114
+ // 普通插件:state 文件有记录则用 state,否则用插件默认配置
115
+ let enabled
116
+ if (pluginInstance.system) {
117
+ enabled = true
118
+ } else if (savedEnabled !== undefined) {
119
+ enabled = savedEnabled
120
+ } else {
121
+ enabled = pluginInstance.enabled !== undefined ? pluginInstance.enabled : true
122
+ }
101
123
 
102
124
  this._plugins.set(pluginInstance.name, {
103
125
  instance: pluginInstance,
104
126
  status: 'registered',
105
- enabled: finalEnabled
127
+ enabled
106
128
  })
107
129
 
108
130
  this.framework.emit('plugin:registered', pluginInstance)
@@ -112,8 +134,10 @@ class PluginManager {
112
134
  /**
113
135
  * 加载插件
114
136
  * @param {Plugin|Object} plugin - 插件实例或定义
137
+ * @param {Object} options - 加载选项
138
+ * @param {boolean} options.forceEnabled - 强制启用插件,忽略 state 文件的 disabled 状态(用于 .agent/plugins 目录的插件)
115
139
  */
116
- async load(plugin) {
140
+ async load(plugin, options = {}) {
117
141
  if (this._loading) {
118
142
  throw new Error('Cannot load plugin during another load operation')
119
143
  }
@@ -158,11 +182,17 @@ class PluginManager {
158
182
  }
159
183
  } else {
160
184
  // 未注册,先注册
161
- this.register(pluginInstance)
185
+ this.register(pluginInstance, options)
162
186
  }
163
187
 
164
188
  const entry = this._plugins.get(pluginInstance.name)
165
189
 
190
+ // 注册后再次检查 enabled 状态
191
+ if (!entry.enabled) {
192
+ console.log(`[PluginManager] Plugin '${pluginInstance.name}' is disabled, skipping install`)
193
+ return pluginInstance
194
+ }
195
+
166
196
  // 调用 install
167
197
  try {
168
198
  await entry.instance.install(this.framework)
@@ -190,6 +220,10 @@ class PluginManager {
190
220
  }
191
221
 
192
222
  this.framework.emit('plugin:loaded', pluginInstance)
223
+
224
+ // 保存状态(创建或更新 state 文件)
225
+ this._saveState()
226
+
193
227
  return pluginInstance
194
228
  } finally {
195
229
  this._loading = false
@@ -410,7 +444,8 @@ class PluginManager {
410
444
  }
411
445
 
412
446
  console.log(`[PluginManager] Loading new plugin: ${pluginName} (${type})`)
413
- await this.load(plugin)
447
+ // .agent/plugins 目录下的插件默认强制启用,不受 state 文件影响
448
+ await this.load(plugin, { forceEnabled: true })
414
449
  } catch (err) {
415
450
  console.error(`[PluginManager] Failed to load plugin ${pluginName}:`, err.message)
416
451
  }
@@ -464,7 +499,8 @@ class PluginManager {
464
499
  name,
465
500
  status: entry?.status || 'unknown',
466
501
  enabled: entry?.enabled || false,
467
- version: entry?.instance?.version
502
+ version: entry?.instance?.version,
503
+ system: entry?.instance?.system || false
468
504
  })
469
505
  }
470
506
  // 也加入已加载但不在 knownPlugins 中的
@@ -474,7 +510,8 @@ class PluginManager {
474
510
  name,
475
511
  status: entry.status,
476
512
  enabled: entry.enabled,
477
- version: entry.instance?.version
513
+ version: entry.instance?.version,
514
+ system: entry.instance?.system || false
478
515
  })
479
516
  }
480
517
  }
@@ -515,6 +552,11 @@ class PluginManager {
515
552
  throw new Error(`Plugin '${name}' not found`)
516
553
  }
517
554
 
555
+ // 系统插件不能被禁用,所以启用没有意义
556
+ if (entry.instance?.system) {
557
+ throw new Error(`Plugin '${name}' is a system plugin, cannot be disabled`)
558
+ }
559
+
518
560
  if (entry.enabled) {
519
561
  console.log(`[PluginManager] Plugin '${name}' already enabled`)
520
562
  return
@@ -566,6 +608,11 @@ class PluginManager {
566
608
  throw new Error(`Plugin '${name}' not found`)
567
609
  }
568
610
 
611
+ // 系统插件不能被禁用
612
+ if (entry.instance?.system) {
613
+ throw new Error(`Plugin '${name}' is a system plugin, cannot be disabled`)
614
+ }
615
+
569
616
  if (!entry.enabled) {
570
617
  console.log(`[PluginManager] Plugin '${name}' already disabled`)
571
618
  return
@@ -193,6 +193,7 @@ class MCPExecutorPlugin extends Plugin {
193
193
  this.version = '1.0.0'
194
194
  this.description = 'MCP (Model Context Protocol) 执行器'
195
195
  this.priority = 11
196
+ this.system = true
196
197
 
197
198
  this._framework = null
198
199
  // serverName -> { client, tools: [{ name, description, inputSchema }], toolObjects: { toolName: actualTool } }