foliko 2.0.5 → 2.0.6
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 +4 -1
- package/.cli_default_systemPrompt.md +291 -0
- package/.editorconfig +56 -56
- package/.lintstagedrc +7 -7
- package/.prettierignore +29 -29
- package/.prettierrc +11 -11
- package/CLAUDE.md +3 -0
- package/Dockerfile +63 -63
- package/README.md +20 -3
- package/docs/architecture.md +34 -2
- package/docs/extensions.md +199 -0
- package/docs/migration.md +100 -0
- package/docs/public-api.md +280 -24
- package/docs/usage.md +122 -30
- package/install.ps1 +129 -129
- package/install.sh +121 -121
- package/package.json +1 -1
- package/plugins/core/audit/index.js +1 -1
- package/plugins/core/default/bootstrap.js +44 -19
- package/plugins/core/python-loader/index.js +43 -25
- package/plugins/core/skill-manager/PROMPT.md +6 -0
- package/plugins/core/skill-manager/index.js +402 -115
- package/plugins/core/sub-agent/PROMPT.md +10 -0
- package/plugins/core/sub-agent/index.js +36 -3
- package/plugins/core/think/index.js +1 -0
- package/plugins/core/workflow/index.js +82 -22
- package/plugins/executors/data-splitter/PROMPT.md +13 -0
- package/plugins/executors/data-splitter/index.js +5 -4
- package/plugins/executors/extension/extension-registry.js +145 -0
- package/plugins/executors/extension/index.js +405 -437
- package/plugins/executors/extension/prompt-builder.js +359 -0
- package/plugins/executors/extension/skill-helper.js +143 -0
- package/plugins/messaging/feishu/index.js +5 -3
- package/plugins/messaging/qq/index.js +6 -4
- package/plugins/messaging/telegram/index.js +6 -3
- package/plugins/messaging/weixin/index.js +5 -3
- package/plugins/tools/PROMPT.md +26 -0
- package/plugins/tools/index.js +6 -5
- package/skills/find-skills/SKILL.md +133 -133
- package/skills/foliko/AGENTS.md +196 -43
- package/skills/foliko/SKILL.md +157 -28
- package/skills/mcp/SKILL.md +77 -118
- package/skills/plugins/SKILL.md +89 -3
- package/skills/python/SKILL.md +57 -39
- package/skills/skill-guide/SKILL.md +42 -34
- package/skills/workflows/SKILL.md +224 -9
- package/skills/workflows/workflow-troubleshooting/SKILL.md +221 -281
- package/src/agent/chat.js +48 -27
- package/src/agent/main.js +34 -13
- package/src/agent/prompt-registry.js +56 -16
- package/src/agent/prompts/PROMPT.md +3 -0
- package/src/agent/sub.js +1 -1
- package/src/cli/ui/chat-ui-old.js +5 -2
- package/src/cli/ui/chat-ui.js +5 -2
- package/src/common/constants.js +12 -0
- package/src/common/error-capture.js +91 -0
- package/src/common/logger.js +2 -2
- package/src/context/compressor.js +6 -2
- package/src/executors/mcp-executor.js +105 -125
- package/src/framework/framework.js +23 -11
- package/src/index.js +4 -0
- package/src/plugin/base.js +908 -5
- package/src/plugin/manager.js +29 -8
- package/src/tool/schema.js +32 -9
- package/website/index.html +821 -0
package/src/plugin/manager.js
CHANGED
|
@@ -42,6 +42,15 @@ class PluginManager {
|
|
|
42
42
|
* 注册插件(不加载,只记录状态)
|
|
43
43
|
*/
|
|
44
44
|
register(plugin, options = {}) {
|
|
45
|
+
// 处理 function(Plugin) { return class... } 格式
|
|
46
|
+
if (typeof plugin === 'function' && !(plugin instanceof Plugin)) {
|
|
47
|
+
try {
|
|
48
|
+
plugin = plugin(Plugin);
|
|
49
|
+
} catch (err) {
|
|
50
|
+
throw new PluginError(`Plugin factory function failed: ${err.message}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
45
54
|
if (!(plugin instanceof Plugin)) {
|
|
46
55
|
throw new PluginError('Plugin must be an instance of Plugin');
|
|
47
56
|
}
|
|
@@ -146,9 +155,18 @@ class PluginManager {
|
|
|
146
155
|
async load(plugin, options = {}) {
|
|
147
156
|
let pluginInstance = plugin;
|
|
148
157
|
|
|
149
|
-
//
|
|
150
|
-
if (typeof plugin === 'function'
|
|
151
|
-
|
|
158
|
+
// 处理 function(Plugin) { return class... } 格式
|
|
159
|
+
if (typeof plugin === 'function') {
|
|
160
|
+
if (plugin.prototype instanceof Plugin) {
|
|
161
|
+
// Plugin 子类
|
|
162
|
+
pluginInstance = new plugin();
|
|
163
|
+
} else {
|
|
164
|
+
// Factory function
|
|
165
|
+
pluginInstance = plugin(Plugin);
|
|
166
|
+
if (pluginInstance.prototype instanceof Plugin) {
|
|
167
|
+
pluginInstance = new pluginInstance();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
152
170
|
}
|
|
153
171
|
|
|
154
172
|
const name = pluginInstance.name;
|
|
@@ -187,7 +205,7 @@ class PluginManager {
|
|
|
187
205
|
this._log.info(`Loading plugin: ${name}`);
|
|
188
206
|
|
|
189
207
|
if (typeof pluginInstance.install === 'function') {
|
|
190
|
-
pluginInstance.install(this.framework);
|
|
208
|
+
await pluginInstance.install(this.framework);
|
|
191
209
|
}
|
|
192
210
|
|
|
193
211
|
entry.status = 'loaded';
|
|
@@ -250,10 +268,10 @@ class PluginManager {
|
|
|
250
268
|
await plugin.reload(this.framework);
|
|
251
269
|
} else {
|
|
252
270
|
if (typeof plugin.uninstall === 'function') {
|
|
253
|
-
plugin.uninstall(this.framework);
|
|
271
|
+
await plugin.uninstall(this.framework);
|
|
254
272
|
}
|
|
255
273
|
if (typeof plugin.install === 'function') {
|
|
256
|
-
plugin.install(this.framework);
|
|
274
|
+
await plugin.install(this.framework);
|
|
257
275
|
}
|
|
258
276
|
if (typeof plugin.start === 'function') {
|
|
259
277
|
await plugin.start(this.framework);
|
|
@@ -342,10 +360,10 @@ class PluginManager {
|
|
|
342
360
|
} else {
|
|
343
361
|
// 没有 reload,走完整 uninstall + install + start
|
|
344
362
|
if (typeof entry.instance.uninstall === 'function') {
|
|
345
|
-
entry.instance.uninstall(this.framework);
|
|
363
|
+
await entry.instance.uninstall(this.framework);
|
|
346
364
|
}
|
|
347
365
|
if (typeof entry.instance.install === 'function') {
|
|
348
|
-
entry.instance.install(this.framework);
|
|
366
|
+
await entry.instance.install(this.framework);
|
|
349
367
|
}
|
|
350
368
|
if (typeof entry.instance.start === 'function') {
|
|
351
369
|
await entry.instance.start(this.framework);
|
|
@@ -405,6 +423,9 @@ class PluginManager {
|
|
|
405
423
|
}
|
|
406
424
|
}
|
|
407
425
|
|
|
426
|
+
// 清理该插件注册的提示词
|
|
427
|
+
entry.instance._cleanupPrompts?.();
|
|
428
|
+
|
|
408
429
|
this.framework?.emit('plugin:disabled', entry.instance);
|
|
409
430
|
this._saveState();
|
|
410
431
|
this._log.info(`Plugin '${name}' disabled`);
|
package/src/tool/schema.js
CHANGED
|
@@ -13,15 +13,36 @@ const { z } = require('zod');
|
|
|
13
13
|
* @param {boolean} [required] - Whether this schema is required (optional when false)
|
|
14
14
|
* @returns {z.ZodType}
|
|
15
15
|
*/
|
|
16
|
+
/**
|
|
17
|
+
* Convert JSON Schema to Zod schema
|
|
18
|
+
* @param {Object} jsonSchema
|
|
19
|
+
* @param {boolean} [required] - Whether the root schema is required (default true)
|
|
20
|
+
* @returns {z.ZodType}
|
|
21
|
+
*/
|
|
16
22
|
function jsonSchemaToZod(jsonSchema, required) {
|
|
17
23
|
if (!jsonSchema || typeof jsonSchema !== 'object') {
|
|
18
24
|
return z.any();
|
|
19
25
|
}
|
|
20
26
|
|
|
21
|
-
|
|
27
|
+
// 根级默认 required=true,optional() 在对象字段级别应用
|
|
28
|
+
const isRequired = required !== false;
|
|
29
|
+
return _applyOptional(_convertSchema(jsonSchema, true), isRequired, jsonSchema);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* 在对象字段构建时调用:根据 required 包装
|
|
34
|
+
*/
|
|
35
|
+
function _applyOptional(zodType, isRequired, schema) {
|
|
36
|
+
if (isRequired) return zodType;
|
|
37
|
+
if (schema && schema.default !== undefined) return zodType;
|
|
38
|
+
return zodType.optional();
|
|
22
39
|
}
|
|
23
40
|
|
|
24
|
-
|
|
41
|
+
/**
|
|
42
|
+
* 内部转换:只负责类型转换,不做 optional 包装
|
|
43
|
+
* optional 包装由调用方根据 required 参数决定
|
|
44
|
+
*/
|
|
45
|
+
function _convertSchema(schema, _required = true) {
|
|
25
46
|
if (!schema) return z.any();
|
|
26
47
|
|
|
27
48
|
let type = schema.type;
|
|
@@ -55,8 +76,10 @@ function _convertSchema(schema, required = false) {
|
|
|
55
76
|
zodType = z.boolean();
|
|
56
77
|
break;
|
|
57
78
|
case 'array': {
|
|
79
|
+
// 数组项的 required 由 _required 决定(通常为 true,因为数组存在即代表"有数组")
|
|
80
|
+
const itemRequired = _required && schema.items?.required !== false;
|
|
58
81
|
if (schema.items) {
|
|
59
|
-
zodType = z.array(_convertSchema(schema.items,
|
|
82
|
+
zodType = z.array(_convertSchema(schema.items, itemRequired));
|
|
60
83
|
} else {
|
|
61
84
|
zodType = z.array(z.any());
|
|
62
85
|
}
|
|
@@ -68,12 +91,14 @@ function _convertSchema(schema, required = false) {
|
|
|
68
91
|
break;
|
|
69
92
|
}
|
|
70
93
|
const shape = {};
|
|
71
|
-
const req = schema.required || [];
|
|
94
|
+
const req = new Set(schema.required || []);
|
|
72
95
|
for (const [key, prop] of Object.entries(schema.properties)) {
|
|
73
|
-
|
|
96
|
+
const isRequired = req.has(key);
|
|
97
|
+
// 子字段的 optional() 在这里统一包装
|
|
98
|
+
const fieldSchema = _convertSchema(prop, isRequired);
|
|
99
|
+
shape[key] = _applyOptional(fieldSchema, isRequired, prop);
|
|
74
100
|
}
|
|
75
|
-
|
|
76
|
-
zodType = req.length === Object.keys(shape).length ? obj : obj.partial();
|
|
101
|
+
zodType = z.object(shape);
|
|
77
102
|
break;
|
|
78
103
|
}
|
|
79
104
|
case 'null':
|
|
@@ -84,8 +109,6 @@ function _convertSchema(schema, required = false) {
|
|
|
84
109
|
}
|
|
85
110
|
|
|
86
111
|
if (schema.nullable) zodType = zodType.nullable();
|
|
87
|
-
if (!required && schema.default === undefined) zodType = zodType.optional();
|
|
88
|
-
|
|
89
112
|
return zodType;
|
|
90
113
|
}
|
|
91
114
|
|