foliko 1.1.68 → 1.1.69

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/.claude/settings.local.json +19 -10
  2. package/.dockerignore +45 -45
  3. package/.env.example +56 -56
  4. package/CLAUDE.md +2 -2
  5. package/README.md +13 -13
  6. package/SPEC.md +3 -3
  7. package/cli/src/commands/chat.js +2 -20
  8. package/cli/src/commands/list.js +7 -6
  9. package/cli/src/commands/plugin.js +3 -2
  10. package/cli/src/daemon.js +2 -2
  11. package/cli/src/ui/chat-ui-old.js +15 -4
  12. package/cli/src/ui/chat-ui.js +152 -38
  13. package/cli/src/ui/footer-bar.js +13 -14
  14. package/cli/src/utils/config.js +29 -0
  15. package/cli/src/utils/plugin-config.js +1 -1
  16. package/docker-compose.yml +33 -33
  17. package/docs/features.md +120 -120
  18. package/docs/quick-reference.md +160 -160
  19. package/docs/user-manual.md +1391 -1391
  20. package/examples/ambient-example.js +2 -2
  21. package/examples/bootstrap.js +3 -3
  22. package/examples/test-chat.js +1 -1
  23. package/examples/test-reload.js +1 -1
  24. package/examples/test-telegram.js +1 -1
  25. package/examples/test-tg-bot.js +1 -1
  26. package/examples/test-tg-simple.js +2 -2
  27. package/examples/test-tg.js +1 -1
  28. package/examples/test-think.js +1 -1
  29. package/examples/test-weixin-feishu.js +3 -3
  30. package/package.json +3 -1
  31. package/plugins/ambient-agent/index.js +1 -1
  32. package/plugins/audit-plugin.js +75 -24
  33. package/plugins/default-plugins.js +21 -11
  34. package/plugins/email/index.js +1 -1
  35. package/plugins/extension-executor-plugin.js +85 -7
  36. package/plugins/feishu-plugin.js +118 -16
  37. package/plugins/install-plugin.js +4 -4
  38. package/plugins/memory-plugin.js +1 -1
  39. package/plugins/plugin-manager-plugin.js +3 -3
  40. package/plugins/python-executor-plugin.js +1 -1
  41. package/plugins/python-plugin-loader.js +1 -1
  42. package/plugins/qq-plugin.js +143 -16
  43. package/plugins/rules-plugin.js +1 -1
  44. package/plugins/scheduler-plugin.js +2 -2
  45. package/plugins/session-plugin.js +309 -393
  46. package/plugins/storage-plugin.js +235 -176
  47. package/plugins/subagent-plugin.js +4 -4
  48. package/plugins/telegram-plugin.js +116 -17
  49. package/plugins/think-plugin.js +1 -1
  50. package/plugins/web-plugin.js +2 -2
  51. package/plugins/weixin-plugin.js +102 -19
  52. package/skills/find-skills/AGENTS.md +2 -2
  53. package/skills/find-skills/SKILL.md +133 -133
  54. package/skills/foliko-dev/AGENTS.md +236 -236
  55. package/skills/foliko-dev/SKILL.md +19 -19
  56. package/skills/mcp-usage/SKILL.md +200 -200
  57. package/skills/plugin-guide/SKILL.md +4 -4
  58. package/skills/python-plugin-dev/SKILL.md +5 -5
  59. package/skills/skill-guide/SKILL.md +104 -6
  60. package/skills/subagent-guide/SKILL.md +237 -237
  61. package/skills/workflow-guide/SKILL.md +646 -646
  62. package/src/capabilities/skill-manager.js +101 -2
  63. package/src/capabilities/workflow-engine.js +1 -1
  64. package/src/core/agent-chat.js +17 -14
  65. package/src/core/branch-summary-auto.js +206 -0
  66. package/src/core/chat-session.js +38 -8
  67. package/src/core/command-registry.js +200 -0
  68. package/src/core/constants.js +11 -11
  69. package/src/core/context-compressor.js +700 -149
  70. package/src/core/context-manager.js +0 -1
  71. package/src/core/enhanced-context-compressor.js +210 -0
  72. package/src/core/framework.js +140 -83
  73. package/src/core/jsonl-storage.js +253 -0
  74. package/src/core/plugin-manager.js +15 -10
  75. package/src/core/provider-registry.js +159 -0
  76. package/src/core/provider.js +2 -0
  77. package/src/core/session-entry.js +225 -0
  78. package/src/core/session-manager.js +701 -0
  79. package/src/core/storage-manager.js +494 -0
  80. package/src/core/sub-agent-config.js +1 -1
  81. package/src/core/token-counter.js +177 -58
  82. package/src/core/ui-extension-context.js +174 -0
  83. package/src/executors/mcp-executor.js +15 -6
  84. package/src/utils/logger.js +152 -180
  85. package/src/utils/plugin-helpers.js +2 -2
  86. package/website_v2/docs/api.html +1 -1
  87. package/website_v2/docs/configuration.html +2 -2
  88. package/website_v2/docs/plugin-development.html +4 -4
  89. package/website_v2/docs/project-structure.html +2 -2
  90. package/website_v2/docs/skill-development.html +2 -2
  91. package/website_v2/index.html +1 -1
  92. package/website_v2/styles/animations.css +7 -7
  93. package/.agent/agents/backend-dev.md +0 -102
  94. package/.agent/agents/data-analyst.md +0 -117
  95. package/.agent/agents/devops.md +0 -115
  96. package/.agent/agents/frontend-dev.md +0 -94
  97. package/.agent/agents/network-requester.md +0 -44
  98. package/.agent/agents/poster-designer.md +0 -52
  99. package/.agent/agents/product-manager.md +0 -85
  100. package/.agent/agents/qa-engineer.md +0 -100
  101. package/.agent/agents/security-engineer.md +0 -99
  102. package/.agent/agents/team-lead.md +0 -137
  103. package/.agent/agents/ui-designer.md +0 -116
  104. package/.agent/data/default.json +0 -58
  105. package/.agent/data/email/processed-emails.json +0 -1
  106. package/.agent/data/plugins-state.json +0 -207
  107. package/.agent/data/scheduler/tasks.json +0 -1
  108. package/.agent/data/web/web-config.json +0 -5
  109. package/.agent/data/weixin/images/file_1776188148383jpg +0 -0
  110. package/.agent/data/weixin/images/file_1776188458326.jpg +0 -0
  111. package/.agent/data/weixin/images/file_1776188689423.jpg +0 -0
  112. package/.agent/data/weixin/images/file_1776188813604.jpg +0 -0
  113. package/.agent/data/weixin/images/file_1776189097450.jpg +0 -0
  114. package/.agent/data/weixin/videos/file_1776188318431.mp4 +0 -0
  115. package/.agent/data/weixin.json +0 -6
  116. package/.agent/mcp_config.json +0 -14
  117. package/.agent/memory/user/mof6gk94-kneeuh.md +0 -9
  118. package/.agent/package.json +0 -8
  119. package/.agent/plugins/marknative/README.md +0 -134
  120. package/.agent/plugins/marknative/fonts/SegoeUI Emoji.ttf +0 -0
  121. package/.agent/plugins/marknative/fonts.zip +0 -0
  122. package/.agent/plugins/marknative/index.js +0 -256
  123. package/.agent/plugins/marknative/package.json +0 -12
  124. package/.agent/plugins/test-plugin.py +0 -99
  125. package/.agent/plugins.json +0 -14
  126. package/.agent/python-scripts/test_sample.py +0 -24
  127. package/.agent/sessions/cli_default.json +0 -4121
  128. package/.agent/skills/agent-browser/SKILL.md +0 -311
  129. package/.agent/skills/agent-browser/TEST_PLAN.md +0 -200
  130. package/.agent/skills/sysinfo/SKILL.md +0 -38
  131. package/.agent/skills/sysinfo/system-info.sh +0 -130
  132. package/.agent/skills/workflow/SKILL.md +0 -324
  133. package/.agent/test-agent.js +0 -35
  134. package/.agent/weixin.json +0 -6
  135. package/.agent/workflows/email-digest.json +0 -50
  136. package/.agent/workflows/file-backup.json +0 -21
  137. package/.agent/workflows/get-ip-notify.json +0 -32
  138. package/.agent/workflows/news-aggregator.json +0 -93
  139. package/.agent/workflows/news-dashboard-v2.json +0 -94
  140. package/.agent/workflows/notification-batch.json +0 -32
  141. package/src/core/session-context.js +0 -346
  142. package/src/core/session-storage.js +0 -295
@@ -15,7 +15,7 @@ async function main() {
15
15
 
16
16
  // Bootstrap with default plugins (including ambient)
17
17
  await framework.bootstrap({
18
- agentDir: './.agent',
18
+ agentDir: './.foliko',
19
19
  aiConfig: {
20
20
  provider: 'deepseek',
21
21
  model: 'deepseek-chat',
@@ -181,7 +181,7 @@ async function main() {
181
181
  }
182
182
 
183
183
  console.log('\n=== All Examples Completed ===');
184
- console.log('Check .agent/data/ambient/ for persisted data');
184
+ console.log('Check .foliko/data/ambient/ for persisted data');
185
185
 
186
186
  // Cleanup
187
187
  console.log('\nShutting down...');
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Bootstrap 示例
3
- * 使用 framework.bootstrap() 自动加载 .agent/ 目录配置
3
+ * 使用 framework.bootstrap() 自动加载 .foliko/ 目录配置
4
4
  */
5
5
 
6
6
  const { Framework } = require('../src');
@@ -13,9 +13,9 @@ async function main() {
13
13
  const framework = new Framework({ debug: true });
14
14
 
15
15
  // 使用 bootstrap 自动加载所有默认插件
16
- // 会自动检测 .agent/ 目录下的配置
16
+ // 会自动检测 .foliko/ 目录下的配置
17
17
  await framework.bootstrap({
18
- agentDir: './.agent', // 配置目录
18
+ agentDir: './.foliko', // 配置目录
19
19
  aiConfig: {
20
20
  // 可选:覆盖 AI 配置
21
21
  provider: 'deepseek',
@@ -18,7 +18,7 @@ async function main() {
18
18
 
19
19
  // Bootstrap
20
20
  await framework.bootstrap({
21
- agentDir: './.agent',
21
+ agentDir: './.foliko',
22
22
  aiConfig: {
23
23
  provider: 'minimax',
24
24
  model: 'MiniMax-M2.7',
@@ -37,7 +37,7 @@ async function test() {
37
37
 
38
38
  // 检查配置
39
39
  console.log('\n3. 当前配置文件:');
40
- const configPath = path.resolve('.agent/mcp_config.json');
40
+ const configPath = path.resolve('.foliko/mcp_config.json');
41
41
  if (fs.existsSync(configPath)) {
42
42
  const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
43
43
  console.log(JSON.stringify(config, null, 2));
@@ -5,7 +5,7 @@ async function main() {
5
5
  const framework = new Framework({ debug: false });
6
6
 
7
7
  await framework.bootstrap({
8
- agentDir: process.cwd() + '/.agent',
8
+ agentDir: process.cwd() + '/.foliko',
9
9
  aiConfig: {
10
10
  provider: process.env.FOLIKO_PROVIDER || 'minimax',
11
11
  model: process.env.FOLIKO_MODEL || 'MiniMax-M2.7',
@@ -7,7 +7,7 @@ async function main() {
7
7
  const framework = new Framework({ debug: false });
8
8
 
9
9
  await framework.bootstrap({
10
- agentDir: process.cwd() + '/.agent',
10
+ agentDir: process.cwd() + '/.foliko',
11
11
  aiConfig: {
12
12
  provider: process.env.FOLIKO_PROVIDER || 'minimax',
13
13
  model: process.env.FOLIKO_MODEL || 'MiniMax-M2.7',
@@ -1,8 +1,8 @@
1
1
  require('dotenv').config();
2
2
 
3
- // 添加 .agent/node_modules 到搜索路径
3
+ // 添加 .foliko/node_modules 到搜索路径
4
4
  const path = require('path');
5
- const agentNodeModules = path.join(process.cwd(), '.agent', 'node_modules');
5
+ const agentNodeModules = path.join(process.cwd(), '.foliko', 'node_modules');
6
6
  if (!module.paths.includes(agentNodeModules)) {
7
7
  module.paths.unshift(agentNodeModules);
8
8
  }
@@ -5,7 +5,7 @@ async function main() {
5
5
  const framework = new Framework({ debug: true });
6
6
 
7
7
  await framework.bootstrap({
8
- agentDir: process.cwd() + '/.agent',
8
+ agentDir: process.cwd() + '/.foliko',
9
9
  aiConfig: {
10
10
  provider: process.env.FOLIKO_PROVIDER || 'minimax',
11
11
  model: process.env.FOLIKO_MODEL || 'MiniMax-M2.7',
@@ -5,7 +5,7 @@ async function main() {
5
5
  const framework = new Framework({ debug: false });
6
6
 
7
7
  await framework.bootstrap({
8
- agentDir: process.cwd() + '/.agent',
8
+ agentDir: process.cwd() + '/.foliko',
9
9
  aiConfig: {
10
10
  provider: process.env.FOLIKO_PROVIDER || 'minimax',
11
11
  model: process.env.FOLIKO_MODEL || 'MiniMax-M2.7',
@@ -12,7 +12,7 @@ async function main() {
12
12
 
13
13
  // Bootstrap 加载默认插件
14
14
  await framework.bootstrap({
15
- agentDir: './.agent',
15
+ agentDir: './.foliko',
16
16
  aiConfig: {
17
17
  provider: 'deepseek',
18
18
  model: 'deepseek-chat',
@@ -68,7 +68,7 @@ async function main() {
68
68
 
69
69
  try {
70
70
  // 使用 chat() 而非 chatStream()
71
- const result = await sessionInfo.agent.chat(mockText, {
71
+ const result = await sessionInfo.foliko.chat(mockText, {
72
72
  sessionId: sessionInfo.sessionId,
73
73
  });
74
74
 
@@ -83,7 +83,7 @@ async function main() {
83
83
  console.log('\n--- Test chatStream() for comparison ---');
84
84
  try {
85
85
  let fullResponse = '';
86
- for await (const chunk of sessionInfo.agent.chatStream('今天天气怎么样?', {
86
+ for await (const chunk of sessionInfo.foliko.chatStream('今天天气怎么样?', {
87
87
  sessionId: sessionInfo.sessionId,
88
88
  })) {
89
89
  if (chunk.type === 'text' && chunk.text) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foliko",
3
- "version": "1.1.68",
3
+ "version": "1.1.69",
4
4
  "description": "简约的插件化 Agent 框架",
5
5
  "main": "src/index.js",
6
6
  "type": "commonjs",
@@ -81,6 +81,8 @@
81
81
  "node-schedule": "^2.1.1",
82
82
  "node-telegram-bot-api": "^0.67.0",
83
83
  "nodemailer": "^6.10.0",
84
+ "pino": "^10.3.1",
85
+ "pino-pretty": "^13.1.3",
84
86
  "qrcode-terminal": "^0.12.0",
85
87
  "remove-markdown": "^0.6.3",
86
88
  "zod": "^3.25.76"
@@ -32,7 +32,7 @@ class AmbientAgentPlugin extends Plugin {
32
32
  enabled: config.enabled !== false,
33
33
  tickInterval: config.tickInterval || 5000, // tick间隔(毫秒)
34
34
  cooldownPeriod: config.cooldownPeriod || 3000, // 冷却时间(毫秒)
35
- persistencePath: config.persistencePath || '.agent/data/ambient',
35
+ persistencePath: config.persistencePath || '.foliko/data/ambient',
36
36
  defaultGoals: config.defaultGoals || []
37
37
  }
38
38
 
@@ -1,36 +1,72 @@
1
1
  /**
2
2
  * Audit 审计日志插件
3
3
  * 记录所有操作日志,支持日志查询和统计
4
+ * 基于 Pino 日志系统
4
5
  */
5
6
 
6
7
  const { Plugin } = require('../src/core/plugin-base')
8
+ const { logger } = require('../src/utils/logger')
7
9
  const { z } = require('zod')
10
+ const path = require('path')
11
+ const fs = require('fs')
12
+ const os = require('os')
8
13
 
9
14
  class AuditPlugin extends Plugin {
10
15
  constructor(config = {}) {
11
16
  super()
12
17
  this.name = 'audit'
13
- this.version = '1.0.0'
18
+ this.version = '2.0.0'
14
19
  this.description = '审计日志插件,记录工具调用、技能执行、错误信息等操作历史'
15
20
  this.priority = 20
16
- this.system = true
21
+ this.system = true
17
22
 
18
23
  this.config = {
19
24
  maxLogs: config.maxLogs || 1000,
20
25
  retentionDays: config.retentionDays || 30,
21
- logDir: config.logDir || '.agent/logs'
26
+ logDir: config.logDir || path.join(os.homedir(), '.vb-agent', 'logs', 'audit')
22
27
  }
23
28
 
24
29
  this._framework = null
25
- this._logs = []
26
30
  this._logIdCounter = 0
31
+ this._auditLogger = null
32
+ this._auditLogFile = null
33
+ this._queryLogs = [] // 内存缓存用于查询
34
+ this._initAuditLogger()
35
+ }
36
+
37
+ /**
38
+ * 初始化审计日志器
39
+ */
40
+ _initAuditLogger() {
41
+ const pino = require('pino')
42
+
43
+ // 确保目录存在
44
+ if (!fs.existsSync(this.config.logDir)) {
45
+ fs.mkdirSync(this.config.logDir, { recursive: true })
46
+ }
47
+
48
+ // 审计日志文件名
49
+ const date = new Date().toISOString().split('T')[0]
50
+ this._auditLogFile = path.join(this.config.logDir, `audit-${date}.jsonl`)
51
+
52
+ // 创建文件写入流
53
+ const fileStream = fs.createWriteStream(this._auditLogFile, { flags: 'a' })
54
+
55
+ // 创建专门的审计 logger
56
+ this._auditLogger = pino({
57
+ name: 'audit',
58
+ level: 'info',
59
+ timestamp: pino.stdTimeFunctions.isoTime,
60
+ formatters: {
61
+ level: (label) => label.toUpperCase(),
62
+ },
63
+ }, fileStream)
27
64
  }
28
65
 
29
66
  install(framework) {
30
67
  this._framework = framework
31
68
 
32
69
  // 监听框架事件
33
- // tool:call 和 tool-call 两种格式都监听(兼容不同来源)
34
70
  framework.on('tool:call', (data) => this._log('tool_call', data))
35
71
  framework.on('tool-call', (data) => this._log('tool_call', data))
36
72
  framework.on('tool:result', (data) => this._log('tool_result', data))
@@ -51,10 +87,11 @@ class AuditPlugin extends Plugin {
51
87
  offset: z.number().optional().describe('偏移量,默认 0')
52
88
  }),
53
89
  execute: async (args) => {
54
- let logs = this._logs
90
+ const logs = this._queryLogs
55
91
 
92
+ let filtered = logs
56
93
  if (args.type) {
57
- logs = logs.filter(log => log.type === args.type)
94
+ filtered = filtered.filter(log => log.type === args.type)
58
95
  }
59
96
 
60
97
  const offset = args.offset || 0
@@ -62,9 +99,9 @@ class AuditPlugin extends Plugin {
62
99
 
63
100
  return {
64
101
  success: true,
65
- data: logs.slice(-limit - offset, logs.length - offset),
102
+ data: filtered.slice(-limit - offset, filtered.length - offset),
66
103
  metadata: {
67
- total: logs.length,
104
+ total: filtered.length,
68
105
  offset,
69
106
  limit
70
107
  }
@@ -111,21 +148,30 @@ class AuditPlugin extends Plugin {
111
148
 
112
149
  /**
113
150
  * 记录日志
114
- * @private
115
151
  */
116
152
  _log(type, data) {
117
153
  const log = {
118
154
  id: ++this._logIdCounter,
119
155
  type,
120
156
  data,
121
- timestamp: new Date()
157
+ timestamp: new Date().toISOString()
122
158
  }
123
159
 
124
- this._logs.push(log)
160
+ // 写入审计日志文件
161
+ if (this._auditLogger) {
162
+ this._auditLogger.info({
163
+ auditId: log.id,
164
+ auditType: log.type,
165
+ auditData: log.data
166
+ }, 'audit event')
167
+ }
125
168
 
126
- // 限制日志数量
127
- if (this._logs.length > this.config.maxLogs) {
128
- this._logs = this._logs.slice(-this.config.maxLogs)
169
+ // 缓存到内存用于查询
170
+ this._queryLogs.push(log)
171
+
172
+ // 限制缓存数量
173
+ if (this._queryLogs.length > this.config.maxLogs) {
174
+ this._queryLogs = this._queryLogs.slice(-this.config.maxLogs)
129
175
  }
130
176
 
131
177
  return log
@@ -136,16 +182,17 @@ class AuditPlugin extends Plugin {
136
182
  */
137
183
  getStats() {
138
184
  const counts = {}
139
- for (const log of this._logs) {
185
+ for (const log of this._queryLogs) {
140
186
  counts[log.type] = (counts[log.type] || 0) + 1
141
187
  }
142
188
 
143
189
  return {
144
- total: this._logs.length,
190
+ total: this._queryLogs.length,
145
191
  maxLogs: this.config.maxLogs,
146
192
  counts,
147
- oldest: this._logs.length > 0 ? this._logs[0].timestamp : null,
148
- newest: this._logs.length > 0 ? this._logs[this._logs.length - 1].timestamp : null
193
+ oldest: this._queryLogs.length > 0 ? this._queryLogs[0].timestamp : null,
194
+ newest: this._queryLogs.length > 0 ? this._queryLogs[this._queryLogs.length - 1].timestamp : null,
195
+ logFile: this._auditLogFile
149
196
  }
150
197
  }
151
198
 
@@ -153,7 +200,7 @@ class AuditPlugin extends Plugin {
153
200
  * 导出日志
154
201
  */
155
202
  exportLogs(options = {}) {
156
- let logs = [...this._logs]
203
+ let logs = [...this._queryLogs]
157
204
 
158
205
  // 按类型过滤
159
206
  if (options.type) {
@@ -163,12 +210,12 @@ class AuditPlugin extends Plugin {
163
210
  // 按日期过滤
164
211
  if (options.startDate) {
165
212
  const start = new Date(options.startDate)
166
- logs = logs.filter(log => log.timestamp >= start)
213
+ logs = logs.filter(log => new Date(log.timestamp) >= start)
167
214
  }
168
215
 
169
216
  if (options.endDate) {
170
217
  const end = new Date(options.endDate)
171
- logs = logs.filter(log => log.timestamp <= end)
218
+ logs = logs.filter(log => new Date(log.timestamp) <= end)
172
219
  }
173
220
 
174
221
  return { logs }
@@ -186,9 +233,13 @@ class AuditPlugin extends Plugin {
186
233
  }
187
234
 
188
235
  uninstall(framework) {
189
- this._logs = []
236
+ this._queryLogs = []
237
+ if (this._auditLogger) {
238
+ // 关闭文件流
239
+ }
240
+ this._auditLogger = null
190
241
  this._framework = null
191
242
  }
192
243
  }
193
244
 
194
- module.exports = AuditPlugin
245
+ module.exports = AuditPlugin
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * 默认插件配置加载器
3
- * 检测 .agent/ 目录下的配置,提供给 bootstrap() 使用
3
+ * 检测 .foliko/ 目录下的配置,提供给 bootstrap() 使用
4
4
  */
5
5
 
6
6
  const fs = require('fs')
@@ -11,10 +11,10 @@ const log = logger.child('AgentConfig')
11
11
  const bootstrapLog = logger.child('Bootstrap')
12
12
 
13
13
  /**
14
- * 加载 .agent 目录下的配置
14
+ * 加载 .foliko 目录下的配置
15
15
  * 返回配置对象,可用于手动加载插件
16
16
  */
17
- function loadAgentConfig(agentDir = '.agent') {
17
+ function loadAgentConfig(agentDir = '.foliko') {
18
18
  const config = {
19
19
  agentDir,
20
20
  ai: {},
@@ -28,7 +28,7 @@ function loadAgentConfig(agentDir = '.agent') {
28
28
  const resolvedDir = path.resolve(process.cwd(), agentDir)
29
29
 
30
30
  if (!fs.existsSync(resolvedDir)) {
31
- log.info(` .agent directory not found: ${resolvedDir}`)
31
+ log.info(` .foliko directory not found: ${resolvedDir}`)
32
32
  return config
33
33
  }
34
34
 
@@ -136,7 +136,7 @@ function loadAgentConfig(agentDir = '.agent') {
136
136
  }
137
137
  }
138
138
 
139
- // 添加 .agent/skills 目录(不存在则创建)
139
+ // 添加 .foliko/skills 目录(不存在则创建)
140
140
  const skillsDir = path.join(resolvedDir, 'skills')
141
141
  if (fs.existsSync(resolvedDir) && !fs.existsSync(skillsDir)) {
142
142
  fs.mkdirSync(skillsDir, { recursive: true })
@@ -146,7 +146,7 @@ function loadAgentConfig(agentDir = '.agent') {
146
146
  config.skillsDirs.push(skillsDir)
147
147
  }
148
148
 
149
- // 添加 .agent/skills 目录(不存在则创建)
149
+ // 添加 .foliko/skills 目录(不存在则创建)
150
150
  const cmdskillsDir = path.join(cmdDir, 'skills')
151
151
  if (fs.existsSync(resolvedDir) && !fs.existsSync(cmdskillsDir)) {
152
152
  fs.mkdirSync(cmdskillsDir, { recursive: true })
@@ -184,7 +184,7 @@ class DefaultPlugins extends Plugin {
184
184
  this.system = true
185
185
 
186
186
  this._framework = null
187
- this._agentDir = config.agentDir || '.agent'
187
+ this._agentDir = config.agentDir || '.foliko'
188
188
  this._config = null
189
189
  }
190
190
 
@@ -364,6 +364,16 @@ async function bootstrapDefaults(framework, config = {}) {
364
364
  }
365
365
  }
366
366
 
367
+ // 6. 大数据分拆插件
368
+ if (shouldLoad('data-splitter')) {
369
+ const { DataSplitterPlugin } = require('./data-splitter-plugin')
370
+ await framework.loadPlugin(new DataSplitterPlugin({
371
+ autoSplitThreshold: agentConfig.dataSplitter?.autoSplitThreshold || 50000,
372
+ chunkSize: agentConfig.dataSplitter?.chunkSize || 60000,
373
+ maxConcurrent: agentConfig.dataSplitter?.maxConcurrent || 3,
374
+ }))
375
+ framework._debug&&bootstrapLog.debug(' DataSplitter Plugin loaded')
376
+ }
367
377
 
368
378
  // 7. 自动加载 plugins/ 目录下的所有插件
369
379
  await loadCustomPlugins(framework, agentConfig)
@@ -383,8 +393,8 @@ async function bootstrapDefaults(framework, config = {}) {
383
393
  /**
384
394
  * 解析插件路径
385
395
  * 支持两种结构:
386
- * 1. 文件夹结构: .agent/plugins/my-plugin/index.js
387
- * 2. 单文件结构: .agent/plugins/my-plugin.js
396
+ * 1. 文件夹结构: .foliko/plugins/my-plugin/index.js
397
+ * 2. 单文件结构: .foliko/plugins/my-plugin.js
388
398
  * 支持符号链接
389
399
  * @param {string} pluginsDir - 插件目录
390
400
  * @param {string} name - 插件名称
@@ -502,10 +512,10 @@ async function loadCustomPlugins(framework, agentConfig) {
502
512
  const { Plugin } = require('../src/core/plugin-base')
503
513
 
504
514
  // 加载两个目录下的自定义插件:
505
- // 1. .agent/plugins/ - 用户自定义插件(强制启用)
515
+ // 1. .foliko/plugins/ - 用户自定义插件(强制启用)
506
516
  // 2. plugins/ - 项目内置插件(自动加载)
507
517
  const dirs = [
508
- { dir: path.resolve(process.cwd(), '.agent', 'plugins'), forceEnabled: true },
518
+ { dir: path.resolve(process.cwd(), '.foliko', 'plugins'), forceEnabled: true },
509
519
  { dir: path.resolve(process.cwd(), 'plugins'), forceEnabled: false },
510
520
  { dir: path.resolve(__dirname, '..', 'plugins'), forceEnabled: false }
511
521
  // 项目下的 plugins 目录(兼容旧版本)
@@ -94,7 +94,7 @@ class EmailPlugin extends Plugin {
94
94
 
95
95
  // 持久化存储
96
96
  this._emailStore = null
97
- this._persistencePath = config.persistencePath || '.agent/data/email/processed-emails.json'
97
+ this._persistencePath = config.persistencePath || '.foliko/data/email/processed-emails.json'
98
98
 
99
99
  // 防抖相关
100
100
  this._emailDebounceMap = new Map() // msgId -> timer
@@ -6,6 +6,7 @@
6
6
  const { Plugin } = require('../src/core/plugin-base');
7
7
  const { logger } = require('../src/utils/logger');
8
8
  const { z } = require('zod');
9
+ const { PROMPT_PRIORITY } = require('../src/core/constants');
9
10
  const { zodSchemaToMarkdown,zodSchemaToTable } = require('@chnak/zod-to-markdown');
10
11
 
11
12
  const log = logger.child('ExtensionExecutor');
@@ -268,7 +269,7 @@ class ExtensionExecutorPlugin extends Plugin {
268
269
  }
269
270
 
270
271
  // 注册扩展插件的提示词部分(使用基类方法)
271
- this.registerPromptPart('extension-tools', 70, () => this._buildExtensionsDescription());
272
+ this.registerPromptPart('extension-tools', PROMPT_PRIORITY.EXTENSION_TOOLS, () => this._buildExtensionsDescription());
272
273
 
273
274
  return this;
274
275
  }
@@ -391,14 +392,41 @@ class ExtensionExecutorPlugin extends Plugin {
391
392
  if (this._extensions.size > 0 || (this._mcpExecutor && Object.keys(this._mcpExecutor.tools || {}).length > 0)) {
392
393
  desc += '## 【Extensions】扩展插件\n\n';
393
394
  desc += '**使用流程(必须按顺序执行):**\n';
394
- desc += '1. 调用 `ext_skill({ skill: "插件名" })` 获取目标扩展的详细工具参数\n';
395
- desc += '2. 根据返回的参数定义,使用 `ext_call({ plugin, tool, args })` 调用扩展\n\n';
395
+ desc += '1. 调用 `ext_skill({ plugin: "skill" })` 获取技能命令的详细参数\n';
396
+ desc += '2. 根据返回的参数定义,使用 `ext_call({ plugin: "skill", tool: "技能名:命令名", args: {...} })` 调用\n\n';
396
397
  desc += '> **警告**:禁止在未执行第1步获取参数的情况下直接调用 `ext_call`!\n\n';
397
398
 
398
399
  for (const [name, ext] of this._extensions) {
399
- desc += `### ${ext.name || name}\n`;
400
- desc += `${ext.description || '无描述'}\n`;
401
- desc += `**工具:** ${ext.tools.map(t => `\`${t.name}\``).join(', ')}\n\n`;
400
+ if (name === 'skill') {
401
+ // Skill 命令按技能名分组显示
402
+ const toolsBySkill = {};
403
+ for (const tool of ext.tools) {
404
+ // 命令格式: skillname:cmdname
405
+ const parts = tool.name.split(':');
406
+ const skillName = parts[0];
407
+ const cmdName = parts.slice(1).join(':');
408
+ if (!toolsBySkill[skillName]) {
409
+ toolsBySkill[skillName] = [];
410
+ }
411
+ toolsBySkill[skillName].push({ name: cmdName, description: tool.description });
412
+ }
413
+
414
+ for (const [skillName, cmds] of Object.entries(toolsBySkill)) {
415
+ desc += `### skill.${skillName}\n`;
416
+ desc += `**调用方式:**\n`;
417
+ desc += `1. 先调用 \`loadSkill({ skill: "${skillName}" })\` 获取 \`${skillName}\` 技能的详细参数\n`;
418
+ desc += `2. 调用 \`ext_call({ plugin: "skill", tool: "${skillName}:<命令名>", args: { args: "参数" } })\`\n\n`;
419
+ desc += `**可用命令:**\n`;
420
+ for (const c of cmds) {
421
+ desc += `- \`${c.name}\`: ${c.description}\n`;
422
+ }
423
+ desc += '\n';
424
+ }
425
+ } else {
426
+ desc += `### ${ext.name || name}\n`;
427
+ desc += `${ext.description || '无描述'}\n`;
428
+ desc += `**工具:** ${ext.tools.map(t => `\`${t.name}\``).join(', ')}\n\n`;
429
+ }
402
430
  }
403
431
 
404
432
  // MCP 服务器工具
@@ -534,6 +562,56 @@ class ExtensionExecutorPlugin extends Plugin {
534
562
  }));
535
563
  }
536
564
 
565
+ /**
566
+ * 获取 skill 命令列表(用于 autocomplete)
567
+ */
568
+ getSkillCommands() {
569
+ const ext = this._extensions.get('skill');
570
+ if (!ext) return [];
571
+ return ext.tools.map(t => ({
572
+ name: t.name.replace(/^([^:]+):(.*)$/, '$1:$2'),
573
+ description: t.description || t.name,
574
+ }));
575
+ }
576
+
577
+ /**
578
+ * 获取 skill 命令帮助文本
579
+ */
580
+ getSkillCommandsHelp() {
581
+ const ext = this._extensions.get('skill');
582
+ if (!ext || ext.tools.length === 0) return '';
583
+
584
+ const lines = [];
585
+ for (const tool of ext.tools) {
586
+ const parts = tool.name.split(':');
587
+ if (parts.length === 2) {
588
+ lines.push(`/${parts[0]}:${parts[1]} - ${tool.description || '无描述'}`);
589
+ }
590
+ }
591
+ return lines.join('\n');
592
+ }
593
+
594
+ /**
595
+ * 检查并执行 skill 命令
596
+ * @param {string} command - 命令名(如 "skillname:cmdname")
597
+ * @param {string} args - 命令参数
598
+ * @returns {Promise<object|null>} 执行结果,失败返回 null
599
+ */
600
+ async executeSkillCommand(command, args) {
601
+ if (!command.includes(':')) return null;
602
+ try {
603
+ const result = await this._framework.executeTool('ext_call', {
604
+ plugin: 'skill',
605
+ tool: command,
606
+ args: { args }
607
+ });
608
+ return result.success !== false ? result : null;
609
+ } catch (err) {
610
+ log.warn('Skill command failed:', err.message);
611
+ return null;
612
+ }
613
+ }
614
+
537
615
  async reload(framework) {
538
616
  this._framework = framework;
539
617
  // 重新扫描所有已加载插件的 tools
@@ -559,7 +637,7 @@ class ExtensionExecutorPlugin extends Plugin {
559
637
  if (!mcpExecutor) return;
560
638
 
561
639
  try {
562
- const configPath = path.resolve('.agent/mcp_config.json');
640
+ const configPath = path.resolve('.foliko/mcp_config.json');
563
641
  if (fs.existsSync(configPath)) {
564
642
  const configContent = fs.readFileSync(configPath, 'utf8');
565
643
  const config = JSON.parse(configContent);