foliko 1.1.67 → 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 (157) 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 +236 -203
  13. package/cli/src/ui/footer-bar.js +20 -46
  14. package/cli/src/ui/message-bubble.js +24 -2
  15. package/cli/src/ui/status-bar.js +177 -0
  16. package/cli/src/utils/config.js +29 -0
  17. package/cli/src/utils/plugin-config.js +1 -1
  18. package/docker-compose.yml +33 -33
  19. package/docs/features.md +120 -120
  20. package/docs/quick-reference.md +160 -160
  21. package/docs/user-manual.md +1391 -1391
  22. package/examples/ambient-example.js +2 -2
  23. package/examples/bootstrap.js +3 -3
  24. package/examples/test-chat.js +1 -1
  25. package/examples/test-reload.js +1 -1
  26. package/examples/test-telegram.js +1 -1
  27. package/examples/test-tg-bot.js +1 -1
  28. package/examples/test-tg-simple.js +2 -2
  29. package/examples/test-tg.js +1 -1
  30. package/examples/test-think.js +1 -1
  31. package/examples/test-weixin-feishu.js +3 -3
  32. package/package.json +3 -1
  33. package/plugins/ambient-agent/index.js +1 -1
  34. package/plugins/audit-plugin.js +84 -29
  35. package/plugins/coordinator-plugin.js +14 -12
  36. package/plugins/data-splitter-plugin.js +323 -0
  37. package/plugins/default-plugins.js +23 -12
  38. package/plugins/email/index.js +1 -1
  39. package/plugins/extension-executor-plugin.js +87 -9
  40. package/plugins/feishu-plugin.js +118 -16
  41. package/plugins/file-system-plugin.js +68 -50
  42. package/plugins/gate-trading.js +10 -10
  43. package/plugins/install-plugin.js +7 -7
  44. package/plugins/memory-plugin.js +9 -12
  45. package/plugins/plugin-manager-plugin.js +12 -14
  46. package/plugins/python-executor-plugin.js +1 -1
  47. package/plugins/python-plugin-loader.js +1 -1
  48. package/plugins/qq-plugin.js +151 -24
  49. package/plugins/rules-plugin.js +8 -8
  50. package/plugins/scheduler-plugin.js +24 -20
  51. package/plugins/session-plugin.js +313 -397
  52. package/plugins/storage-plugin.js +235 -175
  53. package/plugins/subagent-plugin.js +17 -13
  54. package/plugins/telegram-plugin.js +116 -17
  55. package/plugins/think-plugin.js +64 -60
  56. package/plugins/tools-plugin.js +8 -8
  57. package/plugins/web-plugin.js +2 -2
  58. package/plugins/weixin-plugin.js +107 -24
  59. package/skills/find-skills/AGENTS.md +2 -2
  60. package/skills/find-skills/SKILL.md +133 -133
  61. package/skills/foliko-dev/AGENTS.md +236 -236
  62. package/skills/foliko-dev/SKILL.md +19 -19
  63. package/skills/mcp-usage/SKILL.md +200 -200
  64. package/skills/plugin-guide/SKILL.md +4 -4
  65. package/skills/python-plugin-dev/SKILL.md +5 -5
  66. package/skills/skill-guide/SKILL.md +104 -6
  67. package/skills/subagent-guide/SKILL.md +237 -237
  68. package/skills/workflow-guide/SKILL.md +646 -646
  69. package/src/capabilities/skill-manager.js +124 -17
  70. package/src/capabilities/workflow-engine.js +3 -3
  71. package/src/core/agent-chat.js +72 -26
  72. package/src/core/agent.js +17 -27
  73. package/src/core/branch-summary-auto.js +206 -0
  74. package/src/core/chat-session.js +45 -169
  75. package/src/core/command-registry.js +200 -0
  76. package/src/core/constants.js +198 -0
  77. package/src/core/context-compressor.js +702 -326
  78. package/src/core/context-manager.js +0 -1
  79. package/src/core/enhanced-context-compressor.js +210 -0
  80. package/src/core/framework.js +260 -84
  81. package/src/core/jsonl-storage.js +253 -0
  82. package/src/core/plugin-base.js +7 -5
  83. package/src/core/plugin-manager.js +15 -10
  84. package/src/core/provider-registry.js +159 -0
  85. package/src/core/provider.js +2 -0
  86. package/src/core/session-entry.js +225 -0
  87. package/src/core/session-manager.js +701 -0
  88. package/src/core/storage-manager.js +494 -0
  89. package/src/core/sub-agent-config.js +1 -1
  90. package/src/core/subagent.js +16 -135
  91. package/src/core/token-counter.js +177 -58
  92. package/src/core/tool-executor.js +2 -70
  93. package/src/core/ui-extension-context.js +174 -0
  94. package/src/executors/mcp-executor.js +27 -16
  95. package/src/utils/chat-queue.js +11 -22
  96. package/src/utils/data-splitter.js +345 -0
  97. package/src/utils/logger.js +152 -180
  98. package/src/utils/message-validator.js +283 -0
  99. package/src/utils/plugin-helpers.js +2 -2
  100. package/src/utils/retry.js +168 -22
  101. package/website_v2/docs/api.html +1 -1
  102. package/website_v2/docs/configuration.html +2 -2
  103. package/website_v2/docs/plugin-development.html +4 -4
  104. package/website_v2/docs/project-structure.html +2 -2
  105. package/website_v2/docs/skill-development.html +2 -2
  106. package/website_v2/index.html +1 -1
  107. package/website_v2/styles/animations.css +7 -7
  108. package/.agent/agents/backend-dev.md +0 -102
  109. package/.agent/agents/data-analyst.md +0 -117
  110. package/.agent/agents/devops.md +0 -115
  111. package/.agent/agents/frontend-dev.md +0 -94
  112. package/.agent/agents/network-requester.md +0 -44
  113. package/.agent/agents/poster-designer.md +0 -52
  114. package/.agent/agents/product-manager.md +0 -85
  115. package/.agent/agents/qa-engineer.md +0 -100
  116. package/.agent/agents/security-engineer.md +0 -99
  117. package/.agent/agents/team-lead.md +0 -137
  118. package/.agent/agents/ui-designer.md +0 -116
  119. package/.agent/data/default.json +0 -58
  120. package/.agent/data/email/processed-emails.json +0 -1
  121. package/.agent/data/plugins-state.json +0 -199
  122. package/.agent/data/scheduler/tasks.json +0 -1
  123. package/.agent/data/web/web-config.json +0 -5
  124. package/.agent/data/weixin/images/file_1776188148383jpg +0 -0
  125. package/.agent/data/weixin/images/file_1776188458326.jpg +0 -0
  126. package/.agent/data/weixin/images/file_1776188689423.jpg +0 -0
  127. package/.agent/data/weixin/images/file_1776188813604.jpg +0 -0
  128. package/.agent/data/weixin/images/file_1776189097450.jpg +0 -0
  129. package/.agent/data/weixin/videos/file_1776188318431.mp4 +0 -0
  130. package/.agent/data/weixin.json +0 -6
  131. package/.agent/mcp_config.json +0 -14
  132. package/.agent/memory/user/mof6gk94-kneeuh.md +0 -9
  133. package/.agent/package.json +0 -8
  134. package/.agent/plugins/marknative/README.md +0 -134
  135. package/.agent/plugins/marknative/fonts/SegoeUI Emoji.ttf +0 -0
  136. package/.agent/plugins/marknative/fonts.zip +0 -0
  137. package/.agent/plugins/marknative/index.js +0 -256
  138. package/.agent/plugins/marknative/package.json +0 -12
  139. package/.agent/plugins/test-plugin.py +0 -99
  140. package/.agent/plugins.json +0 -14
  141. package/.agent/python-scripts/test_sample.py +0 -24
  142. package/.agent/sessions/cli_default.json +0 -247
  143. package/.agent/skills/agent-browser/SKILL.md +0 -311
  144. package/.agent/skills/agent-browser/TEST_PLAN.md +0 -200
  145. package/.agent/skills/sysinfo/SKILL.md +0 -38
  146. package/.agent/skills/sysinfo/system-info.sh +0 -130
  147. package/.agent/skills/workflow/SKILL.md +0 -324
  148. package/.agent/test-agent.js +0 -35
  149. package/.agent/weixin.json +0 -6
  150. package/.agent/workflows/email-digest.json +0 -50
  151. package/.agent/workflows/file-backup.json +0 -21
  152. package/.agent/workflows/get-ip-notify.json +0 -32
  153. package/.agent/workflows/news-aggregator.json +0 -93
  154. package/.agent/workflows/news-dashboard-v2.json +0 -94
  155. package/.agent/workflows/notification-batch.json +0 -32
  156. package/src/core/session-context.js +0 -346
  157. package/src/core/session-storage.js +0 -295
@@ -1,346 +0,0 @@
1
- /**
2
- * SessionContext - Session 级别的上下文封装
3
- *
4
- * 职责:
5
- * 1. 管理 Per-Session 的消息存储
6
- * 2. 管理会话变量(variables)
7
- * 3. 跟踪会话元数据
8
- * 4. 处理上下文压缩状态
9
- * 5. 持久化到文件(可选)
10
- */
11
-
12
- const { SessionStorageAdapter, getDefaultAdapter } = require('./session-storage');
13
-
14
- class SessionContext {
15
- /**
16
- * @param {string} sessionId - 会话 ID
17
- * @param {Framework} framework - 框架实例
18
- * @param {Object} options - 配置选项
19
- * @param {Object} [options.metadata] - 初始元数据
20
- * @param {Object} [options.variables] - 初始变量
21
- * @param {Array} [options.initialMessages] - 初始消息
22
- * @param {SessionStorageAdapter} [options.storage] - 存储适配器
23
- * @param {boolean} [options.autoSave=true] - 是否自动保存
24
- */
25
- constructor(sessionId, framework, options = {}) {
26
- this.sessionId = sessionId;
27
- this.framework = framework;
28
-
29
- // 存储适配器
30
- this._storage = options.storage || getDefaultAdapter();
31
- this._autoSave = options.autoSave !== false;
32
-
33
- // 会话变量(可被工具读写)
34
- this.variables = new Map();
35
- if (options.variables) {
36
- for (const [key, value] of Object.entries(options.variables)) {
37
- this.variables.set(key, value);
38
- }
39
- }
40
-
41
- // 元数据
42
- this.metadata = {
43
- createdAt: Date.now(),
44
- lastActive: Date.now(),
45
- messageCount: 0,
46
- compressionCount: 0,
47
- ...options.metadata,
48
- };
49
-
50
- // Per-Session 消息存储
51
- this.messageStore = {
52
- messages: options.initialMessages || [], // 对话历史
53
- historyLoaded: false, // 是否已从持久化加载
54
- systemPrompt: null, // 当前系统提示词
55
- // 委托给 SessionContext.recordCompression
56
- recordCompression: (tokenCount) => this.recordCompression(tokenCount),
57
- };
58
-
59
- // 压缩状态
60
- this.compressionState = {
61
- lastCompressedAt: null,
62
- lastTokenCount: 0,
63
- pendingCompression: false,
64
- count: 0,
65
- };
66
-
67
- // 自定义数据插槽
68
- this.customData = new Map();
69
- }
70
-
71
- // ==================== 消息管理 ====================
72
-
73
- /**
74
- * 获取消息历史
75
- * @returns {Array} 消息数组
76
- */
77
- getMessages() {
78
- return this.messageStore.messages;
79
- }
80
-
81
- /**
82
- * 添加消息
83
- * @param {Object} message - 消息对象
84
- */
85
- addMessage(message) {
86
- this.messageStore.messages.push(message);
87
- this.metadata.messageCount++;
88
- this.metadata.lastActive = Date.now();
89
- this._autoSaveIfEnabled();
90
- }
91
-
92
- /**
93
- * 添加多条消息
94
- * @param {Array} messages - 消息数组
95
- */
96
- addMessages(messages) {
97
- for (const msg of messages) {
98
- this.messageStore.messages.push(msg);
99
- this.metadata.messageCount++;
100
- }
101
- this.metadata.lastActive = Date.now();
102
- this._autoSaveIfEnabled();
103
- }
104
-
105
- /**
106
- * 替换所有消息(用于压缩后同步)
107
- * @param {Array} messages - 新消息数组
108
- */
109
- replaceMessages(messages) {
110
- this.messageStore.messages = messages || [];
111
- this._autoSaveIfEnabled();
112
- }
113
-
114
- /**
115
- * 清空消息历史
116
- */
117
- clearMessages() {
118
- this.messageStore.messages = [];
119
- this._autoSaveIfEnabled();
120
- }
121
-
122
- /**
123
- * 如果启用了自动保存,则保存到存储
124
- * @private
125
- */
126
- _autoSaveIfEnabled() {
127
- if (this._autoSave) {
128
- this.save();
129
- }
130
- }
131
-
132
- /**
133
- * 手动保存到存储(立即保存,不 debounce)
134
- * @returns {Promise}
135
- */
136
- async save() {
137
- const data = this.toJSON();
138
- await this._storage.saveImmediate(this.sessionId, data);
139
- }
140
-
141
- /**
142
- * 同步加载(用于文件存储)
143
- * @param {string} sessionId
144
- * @param {Framework} framework
145
- * @param {Object} options
146
- * @returns {SessionContext|null}
147
- */
148
- static loadSync(sessionId, framework, options = {}) {
149
- const storage = options.storage || getDefaultAdapter();
150
-
151
- // 只有 file 类型支持同步加载
152
- if (storage.type !== 'file') {
153
- return null;
154
- }
155
-
156
- const fs = require('fs');
157
- const path = require('path');
158
- const filePath = path.resolve(process.cwd(), storage.baseDir, `${sessionId}.json`);
159
-
160
- if (!fs.existsSync(filePath)) {
161
- return null;
162
- }
163
-
164
- try {
165
- const content = fs.readFileSync(filePath, 'utf-8');
166
- const data = JSON.parse(content);
167
-
168
- // 恢复 SessionContext
169
- const ctx = new SessionContext(sessionId, framework, {
170
- ...options,
171
- initialMessages: data.messages || [],
172
- variables: data.variables || {},
173
- metadata: data.metadata || {},
174
- storage,
175
- });
176
-
177
- ctx.messageStore.historyLoaded = true;
178
- return ctx;
179
- } catch (err) {
180
- console.error(`[SessionContext] Failed to load sync:`, err.message);
181
- return null;
182
- }
183
- }
184
-
185
- /**
186
- * 从存储加载(异步)
187
- * @param {string} sessionId
188
- * @param {Framework} framework
189
- * @param {Object} options
190
- * @returns {Promise<SessionContext|null>}
191
- */
192
- static async load(sessionId, framework, options = {}) {
193
- const storage = options.storage || getDefaultAdapter();
194
- const data = await storage.load(sessionId);
195
-
196
- if (!data) {
197
- return null;
198
- }
199
-
200
- // 恢复 SessionContext
201
- const ctx = new SessionContext(sessionId, framework, {
202
- ...options,
203
- initialMessages: data.messages || [],
204
- variables: data.variables || {},
205
- metadata: data.metadata || {},
206
- storage,
207
- });
208
-
209
- ctx.messageStore.historyLoaded = true;
210
- return ctx;
211
- }
212
-
213
- /**
214
- * 获取消息数量
215
- * @returns {number}
216
- */
217
- getMessageCount() {
218
- return this.messageStore.messages.length;
219
- }
220
-
221
- // ==================== 变量管理 ====================
222
-
223
- /**
224
- * 获取变量
225
- * @param {string} key - 变量名
226
- * @param {*} defaultValue - 默认值
227
- * @returns {*}
228
- */
229
- getVariable(key, defaultValue = undefined) {
230
- return this.variables.get(key) ?? defaultValue;
231
- }
232
-
233
- /**
234
- * 设置变量
235
- * @param {string} key - 变量名
236
- * @param {*} value - 变量值
237
- */
238
- setVariable(key, value) {
239
- this.variables.set(key, value);
240
- this.touch();
241
- this._autoSaveIfEnabled();
242
- }
243
-
244
- /**
245
- * 删除变量
246
- * @param {string} key - 变量名
247
- */
248
- deleteVariable(key) {
249
- this.variables.delete(key);
250
- }
251
-
252
- /**
253
- * 获取所有变量
254
- * @returns {Object}
255
- */
256
- getAllVariables() {
257
- return Object.fromEntries(this.variables);
258
- }
259
-
260
- // ==================== 元数据 ====================
261
-
262
- /**
263
- * 更新最后活跃时间
264
- */
265
- touch() {
266
- this.metadata.lastActive = Date.now();
267
- }
268
-
269
- /**
270
- * 获取会话摘要
271
- * @returns {Object}
272
- */
273
- getSummary() {
274
- return {
275
- sessionId: this.sessionId,
276
- messageCount: this.metadata.messageCount,
277
- createdAt: this.metadata.createdAt,
278
- lastActive: this.metadata.lastActive,
279
- variables: this.getAllVariables(),
280
- };
281
- }
282
-
283
- // ==================== 压缩状态 ====================
284
-
285
- /**
286
- * 更新压缩状态
287
- * @param {number} tokenCount - 压缩后的 token 数
288
- */
289
- recordCompression(tokenCount) {
290
- this.compressionState.lastCompressedAt = Date.now();
291
- this.compressionState.lastTokenCount = tokenCount;
292
- this.compressionState.count++;
293
- this.metadata.compressionCount++;
294
- }
295
-
296
- /**
297
- * 获取压缩状态
298
- * @returns {Object}
299
- */
300
- getCompressionState() {
301
- return { ...this.compressionState };
302
- }
303
-
304
- // ==================== 历史加载状态 ====================
305
-
306
- /**
307
- * 标记为已加载历史
308
- */
309
- markHistoryLoaded() {
310
- this.messageStore.historyLoaded = true;
311
- }
312
-
313
- /**
314
- * 检查是否已加载历史
315
- * @returns {boolean}
316
- */
317
- isHistoryLoaded() {
318
- return this.messageStore.historyLoaded;
319
- }
320
-
321
- // ==================== 生命周期 ====================
322
-
323
- /**
324
- * 销毁会话上下文
325
- */
326
- destroy() {
327
- this.variables.clear();
328
- this.customData.clear();
329
- this.messageStore.messages = [];
330
- }
331
-
332
- /**
333
- * 导出为 JSON(用于持久化)
334
- * @returns {Object}
335
- */
336
- toJSON() {
337
- return {
338
- sessionId: this.sessionId,
339
- messages: this.messageStore.messages,
340
- variables: this.getAllVariables(),
341
- metadata: this.metadata,
342
- };
343
- }
344
- }
345
-
346
- module.exports = { SessionContext };
@@ -1,295 +0,0 @@
1
- /**
2
- * SessionStorageAdapter - Session 持久化存储适配器
3
- *
4
- * 支持多种存储后端:
5
- * - Memory: 内存存储(默认)
6
- * - File: JSON 文件存储
7
- * - Future: Database, Redis 等
8
- */
9
-
10
- const fs = require('fs');
11
- const fsPromises = require('fs').promises;
12
- const path = require('path');
13
-
14
- class SessionStorageAdapter {
15
- /**
16
- * @param {Object} options - 配置选项
17
- * @param {string} [options.type='memory'] - 存储类型: 'memory', 'file'
18
- * @param {string} [options.baseDir='.agent/sessions'] - 文件存储基础目录
19
- */
20
- constructor(options = {}) {
21
- this.type = options.type || 'memory';
22
- this.baseDir = options.baseDir || '.agent/sessions';
23
-
24
- if (this.type === 'file') {
25
- this._ensureDirectory();
26
- }
27
-
28
- // 内存存储
29
- this._memoryStore = new Map();
30
-
31
- // 写回队列(用于 debounce)
32
- this._writeQueue = null;
33
- this._writeTimeout = null;
34
- }
35
-
36
- /**
37
- * 确保目录存在
38
- * @private
39
- */
40
- async _ensureDirectory() {
41
- const dir = path.resolve(process.cwd(), this.baseDir);
42
- try {
43
- await fsPromises.access(dir);
44
- } catch {
45
- await fsPromises.mkdir(dir, { recursive: true });
46
- }
47
- }
48
-
49
- /**
50
- * 获取存储文件路径
51
- * @param {string} sessionId
52
- * @returns {string}
53
- * @private
54
- */
55
- _getFilePath(sessionId) {
56
- return path.resolve(process.cwd(), this.baseDir, `${sessionId}.json`);
57
- }
58
-
59
- /**
60
- * 保存 Session 数据
61
- * @param {string} sessionId - 会话 ID
62
- * @param {Object} data - 要保存的数据
63
- * @returns {Promise}
64
- */
65
- async save(sessionId, data) {
66
- if (this.type === 'memory') {
67
- this._memoryStore.set(sessionId, data);
68
- return;
69
- }
70
-
71
- if (this.type === 'file') {
72
- // Debounce 写操作,500ms 内的多次保存合并为一次
73
- if (this._writeTimeout) {
74
- clearTimeout(this._writeTimeout);
75
- }
76
-
77
- return new Promise((resolve, reject) => {
78
- this._writeQueue = { sessionId, data };
79
- this._writeTimeout = setTimeout(async () => {
80
- try {
81
- await this._writeToFile(this._writeQueue.sessionId, this._writeQueue.data);
82
- resolve();
83
- } catch (err) {
84
- reject(err);
85
- } finally {
86
- this._writeQueue = null;
87
- this._writeTimeout = null;
88
- }
89
- }, 500);
90
- });
91
- }
92
- }
93
-
94
- /**
95
- * 立即保存(不 debounce)
96
- * @param {string} sessionId
97
- * @param {Object} data
98
- */
99
- async saveImmediate(sessionId, data) {
100
- if (this._writeTimeout) {
101
- clearTimeout(this._writeTimeout);
102
- this._writeTimeout = null;
103
- }
104
-
105
- if (this.type === 'memory') {
106
- this._memoryStore.set(sessionId, data);
107
- return;
108
- }
109
-
110
- if (this.type === 'file') {
111
- await this._writeToFile(sessionId, data);
112
- }
113
- }
114
-
115
- /**
116
- * 写入文件
117
- * @param {string} sessionId
118
- * @param {Object} data
119
- * @private
120
- */
121
- async _writeToFile(sessionId, data) {
122
- const filePath = this._getFilePath(sessionId);
123
-
124
- try {
125
- // 确保目录存在
126
- const dir = path.dirname(filePath);
127
- try {
128
- await fsPromises.access(dir);
129
- } catch {
130
- await fsPromises.mkdir(dir, { recursive: true });
131
- }
132
-
133
- const content = JSON.stringify(data, null, 2);
134
- await fsPromises.writeFile(filePath, content, 'utf-8');
135
- } catch (err) {
136
- console.error(`[SessionStorage] Failed to write ${sessionId}:`, err.message);
137
- throw err;
138
- }
139
- }
140
-
141
- /**
142
- * 加载 Session 数据
143
- * @param {string} sessionId - 会话 ID
144
- * @returns {Promise<Object|null>}
145
- */
146
- async load(sessionId) {
147
- if (this.type === 'memory') {
148
- return this._memoryStore.get(sessionId) || null;
149
- }
150
-
151
- if (this.type === 'file') {
152
- const filePath = this._getFilePath(sessionId);
153
-
154
- try {
155
- await fsPromises.access(filePath);
156
- } catch {
157
- return null;
158
- }
159
-
160
- try {
161
- const content = await fsPromises.readFile(filePath, 'utf-8');
162
- return JSON.parse(content);
163
- } catch (err) {
164
- console.error(`[SessionStorage] Failed to read ${sessionId}:`, err.message);
165
- return null;
166
- }
167
- }
168
-
169
- return null;
170
- }
171
-
172
- /**
173
- * 删除 Session 数据
174
- * @param {string} sessionId - 会话 ID
175
- * @returns {Promise<boolean>}
176
- */
177
- async delete(sessionId) {
178
- if (this.type === 'memory') {
179
- return this._memoryStore.delete(sessionId);
180
- }
181
-
182
- if (this.type === 'file') {
183
- const filePath = this._getFilePath(sessionId);
184
-
185
- try {
186
- await fsPromises.access(filePath);
187
- } catch {
188
- return false;
189
- }
190
-
191
- try {
192
- await fsPromises.unlink(filePath);
193
- return true;
194
- } catch (err) {
195
- console.error(`[SessionStorage] Failed to delete ${sessionId}:`, err.message);
196
- return false;
197
- }
198
- }
199
-
200
- return false;
201
- }
202
-
203
- /**
204
- * 列出所有 Session ID
205
- * @returns {Promise<string[]>}
206
- */
207
- async list() {
208
- if (this.type === 'memory') {
209
- return Array.from(this._memoryStore.keys());
210
- }
211
-
212
- if (this.type === 'file') {
213
- const dir = path.resolve(process.cwd(), this.baseDir);
214
-
215
- try {
216
- await fsPromises.access(dir);
217
- } catch {
218
- return [];
219
- }
220
-
221
- try {
222
- const files = await fsPromises.readdir(dir);
223
- return files.filter((f) => f.endsWith('.json')).map((f) => f.replace(/\.json$/, ''));
224
- } catch (err) {
225
- console.error(`[SessionStorage] Failed to list sessions:`, err.message);
226
- return [];
227
- }
228
- }
229
-
230
- return [];
231
- }
232
-
233
- /**
234
- * 强制刷新所有待处理的写操作
235
- */
236
- async flush() {
237
- if (this._writeTimeout) {
238
- clearTimeout(this._writeTimeout);
239
- this._writeTimeout = null;
240
-
241
- if (this._writeQueue) {
242
- await this._writeToFile(this._writeQueue.sessionId, this._writeQueue.data);
243
- this._writeQueue = null;
244
- }
245
- }
246
- }
247
-
248
- /**
249
- * 销毁存储适配器
250
- */
251
- async destroy() {
252
- await this.flush();
253
- this._memoryStore.clear();
254
- }
255
- }
256
-
257
- /**
258
- * 全局默认存储适配器实例
259
- */
260
- let _defaultAdapter = null;
261
-
262
- /**
263
- * 获取默认存储适配器
264
- * @param {Object} options - 配置选项
265
- * @returns {SessionStorageAdapter}
266
- */
267
- function getDefaultAdapter(options = {}) {
268
- if (!_defaultAdapter) {
269
- _defaultAdapter = new SessionStorageAdapter(options);
270
- } else if (Object.keys(options).length > 0) {
271
- // 如果已存在但传入了新选项,用新选项更新默认适配器
272
- // 注意:这会修改全局单例,需要确保调用方知道这一点
273
- if (options.type && options.type !== _defaultAdapter.type) {
274
- _defaultAdapter.type = options.type;
275
- }
276
- if (options.baseDir && options.baseDir !== _defaultAdapter.baseDir) {
277
- _defaultAdapter.baseDir = options.baseDir;
278
- }
279
- }
280
- return _defaultAdapter;
281
- }
282
-
283
- /**
284
- * 设置默认存储适配器
285
- * @param {SessionStorageAdapter} adapter
286
- */
287
- function setDefaultAdapter(adapter) {
288
- _defaultAdapter = adapter;
289
- }
290
-
291
- module.exports = {
292
- SessionStorageAdapter,
293
- getDefaultAdapter,
294
- setDefaultAdapter,
295
- };