foliko 1.0.87 → 1.1.1
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/.agent/.shared/ui-ux-pro-max/data/charts.csv +26 -0
- package/.agent/.shared/ui-ux-pro-max/data/colors.csv +97 -0
- package/.agent/.shared/ui-ux-pro-max/data/icons.csv +101 -0
- package/.agent/.shared/ui-ux-pro-max/data/landing.csv +31 -0
- package/.agent/.shared/ui-ux-pro-max/data/products.csv +97 -0
- package/.agent/.shared/ui-ux-pro-max/data/prompts.csv +24 -0
- package/.agent/.shared/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/.agent/.shared/ui-ux-pro-max/data/styles.csv +59 -0
- package/.agent/.shared/ui-ux-pro-max/data/typography.csv +58 -0
- package/.agent/.shared/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
- package/.agent/.shared/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/.agent/.shared/ui-ux-pro-max/data/web-interface.csv +31 -0
- package/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/core.cpython-313.pyc +0 -0
- package/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-313.pyc +0 -0
- package/.agent/.shared/ui-ux-pro-max/scripts/core.py +258 -0
- package/.agent/.shared/ui-ux-pro-max/scripts/design_system.py +1067 -0
- package/.agent/.shared/ui-ux-pro-max/scripts/search.py +106 -0
- package/.agent/ARCHITECTURE.md +288 -0
- package/.agent/agents/ambient-agent.md +57 -0
- package/.agent/agents/debugger.md +55 -0
- package/.agent/agents/email-assistant.md +49 -0
- package/.agent/agents/file-manager.md +42 -0
- package/.agent/agents/python-developer.md +60 -0
- package/.agent/agents/scheduler.md +59 -0
- package/.agent/agents/web-developer.md +45 -0
- package/.agent/data/default.json +325 -21
- package/.agent/data/plugins-state.json +194 -162
- package/.agent/data/puppeteer-sessions/undefined.json +6 -0
- package/.agent/mcp_config.json +0 -1
- package/.agent/mcp_config_updated.json +12 -0
- package/.agent/plugins/poster-plugin/README.md +304 -0
- package/.agent/plugins/poster-plugin/fonts/NotoColorEmoji-Regular.ttf +0 -0
- package/.agent/plugins/poster-plugin/fonts/PatuaOne-Regular.ttf +0 -0
- package/.agent/plugins/poster-plugin/fonts//345/276/256/350/275/257/351/233/205/351/273/221.ttf +0 -0
- package/.agent/plugins/poster-plugin/fonts//345/276/256/350/275/257/351/233/205/351/273/221/347/262/227/344/275/223.ttf +0 -0
- package/.agent/plugins/poster-plugin/index.js +13 -0
- package/.agent/plugins/poster-plugin/package.json +28 -0
- package/.agent/plugins/poster-plugin/src/canvas.js +161 -0
- package/.agent/plugins/poster-plugin/src/components/arrow.js +84 -0
- package/.agent/plugins/poster-plugin/src/components/avatar.js +71 -0
- package/.agent/plugins/poster-plugin/src/components/badge.js +85 -0
- package/.agent/plugins/poster-plugin/src/components/card.js +88 -0
- package/.agent/plugins/poster-plugin/src/components/chart.js +127 -0
- package/.agent/plugins/poster-plugin/src/components/chip.js +88 -0
- package/.agent/plugins/poster-plugin/src/components/columns.js +107 -0
- package/.agent/plugins/poster-plugin/src/components/cta.js +85 -0
- package/.agent/plugins/poster-plugin/src/components/divider.js +55 -0
- package/.agent/plugins/poster-plugin/src/components/feature.js +85 -0
- package/.agent/plugins/poster-plugin/src/components/featureGrid.js +112 -0
- package/.agent/plugins/poster-plugin/src/components/grid.js +118 -0
- package/.agent/plugins/poster-plugin/src/components/imageFrame.js +155 -0
- package/.agent/plugins/poster-plugin/src/components/index.js +62 -0
- package/.agent/plugins/poster-plugin/src/components/listItem.js +146 -0
- package/.agent/plugins/poster-plugin/src/components/notification.js +123 -0
- package/.agent/plugins/poster-plugin/src/components/progress.js +79 -0
- package/.agent/plugins/poster-plugin/src/components/progressCircle.js +117 -0
- package/.agent/plugins/poster-plugin/src/components/quote.js +97 -0
- package/.agent/plugins/poster-plugin/src/components/rating.js +85 -0
- package/.agent/plugins/poster-plugin/src/components/star.js +70 -0
- package/.agent/plugins/poster-plugin/src/components/statCard.js +105 -0
- package/.agent/plugins/poster-plugin/src/components/stepper.js +118 -0
- package/.agent/plugins/poster-plugin/src/components/table.js +159 -0
- package/.agent/plugins/poster-plugin/src/components/tagCloud.js +78 -0
- package/.agent/plugins/poster-plugin/src/components/timeline.js +105 -0
- package/.agent/plugins/poster-plugin/src/components/watermark.js +52 -0
- package/.agent/plugins/poster-plugin/src/composer.js +1904 -0
- package/.agent/plugins/poster-plugin/src/elements/artText.js +60 -0
- package/.agent/plugins/poster-plugin/src/elements/background.js +52 -0
- package/.agent/plugins/poster-plugin/src/elements/circle.js +31 -0
- package/.agent/plugins/poster-plugin/src/elements/image.js +71 -0
- package/.agent/plugins/poster-plugin/src/elements/index.js +26 -0
- package/.agent/plugins/poster-plugin/src/elements/line.js +23 -0
- package/.agent/plugins/poster-plugin/src/elements/polygon.js +63 -0
- package/.agent/plugins/poster-plugin/src/elements/rectangle.js +32 -0
- package/.agent/plugins/poster-plugin/src/elements/svg.js +92 -0
- package/.agent/plugins/poster-plugin/src/elements/text.js +107 -0
- package/.agent/plugins/poster-plugin/src/fonts.js +233 -0
- package/.agent/plugins/poster-plugin/src/index.js +1658 -0
- package/.agent/plugins/poster-plugin/src/presets.js +36 -0
- package/.agent/plugins/poster-plugin/src/templates/business.js +60 -0
- package/.agent/plugins/poster-plugin/src/templates/gradient.js +64 -0
- package/.agent/plugins/poster-plugin/src/templates/index.js +43 -0
- package/.agent/plugins/poster-plugin/src/templates/modern.js +69 -0
- package/.agent/plugins/poster-plugin/src/templates/simple.js +58 -0
- package/.agent/plugins/poster-plugin/src/templates/social.js +62 -0
- package/.agent/plugins/poster-plugin/src/templates/tech.js +84 -0
- package/.agent/plugins/{temp-repo/puppeteer-plugin → puppeteer-plugin}/index.js +1 -1
- package/.agent/plugins.json +5 -11
- package/.agent/rules/GEMINI.md +273 -0
- package/.agent/rules/allow-rule.md +77 -0
- package/.agent/rules/log-rule.md +83 -0
- package/.agent/rules/security-rule.md +93 -0
- package/.agent/scripts/auto_preview.py +148 -0
- package/.agent/scripts/checklist.py +217 -0
- package/.agent/scripts/session_manager.py +120 -0
- package/.agent/scripts/verify_all.py +327 -0
- package/.agent/sessions/cli_default.json +419 -0
- package/.agent/sessions/weixin_o9cq80zgZqKPA2-s59PN43GdDy1w@im.wechat.json +2195 -0
- package/.agent/skills/api-patterns/SKILL.md +81 -0
- package/.agent/skills/api-patterns/api-style.md +42 -0
- package/.agent/skills/api-patterns/auth.md +24 -0
- package/.agent/skills/api-patterns/documentation.md +26 -0
- package/.agent/skills/api-patterns/graphql.md +41 -0
- package/.agent/skills/api-patterns/rate-limiting.md +31 -0
- package/.agent/skills/api-patterns/response.md +37 -0
- package/.agent/skills/api-patterns/rest.md +40 -0
- package/.agent/skills/api-patterns/scripts/api_validator.py +211 -0
- package/.agent/skills/api-patterns/security-testing.md +122 -0
- package/.agent/skills/api-patterns/trpc.md +41 -0
- package/.agent/skills/api-patterns/versioning.md +22 -0
- package/.agent/skills/app-builder/SKILL.md +75 -0
- package/.agent/skills/app-builder/agent-coordination.md +71 -0
- package/.agent/skills/app-builder/feature-building.md +53 -0
- package/.agent/skills/app-builder/project-detection.md +34 -0
- package/.agent/skills/app-builder/scaffolding.md +118 -0
- package/.agent/skills/app-builder/tech-stack.md +40 -0
- package/.agent/skills/app-builder/templates/SKILL.md +39 -0
- package/.agent/skills/app-builder/templates/astro-static/TEMPLATE.md +76 -0
- package/.agent/skills/app-builder/templates/chrome-extension/TEMPLATE.md +92 -0
- package/.agent/skills/app-builder/templates/cli-tool/TEMPLATE.md +88 -0
- package/.agent/skills/app-builder/templates/electron-desktop/TEMPLATE.md +88 -0
- package/.agent/skills/app-builder/templates/express-api/TEMPLATE.md +83 -0
- package/.agent/skills/app-builder/templates/flutter-app/TEMPLATE.md +90 -0
- package/.agent/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +90 -0
- package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +122 -0
- package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +122 -0
- package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +169 -0
- package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +134 -0
- package/.agent/skills/app-builder/templates/python-fastapi/TEMPLATE.md +83 -0
- package/.agent/skills/app-builder/templates/react-native-app/TEMPLATE.md +119 -0
- package/.agent/skills/architecture/SKILL.md +55 -0
- package/.agent/skills/architecture/context-discovery.md +43 -0
- package/.agent/skills/architecture/examples.md +94 -0
- package/.agent/skills/architecture/pattern-selection.md +68 -0
- package/.agent/skills/architecture/patterns-reference.md +50 -0
- package/.agent/skills/architecture/trade-off-analysis.md +77 -0
- package/.agent/skills/clean-code/SKILL.md +201 -0
- package/.agent/skills/doc.md +177 -0
- package/.agent/skills/frontend-design/SKILL.md +418 -0
- package/.agent/skills/frontend-design/animation-guide.md +331 -0
- package/.agent/skills/frontend-design/color-system.md +311 -0
- package/.agent/skills/frontend-design/decision-trees.md +418 -0
- package/.agent/skills/frontend-design/motion-graphics.md +306 -0
- package/.agent/skills/frontend-design/scripts/accessibility_checker.py +183 -0
- package/.agent/skills/frontend-design/scripts/ux_audit.py +722 -0
- package/.agent/skills/frontend-design/typography-system.md +345 -0
- package/.agent/skills/frontend-design/ux-psychology.md +1116 -0
- package/.agent/skills/frontend-design/visual-effects.md +383 -0
- package/.agent/skills/i18n-localization/SKILL.md +154 -0
- package/.agent/skills/i18n-localization/scripts/i18n_checker.py +241 -0
- package/.agent/skills/mcp-builder/SKILL.md +176 -0
- package/.agent/skills/web-design-guidelines/SKILL.md +57 -0
- package/.agent/workflows/brainstorm.md +113 -0
- package/.agent/workflows/create.md +59 -0
- package/.agent/workflows/debug.md +103 -0
- package/.agent/workflows/deploy.md +176 -0
- package/.agent/workflows/enhance.md +63 -0
- package/.agent/workflows/orchestrate.md +237 -0
- package/.agent/workflows/plan.md +89 -0
- package/.agent/workflows/preview.md +81 -0
- package/.agent/workflows/simple-test.md +42 -0
- package/.agent/workflows/status.md +86 -0
- package/.agent/workflows/structured-orchestrate.md +180 -0
- package/.agent/workflows/test.md +144 -0
- package/.agent/workflows/ui-ux-pro-max.md +296 -0
- package/.claude/settings.local.json +20 -8
- package/.env.example +56 -56
- package/CLAUDE.md +144 -108
- package/README.md +441 -441
- package/calc_tokens_weixin.js +81 -0
- package/cli/src/commands/chat.js +2 -1
- package/docs/CONTEXT_DESIGN.md +1596 -0
- package/examples/test-concurrent-chat.js +60 -60
- package/foliko-creative-3.png +0 -0
- package/foliko-creative-4.png +0 -0
- package/foliko-creative-5.png +0 -0
- package/package.json +2 -2
- package/plugins/default-plugins.js +2 -1
- package/plugins/extension-executor-plugin.js +91 -2
- package/plugins/file-system-plugin.js +2 -2
- package/plugins/memory-plugin.js +984 -0
- package/plugins/session-plugin.js +57 -1
- package/plugins/weixin-plugin.js +33 -23
- package/skills/find-skills/AGENTS.md +162 -162
- package/skills/find-skills/SKILL.md +133 -133
- package/skills/poster-guide/SKILL.md +1059 -0
- package/skills/python-plugin-dev/SKILL.md +238 -238
- package/skills/skill-guide/SKILL.md +130 -108
- package/src/capabilities/skill-manager.js +99 -0
- package/src/core/agent-chat.js +620 -141
- package/src/core/agent-context.js +188 -0
- package/src/core/agent.js +6 -2
- package/src/core/context-manager.js +283 -0
- package/src/core/framework.js +264 -3
- package/src/core/plugin-manager.js +79 -2
- package/src/core/request-context.js +98 -0
- package/src/core/session-context.js +341 -0
- package/src/core/session-storage.js +274 -0
- package/src/executors/mcp-executor.js +2 -2
- package/src/utils/index.js +239 -67
- package/src/utils/plugin-helpers.js +17 -0
- package/story-cover-book-v2.png +0 -0
- package/story-cover-japanese-1.png +0 -0
- package/story-cover-japanese-2.png +0 -0
- package/story-cover-japanese-3.png +0 -0
- package/story-cover-moran.png +0 -0
- package/undefined.png +0 -0
- package//346/265/267/346/212/245/346/217/222/344/273/266.md +621 -0
- package/.agent/agents/code-assistant.json +0 -14
- package/.agent/agents/email-assistant.json +0 -14
- package/.agent/agents/file-assistant.json +0 -15
- package/.agent/agents/system-assistant.json +0 -15
- package/.agent/agents/web-assistant.json +0 -12
- package/.agent/data/ambient/goals.json +0 -50
- package/.agent/data/ambient/memories.json +0 -7
- package/.agent/data/scheduler/tasks.json +0 -1
- package/.agent/package.json +0 -8
- package/.agent/plugins/__pycache__/test_plugin.cpython-312.pyc +0 -0
- package/.agent/plugins/daytona/README.md +0 -89
- package/.agent/plugins/daytona/index.js +0 -377
- package/.agent/plugins/daytona/package.json +0 -12
- package/.agent/plugins/marknative/README.md +0 -134
- package/.agent/plugins/marknative/index.js +0 -228
- package/.agent/plugins/marknative/package.json +0 -12
- package/.agent/plugins/marknative/update-readme.js +0 -134
- package/.agent/plugins/system-info/index.js +0 -387
- package/.agent/plugins/system-info/package.json +0 -4
- package/.agent/plugins/system-info/test.js +0 -40
- package/.agent/plugins/temp-repo/LICENSE +0 -201
- package/.agent/plugins/test_plugin.py +0 -304
- package/.agent/python-scripts/test_sample.py +0 -24
- package/.agent/skills/agent-browser/SKILL.md +0 -311
- package/.agent/skills/agent-browser/TEST_PLAN.md +0 -200
- package/.agent/skills/sysinfo/SKILL.md +0 -38
- package/.agent/skills/sysinfo/system-info.sh +0 -130
- package/.agent/skills/workflow/SKILL.md +0 -324
- package/.agent/workflows/email-digest.json +0 -50
- package/.agent/workflows/file-backup.json +0 -21
- package/.agent/workflows/get-ip-notify.json +0 -32
- package/.agent/workflows/news-aggregator.json +0 -93
- package/.agent/workflows/news-dashboard-v2.json +0 -94
- package/.agent/workflows/notification-batch.json +0 -32
- package/examples/test-chat-debug.js +0 -102
- package/examples/test-chat-result.js +0 -76
- package/examples/test-chat-stream-diff.js +0 -63
- /package/.agent/plugins/{temp-repo/puppeteer-plugin → puppeteer-plugin}/README.md +0 -0
- /package/.agent/plugins/{temp-repo/puppeteer-plugin → puppeteer-plugin}/package.json +0 -0
|
@@ -0,0 +1,341 @@
|
|
|
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
|
+
};
|
|
56
|
+
|
|
57
|
+
// 压缩状态
|
|
58
|
+
this.compressionState = {
|
|
59
|
+
lastCompressedAt: null,
|
|
60
|
+
lastTokenCount: 0,
|
|
61
|
+
pendingCompression: false,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// 自定义数据插槽
|
|
65
|
+
this.customData = new Map();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ==================== 消息管理 ====================
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 获取消息历史
|
|
72
|
+
* @returns {Array} 消息数组
|
|
73
|
+
*/
|
|
74
|
+
getMessages() {
|
|
75
|
+
return this.messageStore.messages;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* 添加消息
|
|
80
|
+
* @param {Object} message - 消息对象
|
|
81
|
+
*/
|
|
82
|
+
addMessage(message) {
|
|
83
|
+
this.messageStore.messages.push(message);
|
|
84
|
+
this.metadata.messageCount++;
|
|
85
|
+
this.metadata.lastActive = Date.now();
|
|
86
|
+
this._autoSaveIfEnabled();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* 添加多条消息
|
|
91
|
+
* @param {Array} messages - 消息数组
|
|
92
|
+
*/
|
|
93
|
+
addMessages(messages) {
|
|
94
|
+
for (const msg of messages) {
|
|
95
|
+
this.messageStore.messages.push(msg);
|
|
96
|
+
this.metadata.messageCount++;
|
|
97
|
+
}
|
|
98
|
+
this.metadata.lastActive = Date.now();
|
|
99
|
+
this._autoSaveIfEnabled();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* 替换所有消息(用于压缩后同步)
|
|
104
|
+
* @param {Array} messages - 新消息数组
|
|
105
|
+
*/
|
|
106
|
+
replaceMessages(messages) {
|
|
107
|
+
this.messageStore.messages = messages || [];
|
|
108
|
+
this._autoSaveIfEnabled();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* 清空消息历史
|
|
113
|
+
*/
|
|
114
|
+
clearMessages() {
|
|
115
|
+
this.messageStore.messages = [];
|
|
116
|
+
this._autoSaveIfEnabled();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* 如果启用了自动保存,则保存到存储
|
|
121
|
+
* @private
|
|
122
|
+
*/
|
|
123
|
+
_autoSaveIfEnabled() {
|
|
124
|
+
if (this._autoSave) {
|
|
125
|
+
this.save();
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* 手动保存到存储(立即保存,不 debounce)
|
|
131
|
+
* @returns {Promise}
|
|
132
|
+
*/
|
|
133
|
+
async save() {
|
|
134
|
+
const data = this.toJSON();
|
|
135
|
+
await this._storage.saveImmediate(this.sessionId, data);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* 同步加载(用于文件存储)
|
|
140
|
+
* @param {string} sessionId
|
|
141
|
+
* @param {Framework} framework
|
|
142
|
+
* @param {Object} options
|
|
143
|
+
* @returns {SessionContext|null}
|
|
144
|
+
*/
|
|
145
|
+
static loadSync(sessionId, framework, options = {}) {
|
|
146
|
+
const storage = options.storage || getDefaultAdapter();
|
|
147
|
+
|
|
148
|
+
// 只有 file 类型支持同步加载
|
|
149
|
+
if (storage.type !== 'file') {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const fs = require('fs');
|
|
154
|
+
const path = require('path');
|
|
155
|
+
const filePath = path.resolve(process.cwd(), storage.baseDir, `${sessionId}.json`);
|
|
156
|
+
|
|
157
|
+
if (!fs.existsSync(filePath)) {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
try {
|
|
162
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
163
|
+
const data = JSON.parse(content);
|
|
164
|
+
|
|
165
|
+
// 恢复 SessionContext
|
|
166
|
+
const ctx = new SessionContext(sessionId, framework, {
|
|
167
|
+
...options,
|
|
168
|
+
initialMessages: data.messages || [],
|
|
169
|
+
variables: data.variables || {},
|
|
170
|
+
metadata: data.metadata || {},
|
|
171
|
+
storage,
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
ctx.messageStore.historyLoaded = true;
|
|
175
|
+
return ctx;
|
|
176
|
+
} catch (err) {
|
|
177
|
+
console.error(`[SessionContext] Failed to load sync:`, err.message);
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* 从存储加载(异步)
|
|
184
|
+
* @param {string} sessionId
|
|
185
|
+
* @param {Framework} framework
|
|
186
|
+
* @param {Object} options
|
|
187
|
+
* @returns {Promise<SessionContext|null>}
|
|
188
|
+
*/
|
|
189
|
+
static async load(sessionId, framework, options = {}) {
|
|
190
|
+
const storage = options.storage || getDefaultAdapter();
|
|
191
|
+
const data = await storage.load(sessionId);
|
|
192
|
+
|
|
193
|
+
if (!data) {
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// 恢复 SessionContext
|
|
198
|
+
const ctx = new SessionContext(sessionId, framework, {
|
|
199
|
+
...options,
|
|
200
|
+
initialMessages: data.messages || [],
|
|
201
|
+
variables: data.variables || {},
|
|
202
|
+
metadata: data.metadata || {},
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
ctx.messageStore.historyLoaded = true;
|
|
206
|
+
return ctx;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* 获取消息数量
|
|
211
|
+
* @returns {number}
|
|
212
|
+
*/
|
|
213
|
+
getMessageCount() {
|
|
214
|
+
return this.messageStore.messages.length;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// ==================== 变量管理 ====================
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* 获取变量
|
|
221
|
+
* @param {string} key - 变量名
|
|
222
|
+
* @param {*} defaultValue - 默认值
|
|
223
|
+
* @returns {*}
|
|
224
|
+
*/
|
|
225
|
+
getVariable(key, defaultValue = undefined) {
|
|
226
|
+
return this.variables.get(key) ?? defaultValue;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* 设置变量
|
|
231
|
+
* @param {string} key - 变量名
|
|
232
|
+
* @param {*} value - 变量值
|
|
233
|
+
*/
|
|
234
|
+
setVariable(key, value) {
|
|
235
|
+
this.variables.set(key, value);
|
|
236
|
+
this.touch();
|
|
237
|
+
this._autoSaveIfEnabled();
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* 删除变量
|
|
242
|
+
* @param {string} key - 变量名
|
|
243
|
+
*/
|
|
244
|
+
deleteVariable(key) {
|
|
245
|
+
this.variables.delete(key);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* 获取所有变量
|
|
250
|
+
* @returns {Object}
|
|
251
|
+
*/
|
|
252
|
+
getAllVariables() {
|
|
253
|
+
return Object.fromEntries(this.variables);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// ==================== 元数据 ====================
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* 更新最后活跃时间
|
|
260
|
+
*/
|
|
261
|
+
touch() {
|
|
262
|
+
this.metadata.lastActive = Date.now();
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* 获取会话摘要
|
|
267
|
+
* @returns {Object}
|
|
268
|
+
*/
|
|
269
|
+
getSummary() {
|
|
270
|
+
return {
|
|
271
|
+
sessionId: this.sessionId,
|
|
272
|
+
messageCount: this.metadata.messageCount,
|
|
273
|
+
createdAt: this.metadata.createdAt,
|
|
274
|
+
lastActive: this.metadata.lastActive,
|
|
275
|
+
variables: this.getAllVariables(),
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// ==================== 压缩状态 ====================
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* 更新压缩状态
|
|
283
|
+
* @param {number} tokenCount - 压缩后的 token 数
|
|
284
|
+
*/
|
|
285
|
+
recordCompression(tokenCount) {
|
|
286
|
+
this.compressionState.lastCompressedAt = Date.now();
|
|
287
|
+
this.compressionState.lastTokenCount = tokenCount;
|
|
288
|
+
this.metadata.compressionCount++;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* 获取压缩状态
|
|
293
|
+
* @returns {Object}
|
|
294
|
+
*/
|
|
295
|
+
getCompressionState() {
|
|
296
|
+
return { ...this.compressionState };
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// ==================== 历史加载状态 ====================
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* 标记为已加载历史
|
|
303
|
+
*/
|
|
304
|
+
markHistoryLoaded() {
|
|
305
|
+
this.messageStore.historyLoaded = true;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* 检查是否已加载历史
|
|
310
|
+
* @returns {boolean}
|
|
311
|
+
*/
|
|
312
|
+
isHistoryLoaded() {
|
|
313
|
+
return this.messageStore.historyLoaded;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// ==================== 生命周期 ====================
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* 销毁会话上下文
|
|
320
|
+
*/
|
|
321
|
+
destroy() {
|
|
322
|
+
this.variables.clear();
|
|
323
|
+
this.customData.clear();
|
|
324
|
+
this.messageStore.messages = [];
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* 导出为 JSON(用于持久化)
|
|
329
|
+
* @returns {Object}
|
|
330
|
+
*/
|
|
331
|
+
toJSON() {
|
|
332
|
+
return {
|
|
333
|
+
sessionId: this.sessionId,
|
|
334
|
+
messages: this.messageStore.messages,
|
|
335
|
+
variables: this.getAllVariables(),
|
|
336
|
+
metadata: this.metadata,
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
module.exports = { SessionContext };
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SessionStorageAdapter - Session 持久化存储适配器
|
|
3
|
+
*
|
|
4
|
+
* 支持多种存储后端:
|
|
5
|
+
* - Memory: 内存存储(默认)
|
|
6
|
+
* - File: JSON 文件存储
|
|
7
|
+
* - Future: Database, Redis 等
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
|
|
13
|
+
class SessionStorageAdapter {
|
|
14
|
+
/**
|
|
15
|
+
* @param {Object} options - 配置选项
|
|
16
|
+
* @param {string} [options.type='memory'] - 存储类型: 'memory', 'file'
|
|
17
|
+
* @param {string} [options.baseDir='.agent/sessions'] - 文件存储基础目录
|
|
18
|
+
*/
|
|
19
|
+
constructor(options = {}) {
|
|
20
|
+
this.type = options.type || 'memory';
|
|
21
|
+
this.baseDir = options.baseDir || '.agent/sessions';
|
|
22
|
+
|
|
23
|
+
if (this.type === 'file') {
|
|
24
|
+
this._ensureDirectory();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// 内存存储
|
|
28
|
+
this._memoryStore = new Map();
|
|
29
|
+
|
|
30
|
+
// 写回队列(用于 debounce)
|
|
31
|
+
this._writeQueue = null;
|
|
32
|
+
this._writeTimeout = null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 确保目录存在
|
|
37
|
+
* @private
|
|
38
|
+
*/
|
|
39
|
+
_ensureDirectory() {
|
|
40
|
+
const dir = path.resolve(process.cwd(), this.baseDir);
|
|
41
|
+
if (!fs.existsSync(dir)) {
|
|
42
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* 获取存储文件路径
|
|
48
|
+
* @param {string} sessionId
|
|
49
|
+
* @returns {string}
|
|
50
|
+
* @private
|
|
51
|
+
*/
|
|
52
|
+
_getFilePath(sessionId) {
|
|
53
|
+
return path.resolve(process.cwd(), this.baseDir, `${sessionId}.json`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 保存 Session 数据
|
|
58
|
+
* @param {string} sessionId - 会话 ID
|
|
59
|
+
* @param {Object} data - 要保存的数据
|
|
60
|
+
* @returns {Promise}
|
|
61
|
+
*/
|
|
62
|
+
async save(sessionId, data) {
|
|
63
|
+
if (this.type === 'memory') {
|
|
64
|
+
this._memoryStore.set(sessionId, data);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (this.type === 'file') {
|
|
69
|
+
// Debounce 写操作,500ms 内的多次保存合并为一次
|
|
70
|
+
if (this._writeTimeout) {
|
|
71
|
+
clearTimeout(this._writeTimeout);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return new Promise((resolve, reject) => {
|
|
75
|
+
this._writeQueue = { sessionId, data };
|
|
76
|
+
this._writeTimeout = setTimeout(async () => {
|
|
77
|
+
try {
|
|
78
|
+
await this._writeToFile(this._writeQueue.sessionId, this._writeQueue.data);
|
|
79
|
+
resolve();
|
|
80
|
+
} catch (err) {
|
|
81
|
+
reject(err);
|
|
82
|
+
} finally {
|
|
83
|
+
this._writeQueue = null;
|
|
84
|
+
this._writeTimeout = null;
|
|
85
|
+
}
|
|
86
|
+
}, 500);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* 立即保存(不 debounce)
|
|
93
|
+
* @param {string} sessionId
|
|
94
|
+
* @param {Object} data
|
|
95
|
+
*/
|
|
96
|
+
async saveImmediate(sessionId, data) {
|
|
97
|
+
if (this._writeTimeout) {
|
|
98
|
+
clearTimeout(this._writeTimeout);
|
|
99
|
+
this._writeTimeout = null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (this.type === 'memory') {
|
|
103
|
+
this._memoryStore.set(sessionId, data);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (this.type === 'file') {
|
|
108
|
+
await this._writeToFile(sessionId, data);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* 写入文件
|
|
114
|
+
* @param {string} sessionId
|
|
115
|
+
* @param {Object} data
|
|
116
|
+
* @private
|
|
117
|
+
*/
|
|
118
|
+
async _writeToFile(sessionId, data) {
|
|
119
|
+
const filePath = this._getFilePath(sessionId);
|
|
120
|
+
|
|
121
|
+
try {
|
|
122
|
+
// 确保目录存在
|
|
123
|
+
const dir = path.dirname(filePath);
|
|
124
|
+
if (!fs.existsSync(dir)) {
|
|
125
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const content = JSON.stringify(data, null, 2);
|
|
129
|
+
fs.writeFileSync(filePath, content, 'utf-8');
|
|
130
|
+
} catch (err) {
|
|
131
|
+
console.error(`[SessionStorage] Failed to write ${sessionId}:`, err.message);
|
|
132
|
+
throw err;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* 加载 Session 数据
|
|
138
|
+
* @param {string} sessionId - 会话 ID
|
|
139
|
+
* @returns {Promise<Object|null>}
|
|
140
|
+
*/
|
|
141
|
+
async load(sessionId) {
|
|
142
|
+
if (this.type === 'memory') {
|
|
143
|
+
return this._memoryStore.get(sessionId) || null;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (this.type === 'file') {
|
|
147
|
+
const filePath = this._getFilePath(sessionId);
|
|
148
|
+
|
|
149
|
+
if (!fs.existsSync(filePath)) {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
try {
|
|
154
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
155
|
+
return JSON.parse(content);
|
|
156
|
+
} catch (err) {
|
|
157
|
+
console.error(`[SessionStorage] Failed to read ${sessionId}:`, err.message);
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* 删除 Session 数据
|
|
167
|
+
* @param {string} sessionId - 会话 ID
|
|
168
|
+
* @returns {Promise<boolean>}
|
|
169
|
+
*/
|
|
170
|
+
async delete(sessionId) {
|
|
171
|
+
if (this.type === 'memory') {
|
|
172
|
+
return this._memoryStore.delete(sessionId);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (this.type === 'file') {
|
|
176
|
+
const filePath = this._getFilePath(sessionId);
|
|
177
|
+
|
|
178
|
+
if (fs.existsSync(filePath)) {
|
|
179
|
+
try {
|
|
180
|
+
fs.unlinkSync(filePath);
|
|
181
|
+
return true;
|
|
182
|
+
} catch (err) {
|
|
183
|
+
console.error(`[SessionStorage] Failed to delete ${sessionId}:`, err.message);
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* 列出所有 Session ID
|
|
195
|
+
* @returns {Promise<string[]>}
|
|
196
|
+
*/
|
|
197
|
+
async list() {
|
|
198
|
+
if (this.type === 'memory') {
|
|
199
|
+
return Array.from(this._memoryStore.keys());
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (this.type === 'file') {
|
|
203
|
+
const dir = path.resolve(process.cwd(), this.baseDir);
|
|
204
|
+
|
|
205
|
+
if (!fs.existsSync(dir)) {
|
|
206
|
+
return [];
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
try {
|
|
210
|
+
const files = fs.readdirSync(dir);
|
|
211
|
+
return files.filter((f) => f.endsWith('.json')).map((f) => f.replace(/\.json$/, ''));
|
|
212
|
+
} catch (err) {
|
|
213
|
+
console.error(`[SessionStorage] Failed to list sessions:`, err.message);
|
|
214
|
+
return [];
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return [];
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* 强制刷新所有待处理的写操作
|
|
223
|
+
*/
|
|
224
|
+
async flush() {
|
|
225
|
+
if (this._writeTimeout) {
|
|
226
|
+
clearTimeout(this._writeTimeout);
|
|
227
|
+
this._writeTimeout = null;
|
|
228
|
+
|
|
229
|
+
if (this._writeQueue) {
|
|
230
|
+
await this._writeToFile(this._writeQueue.sessionId, this._writeQueue.data);
|
|
231
|
+
this._writeQueue = null;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* 销毁存储适配器
|
|
238
|
+
*/
|
|
239
|
+
async destroy() {
|
|
240
|
+
await this.flush();
|
|
241
|
+
this._memoryStore.clear();
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* 全局默认存储适配器实例
|
|
247
|
+
*/
|
|
248
|
+
let _defaultAdapter = null;
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* 获取默认存储适配器
|
|
252
|
+
* @param {Object} options - 配置选项
|
|
253
|
+
* @returns {SessionStorageAdapter}
|
|
254
|
+
*/
|
|
255
|
+
function getDefaultAdapter(options = {}) {
|
|
256
|
+
if (!_defaultAdapter) {
|
|
257
|
+
_defaultAdapter = new SessionStorageAdapter(options);
|
|
258
|
+
}
|
|
259
|
+
return _defaultAdapter;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* 设置默认存储适配器
|
|
264
|
+
* @param {SessionStorageAdapter} adapter
|
|
265
|
+
*/
|
|
266
|
+
function setDefaultAdapter(adapter) {
|
|
267
|
+
_defaultAdapter = adapter;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
module.exports = {
|
|
271
|
+
SessionStorageAdapter,
|
|
272
|
+
getDefaultAdapter,
|
|
273
|
+
setDefaultAdapter,
|
|
274
|
+
};
|
|
@@ -502,7 +502,7 @@ class MCPExecutorPlugin extends Plugin {
|
|
|
502
502
|
_refreshAgentMCPPrompt(agent) {
|
|
503
503
|
// 检查是否已刷新过(通过检查系统提示词是否已包含 MCP 描述)
|
|
504
504
|
const existingPrompt = agent._originalPrompt || '';
|
|
505
|
-
if (existingPrompt.includes('
|
|
505
|
+
if (existingPrompt.includes('【MCP Servers】')) {
|
|
506
506
|
return;
|
|
507
507
|
}
|
|
508
508
|
|
|
@@ -532,7 +532,7 @@ class MCPExecutorPlugin extends Plugin {
|
|
|
532
532
|
return '';
|
|
533
533
|
}
|
|
534
534
|
|
|
535
|
-
let desc = '
|
|
535
|
+
let desc = '【MCP Servers】 工具合集\n\n';
|
|
536
536
|
desc += '你可以通过 `mcp_call` 工具调用以下 MCP 服务器的工具。\n\n';
|
|
537
537
|
|
|
538
538
|
for (const [serverName, info] of this._clients) {
|