foliko 1.1.69 → 1.1.70
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/package.json
CHANGED
|
@@ -392,7 +392,7 @@ class ExtensionExecutorPlugin extends Plugin {
|
|
|
392
392
|
if (this._extensions.size > 0 || (this._mcpExecutor && Object.keys(this._mcpExecutor.tools || {}).length > 0)) {
|
|
393
393
|
desc += '## 【Extensions】扩展插件\n\n';
|
|
394
394
|
desc += '**使用流程(必须按顺序执行):**\n';
|
|
395
|
-
desc += '1. 调用 `ext_skill({ plugin: "skill" })` 获取技能命令的详细参数\n';
|
|
395
|
+
desc += '1. 调用 `ext_skill({ plugin: "<plugin_name>" })` 或 `loadSkill({ skill: "<skill_name>" })` 获取技能命令的详细参数\n';
|
|
396
396
|
desc += '2. 根据返回的参数定义,使用 `ext_call({ plugin: "skill", tool: "技能名:命令名", args: {...} })` 调用\n\n';
|
|
397
397
|
desc += '> **警告**:禁止在未执行第1步获取参数的情况下直接调用 `ext_call`!\n\n';
|
|
398
398
|
|
|
@@ -437,7 +437,7 @@ class ExtensionExecutorPlugin extends Plugin {
|
|
|
437
437
|
}
|
|
438
438
|
|
|
439
439
|
desc += '\n## 禁止事项\n';
|
|
440
|
-
desc += '- 不先调用 `ext_skill` 获取参数就直接使用 `ext_call`\n';
|
|
440
|
+
desc += '- 不先调用 `ext_skill/loadSkill` 获取参数就直接使用 `ext_call`\n';
|
|
441
441
|
}
|
|
442
442
|
|
|
443
443
|
if (!desc) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: skill-guide
|
|
3
|
-
description: 技能安装与开发指南。当用户询问"如何添加技能"、"自定义技能"、"安装技能"
|
|
3
|
+
description: 技能安装与开发指南。当用户询问"如何添加技能"、"自定义技能"、"安装技能"、"创建技能"时立即调用。如果技能有命令,必须在 SKILL.md 中添加 ## 命令 章节详细说明。
|
|
4
4
|
allowed-tools: Read, Write, Edit, Glob, Grep, Bash
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -84,7 +84,146 @@ frontmatter 之后是技能的正文内容,支持 Markdown 格式,包含:
|
|
|
84
84
|
1. 在 `.foliko/skills/` 下创建技能文件夹
|
|
85
85
|
2. 创建 `SKILL.md` 文件,包含完整的 frontmatter
|
|
86
86
|
3. 在正文中详细描述技能的功能和使用方法
|
|
87
|
-
4.
|
|
87
|
+
4. **如有命令**,在 SKILL.md 正文中添加 `## 命令` 章节,详细说明每个命令的用法
|
|
88
|
+
5. 创建 `index.js` 文件导出命令(可选)
|
|
89
|
+
6. 调用 `reloadSkills` 工具重载所有技能
|
|
90
|
+
|
|
91
|
+
### SKILL.md 命令章节示例
|
|
92
|
+
|
|
93
|
+
如果技能有命令,必须在 SKILL.md 正文添加 `## 命令` 章节:
|
|
94
|
+
|
|
95
|
+
```markdown
|
|
96
|
+
## 命令
|
|
97
|
+
|
|
98
|
+
### /my-skill:greet
|
|
99
|
+
|
|
100
|
+
打招呼命令。
|
|
101
|
+
|
|
102
|
+
**参数:**
|
|
103
|
+
- `args`(可选):名字,如 `/my-skill:greet Alice`
|
|
104
|
+
|
|
105
|
+
**示例:**
|
|
106
|
+
- `/my-skill:greet` → "Hello World"
|
|
107
|
+
- `/my-skill:greet Alice` → "Hello Alice"
|
|
108
|
+
|
|
109
|
+
### /my-skill:split
|
|
110
|
+
|
|
111
|
+
切割会话命令。
|
|
112
|
+
|
|
113
|
+
**参数:**
|
|
114
|
+
- `-t, --tokens <value>`:保留 token 数(默认 4000)
|
|
115
|
+
- `-k, --keep-recent <value>`:保留最近 token(默认 1000)
|
|
116
|
+
- `[args...]`:位置参数
|
|
117
|
+
|
|
118
|
+
**示例:**
|
|
119
|
+
- `/my-skill:split` → 使用默认参数
|
|
120
|
+
- `/my-skill:split -t 8000 extra` → tokens=8000,extra 作为位置参数
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### index.js 格式
|
|
124
|
+
|
|
125
|
+
```javascript
|
|
126
|
+
module.exports = [
|
|
127
|
+
{
|
|
128
|
+
name: 'greet', // 命令名
|
|
129
|
+
description: '打招呼', // 命令描述
|
|
130
|
+
execute: async (args, ctx) => {
|
|
131
|
+
// args: 传入的参数(字符串)
|
|
132
|
+
// ctx: 上下文对象 { sessionId, agent, framework }
|
|
133
|
+
return 'Hello ' + (args || 'World');
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
name: 'split',
|
|
138
|
+
description: '切割会话',
|
|
139
|
+
// 简洁方式:定义选项数组,自动使用 Commander.js 解析
|
|
140
|
+
options: [
|
|
141
|
+
{ flags: '-t, --tokens <value>', description: '保留 token 数', defaultValue: '4000' },
|
|
142
|
+
{ flags: '-k, --keep-recent <value>', description: '保留最近 token', defaultValue: '1000' }
|
|
143
|
+
],
|
|
144
|
+
execute: async (parsedArgs, ctx) => {
|
|
145
|
+
// parsedArgs: { tokens: "4000", keepRecent: "1000", args: [...] }
|
|
146
|
+
return `Split: tokens=${parsedArgs.tokens}`;
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
name: 'status',
|
|
151
|
+
description: '显示状态',
|
|
152
|
+
execute: async (args, ctx) => {
|
|
153
|
+
return JSON.stringify({ session: ctx.sessionId });
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
];
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**参数解析说明:**
|
|
160
|
+
|
|
161
|
+
- 不提供 `options` 时,`args` 是原始参数字符串
|
|
162
|
+
- 提供 `options` 数组时,自动使用 Commander.js 解析,`execute` 收到解析后的对象
|
|
163
|
+
- 对象格式:`{ tokens, keepRecent, args: [...] }`
|
|
164
|
+
|
|
165
|
+
### 命令调用方式
|
|
166
|
+
|
|
167
|
+
技能命令通过 `ext_call` 工具调用,格式为 `/skillname:commandname`:
|
|
168
|
+
|
|
169
|
+
| 渠道 | 调用方式 |
|
|
170
|
+
|------|---------|
|
|
171
|
+
| CLI | 输入 `/skillname:cmdname` |
|
|
172
|
+
| 飞书 | 发送 `/skillname:cmdname` |
|
|
173
|
+
| 微信 | 发送 `/skillname:cmdname` |
|
|
174
|
+
| Telegram | 发送 `/skillname:cmdname` |
|
|
175
|
+
| QQ | 发送 `/skillname:cmdname` |
|
|
176
|
+
|
|
177
|
+
### 使用流程
|
|
178
|
+
|
|
179
|
+
1. **查看可用命令**:发送 `/help` 或 `/start` 查看帮助,其中列出所有技能命令
|
|
180
|
+
2. **执行命令**:发送 `/skillname:cmdname` 即可执行命令
|
|
181
|
+
|
|
182
|
+
### 示例:test-skill
|
|
183
|
+
|
|
184
|
+
假设有 `test-skill` 技能,其 `index.js` 导出:
|
|
185
|
+
|
|
186
|
+
```javascript
|
|
187
|
+
module.exports = [
|
|
188
|
+
{ name: 'greet', description: '打招呼', execute: async (args) => 'Hello ' + (args || 'World') },
|
|
189
|
+
{ name: 'echo', description: '回声命令', execute: async (args) => 'Echo: ' + args }
|
|
190
|
+
];
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
对应的 SKILL.md 应包含:
|
|
194
|
+
|
|
195
|
+
```markdown
|
|
196
|
+
## 命令
|
|
197
|
+
|
|
198
|
+
### /test-skill:greet
|
|
199
|
+
|
|
200
|
+
打招呼命令。
|
|
201
|
+
|
|
202
|
+
**参数:**
|
|
203
|
+
- `args`(可选):名字
|
|
204
|
+
|
|
205
|
+
**示例:**
|
|
206
|
+
- `/test-skill:greet` → "Hello World"
|
|
207
|
+
- `/test-skill:greet Alice` → "Hello Alice"
|
|
208
|
+
|
|
209
|
+
### /test-skill:echo
|
|
210
|
+
|
|
211
|
+
回声命令,将输入原样返回。
|
|
212
|
+
|
|
213
|
+
**参数:**
|
|
214
|
+
- `args`:要回显的文本
|
|
215
|
+
|
|
216
|
+
**示例:**
|
|
217
|
+
- `/test-skill:echo Hello` → "Echo: Hello"
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### 自动注册
|
|
221
|
+
|
|
222
|
+
技能命令会在以下时机自动注册:
|
|
223
|
+
- 框架启动时加载技能
|
|
224
|
+
- 调用 `reloadSkills` 工具重载后
|
|
225
|
+
|
|
226
|
+
注册后即可在所有渠道使用 `/技能名:命令名` 格式调用。
|
|
88
227
|
|
|
89
228
|
## 技能重载
|
|
90
229
|
|
|
@@ -115,6 +115,7 @@ class Skill {
|
|
|
115
115
|
this.content = content;
|
|
116
116
|
this._framework = null;
|
|
117
117
|
this._commands = [];
|
|
118
|
+
this.tools = {}; // 用于 extension-executor 扫描
|
|
118
119
|
}
|
|
119
120
|
|
|
120
121
|
/**
|
|
@@ -195,9 +196,7 @@ class Skill {
|
|
|
195
196
|
};
|
|
196
197
|
}
|
|
197
198
|
|
|
198
|
-
|
|
199
|
-
extExecutor.registerTool('skill', skillInfo, {
|
|
200
|
-
name: fullName,
|
|
199
|
+
const toolDef = {
|
|
201
200
|
description: cmd.description || `Skill command: ${fullName}`,
|
|
202
201
|
inputSchema: z.object({
|
|
203
202
|
args: z.string().optional().describe('命令参数'),
|
|
@@ -215,7 +214,13 @@ class Skill {
|
|
|
215
214
|
}
|
|
216
215
|
return await handler(parsedArgs, ctx);
|
|
217
216
|
},
|
|
218
|
-
}
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
// 注册到 extension 系统,通过 ext_call 调用
|
|
220
|
+
extExecutor.registerTool('skill', skillInfo, toolDef);
|
|
221
|
+
|
|
222
|
+
// 同时添加到 this.tools,供 extension-executor 的 _scanPluginTools 扫描
|
|
223
|
+
this.tools[fullName] = toolDef;
|
|
219
224
|
|
|
220
225
|
this._commands.push(fullName);
|
|
221
226
|
}
|
|
@@ -247,6 +252,7 @@ class SkillManagerPlugin extends Plugin {
|
|
|
247
252
|
: [config.skillsDir || '.foliko/skills', 'skills'];
|
|
248
253
|
this._skills = new Map();
|
|
249
254
|
this._loaded = false;
|
|
255
|
+
this.tools = {}; // 用于 extension-executor 扫描(由 Skill.registerCommands 填充)
|
|
250
256
|
}
|
|
251
257
|
|
|
252
258
|
install(framework) {
|
|
@@ -626,6 +632,9 @@ class SkillManagerPlugin extends Plugin {
|
|
|
626
632
|
skill.install(this._framework);
|
|
627
633
|
skill.registerCommands(); // 注册 skill 的命令
|
|
628
634
|
|
|
635
|
+
// 将 skill 的命令添加到 SkillManagerPlugin.tools,供 extension-executor 扫描
|
|
636
|
+
Object.assign(this.tools, skill.tools);
|
|
637
|
+
|
|
629
638
|
// 扫描 references 子目录(按需加载的附加文档)
|
|
630
639
|
const references = this._scanReferences(skillPath);
|
|
631
640
|
|
|
@@ -822,6 +831,15 @@ class SkillManagerPlugin extends Plugin {
|
|
|
822
831
|
this._loaded = false;
|
|
823
832
|
this._framework = framework;
|
|
824
833
|
this._loadAllSkills();
|
|
834
|
+
|
|
835
|
+
// 通知 extension-executor 重载 skill 命令
|
|
836
|
+
const extExecutor = framework.pluginManager?.get('extension-executor');
|
|
837
|
+
if (extExecutor && typeof extExecutor._rescanPluginTools === 'function') {
|
|
838
|
+
const skillPlugin = framework.pluginManager?.get('skill-manager');
|
|
839
|
+
if (skillPlugin) {
|
|
840
|
+
extExecutor._rescanPluginTools(skillPlugin);
|
|
841
|
+
}
|
|
842
|
+
}
|
|
825
843
|
}
|
|
826
844
|
|
|
827
845
|
uninstall(framework) {
|
package/src/core/subagent.js
CHANGED
|
@@ -40,7 +40,7 @@ class Subagent extends EventEmitter {
|
|
|
40
40
|
this.providerOptions = config.providerOptions || {};
|
|
41
41
|
this.framework = config.framework || null;
|
|
42
42
|
|
|
43
|
-
this.defaulTools = ['ext_skill','ext_call','subagent_call','mcp_call','mcp_tool_schema'];
|
|
43
|
+
this.defaulTools = ['ext_skill','loadSkill','ext_call','subagent_call','mcp_call','mcp_tool_schema'];
|
|
44
44
|
|
|
45
45
|
this.bindTools = {
|
|
46
46
|
read: 'read_file',
|
|
@@ -282,7 +282,7 @@ class Subagent extends EventEmitter {
|
|
|
282
282
|
lines.push(`- 处理本职外的任务`);
|
|
283
283
|
lines.push(`- 代替其他子Agent执行操作`);
|
|
284
284
|
lines.push(`- 在回复中透露你的内部实现细节`);
|
|
285
|
-
lines.push(`- 不先调用 ext_skill 就直接使用 ext_call`);
|
|
285
|
+
lines.push(`- 不先调用 ext_skill/loadSkill 就直接使用 ext_call`);
|
|
286
286
|
|
|
287
287
|
return lines.join('\n');
|
|
288
288
|
}
|
package/subagent.md
CHANGED
|
@@ -111,7 +111,7 @@
|
|
|
111
111
|
## 【Extensions】扩展插件
|
|
112
112
|
|
|
113
113
|
**使用流程(必须按顺序执行):**
|
|
114
|
-
1. 调用
|
|
114
|
+
1. 调用 `ext_skill({ plugin: "<plugin_name>" })` 或 `loadSkill({ skill: "<skill_name>" })` 获取目标扩展的详细工具参数
|
|
115
115
|
2. 根据返回的参数定义,使用 `ext_call({ plugin, tool, args })` 调用扩展
|
|
116
116
|
|
|
117
117
|
> **警告**:禁止在未执行第1步获取参数的情况下直接调用 `ext_call`!
|
|
@@ -167,4 +167,4 @@ MCP (Model Context Protocol) 执行器
|
|
|
167
167
|
**工具:** `designmd_search_design_kits`, `designmd_get_design_kit`, `designmd_download_design_kit`, `designmd_upload_design_kit`, `designmd_delete_design_kit`, `designmd_list_popular_kits`, `designmd_list_tags`
|
|
168
168
|
|
|
169
169
|
## 禁止事项
|
|
170
|
-
- 不先调用 `ext_skill` 获取参数就直接使用 `ext_call`
|
|
170
|
+
- 不先调用 `ext_skill/loadSkill` 获取参数就直接使用 `ext_call`
|