foliko 1.0.19 → 1.0.21
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 +62 -61
- package/README.md +1 -1
- package/SPEC.md +1 -1
- package/cli/src/index.js +2 -2
- package/docs/user-manual.md +4 -4
- package/install.ps1 +64 -133
- package/install.sh +121 -0
- package/package.json +2 -2
- package/plugins/subagent-plugin.js +1 -1
- package/skills/vb-agent-dev/SKILL.md +4 -4
- package/website/docs/configuration.html +160 -6
- package/website/docs/plugin-development.html +0 -4
- package/website/docs/project-structure.html +1 -1
- package/website/index.html +78 -44
- package/website/script.js +56 -0
- package/website/styles.css +128 -11
|
@@ -1,61 +1,62 @@
|
|
|
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/@pinixai/weixin-bot && npm run build 2>&1)",
|
|
44
|
-
"Bash(cd node_modules/@pinixai/weixin-bot && npx tsc 2>&1)",
|
|
45
|
-
"Bash(npm install:*)",
|
|
46
|
-
"Bash(cd node_modules/@pinixai/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/@pinixai/weixin-bot && cp -r /tmp/weixin-bot/nodejs/* node_modules/@pinixai/weixin-bot/ && cd node_modules/@pinixai/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\\('@pinixai/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\\('@pinixai/weixin-bot'\\); console.log\\(typeof WeixinBot\\)\" 2>&1)",
|
|
58
|
-
"Bash(node -e \"import\\('@pinixai/weixin-bot'\\).then\\(m => console.log\\('OK:', typeof m.WeixinBot\\)\\).catch\\(e => console.error\\('Error:', e.message\\)\\)\" 2>&1)"
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
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/@pinixai/weixin-bot && npm run build 2>&1)",
|
|
44
|
+
"Bash(cd node_modules/@pinixai/weixin-bot && npx tsc 2>&1)",
|
|
45
|
+
"Bash(npm install:*)",
|
|
46
|
+
"Bash(cd node_modules/@pinixai/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/@pinixai/weixin-bot && cp -r /tmp/weixin-bot/nodejs/* node_modules/@pinixai/weixin-bot/ && cd node_modules/@pinixai/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\\('@pinixai/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\\('@pinixai/weixin-bot'\\); console.log\\(typeof WeixinBot\\)\" 2>&1)",
|
|
58
|
+
"Bash(node -e \"import\\('@pinixai/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
|
+
]
|
|
61
|
+
}
|
|
62
|
+
}
|
package/README.md
CHANGED
package/SPEC.md
CHANGED
package/cli/src/index.js
CHANGED
|
@@ -7,13 +7,13 @@ const { chatCommand } = require('./commands/chat')
|
|
|
7
7
|
/**
|
|
8
8
|
* CLI 主入口
|
|
9
9
|
*/
|
|
10
|
-
function cli() {
|
|
10
|
+
async function cli() {
|
|
11
11
|
const args = process.argv.slice(2)
|
|
12
12
|
const command = args[0] || 'chat'
|
|
13
13
|
|
|
14
14
|
switch (command) {
|
|
15
15
|
case 'chat':
|
|
16
|
-
chatCommand(args.slice(1))
|
|
16
|
+
await chatCommand(args.slice(1))
|
|
17
17
|
break
|
|
18
18
|
|
|
19
19
|
case 'help':
|
package/docs/user-manual.md
CHANGED
|
@@ -31,7 +31,7 @@ VB-Agent 是一个基于插件的 Agent 框架,具有以下特性:
|
|
|
31
31
|
### 项目结构
|
|
32
32
|
|
|
33
33
|
```
|
|
34
|
-
|
|
34
|
+
foliko/
|
|
35
35
|
├── src/ # 核心源码
|
|
36
36
|
│ ├── core/ # 核心模块
|
|
37
37
|
│ │ ├── framework.js # 框架容器
|
|
@@ -733,7 +733,7 @@ module.exports = function(Plugin) {
|
|
|
733
733
|
name: my-skill
|
|
734
734
|
description: 我的技能描述
|
|
735
735
|
license: MIT
|
|
736
|
-
compatibility:
|
|
736
|
+
compatibility: foliko >= 1.0.0
|
|
737
737
|
metadata:
|
|
738
738
|
author: Your Name
|
|
739
739
|
version: 1.0.0
|
|
@@ -753,13 +753,13 @@ Agent 可以通过 `loadSkill` 工具加载技能:
|
|
|
753
753
|
|
|
754
754
|
```
|
|
755
755
|
用户: 帮我创建一个系统信息插件
|
|
756
|
-
Agent: [调用 loadSkill 技能
|
|
756
|
+
Agent: [调用 loadSkill 技能 foliko-dev]
|
|
757
757
|
Agent: [获取插件开发指南后,按照指南创建插件]
|
|
758
758
|
```
|
|
759
759
|
|
|
760
760
|
### 6.4 内置技能
|
|
761
761
|
|
|
762
|
-
- **
|
|
762
|
+
- **foliko-dev** - VB-Agent 插件开发指南
|
|
763
763
|
- **api-patterns** - API 设计模式
|
|
764
764
|
- **app-builder** - 应用程序构建
|
|
765
765
|
- **architecture** - 架构设计
|
package/install.ps1
CHANGED
|
@@ -1,179 +1,110 @@
|
|
|
1
|
-
# Foliko
|
|
2
|
-
# 使用方式: irm https://raw.githubusercontent.com/user/vb-agent/main/install.ps1 | iex
|
|
1
|
+
# Foliko Installer
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
# Fix execution policy first
|
|
4
|
+
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser -Force -ErrorAction SilentlyContinue
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
Write-Host "Foliko 安装器" -ForegroundColor Cyan
|
|
10
|
-
Write-Host "=================" -ForegroundColor Cyan
|
|
6
|
+
Write-Host "Foliko Installer"
|
|
7
|
+
Write-Host "================="
|
|
11
8
|
Write-Host ""
|
|
12
9
|
|
|
13
|
-
#
|
|
14
|
-
|
|
15
|
-
Write-Host "正在检查 Node.js..." -ForegroundColor Cyan
|
|
16
|
-
|
|
17
|
-
if (Get-Command node -ErrorAction SilentlyContinue) {
|
|
18
|
-
Write-Host "Node.js 已安装: $(node --version)" -ForegroundColor Green
|
|
19
|
-
return $true
|
|
20
|
-
}
|
|
10
|
+
# Refresh PATH
|
|
11
|
+
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")
|
|
21
12
|
|
|
22
|
-
|
|
13
|
+
# ============ Check/Install Node.js ============
|
|
14
|
+
Write-Host "Checking Node.js..."
|
|
15
|
+
if (Get-Command node -ErrorAction SilentlyContinue) {
|
|
16
|
+
Write-Host "Node.js installed: $(node --version)" -ForegroundColor Green
|
|
17
|
+
} else {
|
|
18
|
+
Write-Host "Node.js not found, installing..." -ForegroundColor Yellow
|
|
23
19
|
|
|
24
|
-
# 下载 Node.js LTS 安装包
|
|
25
20
|
$nodeUrl = "https://nodejs.org/dist/v20.11.0/node-v20.11.0-x64.msi"
|
|
26
21
|
$nodeInstaller = "$env:TEMP\node-installer.msi"
|
|
27
22
|
|
|
28
|
-
Write-Host "
|
|
29
|
-
Invoke-WebRequest -Uri $nodeUrl -OutFile $nodeInstaller
|
|
23
|
+
Write-Host "Downloading Node.js..." -ForegroundColor Cyan
|
|
24
|
+
Invoke-WebRequest -Uri $nodeUrl -OutFile $nodeInstaller -UseBasicParsing
|
|
30
25
|
|
|
31
|
-
Write-Host "
|
|
26
|
+
Write-Host "Installing Node.js (may require admin)..." -ForegroundColor Cyan
|
|
32
27
|
Start-Process msiexec.exe -ArgumentList "/i", $nodeInstaller, "/quiet", "/norestart" -Wait
|
|
33
28
|
|
|
34
|
-
# 刷新环境变量
|
|
35
29
|
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")
|
|
30
|
+
Start-Sleep -Seconds 3
|
|
36
31
|
|
|
37
|
-
# 验证安装
|
|
38
|
-
Start-Sleep -Seconds 2
|
|
39
32
|
if (Get-Command node -ErrorAction SilentlyContinue) {
|
|
40
|
-
Write-Host "Node.js
|
|
33
|
+
Write-Host "Node.js installed: $(node --version)" -ForegroundColor Green
|
|
41
34
|
Remove-Item $nodeInstaller -Force -ErrorAction SilentlyContinue
|
|
42
|
-
|
|
35
|
+
} else {
|
|
36
|
+
Write-Host "Node.js installation failed" -ForegroundColor Red
|
|
37
|
+
Write-Host "Download manually: https://nodejs.org/" -ForegroundColor Yellow
|
|
43
38
|
}
|
|
44
|
-
|
|
45
|
-
Write-Host "Node.js 安装失败,请手动安装" -ForegroundColor Red
|
|
46
|
-
Write-Host "下载地址: https://nodejs.org/" -ForegroundColor Yellow
|
|
47
|
-
return $false
|
|
48
39
|
}
|
|
40
|
+
Write-Host ""
|
|
49
41
|
|
|
50
|
-
#
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
return $true
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
Write-Host "Python 未安装,正在安装..." -ForegroundColor Yellow
|
|
42
|
+
# ============ Check/Install Python ============
|
|
43
|
+
Write-Host "Checking Python..."
|
|
44
|
+
if (Get-Command python -ErrorAction SilentlyContinue) {
|
|
45
|
+
Write-Host "Python installed: $(python --version)" -ForegroundColor Green
|
|
46
|
+
} else {
|
|
47
|
+
Write-Host "Python not found, installing..." -ForegroundColor Yellow
|
|
60
48
|
|
|
61
|
-
# 下载 Python 安装包
|
|
62
49
|
$pythonUrl = "https://www.python.org/ftp/python/3.12.1/python-3.12.1-amd64.exe"
|
|
63
50
|
$pythonInstaller = "$env:TEMP\python-installer.exe"
|
|
64
51
|
|
|
65
|
-
Write-Host "
|
|
66
|
-
Invoke-WebRequest -Uri $pythonUrl -OutFile $pythonInstaller
|
|
52
|
+
Write-Host "Downloading Python..." -ForegroundColor Cyan
|
|
53
|
+
Invoke-WebRequest -Uri $pythonUrl -OutFile $pythonInstaller -UseBasicParsing
|
|
67
54
|
|
|
68
|
-
Write-Host "
|
|
69
|
-
# 使用静默安装参数,添加 PATH 和 pip
|
|
55
|
+
Write-Host "Installing Python (may require admin)..." -ForegroundColor Cyan
|
|
70
56
|
Start-Process $pythonInstaller -ArgumentList "/quiet", "InstallAllUsers=1", "PrependPath=1", "Include_pip=1" -Wait
|
|
71
57
|
|
|
72
|
-
# 刷新环境变量
|
|
73
58
|
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")
|
|
59
|
+
Start-Sleep -Seconds 3
|
|
74
60
|
|
|
75
|
-
# 验证安装
|
|
76
|
-
Start-Sleep -Seconds 2
|
|
77
61
|
if (Get-Command python -ErrorAction SilentlyContinue) {
|
|
78
|
-
Write-Host "Python
|
|
62
|
+
Write-Host "Python installed: $(python --version)" -ForegroundColor Green
|
|
79
63
|
Remove-Item $pythonInstaller -Force -ErrorAction SilentlyContinue
|
|
80
|
-
|
|
64
|
+
} else {
|
|
65
|
+
Write-Host "Python installation failed" -ForegroundColor Red
|
|
66
|
+
Write-Host "Download manually: https://www.python.org/downloads/" -ForegroundColor Yellow
|
|
81
67
|
}
|
|
82
|
-
|
|
83
|
-
Write-Host "Python 安装失败,请手动安装" -ForegroundColor Red
|
|
84
|
-
Write-Host "下载地址: https://www.python.org/downloads/" -ForegroundColor Yellow
|
|
85
|
-
return $false
|
|
86
68
|
}
|
|
69
|
+
Write-Host ""
|
|
87
70
|
|
|
88
|
-
#
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if (-not (Get-Command python -ErrorAction SilentlyContinue)) {
|
|
95
|
-
Write-Host "Python 未安装,跳过 venv" -ForegroundColor Yellow
|
|
96
|
-
return $false
|
|
97
|
-
}
|
|
71
|
+
# ============ Check/Install uv ============
|
|
72
|
+
Write-Host "Checking uv..."
|
|
73
|
+
if (Get-Command uv -ErrorAction SilentlyContinue) {
|
|
74
|
+
Write-Host "uv installed: $(uv --version)" -ForegroundColor Green
|
|
75
|
+
} else {
|
|
76
|
+
Write-Host "uv not found, installing..." -ForegroundColor Yellow
|
|
98
77
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
return $true
|
|
102
|
-
}
|
|
78
|
+
Write-Host "Downloading uv..." -ForegroundColor Cyan
|
|
79
|
+
$uvInstaller = "$env:TEMP\uv-installer.pyz"
|
|
103
80
|
|
|
104
|
-
|
|
105
|
-
|
|
81
|
+
try {
|
|
82
|
+
Invoke-WebRequest -Uri "https://astral.sh/uv/install.ps1" -OutFile "$env:TEMP\install-uv.ps1" -UseBasicParsing
|
|
83
|
+
powershell -ExecutionPolicy Bypass -File "$env:TEMP\install-uv.ps1" -Version "0.4.0" -PowerShell -Admin
|
|
84
|
+
Remove-Item "$env:TEMP\install-uv.ps1" -Force -ErrorAction SilentlyContinue
|
|
106
85
|
|
|
107
|
-
|
|
108
|
-
Write-Host "虚拟环境创建成功" -ForegroundColor Green
|
|
86
|
+
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")
|
|
109
87
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
88
|
+
if (Get-Command uv -ErrorAction SilentlyContinue) {
|
|
89
|
+
Write-Host "uv installed: $(uv --version)" -ForegroundColor Green
|
|
90
|
+
}
|
|
91
|
+
} catch {
|
|
92
|
+
Write-Host "uv installation failed (optional, can be skipped)" -ForegroundColor Yellow
|
|
114
93
|
}
|
|
115
|
-
|
|
116
|
-
Write-Host "虚拟环境创建失败" -ForegroundColor Red
|
|
117
|
-
return $false
|
|
118
94
|
}
|
|
119
|
-
|
|
120
|
-
# 主安装流程
|
|
121
|
-
Write-Host "环境检查" -ForegroundColor Cyan
|
|
122
|
-
Write-Host "-----------" -ForegroundColor Cyan
|
|
123
95
|
Write-Host ""
|
|
124
96
|
|
|
125
|
-
#
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
$pythonOk = Install-Python
|
|
129
|
-
Write-Host ""
|
|
97
|
+
# ============ Install Foliko ============
|
|
98
|
+
Write-Host "Installing Foliko..."
|
|
99
|
+
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")
|
|
130
100
|
|
|
131
|
-
|
|
132
|
-
Write-Host "警告: Node.js 未正确安装,部分功能可能不可用" -ForegroundColor Yellow
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if (-not $pythonOk) {
|
|
136
|
-
Write-Host "警告: Python 未正确安装,部分功能可能不可用" -ForegroundColor Yellow
|
|
137
|
-
}
|
|
101
|
+
npm install -g foliko
|
|
138
102
|
|
|
139
|
-
|
|
140
|
-
$venvDir = "$InstallDir\venv"
|
|
141
|
-
if ($pythonOk) {
|
|
103
|
+
if (Get-Command foliko -ErrorAction SilentlyContinue) {
|
|
142
104
|
Write-Host ""
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
# 创建安装目录
|
|
147
|
-
if (-not (Test-Path $InstallDir)) {
|
|
148
|
-
New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
Write-Host "安装到: $InstallDir" -ForegroundColor Cyan
|
|
152
|
-
Write-Host ""
|
|
153
|
-
|
|
154
|
-
Push-Location $InstallDir
|
|
155
|
-
|
|
156
|
-
if (Test-Path ".git") {
|
|
157
|
-
Write-Host "更新现有安装..." -ForegroundColor Cyan
|
|
158
|
-
git pull
|
|
105
|
+
Write-Host "Installation complete!" -ForegroundColor Green
|
|
106
|
+
Write-Host "Run: foliko chat"
|
|
159
107
|
} else {
|
|
160
|
-
Write-Host "
|
|
161
|
-
|
|
108
|
+
Write-Host ""
|
|
109
|
+
Write-Host "Installation may have failed. Try manually: npm install -g foliko" -ForegroundColor Yellow
|
|
162
110
|
}
|
|
163
|
-
|
|
164
|
-
# 安装依赖
|
|
165
|
-
Write-Host "安装 npm 依赖..." -ForegroundColor Cyan
|
|
166
|
-
npm install
|
|
167
|
-
|
|
168
|
-
# 全局链接 CLI
|
|
169
|
-
Write-Host "安装 CLI..." -ForegroundColor Cyan
|
|
170
|
-
npm link
|
|
171
|
-
|
|
172
|
-
Pop-Location
|
|
173
|
-
|
|
174
|
-
Write-Host ""
|
|
175
|
-
Write-Host "安装完成!" -ForegroundColor Green
|
|
176
|
-
Write-Host ""
|
|
177
|
-
Write-Host "使用方法:" -ForegroundColor Yellow
|
|
178
|
-
Write-Host " foliko chat" -ForegroundColor White
|
|
179
|
-
Write-Host ""
|
package/install.sh
ADDED
|
@@ -0,0 +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
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "foliko",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.21",
|
|
4
4
|
"description": "简约的插件化 Agent 框架",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"@ai-sdk/openai-compatible": "^2.0.35",
|
|
27
27
|
"@anthropic-ai/sdk": "^0.39.0",
|
|
28
28
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
29
|
-
"@pinixai/weixin-bot": "github
|
|
29
|
+
"@pinixai/weixin-bot": "https://github.com/chnak/weixin-bot.git",
|
|
30
30
|
"ai": "^6.0.116",
|
|
31
31
|
"dotenv": "^17.3.1",
|
|
32
32
|
"imap": "^0.8.19",
|
|
@@ -127,7 +127,7 @@ class SubAgentPlugin extends Plugin {
|
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
// 尝试从framework获取主agent
|
|
130
|
-
// 在
|
|
130
|
+
// 在foliko中,主agent通常是通过framework.createAgent创建的
|
|
131
131
|
if (this._framework._mainAgent) {
|
|
132
132
|
return this._framework._mainAgent
|
|
133
133
|
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
3
|
-
description:
|
|
2
|
+
name: foliko-dev
|
|
3
|
+
description: Foliko Framework 插件开发指南。当用户说"创建插件"、"开发插件"时立即调用此 skill。
|
|
4
4
|
allowed-tools: Read, Write, Edit, Glob, Grep, Bash
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
#
|
|
7
|
+
# Foliko Plugin Development Guide
|
|
8
8
|
|
|
9
9
|
## 概述
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Foliko 是一个基于插件的 Agent 框架,核心简单,通过插件扩展功能。
|
|
12
12
|
|
|
13
13
|
---
|
|
14
14
|
|
|
@@ -49,6 +49,29 @@
|
|
|
49
49
|
<div class="main-content">
|
|
50
50
|
<h1>配置指南</h1>
|
|
51
51
|
|
|
52
|
+
<h2>环境变量配置 (.env)</h2>
|
|
53
|
+
<p>在项目根目录创建 <code>.env</code> 文件:</p>
|
|
54
|
+
<pre><code># AI Provider: minimax, deepseek, openai, anthropic 等
|
|
55
|
+
FOLIKO_PROVIDER=minimax
|
|
56
|
+
|
|
57
|
+
# AI Model(可选,不填则使用 provider 默认值)
|
|
58
|
+
# MiniMax: MiniMax-M2.7
|
|
59
|
+
# DeepSeek: deepseek-chat, deepseek-coder 等
|
|
60
|
+
FOLIKO_MODEL=
|
|
61
|
+
|
|
62
|
+
# API Base URL(可选,不填则使用 provider 默认值)
|
|
63
|
+
# MiniMax: https://api.minimaxi.com/v1
|
|
64
|
+
# DeepSeek: https://api.deepseek.com/v1
|
|
65
|
+
FOLIKO_BASE_URL=
|
|
66
|
+
|
|
67
|
+
# API Key(通用,不填则使用 provider 专用 key)
|
|
68
|
+
FOLIKO_API_KEY=
|
|
69
|
+
|
|
70
|
+
# Provider 专用 API Key(可选)
|
|
71
|
+
DEEPSEEK_API_KEY=sk-your-deepseek-api-key
|
|
72
|
+
MINIMAX_API_KEY=sk-your-minimax-api-key</code></pre>
|
|
73
|
+
<p><strong>配置优先级</strong>:命令行参数 > .env配置 > provider默认值</p>
|
|
74
|
+
|
|
52
75
|
<h2>目录结构</h2>
|
|
53
76
|
<p>在项目根目录创建 <code>.agent</code> 目录:</p>
|
|
54
77
|
<pre><code>项目目录/
|
|
@@ -92,28 +115,159 @@ ai_base_url: https://api.minimaxi.com/v1</code></pre>
|
|
|
92
115
|
}</code></pre>
|
|
93
116
|
|
|
94
117
|
<h2>CLI 参数</h2>
|
|
118
|
+
<p>命令行参数会覆盖 .env 配置:</p>
|
|
95
119
|
<table>
|
|
96
120
|
<tr>
|
|
97
121
|
<th>参数</th>
|
|
98
122
|
<th>说明</th>
|
|
99
|
-
|
|
100
|
-
<tr>
|
|
101
|
-
<td><code>--model</code></td>
|
|
102
|
-
<td>指定 AI 模型</td>
|
|
123
|
+
<th>示例</th>
|
|
103
124
|
</tr>
|
|
104
125
|
<tr>
|
|
105
126
|
<td><code>--provider</code></td>
|
|
106
127
|
<td>指定 AI 提供商</td>
|
|
128
|
+
<td><code>deepseek</code>, <code>minimax</code></td>
|
|
107
129
|
</tr>
|
|
108
130
|
<tr>
|
|
109
|
-
<td><code>--
|
|
110
|
-
<td>指定
|
|
131
|
+
<td><code>--model</code></td>
|
|
132
|
+
<td>指定 AI 模型</td>
|
|
133
|
+
<td><code>deepseek-chat</code>, <code>MiniMax-M2.7</code></td>
|
|
111
134
|
</tr>
|
|
112
135
|
<tr>
|
|
113
136
|
<td><code>--base-url</code></td>
|
|
114
137
|
<td>指定 API 地址</td>
|
|
138
|
+
<td><code>https://api.deepseek.com/v1</code></td>
|
|
139
|
+
</tr>
|
|
140
|
+
<tr>
|
|
141
|
+
<td><code>--api-key</code></td>
|
|
142
|
+
<td>指定 API 密钥</td>
|
|
143
|
+
<td><code>sk-xxx</code></td>
|
|
115
144
|
</tr>
|
|
116
145
|
</table>
|
|
146
|
+
|
|
147
|
+
<h3>使用示例</h3>
|
|
148
|
+
<pre><code># 使用 .env 中的配置
|
|
149
|
+
npm run chat
|
|
150
|
+
|
|
151
|
+
# 指定完整配置
|
|
152
|
+
foliko chat --provider deepseek --model deepseek-chat --base-url https://api.deepseek.com/v1 --api-key sk-xxx
|
|
153
|
+
|
|
154
|
+
# 只指定 provider(使用 provider 默认 model 和 baseURL)
|
|
155
|
+
foliko chat --provider deepseek --api-key sk-xxx
|
|
156
|
+
|
|
157
|
+
# 只指定 api-key(使用 FOLIKO_PROVIDER 设定的 provider)
|
|
158
|
+
foliko chat --api-key sk-xxx</code></pre>
|
|
159
|
+
|
|
160
|
+
<h2>插件配置</h2>
|
|
161
|
+
|
|
162
|
+
<h3>Telegram 插件</h3>
|
|
163
|
+
<pre><code>{
|
|
164
|
+
"telegram": {
|
|
165
|
+
"botToken": "your-bot-token",
|
|
166
|
+
"allowedChats": ["123456789"],
|
|
167
|
+
"groupMode": false,
|
|
168
|
+
"prefix": "/"
|
|
169
|
+
}
|
|
170
|
+
}</code></pre>
|
|
171
|
+
<table>
|
|
172
|
+
<tr><th>配置项</th><th>说明</th><th>默认值</th></tr>
|
|
173
|
+
<tr><td>botToken</td><td>Telegram Bot Token</td><td>TELEGRAM_BOT_TOKEN 环境变量</td></tr>
|
|
174
|
+
<tr><td>allowedChats</td><td>允许的聊天 ID 数组</td><td>[] (允许所有人)</td></tr>
|
|
175
|
+
<tr><td>groupMode</td><td>是否启用群组模式</td><td>false</td></tr>
|
|
176
|
+
<tr><td>prefix</td><td>命令前缀</td><td>/</td></tr>
|
|
177
|
+
</table>
|
|
178
|
+
|
|
179
|
+
<h3>WeChat 插件</h3>
|
|
180
|
+
<pre><code>{
|
|
181
|
+
"weixin": {
|
|
182
|
+
"forceLogin": false,
|
|
183
|
+
"qrcodeTerminal": true,
|
|
184
|
+
"allowedUsers": []
|
|
185
|
+
}
|
|
186
|
+
}</code></pre>
|
|
187
|
+
<table>
|
|
188
|
+
<tr><th>配置项</th><th>说明</th><th>默认值</th></tr>
|
|
189
|
+
<tr><td>forceLogin</td><td>强制重新扫码登录</td><td>false</td></tr>
|
|
190
|
+
<tr><td>qrcodeTerminal</td><td>终端渲染二维码</td><td>true</td></tr>
|
|
191
|
+
<tr><td>allowedUsers</td><td>允许的用户 ID 数组</td><td>[] (允许所有人)</td></tr>
|
|
192
|
+
</table>
|
|
193
|
+
|
|
194
|
+
<h3>Session 插件</h3>
|
|
195
|
+
<pre><code>{
|
|
196
|
+
"session": {
|
|
197
|
+
"sessionTTL": 1800000,
|
|
198
|
+
"maxSessions": 100,
|
|
199
|
+
"maxHistoryLength": 50,
|
|
200
|
+
"autoCleanup": true,
|
|
201
|
+
"cleanupInterval": 300000
|
|
202
|
+
}
|
|
203
|
+
}</code></pre>
|
|
204
|
+
<table>
|
|
205
|
+
<tr><th>配置项</th><th>说明</th><th>默认值</th></tr>
|
|
206
|
+
<tr><td>sessionTTL</td><td>会话过期时间(毫秒)</td><td>30分钟</td></tr>
|
|
207
|
+
<tr><td>maxSessions</td><td>最大会话数</td><td>100</td></tr>
|
|
208
|
+
<tr><td>maxHistoryLength</td><td>最大历史消息数</td><td>50</td></tr>
|
|
209
|
+
<tr><td>autoCleanup</td><td>自动清理过期会话</td><td>true</td></tr>
|
|
210
|
+
<tr><td>cleanupInterval</td><td>清理检查间隔(毫秒)</td><td>5分钟</td></tr>
|
|
211
|
+
</table>
|
|
212
|
+
|
|
213
|
+
<h3>Storage 插件</h3>
|
|
214
|
+
<pre><code>{
|
|
215
|
+
"storage": {
|
|
216
|
+
"type": "json",
|
|
217
|
+
"path": ".agent/data",
|
|
218
|
+
"namespace": "default"
|
|
219
|
+
}
|
|
220
|
+
}</code></pre>
|
|
221
|
+
<table>
|
|
222
|
+
<tr><th>配置项</th><th>说明</th><th>默认值</th></tr>
|
|
223
|
+
<tr><td>type</td><td>存储类型 (json/memory)</td><td>json</td></tr>
|
|
224
|
+
<tr><td>path</td><td>存储文件路径</td><td>.agent/data</td></tr>
|
|
225
|
+
<tr><td>namespace</td><td>命名空间</td><td>default</td></tr>
|
|
226
|
+
</table>
|
|
227
|
+
|
|
228
|
+
<h3>Scheduler 插件</h3>
|
|
229
|
+
<pre><code>{
|
|
230
|
+
"scheduler": {
|
|
231
|
+
"checkInterval": 1000
|
|
232
|
+
}
|
|
233
|
+
}</code></pre>
|
|
234
|
+
<table>
|
|
235
|
+
<tr><th>配置项</th><th>说明</th><th>默认值</th></tr>
|
|
236
|
+
<tr><td>checkInterval</td><td>任务检查间隔(毫秒)</td><td>1000</td></tr>
|
|
237
|
+
</table>
|
|
238
|
+
|
|
239
|
+
<h3>Email 插件</h3>
|
|
240
|
+
<p>通过环境变量配置:</p>
|
|
241
|
+
<pre><code># SMTP 配置 (发送邮件)
|
|
242
|
+
SMTP_HOST=smtp.gmail.com
|
|
243
|
+
SMTP_PORT=587
|
|
244
|
+
SMTP_SECURE=false
|
|
245
|
+
SMTP_USER=your-email@gmail.com
|
|
246
|
+
SMTP_PASS=your-app-password
|
|
247
|
+
|
|
248
|
+
# IMAP 配置 (读取邮件)
|
|
249
|
+
IMAP_HOST=imap.gmail.com
|
|
250
|
+
IMAP_PORT=993
|
|
251
|
+
IMAP_USER=your-email@gmail.com
|
|
252
|
+
IMAP_PASS=your-app-password
|
|
253
|
+
|
|
254
|
+
# 默认发件人
|
|
255
|
+
FROM_EMAIL=your-email@gmail.com</code></pre>
|
|
256
|
+
|
|
257
|
+
<h3>MCP 配置</h3>
|
|
258
|
+
<p>在 <code>.agent/mcp_config.json</code> 中配置 MCP 服务器:</p>
|
|
259
|
+
<pre><code>{
|
|
260
|
+
"mcpServers": {
|
|
261
|
+
"fetch": {
|
|
262
|
+
"command": "npx",
|
|
263
|
+
"args": ["-y", "@modelcontextprotocol/server-fetch"]
|
|
264
|
+
},
|
|
265
|
+
"filesystem": {
|
|
266
|
+
"command": "npx",
|
|
267
|
+
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/dir"]
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}</code></pre>
|
|
117
271
|
</div>
|
|
118
272
|
</body>
|
|
119
273
|
</html>
|
package/website/index.html
CHANGED
|
@@ -22,14 +22,28 @@
|
|
|
22
22
|
|
|
23
23
|
<main>
|
|
24
24
|
<section id="home" class="hero">
|
|
25
|
-
<
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
25
|
+
<div class="hero-content">
|
|
26
|
+
<h1>Foliko</h1>
|
|
27
|
+
<p class="tagline">简约的插件化 Agent 框架</p>
|
|
28
|
+
|
|
29
|
+
<div class="install-box">
|
|
30
|
+
<div class="install-tabs">
|
|
31
|
+
<button class="tab active" data-cmd="irm https://foliko.com/install.ps1 | iex">Windows</button>
|
|
32
|
+
<button class="tab" data-cmd="curl -fsSL https://foliko.com/install.sh | bash">Mac / Linux</button>
|
|
33
|
+
<button class="tab" data-cmd="npm install -g foliko">npm</button>
|
|
34
|
+
</div>
|
|
35
|
+
<div class="install-cmd">
|
|
36
|
+
<code id="install-cmd">irm https://foliko.com/install.ps1 | iex</code>
|
|
37
|
+
<button class="copy-btn" onclick="copyCmd()">复制</button>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
<div class="hero-links">
|
|
42
|
+
<a href="#features">核心特性</a>
|
|
43
|
+
<a href="#quickstart">快速开始</a>
|
|
44
|
+
<a href="#docs">文档</a>
|
|
45
|
+
<a href="#plugins">插件</a>
|
|
46
|
+
</div>
|
|
33
47
|
</div>
|
|
34
48
|
</section>
|
|
35
49
|
|
|
@@ -72,27 +86,19 @@
|
|
|
72
86
|
<section id="quickstart" class="quickstart">
|
|
73
87
|
<h2>快速开始</h2>
|
|
74
88
|
|
|
75
|
-
<div class="code-block">
|
|
76
|
-
<h3>安装</h3>
|
|
77
|
-
<pre><code># PowerShell (Windows)
|
|
78
|
-
irm https://raw.githubusercontent.com/your-username/vb-agent/main/install.ps1 | iex
|
|
79
|
-
|
|
80
|
-
# 或者克隆仓库
|
|
81
|
-
git clone https://github.com/your-username/vb-agent.git
|
|
82
|
-
cd vb-agent
|
|
83
|
-
npm install
|
|
84
|
-
npm link</code></pre>
|
|
85
|
-
</div>
|
|
86
|
-
|
|
87
89
|
<div class="code-block">
|
|
88
90
|
<h3>配置</h3>
|
|
89
|
-
<pre><code>#
|
|
90
|
-
|
|
91
|
+
<pre><code># 创建 .env 文件
|
|
92
|
+
touch .env
|
|
91
93
|
|
|
92
|
-
#
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
94
|
+
# 编辑 .env 添加配置
|
|
95
|
+
# MiniMax 示例:
|
|
96
|
+
# FOLIKO_PROVIDER=minimax
|
|
97
|
+
# MINIMAX_API_KEY=sk-your-api-key
|
|
98
|
+
|
|
99
|
+
# DeepSeek 示例:
|
|
100
|
+
# FOLIKO_PROVIDER=deepseek
|
|
101
|
+
# DEEPSEEK_API_KEY=sk-your-api-key</code></pre>
|
|
96
102
|
</div>
|
|
97
103
|
|
|
98
104
|
<div class="code-block">
|
|
@@ -131,53 +137,81 @@ echo "ai_provider: minimax" >> .agent/config</code></pre>
|
|
|
131
137
|
<th>插件</th>
|
|
132
138
|
<th>说明</th>
|
|
133
139
|
<th>工具</th>
|
|
140
|
+
<th>配置</th>
|
|
134
141
|
</tr>
|
|
135
142
|
</thead>
|
|
136
143
|
<tbody>
|
|
137
144
|
<tr>
|
|
138
|
-
<td>AI</td>
|
|
145
|
+
<td><strong>AI</strong></td>
|
|
139
146
|
<td>AI 提供商集成</td>
|
|
140
147
|
<td>chat, chatStream</td>
|
|
148
|
+
<td>provider, model, apiKey, baseURL</td>
|
|
149
|
+
</tr>
|
|
150
|
+
<tr>
|
|
151
|
+
<td><strong>Session</strong></td>
|
|
152
|
+
<td>会话管理,多会话隔离、历史记录</td>
|
|
153
|
+
<td>session_create, session_get, session_list, session_delete, session_history</td>
|
|
154
|
+
<td>sessionTTL, maxSessions, maxHistoryLength</td>
|
|
155
|
+
</tr>
|
|
156
|
+
<tr>
|
|
157
|
+
<td><strong>Telegram</strong></td>
|
|
158
|
+
<td>Telegram Bot 对话</td>
|
|
159
|
+
<td>Bot 接收消息,自动对话</td>
|
|
160
|
+
<td>botToken, allowedChats, groupMode, prefix</td>
|
|
161
|
+
</tr>
|
|
162
|
+
<tr>
|
|
163
|
+
<td><strong>WeChat</strong></td>
|
|
164
|
+
<td>微信对话</td>
|
|
165
|
+
<td>Bot 接收消息,自动对话</td>
|
|
166
|
+
<td>forceLogin, qrcodeTerminal, allowedUsers</td>
|
|
141
167
|
</tr>
|
|
142
168
|
<tr>
|
|
143
|
-
<td>Storage</td>
|
|
144
|
-
<td
|
|
145
|
-
<td>
|
|
169
|
+
<td><strong>Storage</strong></td>
|
|
170
|
+
<td>数据持久化存储</td>
|
|
171
|
+
<td>storage_set, storage_get, storage_delete, storage_list, storage_clear</td>
|
|
172
|
+
<td>type (json/memory), path, namespace</td>
|
|
146
173
|
</tr>
|
|
147
174
|
<tr>
|
|
148
|
-
<td>
|
|
149
|
-
<td
|
|
150
|
-
<td
|
|
175
|
+
<td><strong>Scheduler</strong></td>
|
|
176
|
+
<td>定时任务调度</td>
|
|
177
|
+
<td>schedule_task, schedule_list, schedule_cancel, cron_examples</td>
|
|
178
|
+
<td>checkInterval</td>
|
|
151
179
|
</tr>
|
|
152
180
|
<tr>
|
|
153
|
-
<td>
|
|
154
|
-
<td
|
|
155
|
-
<td>
|
|
181
|
+
<td><strong>Email</strong></td>
|
|
182
|
+
<td>邮件收发</td>
|
|
183
|
+
<td>email_send, email_read, email_unread_count, email_mark_read, email_configure</td>
|
|
184
|
+
<td>SMTP/IMAP 配置</td>
|
|
156
185
|
</tr>
|
|
157
186
|
<tr>
|
|
158
|
-
<td>Shell</td>
|
|
187
|
+
<td><strong>Shell</strong></td>
|
|
159
188
|
<td>Shell 命令执行</td>
|
|
160
189
|
<td>shell_execute</td>
|
|
190
|
+
<td>-</td>
|
|
161
191
|
</tr>
|
|
162
192
|
<tr>
|
|
163
|
-
<td>Python</td>
|
|
193
|
+
<td><strong>Python</strong></td>
|
|
164
194
|
<td>Python 代码执行</td>
|
|
165
195
|
<td>python_execute</td>
|
|
196
|
+
<td>-</td>
|
|
166
197
|
</tr>
|
|
167
198
|
<tr>
|
|
168
|
-
<td>MCP</td>
|
|
199
|
+
<td><strong>MCP</strong></td>
|
|
169
200
|
<td>MCP 协议支持</td>
|
|
170
201
|
<td>mcp_execute, mcp_reload</td>
|
|
202
|
+
<td>mcp_config.json</td>
|
|
171
203
|
</tr>
|
|
172
204
|
<tr>
|
|
173
|
-
<td>
|
|
174
|
-
<td
|
|
175
|
-
<td>
|
|
205
|
+
<td><strong>Install</strong></td>
|
|
206
|
+
<td>npm 包安装</td>
|
|
207
|
+
<td>install</td>
|
|
208
|
+
<td>-</td>
|
|
176
209
|
</tr>
|
|
177
210
|
<tr>
|
|
178
|
-
<td>Audit</td>
|
|
211
|
+
<td><strong>Audit</strong></td>
|
|
179
212
|
<td>审计日志</td>
|
|
180
213
|
<td>audit_query</td>
|
|
214
|
+
<td>-</td>
|
|
181
215
|
</tr>
|
|
182
216
|
</tbody>
|
|
183
217
|
</table>
|
|
@@ -187,7 +221,7 @@ echo "ai_provider: minimax" >> .agent/config</code></pre>
|
|
|
187
221
|
<footer>
|
|
188
222
|
<p>© 2024 Foliko. MIT License.</p>
|
|
189
223
|
<p>
|
|
190
|
-
<a href="https://
|
|
224
|
+
<a href="https://www.npmjs.com/package/foliko">npm</a> |
|
|
191
225
|
<a href="docs/api.html">API 文档</a>
|
|
192
226
|
</p>
|
|
193
227
|
</footer>
|
package/website/script.js
CHANGED
|
@@ -1,3 +1,59 @@
|
|
|
1
|
+
// Install tab switching
|
|
2
|
+
document.querySelectorAll('.install-tabs .tab').forEach(tab => {
|
|
3
|
+
tab.addEventListener('click', () => {
|
|
4
|
+
document.querySelectorAll('.install-tabs .tab').forEach(t => t.classList.remove('active'));
|
|
5
|
+
tab.classList.add('active');
|
|
6
|
+
document.getElementById('install-cmd').textContent = tab.dataset.cmd;
|
|
7
|
+
});
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
// Copy install command
|
|
11
|
+
function copyCmd() {
|
|
12
|
+
const code = document.getElementById('install-cmd').textContent;
|
|
13
|
+
const btn = document.querySelector('.install-cmd .copy-btn');
|
|
14
|
+
|
|
15
|
+
// 复制到剪贴板
|
|
16
|
+
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
17
|
+
navigator.clipboard.writeText(code).then(() => {
|
|
18
|
+
btn.textContent = '已复制';
|
|
19
|
+
btn.classList.add('copied');
|
|
20
|
+
setTimeout(() => {
|
|
21
|
+
btn.textContent = '复制';
|
|
22
|
+
btn.classList.remove('copied');
|
|
23
|
+
}, 2000);
|
|
24
|
+
}).catch(() => {
|
|
25
|
+
fallbackCopy(code, btn);
|
|
26
|
+
});
|
|
27
|
+
} else {
|
|
28
|
+
fallbackCopy(code, btn);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// 备用复制方法
|
|
33
|
+
function fallbackCopy(text, btn) {
|
|
34
|
+
const textarea = document.createElement('textarea');
|
|
35
|
+
textarea.value = text;
|
|
36
|
+
textarea.style.position = 'fixed';
|
|
37
|
+
textarea.style.opacity = '0';
|
|
38
|
+
document.body.appendChild(textarea);
|
|
39
|
+
textarea.select();
|
|
40
|
+
try {
|
|
41
|
+
document.execCommand('copy');
|
|
42
|
+
btn.textContent = '已复制';
|
|
43
|
+
btn.classList.add('copied');
|
|
44
|
+
setTimeout(() => {
|
|
45
|
+
btn.textContent = '复制';
|
|
46
|
+
btn.classList.remove('copied');
|
|
47
|
+
}, 2000);
|
|
48
|
+
} catch (err) {
|
|
49
|
+
btn.textContent = '复制失败';
|
|
50
|
+
setTimeout(() => {
|
|
51
|
+
btn.textContent = '复制';
|
|
52
|
+
}, 2000);
|
|
53
|
+
}
|
|
54
|
+
document.body.removeChild(textarea);
|
|
55
|
+
}
|
|
56
|
+
|
|
1
57
|
// Smooth scrolling
|
|
2
58
|
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
|
3
59
|
anchor.addEventListener('click', function (e) {
|
package/website/styles.css
CHANGED
|
@@ -69,14 +69,17 @@ nav {
|
|
|
69
69
|
.hero {
|
|
70
70
|
min-height: 100vh;
|
|
71
71
|
display: flex;
|
|
72
|
-
flex-direction: column;
|
|
73
|
-
justify-content: center;
|
|
74
72
|
align-items: center;
|
|
75
|
-
|
|
76
|
-
padding: 6rem 2rem
|
|
73
|
+
justify-content: center;
|
|
74
|
+
padding: 6rem 2rem;
|
|
77
75
|
background: linear-gradient(180deg, var(--bg-dark) 0%, var(--bg-card) 100%);
|
|
78
76
|
}
|
|
79
77
|
|
|
78
|
+
.hero-content {
|
|
79
|
+
text-align: center;
|
|
80
|
+
max-width: 600px;
|
|
81
|
+
}
|
|
82
|
+
|
|
80
83
|
.hero h1 {
|
|
81
84
|
font-size: 4rem;
|
|
82
85
|
font-weight: 800;
|
|
@@ -84,27 +87,112 @@ nav {
|
|
|
84
87
|
-webkit-background-clip: text;
|
|
85
88
|
-webkit-text-fill-color: transparent;
|
|
86
89
|
background-clip: text;
|
|
87
|
-
margin-bottom:
|
|
90
|
+
margin-bottom: 0.5rem;
|
|
88
91
|
}
|
|
89
92
|
|
|
90
93
|
.tagline {
|
|
91
94
|
font-size: 1.5rem;
|
|
92
95
|
color: var(--text-secondary);
|
|
93
|
-
margin-bottom:
|
|
96
|
+
margin-bottom: 2rem;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/* Install Box */
|
|
100
|
+
.install-box {
|
|
101
|
+
background: var(--bg-card);
|
|
102
|
+
border: 1px solid var(--border);
|
|
103
|
+
border-radius: 12px;
|
|
104
|
+
overflow: hidden;
|
|
105
|
+
margin: 0 auto 2rem;
|
|
106
|
+
text-align: left;
|
|
107
|
+
min-width: 600px;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.install-tabs {
|
|
111
|
+
display: flex;
|
|
112
|
+
background: var(--bg-dark);
|
|
113
|
+
border-bottom: 1px solid var(--border);
|
|
94
114
|
}
|
|
95
115
|
|
|
96
|
-
.
|
|
97
|
-
|
|
116
|
+
.install-tabs .tab {
|
|
117
|
+
flex: 1;
|
|
118
|
+
min-width: 100px;
|
|
119
|
+
padding: 0.75rem 1rem;
|
|
120
|
+
background: transparent;
|
|
121
|
+
border: none;
|
|
98
122
|
color: var(--text-secondary);
|
|
99
|
-
|
|
100
|
-
|
|
123
|
+
font-size: 0.9rem;
|
|
124
|
+
cursor: pointer;
|
|
125
|
+
transition: all 0.2s;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.install-tabs .tab:hover {
|
|
129
|
+
color: var(--text-primary);
|
|
130
|
+
background: rgba(255,255,255,0.03);
|
|
101
131
|
}
|
|
102
132
|
|
|
103
|
-
.
|
|
133
|
+
.install-tabs .tab.active {
|
|
134
|
+
color: var(--primary);
|
|
135
|
+
background: var(--bg-card);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.install-cmd {
|
|
104
139
|
display: flex;
|
|
140
|
+
align-items: center;
|
|
141
|
+
justify-content: space-between;
|
|
142
|
+
padding: 1rem 1.25rem;
|
|
105
143
|
gap: 1rem;
|
|
106
144
|
}
|
|
107
145
|
|
|
146
|
+
.install-cmd code {
|
|
147
|
+
font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;
|
|
148
|
+
font-size: 0.9rem;
|
|
149
|
+
color: var(--secondary);
|
|
150
|
+
flex: 1;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.copy-btn {
|
|
154
|
+
background: transparent;
|
|
155
|
+
color: var(--text-secondary);
|
|
156
|
+
border: 1px solid var(--border);
|
|
157
|
+
border-radius: 6px;
|
|
158
|
+
padding: 0.4rem 0.75rem;
|
|
159
|
+
font-size: 0.8rem;
|
|
160
|
+
cursor: pointer;
|
|
161
|
+
transition: all 0.2s;
|
|
162
|
+
white-space: nowrap;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.copy-btn:hover {
|
|
166
|
+
color: var(--text-primary);
|
|
167
|
+
border-color: var(--primary);
|
|
168
|
+
background: rgba(99, 102, 241, 0.1);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.copy-btn.copied {
|
|
172
|
+
color: #22c55e;
|
|
173
|
+
border-color: #22c55e;
|
|
174
|
+
background: rgba(34, 197, 94, 0.1);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/* Hero Links */
|
|
178
|
+
.hero-links {
|
|
179
|
+
display: flex;
|
|
180
|
+
justify-content: center;
|
|
181
|
+
gap: 1.5rem;
|
|
182
|
+
flex-wrap: wrap;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.hero-links a {
|
|
186
|
+
color: var(--text-secondary);
|
|
187
|
+
text-decoration: none;
|
|
188
|
+
font-size: 0.95rem;
|
|
189
|
+
transition: color 0.2s;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.hero-links a:hover {
|
|
193
|
+
color: var(--primary);
|
|
194
|
+
}
|
|
195
|
+
|
|
108
196
|
.btn {
|
|
109
197
|
padding: 0.75rem 1.5rem;
|
|
110
198
|
border-radius: 8px;
|
|
@@ -288,10 +376,39 @@ footer a:hover {
|
|
|
288
376
|
|
|
289
377
|
/* Responsive */
|
|
290
378
|
@media (max-width: 768px) {
|
|
379
|
+
.hero {
|
|
380
|
+
padding: 5rem 1rem 3rem;
|
|
381
|
+
min-height: auto;
|
|
382
|
+
}
|
|
383
|
+
|
|
291
384
|
.hero h1 {
|
|
292
385
|
font-size: 2.5rem;
|
|
293
386
|
}
|
|
294
387
|
|
|
388
|
+
.hero .tagline {
|
|
389
|
+
font-size: 1.2rem;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
.install-box {
|
|
393
|
+
min-width: auto;
|
|
394
|
+
width: 100%;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
.install-tabs .tab {
|
|
398
|
+
min-width: 80px;
|
|
399
|
+
padding: 0.6rem 0.5rem;
|
|
400
|
+
font-size: 0.8rem;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.install-cmd code {
|
|
404
|
+
font-size: 0.75rem;
|
|
405
|
+
word-break: break-all;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
.hero-links {
|
|
409
|
+
gap: 1rem;
|
|
410
|
+
}
|
|
411
|
+
|
|
295
412
|
.nav-links {
|
|
296
413
|
display: none;
|
|
297
414
|
}
|