foliko 1.1.93 → 2.0.0
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 +2 -1
- package/CLAUDE.md +56 -30
- package/REFACTORING_PLAN.md +645 -0
- package/docs/architecture.md +131 -0
- package/docs/migration.md +57 -0
- package/docs/public-api.md +138 -0
- package/docs/usage.md +385 -0
- package/examples/ambient-example.js +20 -137
- package/examples/basic.js +21 -48
- package/examples/bootstrap.js +16 -74
- package/examples/mcp-example.js +6 -29
- package/examples/skill-example.js +6 -19
- package/examples/workflow.js +8 -56
- package/package.json +8 -4
- package/plugins/README.md +49 -0
- package/plugins/{ambient-agent → ambient}/EventWatcher.js +1 -1
- package/plugins/{ambient-agent → ambient}/ExplorerLoop.js +3 -3
- package/plugins/{ambient-agent → ambient}/GoalManager.js +2 -2
- package/plugins/ambient/README.md +14 -0
- package/plugins/{ambient-agent → ambient}/Reflector.js +1 -1
- package/plugins/{ambient-agent → ambient}/StateStore.js +1 -1
- package/plugins/{ambient-agent → ambient}/index.js +2 -2
- package/plugins/{ai-plugin.js → core/ai/index.js} +14 -30
- package/plugins/{audit-plugin.js → core/audit/index.js} +3 -30
- package/plugins/{coordinator-plugin.js → core/coordinator/index.js} +3 -35
- package/plugins/core/default/bootstrap.js +202 -0
- package/plugins/core/default/config.js +220 -0
- package/plugins/core/default/index.js +58 -0
- package/plugins/core/mcp/index.js +1 -0
- package/plugins/{python-plugin-loader.js → core/python-loader/index.js} +7 -187
- package/plugins/{rules-plugin.js → core/rules/index.js} +121 -64
- package/plugins/{scheduler-plugin.js → core/scheduler/index.js} +12 -114
- package/plugins/{session-plugin.js → core/session/index.js} +9 -73
- package/{src/capabilities/skill-manager.js → plugins/core/skill-manager/index.js} +64 -18
- package/plugins/{storage-plugin.js → core/storage/index.js} +5 -29
- package/plugins/{subagent-plugin.js → core/sub-agent/index.js} +10 -171
- package/plugins/{think-plugin.js → core/think/index.js} +24 -91
- package/{src/capabilities/workflow-engine.js → plugins/core/workflow/index.js} +87 -85
- package/plugins/default-plugins.js +6 -720
- package/plugins/{data-splitter-plugin.js → executors/data-splitter/index.js} +9 -83
- package/plugins/{extension-executor-plugin.js → executors/extension/index.js} +13 -97
- package/plugins/{python-executor-plugin.js → executors/python/index.js} +6 -31
- package/plugins/{shell-executor-plugin.js → executors/shell/index.js} +2 -5
- package/plugins/install/README.md +9 -0
- package/plugins/{install-plugin.js → install/index.js} +3 -3
- package/plugins/{file-system-plugin.js → io/file-system/index.js} +34 -236
- package/plugins/{web-plugin.js → io/web/index.js} +11 -113
- package/plugins/memory/README.md +13 -0
- package/plugins/{memory-plugin.js → memory/index.js} +4 -18
- package/plugins/messaging/email/README.md +19 -0
- package/plugins/{email → messaging/email}/index.js +2 -2
- package/plugins/{feishu-plugin.js → messaging/feishu/index.js} +3 -3
- package/plugins/{qq-plugin.js → messaging/qq/index.js} +5 -16
- package/plugins/{telegram-plugin.js → messaging/telegram/index.js} +3 -3
- package/plugins/{weixin-plugin.js → messaging/weixin/index.js} +15 -15
- package/plugins/{plugin-manager-plugin.js → plugin-manager/index.js} +36 -180
- package/plugins/{tools-plugin.js → tools/index.js} +68 -116
- package/plugins/trading/README.md +15 -0
- package/plugins/{gate-trading.js → trading/index.js} +8 -8
- package/{examples → sandbox}/test-concurrent-chat.js +2 -2
- package/{examples → sandbox}/test-long-chat.js +2 -2
- package/{examples → sandbox}/test-session-chat.js +2 -2
- package/{examples → sandbox}/test-web-plugin.js +1 -1
- package/{examples → sandbox}/test-weixin-feishu.js +2 -2
- package/src/agent/base.js +56 -0
- package/src/{core/agent-chat.js → agent/chat.js} +11 -11
- package/src/{core/coordinator-manager.js → agent/coordinator.js} +3 -3
- package/src/agent/index.js +111 -0
- package/src/agent/main.js +337 -0
- package/src/agent/prompt.js +78 -0
- package/src/agent/sub.js +198 -0
- package/src/agent/worker.js +104 -0
- package/{cli/bin/foliko.js → src/cli/bin.js} +1 -1
- package/{cli/src → src/cli}/commands/chat.js +25 -21
- package/{cli/src → src/cli}/index.js +1 -0
- package/{cli/src → src/cli}/ui/chat-ui-old.js +40 -178
- package/{cli/src → src/cli}/ui/chat-ui.js +3 -3
- package/{cli/src → src/cli}/ui/components/footer-bar.js +1 -1
- package/src/common/errors.js +402 -0
- package/src/{utils → common}/logger.js +33 -0
- package/src/{utils/chat-queue.js → common/queue.js} +2 -2
- package/src/config/plugin-config.js +50 -0
- package/src/context/agent.js +32 -0
- package/src/context/compaction-prompts.js +170 -0
- package/src/context/compaction-utils.js +191 -0
- package/src/context/compressor.js +413 -0
- package/src/context/index.js +9 -0
- package/src/{core/context-manager.js → context/manager.js} +1 -1
- package/src/context/request.js +50 -0
- package/src/context/session.js +33 -0
- package/src/context/storage.js +30 -0
- package/src/executors/mcp-client.js +153 -0
- package/src/executors/mcp-desc.js +236 -0
- package/src/executors/mcp-executor.js +91 -956
- package/src/{core → framework}/command-registry.js +1 -1
- package/src/framework/framework.js +300 -0
- package/src/framework/index.js +18 -0
- package/src/framework/lifecycle.js +203 -0
- package/src/framework/loader.js +78 -0
- package/src/framework/registry.js +86 -0
- package/src/{core/ui-extension-context.js → framework/ui-extension.js} +1 -1
- package/src/index.js +130 -15
- package/src/llm/index.js +26 -0
- package/src/llm/provider.js +212 -0
- package/src/llm/registry.js +11 -0
- package/src/{core/token-counter.js → llm/tokens.js} +4 -37
- package/src/{core/plugin-base.js → plugin/base.js} +10 -136
- package/src/plugin/index.js +14 -0
- package/src/plugin/loader.js +101 -0
- package/src/plugin/manager.js +261 -0
- package/src/{core → session}/branch-summary-auto.js +2 -2
- package/src/{core/chat-session.js → session/chat.js} +2 -2
- package/src/session/index.js +7 -0
- package/src/{core/session-manager.js → session/session.js} +2 -2
- package/src/session/ttl.js +92 -0
- package/src/{core/jsonl-storage.js → storage/jsonl.js} +1 -1
- package/src/tool/executor.js +85 -0
- package/src/tool/index.js +15 -0
- package/src/tool/registry.js +143 -0
- package/src/{core/tool-router.js → tool/router.js} +17 -124
- package/src/tool/schema.js +108 -0
- package/src/utils/data-splitter.js +1 -1
- package/src/utils/download.js +1 -1
- package/src/utils/index.js +6 -6
- package/src/utils/message-validator.js +1 -1
- package/tests/core/context-storage.test.js +46 -0
- package/tests/core/llm.test.js +54 -0
- package/tests/core/plugin.test.js +42 -0
- package/tests/core/tool.test.js +60 -0
- package/tests/setup.js +10 -0
- package/tests/smoke.test.js +58 -0
- package/vitest.config.js +9 -0
- package/cli/src/daemon.js +0 -149
- package/docs/CONTEXT_DESIGN.md +0 -1596
- package/docs/ai-sdk-optimization.md +0 -655
- package/docs/features.md +0 -120
- package/docs/qq-bot.md +0 -976
- package/docs/quick-reference.md +0 -160
- package/docs/user-manual.md +0 -1391
- package/images/geometric_shapes.jpg +0 -0
- package/images/sunset_mountain_lake.jpg +0 -0
- package/skills/poster-guide/SKILL.md +0 -792
- package/src/capabilities/index.js +0 -11
- package/src/core/agent.js +0 -808
- package/src/core/context-compressor.js +0 -959
- package/src/core/enhanced-context-compressor.js +0 -210
- package/src/core/framework.js +0 -1422
- package/src/core/index.js +0 -30
- package/src/core/plugin-manager.js +0 -961
- package/src/core/provider-registry.js +0 -159
- package/src/core/provider.js +0 -156
- package/src/core/request-context.js +0 -98
- package/src/core/subagent.js +0 -442
- package/src/core/system-prompt-builder.js +0 -120
- package/src/core/tool-executor.js +0 -202
- package/src/core/tool-registry.js +0 -517
- package/src/core/worker-agent.js +0 -192
- package/src/executors/executor-base.js +0 -58
- package/src/utils/error-boundary.js +0 -363
- package/src/utils/error.js +0 -374
- package/system.md +0 -1645
- package/website_v2/README.md +0 -57
- package/website_v2/SPEC.md +0 -1
- package/website_v2/docs/api.html +0 -128
- package/website_v2/docs/configuration.html +0 -147
- package/website_v2/docs/plugin-development.html +0 -129
- package/website_v2/docs/project-structure.html +0 -89
- package/website_v2/docs/skill-development.html +0 -85
- package/website_v2/index.html +0 -489
- package/website_v2/scripts/main.js +0 -93
- package/website_v2/styles/animations.css +0 -8
- package/website_v2/styles/docs.css +0 -83
- package/website_v2/styles/main.css +0 -417
- package/xhs_auth.json +0 -268
- package//346/265/267/346/212/245/346/217/222/344/273/266.md +0 -621
- /package/plugins/{ambient-agent → ambient}/constants.js +0 -0
- /package/plugins/{email → messaging/email}/constants.js +0 -0
- /package/plugins/{email → messaging/email}/handlers.js +0 -0
- /package/plugins/{email → messaging/email}/monitor.js +0 -0
- /package/plugins/{email → messaging/email}/parser.js +0 -0
- /package/plugins/{email → messaging/email}/reply.js +0 -0
- /package/plugins/{email → messaging/email}/utils.js +0 -0
- /package/{examples → sandbox}/test-chat.js +0 -0
- /package/{examples → sandbox}/test-mcp.js +0 -0
- /package/{examples → sandbox}/test-reload.js +0 -0
- /package/{examples → sandbox}/test-telegram.js +0 -0
- /package/{examples → sandbox}/test-tg-bot.js +0 -0
- /package/{examples → sandbox}/test-tg-simple.js +0 -0
- /package/{examples → sandbox}/test-tg.js +0 -0
- /package/{examples → sandbox}/test-think.js +0 -0
- /package/src/{core/sub-agent-config.js → agent/sub-config.js} +0 -0
- /package/{cli/src → src/cli}/commands/daemon.js +0 -0
- /package/{cli/src → src/cli}/commands/list.js +0 -0
- /package/{cli/src → src/cli}/commands/plugin.js +0 -0
- /package/{cli/src → src/cli}/ui/components/agent-mention-provider.js +0 -0
- /package/{cli/src → src/cli}/ui/components/chained-autocomplete-provider.js +0 -0
- /package/{cli/src → src/cli}/ui/components/message-bubble.js +0 -0
- /package/{cli/src → src/cli}/ui/components/status-bar.js +0 -0
- /package/{cli/src → src/cli}/utils/ansi.js +0 -0
- /package/{cli/src → src/cli}/utils/config.js +0 -0
- /package/{cli/src → src/cli}/utils/markdown.js +0 -0
- /package/{cli/src → src/cli}/utils/plugin-config.js +0 -0
- /package/{cli/src → src/cli}/utils/render-diff.js +0 -0
- /package/src/{utils/circuit-breaker.js → common/circuit.js} +0 -0
- /package/src/{core → common}/constants.js +0 -0
- /package/src/{utils/edit-diff.js → common/diff.js} +0 -0
- /package/src/{utils/event-emitter.js → common/events.js} +0 -0
- /package/src/{utils → common}/id.js +0 -0
- /package/src/{utils → common}/retry.js +0 -0
- /package/src/{core/notification-manager.js → notification/manager.js} +0 -0
- /package/src/{core/session-entry.js → session/entry.js} +0 -0
- /package/src/{core/storage-manager.js → storage/manager.js} +0 -0
|
@@ -1,20 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Session Plugin - Session management with JSONL tree structure
|
|
3
|
-
* Rewritten to use pi-style SessionManager
|
|
4
3
|
*/
|
|
5
4
|
|
|
6
|
-
const { Plugin } = require('
|
|
7
|
-
const { logger } = require('
|
|
5
|
+
const { Plugin } = require('../../../src/plugin/base');
|
|
6
|
+
const { logger } = require('../../../src/common/logger');
|
|
8
7
|
const log = logger.child('Session');
|
|
9
8
|
const { z } = require('zod');
|
|
10
9
|
const { EventEmitter } = require('events');
|
|
11
10
|
const path = require('path');
|
|
12
|
-
const { SessionManager } = require('
|
|
13
|
-
const { buildSessionContext, EntryTypes } = require('
|
|
11
|
+
const { SessionManager } = require('../../../src/session/session');
|
|
12
|
+
const { buildSessionContext, EntryTypes } = require('../../../src/session/entry');
|
|
14
13
|
|
|
15
|
-
/**
|
|
16
|
-
* Get default session directory for a cwd
|
|
17
|
-
*/
|
|
18
14
|
function getDefaultSessionDir(cwd) {
|
|
19
15
|
const agentDir = path.join(cwd, '.foliko');
|
|
20
16
|
const sessionDir = path.join(agentDir, 'sessions');
|
|
@@ -44,7 +40,7 @@ class SessionPlugin extends Plugin {
|
|
|
44
40
|
};
|
|
45
41
|
|
|
46
42
|
this._framework = null;
|
|
47
|
-
this._sessionManagers = new Map();
|
|
43
|
+
this._sessionManagers = new Map();
|
|
48
44
|
this._cleanupTimer = null;
|
|
49
45
|
this._events = new EventEmitter();
|
|
50
46
|
}
|
|
@@ -54,16 +50,10 @@ class SessionPlugin extends Plugin {
|
|
|
54
50
|
return this;
|
|
55
51
|
}
|
|
56
52
|
|
|
57
|
-
/**
|
|
58
|
-
* 获取当前工作目录(framework.getCwd() 优先, fallback 到 process.cwd())
|
|
59
|
-
*/
|
|
60
53
|
_defaultCwd() {
|
|
61
54
|
return this._framework?.getCwd?.() ?? process.cwd();
|
|
62
55
|
}
|
|
63
56
|
|
|
64
|
-
/**
|
|
65
|
-
* Get or create a SessionManager for a session
|
|
66
|
-
*/
|
|
67
57
|
_getSessionManager(sessionId, cwd) {
|
|
68
58
|
cwd = cwd ?? this._defaultCwd();
|
|
69
59
|
if (this._sessionManagers.has(sessionId)) {
|
|
@@ -77,9 +67,6 @@ class SessionPlugin extends Plugin {
|
|
|
77
67
|
return manager;
|
|
78
68
|
}
|
|
79
69
|
|
|
80
|
-
/**
|
|
81
|
-
* List all sessions for current cwd
|
|
82
|
-
*/
|
|
83
70
|
async listSessions(cwd = this._defaultCwd()) {
|
|
84
71
|
const sessionDir = getDefaultSessionDir(cwd);
|
|
85
72
|
const sessions = [];
|
|
@@ -103,7 +90,6 @@ class SessionPlugin extends Plugin {
|
|
|
103
90
|
leafId: manager.getLeafId()
|
|
104
91
|
});
|
|
105
92
|
} catch {
|
|
106
|
-
// Skip invalid session files
|
|
107
93
|
}
|
|
108
94
|
}
|
|
109
95
|
} catch (err) {
|
|
@@ -114,7 +100,6 @@ class SessionPlugin extends Plugin {
|
|
|
114
100
|
}
|
|
115
101
|
|
|
116
102
|
start(framework) {
|
|
117
|
-
// Register session management tools
|
|
118
103
|
framework.registerTool({
|
|
119
104
|
name: 'session_create',
|
|
120
105
|
description: '创建新会话',
|
|
@@ -304,7 +289,6 @@ class SessionPlugin extends Plugin {
|
|
|
304
289
|
}
|
|
305
290
|
});
|
|
306
291
|
|
|
307
|
-
// Start auto cleanup if enabled
|
|
308
292
|
if (this.config.autoCleanup) {
|
|
309
293
|
this._startAutoCleanup();
|
|
310
294
|
}
|
|
@@ -312,14 +296,10 @@ class SessionPlugin extends Plugin {
|
|
|
312
296
|
return this;
|
|
313
297
|
}
|
|
314
298
|
|
|
315
|
-
/**
|
|
316
|
-
* Add message to session
|
|
317
|
-
*/
|
|
318
299
|
addMessage(sessionId, message, cwd = this._defaultCwd()) {
|
|
319
300
|
const manager = this._getSessionManager(sessionId, cwd);
|
|
320
301
|
const entryId = manager.appendMessage(message);
|
|
321
302
|
|
|
322
|
-
// Emit session event
|
|
323
303
|
if (manager.getEntries().length === 1) {
|
|
324
304
|
this._events.emit('session:created', { sessionId, manager });
|
|
325
305
|
}
|
|
@@ -327,72 +307,45 @@ class SessionPlugin extends Plugin {
|
|
|
327
307
|
return entryId;
|
|
328
308
|
}
|
|
329
309
|
|
|
330
|
-
/**
|
|
331
|
-
* Get session context for LLM
|
|
332
|
-
*/
|
|
333
310
|
getSessionContext(sessionId, cwd = this._defaultCwd()) {
|
|
334
311
|
const manager = this._getSessionManager(sessionId, cwd);
|
|
335
312
|
return manager.buildSessionContext();
|
|
336
313
|
}
|
|
337
314
|
|
|
338
|
-
/**
|
|
339
|
-
* Get or create session (alias for getSessionContext)
|
|
340
|
-
*/
|
|
341
315
|
getOrCreateSession(sessionId, options = {}, cwd = this._defaultCwd()) {
|
|
342
316
|
return this.getSessionContext(sessionId, cwd);
|
|
343
317
|
}
|
|
344
318
|
|
|
345
|
-
/**
|
|
346
|
-
* Get specific entry
|
|
347
|
-
*/
|
|
348
319
|
getEntry(sessionId, entryId, cwd = this._defaultCwd()) {
|
|
349
320
|
const manager = this._getSessionManager(sessionId, cwd);
|
|
350
321
|
return manager.getEntry(entryId);
|
|
351
322
|
}
|
|
352
323
|
|
|
353
|
-
/**
|
|
354
|
-
* Get branch (path from root to leaf)
|
|
355
|
-
*/
|
|
356
324
|
getBranch(sessionId, fromId, cwd = this._defaultCwd()) {
|
|
357
325
|
const manager = this._getSessionManager(sessionId, cwd);
|
|
358
326
|
return manager.getBranch(fromId);
|
|
359
327
|
}
|
|
360
328
|
|
|
361
|
-
/**
|
|
362
|
-
* Append compaction entry
|
|
363
|
-
*/
|
|
364
329
|
appendCompaction(sessionId, summary, firstKeptEntryId, tokensBefore, details, cwd = this._defaultCwd()) {
|
|
365
330
|
const manager = this._getSessionManager(sessionId, cwd);
|
|
366
331
|
return manager.appendCompaction(summary, firstKeptEntryId, tokensBefore, details, false);
|
|
367
332
|
}
|
|
368
333
|
|
|
369
|
-
/**
|
|
370
|
-
* Append thinking level change
|
|
371
|
-
*/
|
|
372
334
|
appendThinkingLevelChange(sessionId, thinkingLevel, cwd = this._defaultCwd()) {
|
|
373
335
|
const manager = this._getSessionManager(sessionId, cwd);
|
|
374
336
|
return manager.appendThinkingLevelChange(thinkingLevel);
|
|
375
337
|
}
|
|
376
338
|
|
|
377
|
-
/**
|
|
378
|
-
* Append model change
|
|
379
|
-
*/
|
|
380
339
|
appendModelChange(sessionId, provider, modelId, cwd = this._defaultCwd()) {
|
|
381
340
|
const manager = this._getSessionManager(sessionId, cwd);
|
|
382
341
|
return manager.appendModelChange(provider, modelId);
|
|
383
342
|
}
|
|
384
343
|
|
|
385
|
-
/**
|
|
386
|
-
* Set session label
|
|
387
|
-
*/
|
|
388
344
|
setLabel(sessionId, entryId, label, cwd = this._defaultCwd()) {
|
|
389
345
|
const manager = this._getSessionManager(sessionId, cwd);
|
|
390
346
|
return manager.appendLabelChange(entryId, label);
|
|
391
347
|
}
|
|
392
348
|
|
|
393
|
-
/**
|
|
394
|
-
* Get session info (compatible with external callers)
|
|
395
|
-
*/
|
|
396
349
|
getSession(sessionId, cwd = this._defaultCwd()) {
|
|
397
350
|
const manager = this._getSessionManager(sessionId, cwd);
|
|
398
351
|
const entries = manager.getEntries();
|
|
@@ -403,9 +356,6 @@ class SessionPlugin extends Plugin {
|
|
|
403
356
|
};
|
|
404
357
|
}
|
|
405
358
|
|
|
406
|
-
/**
|
|
407
|
-
* Start auto cleanup timer
|
|
408
|
-
*/
|
|
409
359
|
_startAutoCleanup() {
|
|
410
360
|
if (this._cleanupTimer) {
|
|
411
361
|
clearInterval(this._cleanupTimer);
|
|
@@ -413,12 +363,8 @@ class SessionPlugin extends Plugin {
|
|
|
413
363
|
this._cleanupTimer = setInterval(async () => {
|
|
414
364
|
await this._doCleanup();
|
|
415
365
|
}, this.config.cleanupInterval);
|
|
416
|
-
//log.info(`Auto cleanup started (interval: ${this.config.cleanupInterval}ms)`);
|
|
417
366
|
}
|
|
418
367
|
|
|
419
|
-
/**
|
|
420
|
-
* Perform cleanup of old sessions and message history
|
|
421
|
-
*/
|
|
422
368
|
async _doCleanup() {
|
|
423
369
|
try {
|
|
424
370
|
const fs = require('fs');
|
|
@@ -437,20 +383,17 @@ class SessionPlugin extends Plugin {
|
|
|
437
383
|
try {
|
|
438
384
|
const manager = SessionManager.open(filePath, sessionDir, cwd);
|
|
439
385
|
const entries = manager.getEntries();
|
|
440
|
-
|
|
441
|
-
// Clean up if exceeds maxHistoryLength
|
|
386
|
+
|
|
442
387
|
if (entries.length > this.config.maxHistoryLength) {
|
|
443
|
-
const toRemove = entries.length - this.config.maxHistoryLength;
|
|
444
|
-
// Keep session header, remove oldest entries
|
|
445
388
|
const entriesToKeep = manager.fileEntries.filter(e => e.type === 'session');
|
|
446
389
|
const messagesToKeep = manager.fileEntries
|
|
447
390
|
.filter(e => e.type !== 'session')
|
|
448
391
|
.slice(-this.config.maxHistoryLength);
|
|
449
|
-
|
|
392
|
+
|
|
450
393
|
manager.fileEntries = [...entriesToKeep, ...messagesToKeep];
|
|
451
394
|
manager._rewriteFile();
|
|
452
395
|
cleanedCount++;
|
|
453
|
-
log.debug(`Cleaned ${file}: removed ${
|
|
396
|
+
log.debug(`Cleaned ${file}: removed ${entries.length - this.config.maxHistoryLength} entries, kept ${this.config.maxHistoryLength}`);
|
|
454
397
|
}
|
|
455
398
|
} catch (err) {
|
|
456
399
|
log.warn(`Failed to cleanup session ${file}: ${err.message}`);
|
|
@@ -458,23 +401,16 @@ class SessionPlugin extends Plugin {
|
|
|
458
401
|
}
|
|
459
402
|
|
|
460
403
|
if (cleanedCount > 0) {
|
|
461
|
-
//log.info(`Auto cleanup completed: cleaned ${cleanedCount} sessions`);
|
|
462
404
|
}
|
|
463
405
|
} catch (err) {
|
|
464
406
|
log.error(`Auto cleanup error: ${err.message}`);
|
|
465
407
|
}
|
|
466
408
|
}
|
|
467
409
|
|
|
468
|
-
/**
|
|
469
|
-
* On session event listener
|
|
470
|
-
*/
|
|
471
410
|
on(event, listener) {
|
|
472
411
|
this._events.on(event, listener);
|
|
473
412
|
}
|
|
474
413
|
|
|
475
|
-
/**
|
|
476
|
-
* Off session event listener
|
|
477
|
-
*/
|
|
478
414
|
off(event, listener) {
|
|
479
415
|
this._events.off(event, listener);
|
|
480
416
|
}
|
|
@@ -494,4 +430,4 @@ class SessionPlugin extends Plugin {
|
|
|
494
430
|
}
|
|
495
431
|
}
|
|
496
432
|
|
|
497
|
-
module.exports = { SessionPlugin };
|
|
433
|
+
module.exports = { SessionPlugin };
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
const fs = require('fs');
|
|
7
7
|
const path = require('path');
|
|
8
|
-
const { Plugin } = require('
|
|
9
|
-
const { logger } = require('
|
|
8
|
+
const { Plugin } = require('../../../src/plugin/base');
|
|
9
|
+
const { logger } = require('../../../src/common/logger');
|
|
10
10
|
const log = logger.child('SkillManager');
|
|
11
11
|
const { z } = require('zod');
|
|
12
12
|
const { Command } = require('commander');
|
|
@@ -550,19 +550,29 @@ class SkillManagerPlugin extends Plugin {
|
|
|
550
550
|
}
|
|
551
551
|
}
|
|
552
552
|
|
|
553
|
-
if (
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
553
|
+
if (skillPath) {
|
|
554
|
+
if (!isValidSkillName(entry.name)) continue;
|
|
555
|
+
if (this._skills.has(entry.name)) continue;
|
|
556
|
+
try {
|
|
557
|
+
this._loadSkill(entry.name, skillPath);
|
|
558
|
+
totalLoaded++;
|
|
559
|
+
} catch (err) {
|
|
560
|
+
log.error(` Failed to load skill '${entry.name}':`, err.message);
|
|
561
|
+
}
|
|
558
562
|
continue;
|
|
559
563
|
}
|
|
560
564
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
565
|
+
// 支持直接放在 skills 目录下的 .md 文件(如 workflows/*.md)
|
|
566
|
+
if (entry.isFile() && entry.name.endsWith('.md') && entry.name !== 'SKILL.md') {
|
|
567
|
+
const skillName = path.basename(entry.name, '.md');
|
|
568
|
+
if (!isValidSkillName(skillName)) continue;
|
|
569
|
+
if (this._skills.has(skillName)) continue;
|
|
570
|
+
try {
|
|
571
|
+
this._loadSkillFromStandaloneFile(skillName, entryPath);
|
|
572
|
+
totalLoaded++;
|
|
573
|
+
} catch (err) {
|
|
574
|
+
log.error(` Failed to load skill from file '${entry.name}':`, err.message);
|
|
575
|
+
}
|
|
566
576
|
}
|
|
567
577
|
}
|
|
568
578
|
} catch (err) {
|
|
@@ -672,6 +682,27 @@ class SkillManagerPlugin extends Plugin {
|
|
|
672
682
|
});
|
|
673
683
|
}
|
|
674
684
|
|
|
685
|
+
/**
|
|
686
|
+
* 从独立 .md 文件加载技能(直接放在 skills 目录下,无子目录)
|
|
687
|
+
*/
|
|
688
|
+
_loadSkillFromStandaloneFile(name, filePath) {
|
|
689
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
690
|
+
const frontmatter = parseFrontmatter(content);
|
|
691
|
+
|
|
692
|
+
const metadata = new SkillMetadata({
|
|
693
|
+
name: frontmatter?.name || name,
|
|
694
|
+
description: frontmatter?.description || '',
|
|
695
|
+
});
|
|
696
|
+
|
|
697
|
+
const skill = new Skill(metadata, stripFrontmatter(content));
|
|
698
|
+
skill.install(this._framework);
|
|
699
|
+
|
|
700
|
+
this._skills.set(name, {
|
|
701
|
+
name, metadata, content: skill.content, instance: skill,
|
|
702
|
+
path: path.dirname(filePath), references: new Map(), scripts: new Map(),
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
|
|
675
706
|
/**
|
|
676
707
|
* 递归查找 SKILL.md 或 AGENTS.md(支持多层嵌套目录)
|
|
677
708
|
* @param {string} dir - 要搜索的目录
|
|
@@ -936,27 +967,42 @@ class SkillManagerPlugin extends Plugin {
|
|
|
936
967
|
}
|
|
937
968
|
|
|
938
969
|
reload(framework) {
|
|
939
|
-
// log.info(' Reloading...');
|
|
940
970
|
this._skills.clear();
|
|
941
|
-
// 清空 this.tools,避免旧 skill 命令残留(否则 setCwd 后旧 cwd 的命令会留在 _extensions 中)
|
|
942
971
|
this.tools = {};
|
|
943
972
|
this._loaded = false;
|
|
944
973
|
this._framework = framework;
|
|
945
|
-
this._loadAllSkills();
|
|
946
974
|
|
|
947
|
-
//
|
|
948
|
-
|
|
949
|
-
|
|
975
|
+
// 清理 extension-executor 中的旧 skill 命令,避免重载后残留
|
|
976
|
+
const extExecutor = framework.pluginManager?.get('extension-executor');
|
|
977
|
+
if (extExecutor) {
|
|
978
|
+
extExecutor._extensions.delete('skill');
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
this._loadAllSkills();
|
|
950
982
|
|
|
951
983
|
// 通知 UI 刷新 skill 命令(用于 autocomplete 热重载)
|
|
952
984
|
framework.emit('skill:reloaded', { skills: Array.from(this._skills.keys()) });
|
|
953
985
|
}
|
|
954
986
|
|
|
987
|
+
async onCwdChanged(oldCwd, newCwd, framework) {
|
|
988
|
+
// 切换工作目录前清理旧 skill 命令
|
|
989
|
+
const extExecutor = framework.pluginManager?.get('extension-executor');
|
|
990
|
+
if (extExecutor) {
|
|
991
|
+
extExecutor._extensions.delete('skill');
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
|
|
955
995
|
uninstall(framework) {
|
|
956
996
|
this._skills.clear();
|
|
957
997
|
this._framework = null;
|
|
958
998
|
this._loaded = false;
|
|
959
999
|
}
|
|
1000
|
+
|
|
1001
|
+
setSearchDirs(dirs) {
|
|
1002
|
+
if (Array.isArray(dirs)) {
|
|
1003
|
+
this._skillsDirs = dirs;
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
960
1006
|
}
|
|
961
1007
|
|
|
962
1008
|
module.exports = {
|
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
* Supports delayed compaction to reduce file size
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
const { Plugin } = require('
|
|
7
|
-
const { logger } = require('
|
|
6
|
+
const { Plugin } = require('../../../src/plugin/base');
|
|
7
|
+
const { logger } = require('../../../src/common/logger');
|
|
8
8
|
const log = logger.child('Storage');
|
|
9
9
|
const { z } = require('zod');
|
|
10
10
|
const path = require('path');
|
|
11
|
-
const { StorageManager } = require('
|
|
11
|
+
const { StorageManager } = require('../../../src/storage/manager');
|
|
12
12
|
|
|
13
13
|
class StoragePlugin extends Plugin {
|
|
14
14
|
constructor(config = {}) {
|
|
@@ -23,7 +23,6 @@ class StoragePlugin extends Plugin {
|
|
|
23
23
|
this.config = {
|
|
24
24
|
path: config.path || '.foliko/data',
|
|
25
25
|
namespace: config.namespace || 'default',
|
|
26
|
-
// Compaction 配置
|
|
27
26
|
compactionThreshold: config.compactionThreshold || 1000,
|
|
28
27
|
compactionIntervalMs: config.compactionIntervalMs || 5000,
|
|
29
28
|
autoCompact: config.autoCompact !== false,
|
|
@@ -38,16 +37,12 @@ class StoragePlugin extends Plugin {
|
|
|
38
37
|
return this;
|
|
39
38
|
}
|
|
40
39
|
|
|
41
|
-
/**
|
|
42
|
-
* Initialize storage manager with compaction settings
|
|
43
|
-
*/
|
|
44
40
|
_initStorage() {
|
|
45
41
|
if (this._storageManager) return;
|
|
46
42
|
|
|
47
43
|
const baseDir = path.resolve(this._framework?.getCwd?.() ?? process.cwd(), this.config.path);
|
|
48
44
|
const filePath = path.join(baseDir, `${this.config.namespace}.jsonl`);
|
|
49
45
|
|
|
50
|
-
// 传递 compaction 配置
|
|
51
46
|
this._storageManager = new StorageManager(filePath, true, {
|
|
52
47
|
compactionThreshold: this.config.compactionThreshold,
|
|
53
48
|
compactionIntervalMs: this.config.compactionIntervalMs,
|
|
@@ -55,25 +50,16 @@ class StoragePlugin extends Plugin {
|
|
|
55
50
|
});
|
|
56
51
|
}
|
|
57
52
|
|
|
58
|
-
/**
|
|
59
|
-
* Get storage store (for internal use)
|
|
60
|
-
*/
|
|
61
53
|
getStore() {
|
|
62
54
|
this._initStorage();
|
|
63
55
|
return this._storageManager;
|
|
64
56
|
}
|
|
65
57
|
|
|
66
|
-
/**
|
|
67
|
-
* Set value directly (for internal use by other plugins)
|
|
68
|
-
*/
|
|
69
58
|
setDirect(key, value) {
|
|
70
59
|
this._initStorage();
|
|
71
60
|
return this._storageManager.set(key, value);
|
|
72
61
|
}
|
|
73
62
|
|
|
74
|
-
/**
|
|
75
|
-
* Delete key directly (for internal use by other plugins)
|
|
76
|
-
*/
|
|
77
63
|
deleteDirect(key) {
|
|
78
64
|
this._initStorage();
|
|
79
65
|
return this._storageManager.delete(key);
|
|
@@ -82,7 +68,6 @@ class StoragePlugin extends Plugin {
|
|
|
82
68
|
start(framework) {
|
|
83
69
|
this._initStorage();
|
|
84
70
|
|
|
85
|
-
// Register storage tools
|
|
86
71
|
framework.registerTool({
|
|
87
72
|
name: 'storage_set',
|
|
88
73
|
description: '存储数据到键值存储',
|
|
@@ -96,7 +81,7 @@ class StoragePlugin extends Plugin {
|
|
|
96
81
|
this._initStorage();
|
|
97
82
|
const ns = args.namespace ? `${args.namespace}:` : '';
|
|
98
83
|
const fullKey = `${ns}${args.key}`;
|
|
99
|
-
|
|
84
|
+
this._storageManager.set(fullKey, args.value);
|
|
100
85
|
|
|
101
86
|
return {
|
|
102
87
|
success: true,
|
|
@@ -244,11 +229,6 @@ class StoragePlugin extends Plugin {
|
|
|
244
229
|
}
|
|
245
230
|
});
|
|
246
231
|
|
|
247
|
-
/**
|
|
248
|
-
* 新增: 手动触发 compaction
|
|
249
|
-
* 当 tombstone 数量达到阈值时,compaction 会自动在后台执行
|
|
250
|
-
* 此工具可手动触发 compaction 立即清理
|
|
251
|
-
*/
|
|
252
232
|
framework.registerTool({
|
|
253
233
|
name: 'storage_compact',
|
|
254
234
|
description: '手动触发 compaction,清理已删除的墓碑记录并重写文件',
|
|
@@ -258,7 +238,6 @@ class StoragePlugin extends Plugin {
|
|
|
258
238
|
execute: async (args) => {
|
|
259
239
|
try {
|
|
260
240
|
this._initStorage();
|
|
261
|
-
|
|
262
241
|
const result = await this._storageManager.compact();
|
|
263
242
|
|
|
264
243
|
return {
|
|
@@ -276,9 +255,6 @@ class StoragePlugin extends Plugin {
|
|
|
276
255
|
}
|
|
277
256
|
});
|
|
278
257
|
|
|
279
|
-
/**
|
|
280
|
-
* 新增: 获取存储统计信息
|
|
281
|
-
*/
|
|
282
258
|
framework.registerTool({
|
|
283
259
|
name: 'storage_stats',
|
|
284
260
|
description: '获取存储统计信息,包括条目数、墓碑数量、compaction 配置等',
|
|
@@ -321,4 +297,4 @@ class StoragePlugin extends Plugin {
|
|
|
321
297
|
}
|
|
322
298
|
}
|
|
323
299
|
|
|
324
|
-
module.exports = { StoragePlugin };
|
|
300
|
+
module.exports = { StoragePlugin };
|