foliko 1.0.76 → 1.0.78
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/data/default.json +31559 -0
- package/.agent/data/plugins-state.json +10 -1
- package/.claude/settings.local.json +13 -2
- package/.env.example +56 -54
- package/examples/basic.js +1 -1
- package/package.json +83 -81
- package/plugins/ai-plugin.js +2 -2
- package/plugins/ambient-agent/index.js +1 -1
- package/plugins/audit-plugin.js +1 -1
- package/plugins/default-plugins.js +92 -209
- package/plugins/email/index.js +1 -1
- package/plugins/extension-executor-plugin.js +326 -0
- package/plugins/feishu-plugin.js +1 -1
- package/plugins/file-system-plugin.js +57 -6
- package/plugins/gate-trading.js +747 -0
- package/plugins/install-plugin.js +1 -1
- package/plugins/python-executor-plugin.js +1 -1
- package/plugins/python-plugin-loader.js +275 -105
- package/plugins/rules-plugin.js +1 -1
- package/plugins/scheduler-plugin.js +1 -1
- package/plugins/session-plugin.js +132 -7
- package/plugins/shell-executor-plugin.js +1 -1
- package/plugins/storage-plugin.js +24 -1
- package/plugins/subagent-plugin.js +2 -2
- package/plugins/telegram-plugin.js +1 -1
- package/plugins/think-plugin.js +10 -10
- package/plugins/tools-plugin.js +1 -1
- package/plugins/web-plugin.js +49 -18
- package/plugins/weixin-plugin.js +1 -1
- package/skills/foliko-dev/SKILL.md +583 -500
- package/skills/python-plugin-dev/SKILL.md +238 -266
- package/src/core/agent-chat.js +103 -4
- package/src/core/agent.js +84 -18
- package/src/core/plugin-base.js +43 -0
- package/src/executors/mcp-executor.js +126 -22
|
@@ -31,20 +31,22 @@ class SessionPlugin extends Plugin {
|
|
|
31
31
|
this.description = '会话管理插件,支持多会话隔离、历史记录、会话超时清理'
|
|
32
32
|
this.priority = 5
|
|
33
33
|
|
|
34
|
-
this.system = true
|
|
34
|
+
this.system = true
|
|
35
35
|
|
|
36
36
|
this.config = {
|
|
37
37
|
sessionTTL: config.sessionTTL || 30 * 60 * 1000, // 30分钟
|
|
38
38
|
maxSessions: config.maxSessions || 100,
|
|
39
39
|
maxHistoryLength: config.maxHistoryLength || 150, // 放宽到 150,Agent 已有智能压缩
|
|
40
|
-
autoCleanup: config.autoCleanup
|
|
41
|
-
cleanupInterval: config.cleanupInterval || 5 * 60 * 1000 // 5分钟
|
|
40
|
+
autoCleanup: config.autoCleanup||false, // 默认不开启自动清理,避免误删会话
|
|
41
|
+
cleanupInterval: config.cleanupInterval || 5 * 60 * 1000, // 5分钟
|
|
42
|
+
persistToStorage: config.persistToStorage !== false // 默认持久化到 storage
|
|
42
43
|
}
|
|
43
|
-
|
|
44
|
+
// console.log('SessionPlugin config:', this.config)
|
|
44
45
|
this._framework = null
|
|
45
46
|
this._sessions = new Map()
|
|
46
47
|
this._cleanupTimer = null
|
|
47
48
|
this._events = new EventEmitter()
|
|
49
|
+
this._storageKeyPrefix = 'session:'
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
install(framework) {
|
|
@@ -52,7 +54,108 @@ class SessionPlugin extends Plugin {
|
|
|
52
54
|
return this
|
|
53
55
|
}
|
|
54
56
|
|
|
57
|
+
/**
|
|
58
|
+
* 获取存储实例
|
|
59
|
+
* @private
|
|
60
|
+
*/
|
|
61
|
+
_getStorage() {
|
|
62
|
+
if (!this._framework) return null;
|
|
63
|
+
return this._framework.pluginManager.get('storage');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* 从 storage 加载会话数据
|
|
68
|
+
* @private
|
|
69
|
+
*/
|
|
70
|
+
_loadFromStorage(sessionId) {
|
|
71
|
+
const storage = this._getStorage();
|
|
72
|
+
if (!storage) return null;
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
const store = storage.getStore();
|
|
76
|
+
const data = store.get(this._storageKeyPrefix + sessionId);
|
|
77
|
+
if (data && data.messages) {
|
|
78
|
+
return data;
|
|
79
|
+
}
|
|
80
|
+
} catch (err) {
|
|
81
|
+
// 忽略加载错误
|
|
82
|
+
}
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* 保存会话数据到 storage
|
|
88
|
+
* @private
|
|
89
|
+
*/
|
|
90
|
+
_saveToStorage(session) {
|
|
91
|
+
const storage = this._getStorage();
|
|
92
|
+
if (!storage || !this.config.persistToStorage) return;
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
storage.setDirect(this._storageKeyPrefix + session.id, {
|
|
96
|
+
messages: session.messages,
|
|
97
|
+
variables: session.variables,
|
|
98
|
+
metadata: session.metadata,
|
|
99
|
+
createdAt: session.createdAt,
|
|
100
|
+
lastActive: session.lastActive
|
|
101
|
+
});
|
|
102
|
+
} catch (err) {
|
|
103
|
+
// 忽略保存错误
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* 从 storage 删除会话数据
|
|
109
|
+
* @private
|
|
110
|
+
*/
|
|
111
|
+
_deleteFromStorage(sessionId) {
|
|
112
|
+
const storage = this._getStorage();
|
|
113
|
+
if (!storage) return;
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
storage.deleteDirect(this._storageKeyPrefix + sessionId);
|
|
117
|
+
} catch (err) {
|
|
118
|
+
// 忽略删除错误
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* 从 storage 加载所有会话
|
|
124
|
+
* @private
|
|
125
|
+
*/
|
|
126
|
+
_loadAllFromStorage() {
|
|
127
|
+
const storage = this._getStorage();
|
|
128
|
+
if (!storage) return;
|
|
129
|
+
|
|
130
|
+
try {
|
|
131
|
+
const store = storage.getStore();
|
|
132
|
+
// 遍历 storage 找出所有 session: 开头的键
|
|
133
|
+
for (const [key, value] of store.entries()) {
|
|
134
|
+
if (key.startsWith(this._storageKeyPrefix)) {
|
|
135
|
+
const sessionId = key.substring(this._storageKeyPrefix.length);
|
|
136
|
+
const sessionData = value;
|
|
137
|
+
if (sessionId && sessionData && sessionData.messages) {
|
|
138
|
+
// 恢复会话到内存
|
|
139
|
+
this._sessions.set(sessionId, {
|
|
140
|
+
id: sessionId,
|
|
141
|
+
messages: sessionData.messages || [],
|
|
142
|
+
variables: sessionData.variables || {},
|
|
143
|
+
metadata: sessionData.metadata || {},
|
|
144
|
+
createdAt: sessionData.createdAt ? new Date(sessionData.createdAt) : new Date(),
|
|
145
|
+
lastActive: sessionData.lastActive ? new Date(sessionData.lastActive) : new Date()
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
log.info(`Loaded ${this._sessions.size} sessions from storage`);
|
|
151
|
+
} catch (err) {
|
|
152
|
+
log.warn('Failed to load sessions from storage:', err.message);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
55
156
|
start(framework) {
|
|
157
|
+
// 从 storage 加载所有会话
|
|
158
|
+
this._loadAllFromStorage();
|
|
56
159
|
// 注册会话管理工具
|
|
57
160
|
framework.registerTool({
|
|
58
161
|
name: 'session_create',
|
|
@@ -183,6 +286,7 @@ class SessionPlugin extends Plugin {
|
|
|
183
286
|
}
|
|
184
287
|
|
|
185
288
|
this._sessions.set(id, session)
|
|
289
|
+
this._saveToStorage(session)
|
|
186
290
|
return session
|
|
187
291
|
}
|
|
188
292
|
|
|
@@ -190,11 +294,28 @@ class SessionPlugin extends Plugin {
|
|
|
190
294
|
* 获取会话
|
|
191
295
|
*/
|
|
192
296
|
getSession(sessionId) {
|
|
193
|
-
|
|
297
|
+
let session = this._sessions.get(sessionId)
|
|
194
298
|
if (session) {
|
|
195
299
|
session.lastActive = new Date()
|
|
300
|
+
return session
|
|
196
301
|
}
|
|
197
|
-
|
|
302
|
+
|
|
303
|
+
// 尝试从 storage 加载
|
|
304
|
+
const storageData = this._loadFromStorage(sessionId)
|
|
305
|
+
if (storageData) {
|
|
306
|
+
session = {
|
|
307
|
+
id: sessionId,
|
|
308
|
+
messages: storageData.messages || [],
|
|
309
|
+
variables: storageData.variables || {},
|
|
310
|
+
metadata: storageData.metadata || {},
|
|
311
|
+
createdAt: storageData.createdAt ? new Date(storageData.createdAt) : new Date(),
|
|
312
|
+
lastActive: new Date()
|
|
313
|
+
}
|
|
314
|
+
this._sessions.set(sessionId, session)
|
|
315
|
+
return session
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
return null
|
|
198
319
|
}
|
|
199
320
|
|
|
200
321
|
/**
|
|
@@ -221,6 +342,9 @@ class SessionPlugin extends Plugin {
|
|
|
221
342
|
if (session.messages.length > this.config.maxHistoryLength) {
|
|
222
343
|
session.messages = session.messages.slice(-this.config.maxHistoryLength)
|
|
223
344
|
}
|
|
345
|
+
|
|
346
|
+
// 持久化到 storage
|
|
347
|
+
this._saveToStorage(session)
|
|
224
348
|
}
|
|
225
349
|
return session
|
|
226
350
|
}
|
|
@@ -245,6 +369,7 @@ class SessionPlugin extends Plugin {
|
|
|
245
369
|
deleteSession(sessionId) {
|
|
246
370
|
const deleted = this._sessions.delete(sessionId)
|
|
247
371
|
if (deleted) {
|
|
372
|
+
this._deleteFromStorage(sessionId)
|
|
248
373
|
this._events.emit('session:deleted', sessionId)
|
|
249
374
|
}
|
|
250
375
|
return deleted
|
|
@@ -367,4 +492,4 @@ class SessionPlugin extends Plugin {
|
|
|
367
492
|
}
|
|
368
493
|
}
|
|
369
494
|
|
|
370
|
-
module.exports =
|
|
495
|
+
module.exports = SessionPlugin
|
|
@@ -223,6 +223,29 @@ class StoragePlugin extends Plugin {
|
|
|
223
223
|
return this._store
|
|
224
224
|
}
|
|
225
225
|
|
|
226
|
+
/**
|
|
227
|
+
* 直接设置值并自动持久化(供其他插件使用)
|
|
228
|
+
* @param {string} key - 键
|
|
229
|
+
* @param {any} value - 值
|
|
230
|
+
*/
|
|
231
|
+
setDirect(key, value) {
|
|
232
|
+
this._store.set(key, value)
|
|
233
|
+
if (this.config.type === 'json') {
|
|
234
|
+
this._persistToFile()
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* 删除键并自动持久化(供其他插件使用)
|
|
240
|
+
* @param {string} key - 键
|
|
241
|
+
*/
|
|
242
|
+
deleteDirect(key) {
|
|
243
|
+
this._store.delete(key)
|
|
244
|
+
if (this.config.type === 'json') {
|
|
245
|
+
this._persistToFile()
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
226
249
|
reload(framework) {
|
|
227
250
|
this._framework = framework
|
|
228
251
|
this._store.clear()
|
|
@@ -238,4 +261,4 @@ class StoragePlugin extends Plugin {
|
|
|
238
261
|
}
|
|
239
262
|
}
|
|
240
263
|
|
|
241
|
-
module.exports =
|
|
264
|
+
module.exports = StoragePlugin
|
package/plugins/think-plugin.js
CHANGED
|
@@ -22,7 +22,7 @@ class ThinkPlugin extends Plugin {
|
|
|
22
22
|
maxReflectDepth: config.maxReflectDepth || 3, // 最大反思深度
|
|
23
23
|
enableContinuous: config.enableContinuous || false // 是否启用持续思考
|
|
24
24
|
}
|
|
25
|
-
|
|
25
|
+
this.tools = {} // 存储注册的工具函数
|
|
26
26
|
this._framework = null
|
|
27
27
|
this._thoughts = [] // 思考记录
|
|
28
28
|
this._reflectionChain = [] // 反思链
|
|
@@ -38,7 +38,7 @@ class ThinkPlugin extends Plugin {
|
|
|
38
38
|
|
|
39
39
|
start(framework) {
|
|
40
40
|
// 注册思考工具
|
|
41
|
-
|
|
41
|
+
this.tools.think_now = {
|
|
42
42
|
name: 'think_now',
|
|
43
43
|
description: '立即触发 LLM 主动思考(用于反思、自我检视、生成想法)',
|
|
44
44
|
inputSchema: z.object({
|
|
@@ -49,9 +49,9 @@ class ThinkPlugin extends Plugin {
|
|
|
49
49
|
execute: async (args) => {
|
|
50
50
|
return await this._triggerThinking(args)
|
|
51
51
|
}
|
|
52
|
-
}
|
|
52
|
+
}
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
this.tools.think_continue = {
|
|
55
55
|
name: 'think_continue',
|
|
56
56
|
description: '让 LLM 持续思考模式(后台自动思考,定期输出结果)',
|
|
57
57
|
inputSchema: z.object({
|
|
@@ -61,18 +61,18 @@ class ThinkPlugin extends Plugin {
|
|
|
61
61
|
execute: async (args) => {
|
|
62
62
|
return await this._startContinuousThinking(args)
|
|
63
63
|
}
|
|
64
|
-
}
|
|
64
|
+
}
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
this.tools.think_stop = {
|
|
67
67
|
name: 'think_stop',
|
|
68
68
|
description: '停止持续思考模式',
|
|
69
69
|
inputSchema: z.object({}),
|
|
70
70
|
execute: async () => {
|
|
71
71
|
return this._stopContinuousThinking()
|
|
72
72
|
}
|
|
73
|
-
}
|
|
73
|
+
}
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
this.tools.think_get_thoughts = {
|
|
76
76
|
name: 'think_get_thoughts',
|
|
77
77
|
description: '获取思考历史记录',
|
|
78
78
|
inputSchema: z.object({
|
|
@@ -86,7 +86,7 @@ class ThinkPlugin extends Plugin {
|
|
|
86
86
|
total: this._thoughts.length
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
|
-
}
|
|
89
|
+
}
|
|
90
90
|
|
|
91
91
|
return this
|
|
92
92
|
}
|
|
@@ -342,4 +342,4 @@ ${topic || '接下来的行动'}
|
|
|
342
342
|
}
|
|
343
343
|
}
|
|
344
344
|
|
|
345
|
-
module.exports =
|
|
345
|
+
module.exports = ThinkPlugin
|
package/plugins/tools-plugin.js
CHANGED
package/plugins/web-plugin.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
const { Plugin } = require('../src/core/plugin-base')
|
|
7
7
|
const { logger } = require('../src/utils/logger')
|
|
8
|
+
const { runInSandbox } = require('../src/utils/sandbox')
|
|
8
9
|
const log = logger.child('Web')
|
|
9
10
|
const { z } = require('zod')
|
|
10
11
|
const { serve } = require('@hono/node-server')
|
|
@@ -32,6 +33,8 @@ class WebPlugin extends Plugin {
|
|
|
32
33
|
this._app = null
|
|
33
34
|
this._framework = null
|
|
34
35
|
|
|
36
|
+
this.tools = {}
|
|
37
|
+
|
|
35
38
|
// 数据存储(始终保持原始类型)
|
|
36
39
|
this._routes = [] // 路由列表
|
|
37
40
|
this._webhooks = new Map() // webhook Map: id -> {id, path, prompt, sessionId}
|
|
@@ -73,7 +76,7 @@ class WebPlugin extends Plugin {
|
|
|
73
76
|
|
|
74
77
|
_registerTools() {
|
|
75
78
|
// 启动 Web 服务
|
|
76
|
-
this.
|
|
79
|
+
this.tools.web_start = {
|
|
77
80
|
name: 'web_start',
|
|
78
81
|
description: '启动 Web 服务',
|
|
79
82
|
inputSchema: z.object({
|
|
@@ -81,18 +84,18 @@ class WebPlugin extends Plugin {
|
|
|
81
84
|
host: z.string().optional().describe('主机地址,默认 0.0.0.0')
|
|
82
85
|
}),
|
|
83
86
|
execute: async (args) => this._startServer(args.port, args.host)
|
|
84
|
-
}
|
|
87
|
+
}
|
|
85
88
|
|
|
86
89
|
// 停止 Web 服务
|
|
87
|
-
this.
|
|
90
|
+
this.tools.web_stop = {
|
|
88
91
|
name: 'web_stop',
|
|
89
92
|
description: '停止 Web 服务',
|
|
90
93
|
inputSchema: z.object({}),
|
|
91
94
|
execute: async () => this._stopServer()
|
|
92
|
-
}
|
|
95
|
+
}
|
|
93
96
|
|
|
94
97
|
// 注册 HTTP 路由
|
|
95
|
-
this.
|
|
98
|
+
this.tools.web_register_route = {
|
|
96
99
|
name: 'web_register_route',
|
|
97
100
|
description: '注册 HTTP 路由',
|
|
98
101
|
inputSchema: z.object({
|
|
@@ -107,10 +110,10 @@ class WebPlugin extends Plugin {
|
|
|
107
110
|
description: z.string().optional().describe('路由描述')
|
|
108
111
|
}),
|
|
109
112
|
execute: async (args) => this._registerRoute(args.method, args.path, args.handler, args.description)
|
|
110
|
-
}
|
|
113
|
+
}
|
|
111
114
|
|
|
112
115
|
// 注册 Webhook(自动生成 /webhook/{id} 链接)
|
|
113
|
-
this.
|
|
116
|
+
this.tools.web_register_webhook = {
|
|
114
117
|
name: 'web_register_webhook',
|
|
115
118
|
description: '注册 Webhook,接收的数据会交给 LLM 处理。自动生成唯一 URL',
|
|
116
119
|
inputSchema: z.object({
|
|
@@ -118,10 +121,10 @@ class WebPlugin extends Plugin {
|
|
|
118
121
|
awaitResponse: z.boolean().optional().describe('是否等待 LLM 处理完成再返回响应,默认 false')
|
|
119
122
|
}),
|
|
120
123
|
execute: async (args) => this._registerWebhook(args.prompt, args.awaitResponse)
|
|
121
|
-
}
|
|
124
|
+
}
|
|
122
125
|
|
|
123
126
|
// 注册静态资源
|
|
124
|
-
this.
|
|
127
|
+
this.tools.web_register_static = {
|
|
125
128
|
name: 'web_register_static',
|
|
126
129
|
description: '注册静态资源文件夹',
|
|
127
130
|
inputSchema: z.object({
|
|
@@ -133,18 +136,18 @@ class WebPlugin extends Plugin {
|
|
|
133
136
|
}).optional()
|
|
134
137
|
}),
|
|
135
138
|
execute: async (args) => this._registerStatic(args.urlPath, args.folder, args.options)
|
|
136
|
-
}
|
|
139
|
+
}
|
|
137
140
|
|
|
138
141
|
// 列出所有路由
|
|
139
|
-
this.
|
|
142
|
+
this.tools.web_list_routes = {
|
|
140
143
|
name: 'web_list_routes',
|
|
141
144
|
description: '列出所有已注册的路由和 Webhook',
|
|
142
145
|
inputSchema: z.object({}),
|
|
143
146
|
execute: async () => this._listRoutes()
|
|
144
|
-
}
|
|
147
|
+
}
|
|
145
148
|
|
|
146
149
|
// 发送 HTTP 请求
|
|
147
|
-
this.
|
|
150
|
+
this.tools.web_request = {
|
|
148
151
|
name: 'web_request',
|
|
149
152
|
description: '发送 HTTP 请求',
|
|
150
153
|
inputSchema: z.object({
|
|
@@ -154,7 +157,7 @@ class WebPlugin extends Plugin {
|
|
|
154
157
|
headers: z.record(z.string()).optional().describe('请求头')
|
|
155
158
|
}),
|
|
156
159
|
execute: async (args) => this._sendRequest(args.method, args.path, args.body, args.headers)
|
|
157
|
-
}
|
|
160
|
+
}
|
|
158
161
|
}
|
|
159
162
|
|
|
160
163
|
// ==================== 服务器控制 ====================
|
|
@@ -241,9 +244,12 @@ class WebPlugin extends Plugin {
|
|
|
241
244
|
}
|
|
242
245
|
}
|
|
243
246
|
|
|
244
|
-
// 2. Webhook
|
|
247
|
+
// 2. Webhook(仅接受 POST)
|
|
245
248
|
const webhook = this._webhooks.get(pathname)
|
|
246
249
|
if (webhook) {
|
|
250
|
+
if (c.req.method !== 'POST') {
|
|
251
|
+
return c.json({ success: false, error: 'Method Not Allowed. Webhook only accepts POST.' }, 405)
|
|
252
|
+
}
|
|
247
253
|
const result = await this._handleWebhook(c, webhook)
|
|
248
254
|
return c.json(result)
|
|
249
255
|
}
|
|
@@ -336,7 +342,7 @@ class WebPlugin extends Plugin {
|
|
|
336
342
|
}
|
|
337
343
|
|
|
338
344
|
// 触发 webhook 处理完成事件
|
|
339
|
-
this._framework.emit('webhook:
|
|
345
|
+
this._framework.emit('webhook:processed', { webhook, data: webhookData, response: responseText, sessionId: finalSessionId })
|
|
340
346
|
}).catch(err => {
|
|
341
347
|
log.error(' Webhook error:', err.message)
|
|
342
348
|
})
|
|
@@ -535,8 +541,33 @@ class WebPlugin extends Plugin {
|
|
|
535
541
|
|
|
536
542
|
async _executeHandler(handlerCode, context, tools) {
|
|
537
543
|
try {
|
|
544
|
+
// 辅助函数
|
|
545
|
+
const helpers = {
|
|
546
|
+
// 基础工具
|
|
547
|
+
echo: (val) => val,
|
|
548
|
+
json: (val) => JSON.stringify(val),
|
|
549
|
+
JSON: JSON,
|
|
550
|
+
// 日期时间
|
|
551
|
+
Date: Date,
|
|
552
|
+
now: () => Date.now(),
|
|
553
|
+
// 字符串
|
|
554
|
+
Str: String,
|
|
555
|
+
// 编码
|
|
556
|
+
btoa: (str) => Buffer.from(str).toString('base64'),
|
|
557
|
+
atob: (str) => Buffer.from(str, 'base64').toString(),
|
|
558
|
+
// 格式化
|
|
559
|
+
template: (str, vars) => str.replace(/\{\{(\w+)\}\}/g, (_, k) => vars[k] ?? `{{${k}}}`),
|
|
560
|
+
// 随机
|
|
561
|
+
uuid: () => Math.random().toString(36).substring(2) + Date.now().toString(36),
|
|
562
|
+
// HTTP 请求(通过 fetch)
|
|
563
|
+
fetch: async (url, options = {}) => {
|
|
564
|
+
const { method = 'GET', headers = {}, body } = options
|
|
565
|
+
const res = await fetch(url, { method, headers, body })
|
|
566
|
+
return { status: res.status, headers: Object.fromEntries(res.headers), body: await res.text() }
|
|
567
|
+
}
|
|
568
|
+
}
|
|
538
569
|
// 使用沙箱执行用户代码,防止恶意代码执行
|
|
539
|
-
return await runInSandbox(handlerCode, { context, tools }, { timeout: 10000 })
|
|
570
|
+
return await runInSandbox(handlerCode, { context, tools, ...helpers }, { timeout: 10000 })
|
|
540
571
|
} catch (err) {
|
|
541
572
|
return { success: false, error: `Handler error: ${err.message}` }
|
|
542
573
|
}
|
|
@@ -603,4 +634,4 @@ class WebPlugin extends Plugin {
|
|
|
603
634
|
}
|
|
604
635
|
}
|
|
605
636
|
|
|
606
|
-
module.exports =
|
|
637
|
+
module.exports = WebPlugin
|
package/plugins/weixin-plugin.js
CHANGED