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
@@ -6,12 +6,13 @@
6
6
  */
7
7
 
8
8
  const chalk = require('chalk').default;
9
+ const { visibleWidth, truncateToWidth } = require('@earendil-works/pi-tui');
9
10
  const { TokenCounter } = require('../../../src/core/token-counter');
10
11
 
11
12
  // Foliko 配色
12
13
  const folikoDim = chalk.hex('#6B7280');
13
14
  const folikoAccent = chalk.hex('#2A9D8F');
14
- const folikoGold = chalk.hex('#E9C46A');
15
+ const folikoGold = chalk.hex('#999a9c');
15
16
 
16
17
  class FooterBar {
17
18
  /**
@@ -116,7 +117,7 @@ class FooterBar {
116
117
 
117
118
  /**
118
119
  * 从 agent 刷新数据
119
- * 从 messageStore 获取最新一次调用的用量,计算增量后累加
120
+ * 从 SessionManager 获取最新一次调用的用量,计算增量后累加
120
121
  */
121
122
  refreshFromAgent() {
122
123
  try {
@@ -125,14 +126,9 @@ class FooterBar {
125
126
 
126
127
  const sessionId = 'cli_default';
127
128
 
128
- // 主动加载历史记录(确保从 SessionContext/文件加载历史消息)
129
- chatHandler._chatSession.loadHistory(sessionId);
130
-
131
- const messageStore = chatHandler._chatSession.getSessionMessageStore(sessionId);
132
- if (!messageStore) return;
133
-
134
129
  // 1. Token 用量:计算与上次记录的增量
135
- if (messageStore.usage) {
130
+ const messageStore = chatHandler._chatSession.getSessionMessageStore(sessionId);
131
+ if (messageStore && messageStore.usage) {
136
132
  const u = messageStore.usage;
137
133
  const inputTokens = u.promptTokens || u.prompt_tokens || 0;
138
134
  const outputTokens = u.completionTokens || u.completion_tokens || 0;
@@ -152,12 +148,16 @@ class FooterBar {
152
148
  this._lastUsage = { inputTokens, outputTokens };
153
149
  }
154
150
 
155
- // 2. 上下文 token 估算(使用 TokenCounter
156
- if (messageStore.messages && messageStore.messages.length > 0) {
157
- const msgTokens = this._tokenCounter.countMessages(messageStore.messages);
158
- this._stats.contextTokens = msgTokens;
159
- if (this._stats.maxContextTokens > 0) {
160
- this._stats.contextPercent = Math.min(100, (msgTokens / this._stats.maxContextTokens) * 100);
151
+ // 2. 上下文 token 估算(使用 SessionManager
152
+ const sessionCtx = this.agent.framework?.getSessionContext(sessionId);
153
+ if (sessionCtx && typeof sessionCtx.getMessages === 'function') {
154
+ const messages = sessionCtx.getMessages();
155
+ if (messages && messages.length > 0) {
156
+ const msgTokens = this._tokenCounter.countMessages(messages);
157
+ this._stats.contextTokens = msgTokens;
158
+ if (this._stats.maxContextTokens > 0) {
159
+ this._stats.contextPercent = Math.min(100, (msgTokens / this._stats.maxContextTokens) * 100);
160
+ }
161
161
  }
162
162
  }
163
163
 
@@ -182,10 +182,10 @@ class FooterBar {
182
182
  const parts = [];
183
183
 
184
184
  // ↑ input tokens
185
- parts.push(folikoGold(`↑${this._formatNum(s.inputTokens)}`));
185
+ parts.push(chalk.dim(`↑${this._formatNum(s.inputTokens)}`));
186
186
 
187
187
  // ↓ output tokens
188
- parts.push(folikoGold(`↓${this._formatNum(s.outputTokens)}`));
188
+ parts.push(chalk.dim(`↓${this._formatNum(s.outputTokens)}`));
189
189
 
190
190
  // $ cost
191
191
  if (s.cost > 0) {
@@ -212,7 +212,7 @@ class FooterBar {
212
212
  let line = parts.join(' ');
213
213
 
214
214
  // 计算实际显示宽度(去除 ANSI 编码)
215
- const visibleLen = visibleWidth ? visibleWidth(line) : line.length;
215
+ const visibleLen = visibleWidth(line);
216
216
 
217
217
  // 如果太长,缩短模型名
218
218
  if (visibleLen > width) {
@@ -226,38 +226,12 @@ class FooterBar {
226
226
  }
227
227
 
228
228
  // 截断到可用宽度
229
- if (visibleWidth && visibleWidth(line) > width) {
230
- line = truncateToWidth ? truncateToWidth(line, width) : line.slice(0, width);
229
+ if (visibleWidth(line) > width) {
230
+ line = truncateToWidth(line, width);
231
231
  }
232
232
 
233
233
  return [line];
234
234
  }
235
235
  }
236
236
 
237
- function visibleWidth(text) {
238
- // 简易 ANSI 不可见宽度计算
239
- const stripped = text.replace(/\x1B\[[0-9;]*m/g, '');
240
- return stripped.length;
241
- }
242
-
243
- function truncateToWidth(text, maxWidth) {
244
- const stripped = text.replace(/\x1B\[[0-9;]*m/g, '');
245
- if (stripped.length <= maxWidth) return text;
246
-
247
- // 需要截断,保留 ANSI 编码不变
248
- let result = '';
249
- let visLen = 0;
250
- const regex = /(\x1B\[[0-9;]*m)|(.)/g;
251
- let match;
252
- while ((match = regex.exec(text)) !== null && visLen < maxWidth) {
253
- if (match[1]) {
254
- result += match[1];
255
- } else {
256
- result += match[2];
257
- visLen++;
258
- }
259
- }
260
- return result;
261
- }
262
-
263
237
  module.exports = { FooterBar };
@@ -28,11 +28,22 @@ class MessageBubble {
28
28
  this._cachedLines = null;
29
29
  }
30
30
 
31
+ /**
32
+ * 实现 pi-tui Component 的 invalidate 接口
33
+ * 主题变化时由 TUI 调用,清除所有缓存
34
+ */
35
+ invalidate() {
36
+ this._cacheKey = null;
37
+ this._cachedLines = null;
38
+ if (this._markdown) {
39
+ this._markdown.invalidate?.();
40
+ }
41
+ }
42
+
31
43
  setContent(content) {
32
44
  if (this.content !== content) {
33
45
  this.content = content;
34
- this._cacheKey = null;
35
- this._cachedLines = null;
46
+ this.invalidate();
36
47
  }
37
48
  }
38
49
 
@@ -41,6 +52,17 @@ class MessageBubble {
41
52
  this.setContent(content);
42
53
  }
43
54
 
55
+ /**
56
+ * 追加已渲染的内容(流式输出增量追加)
57
+ * 比 setText 更高效:跳过全量置换,只追加新内容并清缓存
58
+ * @param {string} renderedDelta - 新渲染的 ANSI 文本片段
59
+ */
60
+ appendContent(renderedDelta) {
61
+ this.content += renderedDelta;
62
+ this._cacheKey = null;
63
+ this._cachedLines = null;
64
+ }
65
+
44
66
  render(width) {
45
67
  // 检查缓存
46
68
  const cacheKey = `${width}:${this.content}`;
@@ -0,0 +1,177 @@
1
+ /**
2
+ * StatusBar — 状态栏组件
3
+ *
4
+ * 封装三个状态槽位:通知(notifier) / 工具调用(tooler) / 思考中(loader)
5
+ * 每个槽位通过子 Container 管理显示/隐藏
6
+ */
7
+
8
+ const { Container, Spacer,Loader } = require('@earendil-works/pi-tui');
9
+ const chalk = require('chalk').default;
10
+
11
+ // Foliko 配色
12
+ const folikoPrimary = chalk.hex('#2A9D8F');
13
+ const folikoGold = chalk.hex('#E9C46A');
14
+
15
+ /**
16
+ * NoMarginLoader — 去掉 Loader 默认的上方空行
17
+ */
18
+ class NoMarginLoader extends Loader {
19
+ render(width) {
20
+ return super.render(width).slice(1); // 去掉 Loader 自动追加的空行
21
+ }
22
+ }
23
+
24
+ class StatusBar {
25
+ constructor(tui, editor) {
26
+ this.tui = tui;
27
+ this.editor = editor;
28
+
29
+ // 顶层容器
30
+ this.container = new Container();
31
+
32
+ // 三个子 Container 槽位
33
+ this._notifierSlot = new Container();
34
+ this._toolerSlot = new Container();
35
+ this._loaderSlot = new Container();
36
+
37
+ // 工具调用 Loader
38
+ const tooler = new NoMarginLoader(
39
+ tui,
40
+ (s) => chalk.green(s),
41
+ (s) => chalk.yellow(s),
42
+ '工具调用...',
43
+ { frames: ['|', '/', '-', '\\'].map((str) => folikoGold(str)) },
44
+ );
45
+
46
+ // 思考中 Loader
47
+ const loader = new NoMarginLoader(
48
+ tui,
49
+ (s) => chalk.cyan(s),
50
+ (s) => chalk.dim(s),
51
+ '正在思考中...',
52
+ { frames: ['⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷'].map((str) => folikoPrimary(str)) },
53
+ );
54
+
55
+ // Spacer 占位(隐藏时填充)
56
+ const toolerSpacer = new Spacer(0);
57
+ const loaderSpacer = new Spacer(0);
58
+ const notifierSpacer = new Spacer(0);
59
+
60
+ // 初始化所有槽位为 Spacer
61
+ this._notifierSlot.addChild(notifierSpacer);
62
+ this._toolerSlot.addChild(toolerSpacer);
63
+ this._loaderSlot.addChild(loaderSpacer);
64
+
65
+ // 挂载到顶层容器
66
+ this.container.addChild(this._notifierSlot);
67
+ this.container.addChild(this._toolerSlot);
68
+ this.container.addChild(this._loaderSlot);
69
+
70
+ // ——— 公开 API ———
71
+ const self = this;
72
+
73
+ /** 工具调用状态 */
74
+ this.tooler = {
75
+ dom: tooler,
76
+ _spacer: toolerSpacer,
77
+ _showed: false,
78
+ show(text) {
79
+ this._showed = true;
80
+ self._toolerSlot.clear();
81
+ self._toolerSlot.addChild(this.dom);
82
+ this.dom.setMessage(text);
83
+ return this.dom;
84
+ },
85
+ hide() {
86
+ this._showed = false;
87
+ self._toolerSlot.clear();
88
+ self._toolerSlot.addChild(this._spacer);
89
+ self.tui.requestRender();
90
+ },
91
+ setText(text) {
92
+ if (!this._showed) {
93
+ this.show(text);
94
+ } else {
95
+ this.dom.setMessage(text);
96
+ }
97
+ },
98
+ };
99
+
100
+ /** 通知提示 */
101
+ this.notifier = {
102
+ dom: null,
103
+ _spacer: notifierSpacer,
104
+ _showed: false,
105
+ _timeout: null,
106
+ show(text, duration = 5000) {
107
+ if (this._timeout) clearTimeout(this._timeout);
108
+
109
+ if (!this.dom) {
110
+ this.dom = new NoMarginLoader(tui, (s) => chalk.cyan(s), (s) => chalk.yellow(s), text);
111
+ }
112
+ this.dom.setMessage(text);
113
+ self._notifierSlot.clear();
114
+ self._notifierSlot.addChild(this.dom);
115
+ this._showed = true;
116
+
117
+ this._timeout = setTimeout(() => this.hide(), duration);
118
+ },
119
+ hide() {
120
+ if (this._timeout) {
121
+ clearTimeout(this._timeout);
122
+ this._timeout = null;
123
+ }
124
+ this._showed = false;
125
+ self._notifierSlot.clear();
126
+ self._notifierSlot.addChild(this._spacer);
127
+ self.tui.requestRender();
128
+ },
129
+ };
130
+
131
+ /** 思考中 Loader(带计时) */
132
+ this.loader = {
133
+ dom: loader,
134
+ _spacer: loaderSpacer,
135
+ _startTime: null,
136
+ _timer: null,
137
+ show() {
138
+ self._loaderSlot.clear();
139
+ self._loaderSlot.addChild(this.dom);
140
+ if (self.editor) self.editor.disableSubmit = true;
141
+
142
+ this._startTime = Date.now();
143
+ this.dom.setMessage('正在思考中... (0秒)');
144
+ this.dom.start();
145
+
146
+ this._timer = setInterval(() => {
147
+ const elapsed = Math.floor((Date.now() - this._startTime) / 1000);
148
+ const seconds = elapsed % 60;
149
+ const minutes = Math.floor(elapsed / 60);
150
+ const timeStr = minutes > 0 ? `${minutes}分${seconds}秒` : `${seconds}秒`;
151
+ this.dom.setMessage(`正在思考中... (${timeStr})`);
152
+ }, 1000);
153
+
154
+ return this.dom;
155
+ },
156
+ hide() {
157
+ if (self.editor) self.editor.disableSubmit = false;
158
+ if (this._timer) {
159
+ clearInterval(this._timer);
160
+ this._timer = null;
161
+ }
162
+ this.dom.stop();
163
+ self._loaderSlot.clear();
164
+ self._loaderSlot.addChild(this._spacer);
165
+ self.tui.requestRender();
166
+ },
167
+ };
168
+ }
169
+
170
+ invalidate() {
171
+ for (const child of this.container.children) {
172
+ child.invalidate?.();
173
+ }
174
+ }
175
+ }
176
+
177
+ module.exports = { StatusBar };
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Foliko 公共配置
3
+ */
4
+
5
+ // 配置目录名(统一管理,方便改名)
6
+ const AGENT_DIR_NAME = '.foliko';
7
+
8
+ // 其他配置目录
9
+ const AGENT_SUBDIRS = {
10
+ AGENTS: 'agents',
11
+ PLUGINS: 'plugins',
12
+ SKILLS: 'skills',
13
+ DATA: 'data',
14
+ SESSIONS: 'sessions',
15
+ LOGS: 'logs',
16
+ MCP_CONFIG: 'mcp_config.json',
17
+ RULES: 'rules',
18
+ };
19
+
20
+ module.exports = {
21
+ AGENT_DIR_NAME,
22
+ AGENT_SUBDIRS,
23
+ getAgentDir: () => AGENT_DIR_NAME,
24
+ getAgentsDir: () => `${AGENT_DIR_NAME}/${AGENT_SUBDIRS.AGENTS}`,
25
+ getPluginsDir: () => `${AGENT_DIR_NAME}/${AGENT_SUBDIRS.PLUGINS}`,
26
+ getDataDir: () => `${AGENT_DIR_NAME}/${AGENT_SUBDIRS.DATA}`,
27
+ getSessionsDir: () => `${AGENT_DIR_NAME}/${AGENT_SUBDIRS.SESSIONS}`,
28
+ getLogsDir: () => `${AGENT_DIR_NAME}/${AGENT_SUBDIRS.LOGS}`,
29
+ };
@@ -16,7 +16,7 @@ const IGNORE_PATTERNS = [
16
16
  '*.lock',
17
17
  '*.bak',
18
18
  '.claude',
19
- '.agent',
19
+ '.foliko',
20
20
  'examples',
21
21
  'dist',
22
22
  'build',
@@ -1,33 +1,33 @@
1
- # ========== Foliko Docker Compose ==========
2
- # 使用方式: docker-compose up -d
3
-
4
- services:
5
- foliko:
6
- build: .
7
- container_name: foliko-agent
8
- restart: unless-stopped
9
- ports:
10
- - '3000:3000'
11
- environment:
12
- # AI 配置
13
- - FOLIKO_PROVIDER=${FOLIKO_PROVIDER:-minimax}
14
- - FOLIKO_MODEL=${FOLIKO_MODEL:-}
15
- - FOLIKO_BASE_URL=${FOLIKO_BASE_URL:-}
16
- - FOLIKO_API_KEY=${FOLIKO_API_KEY:-}
17
- # Web 服务配置
18
- - WEB_PORT=3000
19
- - WEB_HOST=0.0.0.0
20
- - WEB_BASE_URL=${WEB_BASE_URL:-}
21
- # Telegram 配置(可选)
22
- - TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN:-}
23
- # 飞书配置(可选)
24
- - FEISHU_APP_ID=${FEISHU_APP_ID:-}
25
- - FEISHU_APP_SECRET=${FEISHU_APP_SECRET:-}
26
- volumes:
27
- # 持久化数据
28
- - foliko-data:/app/.agent/data
29
- tty: true
30
- stdin_open: true
31
-
32
- volumes:
33
- foliko-data:
1
+ # ========== Foliko Docker Compose ==========
2
+ # 使用方式: docker-compose up -d
3
+
4
+ services:
5
+ foliko:
6
+ build: .
7
+ container_name: foliko-agent
8
+ restart: unless-stopped
9
+ ports:
10
+ - '3000:3000'
11
+ environment:
12
+ # AI 配置
13
+ - FOLIKO_PROVIDER=${FOLIKO_PROVIDER:-minimax}
14
+ - FOLIKO_MODEL=${FOLIKO_MODEL:-}
15
+ - FOLIKO_BASE_URL=${FOLIKO_BASE_URL:-}
16
+ - FOLIKO_API_KEY=${FOLIKO_API_KEY:-}
17
+ # Web 服务配置
18
+ - WEB_PORT=3000
19
+ - WEB_HOST=0.0.0.0
20
+ - WEB_BASE_URL=${WEB_BASE_URL:-}
21
+ # Telegram 配置(可选)
22
+ - TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN:-}
23
+ # 飞书配置(可选)
24
+ - FEISHU_APP_ID=${FEISHU_APP_ID:-}
25
+ - FEISHU_APP_SECRET=${FEISHU_APP_SECRET:-}
26
+ volumes:
27
+ # 持久化数据
28
+ - foliko-data:/app/.foliko/data
29
+ tty: true
30
+ stdin_open: true
31
+
32
+ volumes:
33
+ foliko-data: