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
@@ -1,32 +0,0 @@
1
- {
2
- "name": "notification-batch",
3
- "description": "批量通知工作流",
4
- "steps": [
5
- {
6
- "type": "script",
7
- "name": "初始化",
8
- "script": "context.variables.total=3; context.variables.sent=0; return {total:3};"
9
- },
10
- {
11
- "type": "loop",
12
- "name": "发送通知",
13
- "maxIterations": 3,
14
- "steps": [
15
- {
16
- "type": "script",
17
- "name": "计数",
18
- "script": "context.variables.sent=context.variables.sent+1;"
19
- },
20
- {
21
- "type": "tool",
22
- "name": "发送单个通知",
23
- "tool": "notification_send",
24
- "args": {
25
- "title": "进度",
26
- "message": "已发送: {{sent}}/{{total}}"
27
- }
28
- }
29
- ]
30
- }
31
- ]
32
- }
@@ -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
- };