foliko 2.0.5 → 2.0.7
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/CLAUDE.md +3 -0
- 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/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/scheduler/index.js +1 -0
- 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/context.js +941 -0
- package/plugins/core/workflow/engine.js +66 -0
- package/plugins/core/workflow/examples/01-basic.js +42 -0
- package/plugins/core/workflow/examples/01-basic.json +30 -0
- package/plugins/core/workflow/examples/02-choice.js +75 -0
- package/plugins/core/workflow/examples/02-choice.json +59 -0
- package/plugins/core/workflow/examples/03-chain-style.js +114 -0
- package/plugins/core/workflow/examples/03-each.json +41 -0
- package/plugins/core/workflow/examples/04-parallel.js +52 -0
- package/plugins/core/workflow/examples/04-parallel.json +51 -0
- package/plugins/core/workflow/examples/05-chain-style.json +68 -0
- package/plugins/core/workflow/examples/05-each.js +65 -0
- package/plugins/core/workflow/examples/06-script.js +82 -0
- package/plugins/core/workflow/examples/07-module-export.js +43 -0
- package/plugins/core/workflow/examples/08-default-export.js +29 -0
- package/plugins/core/workflow/examples/09-next-with-args.js +50 -0
- package/plugins/core/workflow/examples/10-logger.js +34 -0
- package/plugins/core/workflow/examples/11-storage.js +68 -0
- package/plugins/core/workflow/examples/simple.js +77 -0
- package/plugins/core/workflow/examples/simple.json +75 -0
- package/plugins/core/workflow/index.js +204 -78
- package/plugins/core/workflow/js-runner.js +318 -0
- package/plugins/core/workflow/json-runner.js +323 -0
- package/plugins/core/workflow/stages/action.js +211 -0
- package/plugins/core/workflow/stages/choice.js +74 -0
- package/plugins/core/workflow/stages/delay.js +73 -0
- package/plugins/core/workflow/stages/each.js +123 -0
- package/plugins/core/workflow/stages/parallel.js +69 -0
- package/plugins/core/workflow/stages/try.js +142 -0
- package/plugins/executors/data-splitter/PROMPT.md +13 -0
- package/plugins/executors/data-splitter/index.js +8 -6
- 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/sandbox/check-context.js +5 -0
- package/sandbox/test-context.js +27 -0
- package/sandbox/test-fixes.js +40 -0
- package/sandbox/test-hello-js.js +46 -0
- 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 +753 -436
- package/src/agent/chat.js +56 -28
- package/src/agent/main.js +39 -14
- 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 +9 -5
- package/src/common/constants.js +12 -0
- package/src/common/error-capture.js +91 -0
- package/src/common/json-safe.js +20 -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 +78 -12
- package/src/index.js +4 -0
- package/src/plugin/base.js +908 -5
- package/src/plugin/manager.js +124 -9
- package/src/tool/schema.js +32 -9
- package/src/utils/sandbox.js +1 -1
- package/website/index.html +821 -0
- package/skills/workflows/workflow-troubleshooting/DEBUGGING.md +0 -197
- package/skills/workflows/workflow-troubleshooting/SKILL.md +0 -391
package/docs/migration.md
CHANGED
|
@@ -55,3 +55,103 @@
|
|
|
55
55
|
|------|------|
|
|
56
56
|
| `_setReady()` | 标记框架就绪并触发 `framework:ready` 事件 |
|
|
57
57
|
| `isEnabled(name)` | 代理到 `pluginManager.isEnabled()` |
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 扩展调用统一重构(v2.x → v3.x)
|
|
62
|
+
|
|
63
|
+
### 背景
|
|
64
|
+
|
|
65
|
+
之前 MCP 工具调用有自己的 `mcp_call` / `mcp_tool_schema`,Skill 命令使用 `args.command: "<string>"` 字符串模式,与其他扩展的 Zod 结构化参数风格不一致。本次重构统一了所有"非 AI SDK 直调"的工具调用方式。
|
|
66
|
+
|
|
67
|
+
### 旧 → 新对照
|
|
68
|
+
|
|
69
|
+
#### 1. MCP 工具调用
|
|
70
|
+
|
|
71
|
+
| 旧方式 | 新方式 |
|
|
72
|
+
|---|---|
|
|
73
|
+
| `mcp_call({ server, tool, args_json: '{"x":"y"}' })` | `ext_call({ plugin: "mcp:<server>", tool, args: { x: "y" } })` |
|
|
74
|
+
| `mcp_tool_schema({ server, tool })` | `ext_skill({ plugin: "mcp:<server>" })` |
|
|
75
|
+
| 工具名带前缀:`designmd_search_design_kits` | 原始 MCP 名:`search_design_kits` |
|
|
76
|
+
|
|
77
|
+
**移除的工具**:`mcp_call`、`mcp_tool_schema`(不再注册)
|
|
78
|
+
|
|
79
|
+
#### 2. Skill 命令调用
|
|
80
|
+
|
|
81
|
+
Skill 命令通过 `skill:<name>` 命名空间调用:
|
|
82
|
+
|
|
83
|
+
```js
|
|
84
|
+
ext_call({
|
|
85
|
+
plugin: "skill:my-skill", // skill:<name>
|
|
86
|
+
tool: "cmd", // 命令名(不是 <skill>:<cmd>)
|
|
87
|
+
args: { command: "-n x -v" }
|
|
88
|
+
})
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**要点**:
|
|
92
|
+
- 每个 skill 是独立扩展 `skill:<name>`
|
|
93
|
+
- 命令是该扩展下的 tool
|
|
94
|
+
- `args: { command: "..." }` 传命令行字符串
|
|
95
|
+
- Commander.js 解析后传给 handler
|
|
96
|
+
|
|
97
|
+
#### 3. ext_skill 返回内容
|
|
98
|
+
|
|
99
|
+
`ext_skill({ plugin })` 通用返回(普通扩展):
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
#### `<tool_name>`
|
|
103
|
+
|
|
104
|
+
<description>
|
|
105
|
+
|
|
106
|
+
**参数:**
|
|
107
|
+
- field
|
|
108
|
+
- Type
|
|
109
|
+
- ...
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
`ext_skill({ plugin: "skill:<name>" })` 增强返回:
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
# Skill: <name>
|
|
116
|
+
|
|
117
|
+
**<description>**
|
|
118
|
+
|
|
119
|
+
## 技能说明
|
|
120
|
+
|
|
121
|
+
<SKILL.md 内容(剥掉 frontmatter)>
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## 调用规则
|
|
126
|
+
|
|
127
|
+
> 通过 `ext_call({ plugin: "skill:<name>", tool: "<command>", args: {...} })` 调用
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## 可用命令
|
|
132
|
+
|
|
133
|
+
### `<command>`
|
|
134
|
+
|
|
135
|
+
<description>
|
|
136
|
+
|
|
137
|
+
**参数:**
|
|
138
|
+
- ...
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### 内部变更
|
|
142
|
+
|
|
143
|
+
- `plugins/executors/extension/prompt-builder.js`:MCP 特殊处理移除,所有扩展统一通过 `zodSchemaToMarkdown` 渲染
|
|
144
|
+
- `plugins/executors/extension/skill-helper.js`:按 `skill:<name>` 命名空间迭代
|
|
145
|
+
- `src/plugin/base.js`:`Plugin` 基类新增 `skill` accessor(`register`/`get`/`has`/`remove`/`list`/`details`/`listOwned`/`execute`)
|
|
146
|
+
- `src/tool/schema.js`:`jsonSchemaToZod` 重构,避免嵌套 `Optional` 包装
|
|
147
|
+
|
|
148
|
+
### Plugin 基类新增 accessor
|
|
149
|
+
|
|
150
|
+
| Accessor | 用途 |
|
|
151
|
+
|---|---|
|
|
152
|
+
| `this.skill.register(name, content, metadata, options)` | 程序化注册技能 |
|
|
153
|
+
| `this.skill.get(name)` / `this.skill.has(name)` | 查询 |
|
|
154
|
+
| `this.skill.details(name)` | 结构化详情 |
|
|
155
|
+
| `this.skill.list()` / `this.skill.listOwned()` | 列表 |
|
|
156
|
+
| `this.skill.remove(name)` | 删除 |
|
|
157
|
+
| `this.skill.execute('<skill>:<cmd>', args)` | 直接执行 |
|
package/docs/public-api.md
CHANGED
|
@@ -486,10 +486,10 @@ framework.skills.listCommands('my-skill');
|
|
|
486
486
|
|
|
487
487
|
// 获取单个命令详情
|
|
488
488
|
framework.skills.getCommand('my-skill', 'run');
|
|
489
|
-
// { name: '
|
|
489
|
+
// { name: 'run', description: '...', options: [...], inputSchema: {...} }
|
|
490
490
|
|
|
491
491
|
// 调用命令(通过 extension 执行)
|
|
492
|
-
await framework.extensions.execute('skill', '
|
|
492
|
+
await framework.extensions.execute('skill:my-skill', 'run', { command: '--arg value' });
|
|
493
493
|
```
|
|
494
494
|
|
|
495
495
|
#### Reference 管理(按需加载的附加文档)
|
|
@@ -616,7 +616,7 @@ module.exports = [
|
|
|
616
616
|
|
|
617
617
|
```js
|
|
618
618
|
// 通过 extension 执行
|
|
619
|
-
await framework.extensions.execute('skill', '
|
|
619
|
+
await framework.extensions.execute('skill:my-skill', 'hello', { command: '-n Alice' });
|
|
620
620
|
```
|
|
621
621
|
|
|
622
622
|
#### 3. 添附加文档(可选)
|
|
@@ -1017,11 +1017,13 @@ await framework.mcps.getToolSchema('my-server', 'tool-name');
|
|
|
1017
1017
|
|
|
1018
1018
|
| 工具 | 说明 |
|
|
1019
1019
|
|------|------|
|
|
1020
|
-
| `mcp_list_servers` | 列出所有 MCP
|
|
1021
|
-
| `
|
|
1022
|
-
| `
|
|
1023
|
-
|
|
1024
|
-
|
|
1020
|
+
| `mcp_list_servers` | 列出所有 MCP 服务器及其状态 |
|
|
1021
|
+
| `mcp_set_enabled` | 动态开启/关闭某个 MCP 服务器 |
|
|
1022
|
+
| `mcp_reload` | 重载 MCP 配置(`.foliko/mcp_config.json`) |
|
|
1023
|
+
|
|
1024
|
+
> **MCP 工具调用已统一**:MCP 服务器启动后自动注册为 `mcp:<servername>` 扩展,
|
|
1025
|
+
> 工具通过 `ext_skill({ plugin: "mcp:<servername>" })` + `ext_call(...)` 统一调度,
|
|
1026
|
+
> 不再需要独立的 `mcp_call` / `mcp_tool_schema`。
|
|
1025
1027
|
|
|
1026
1028
|
---
|
|
1027
1029
|
|
|
@@ -1080,37 +1082,291 @@ class MyPlugin extends Plugin {
|
|
|
1080
1082
|
},
|
|
1081
1083
|
];
|
|
1082
1084
|
|
|
1083
|
-
|
|
1084
|
-
//
|
|
1085
|
-
|
|
1085
|
+
onStart(framework) {
|
|
1086
|
+
// 注册 AI SDK 工具(直接调用)
|
|
1087
|
+
this.tool.register({
|
|
1086
1088
|
name: 'my_tool',
|
|
1087
1089
|
description: '做某事',
|
|
1088
1090
|
inputSchema: framework.z.object({ msg: framework.z.string() }),
|
|
1089
1091
|
execute: async (args) => ({ result: args.msg }),
|
|
1090
1092
|
});
|
|
1091
1093
|
|
|
1092
|
-
//
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1094
|
+
// 注册扩展工具(通过 ext_call 调用)
|
|
1095
|
+
this.extension.register({
|
|
1096
|
+
name: 'my_ext_tool',
|
|
1097
|
+
description: '扩展工具',
|
|
1098
|
+
inputSchema: framework.z.object({ data: framework.z.string() }),
|
|
1099
|
+
execute: async (args) => ({ data: args.data }),
|
|
1100
|
+
});
|
|
1096
1101
|
}
|
|
1097
1102
|
|
|
1098
|
-
|
|
1099
|
-
//
|
|
1103
|
+
onStop() {
|
|
1104
|
+
// 自定义清理逻辑(工具/扩展基类自动处理)
|
|
1100
1105
|
}
|
|
1106
|
+
}
|
|
1101
1107
|
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
}
|
|
1108
|
+
module.exports = MyPlugin;
|
|
1109
|
+
```
|
|
1105
1110
|
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1111
|
+
---
|
|
1112
|
+
|
|
1113
|
+
### 工具注册(tool.register / extension.register)
|
|
1114
|
+
|
|
1115
|
+
Plugin 基类提供两个属性用于注册工具:
|
|
1116
|
+
|
|
1117
|
+
#### tool.register - AI SDK 直接调用
|
|
1118
|
+
|
|
1119
|
+
通过 `this.tool.register()` 注册的工具会直接暴露给 AI 模型调用:
|
|
1120
|
+
|
|
1121
|
+
```js
|
|
1122
|
+
this.tool.register({
|
|
1123
|
+
name: 'get-weather',
|
|
1124
|
+
description: '获取天气',
|
|
1125
|
+
inputSchema: framework.z.object({ city: framework.z.string() }),
|
|
1126
|
+
execute: async (args, framework) => {
|
|
1127
|
+
return { weather: '晴天', temp: 25 };
|
|
1128
|
+
},
|
|
1129
|
+
});
|
|
1130
|
+
```
|
|
1131
|
+
|
|
1132
|
+
#### extension.register - ext_call 间接调用
|
|
1133
|
+
|
|
1134
|
+
通过 `this.extension.register()` 注册的工具通过 `ext_call` 间接调用:
|
|
1135
|
+
|
|
1136
|
+
```js
|
|
1137
|
+
this.extension.register({
|
|
1138
|
+
name: 'send-notification',
|
|
1139
|
+
description: '发送通知',
|
|
1140
|
+
inputSchema: framework.z.object({
|
|
1141
|
+
title: framework.z.string(),
|
|
1142
|
+
message: framework.z.string(),
|
|
1143
|
+
}),
|
|
1144
|
+
execute: async (args) => {
|
|
1145
|
+
// ...
|
|
1146
|
+
},
|
|
1147
|
+
});
|
|
1148
|
+
```
|
|
1149
|
+
|
|
1150
|
+
扩展名自动使用 `this.name`。
|
|
1151
|
+
|
|
1152
|
+
#### 生命周期管理
|
|
1153
|
+
|
|
1154
|
+
| 操作 | 效果 |
|
|
1155
|
+
|------|------|
|
|
1156
|
+
| `disable` | 自动移除工具/扩展(保留注册记录) |
|
|
1157
|
+
| `enable` | 自动重新注册工具/扩展 |
|
|
1158
|
+
| `reload` | 移除后重新注册 |
|
|
1159
|
+
| `uninstall` | 移除并清空注册记录 |
|
|
1160
|
+
|
|
1161
|
+
#### 手动移除
|
|
1162
|
+
|
|
1163
|
+
```js
|
|
1164
|
+
this.tool.remove('tool-name');
|
|
1165
|
+
this.extension.remove('tool-name');
|
|
1166
|
+
```
|
|
1167
|
+
|
|
1168
|
+
#### 执行工具
|
|
1169
|
+
|
|
1170
|
+
**tool.execute** - 执行所有已注册的 AI SDK 工具(不仅限当前插件):
|
|
1171
|
+
|
|
1172
|
+
```js
|
|
1173
|
+
// 执行任何已注册的工具
|
|
1174
|
+
const result = await this.tool.execute('any-tool-name', { arg1: 'value' });
|
|
1175
|
+
```
|
|
1176
|
+
|
|
1177
|
+
**extension.execute** - 执行扩展工具,支持两种调用方式:
|
|
1178
|
+
|
|
1179
|
+
```js
|
|
1180
|
+
// 执行当前插件注册的扩展工具
|
|
1181
|
+
const result = await this.extension.execute('tool-name', { arg1: 'value' });
|
|
1182
|
+
|
|
1183
|
+
// 执行指定插件注册的扩展工具
|
|
1184
|
+
const result = await this.extension.execute('plugin-name', 'tool-name', { arg1: 'value' });
|
|
1185
|
+
```
|
|
1186
|
+
|
|
1187
|
+
---
|
|
1188
|
+
|
|
1189
|
+
### 工作流注册(workflow.register)
|
|
1190
|
+
|
|
1191
|
+
Plugin 基类提供 `workflow` 属性用于注册和执行工作流:
|
|
1192
|
+
|
|
1193
|
+
```js
|
|
1194
|
+
// 注册工作流
|
|
1195
|
+
this.workflow.register('my-workflow', {
|
|
1196
|
+
name: 'my-workflow',
|
|
1197
|
+
description: '我的工作流',
|
|
1198
|
+
steps: [
|
|
1199
|
+
{ type: 'tool', tool: 'hello', args: {} },
|
|
1200
|
+
{ type: 'script', script: 'return context.variables;' }
|
|
1201
|
+
]
|
|
1202
|
+
});
|
|
1203
|
+
|
|
1204
|
+
// 执行工作流
|
|
1205
|
+
const result = await this.workflow.execute('my-workflow', { input: 'value' });
|
|
1206
|
+
|
|
1207
|
+
// 移除工作流
|
|
1208
|
+
this.workflow.remove('my-workflow');
|
|
1209
|
+
```
|
|
1210
|
+
|
|
1211
|
+
#### 执行结果
|
|
1212
|
+
|
|
1213
|
+
`workflow.execute` 返回:
|
|
1214
|
+
|
|
1215
|
+
```js
|
|
1216
|
+
{
|
|
1217
|
+
success: true,
|
|
1218
|
+
stepCount: 2,
|
|
1219
|
+
result: { ... }, // 最后一步的结果
|
|
1220
|
+
output: { ... } // 所有非下划线开头的变量
|
|
1109
1221
|
}
|
|
1222
|
+
```
|
|
1110
1223
|
|
|
1111
|
-
|
|
1224
|
+
#### 生命周期管理
|
|
1225
|
+
|
|
1226
|
+
| 操作 | 效果 |
|
|
1227
|
+
|------|------|
|
|
1228
|
+
| `disable` | 自动移除工作流(保留注册记录) |
|
|
1229
|
+
| `enable` | 自动重新注册工作流 |
|
|
1230
|
+
| `reload` | 移除后重新注册 |
|
|
1231
|
+
| `uninstall` | 移除并清空注册记录 |
|
|
1232
|
+
|
|
1233
|
+
---
|
|
1234
|
+
|
|
1235
|
+
### 子代理注册(agent.register)
|
|
1236
|
+
|
|
1237
|
+
Plugin 基类提供 `agent` 属性用于注册子代理:
|
|
1238
|
+
|
|
1239
|
+
```js
|
|
1240
|
+
// 注册子代理
|
|
1241
|
+
this.agent.register({
|
|
1242
|
+
name: 'my-agent',
|
|
1243
|
+
role: '助手',
|
|
1244
|
+
goal: '描述',
|
|
1245
|
+
tools: {},
|
|
1246
|
+
parentTools: ['read_file', 'write_file']
|
|
1247
|
+
});
|
|
1248
|
+
|
|
1249
|
+
// 获取已注册的子代理
|
|
1250
|
+
const agent = this.agent.get('my-agent');
|
|
1251
|
+
|
|
1252
|
+
// 移除子代理
|
|
1253
|
+
this.agent.remove('my-agent');
|
|
1112
1254
|
```
|
|
1113
1255
|
|
|
1256
|
+
#### 生命周期管理
|
|
1257
|
+
|
|
1258
|
+
| 操作 | 效果 |
|
|
1259
|
+
|------|------|
|
|
1260
|
+
| `disable` | 自动移除子代理(保留注册记录) |
|
|
1261
|
+
| `enable` | 自动重新注册子代理 |
|
|
1262
|
+
| `reload` | 移除后重新注册 |
|
|
1263
|
+
| `uninstall` | 移除并清空注册记录 |
|
|
1264
|
+
|
|
1265
|
+
---
|
|
1266
|
+
|
|
1267
|
+
### Prompt 注册(prompt.register)
|
|
1268
|
+
|
|
1269
|
+
Plugin 基类提供 `prompt` 属性用于注册 prompt parts:
|
|
1270
|
+
|
|
1271
|
+
```js
|
|
1272
|
+
// 注册 prompt part
|
|
1273
|
+
this.prompt.register('my-prompt', () => 'Prompt content here', {
|
|
1274
|
+
scope: 'global',
|
|
1275
|
+
priority: 50,
|
|
1276
|
+
description: '描述'
|
|
1277
|
+
});
|
|
1278
|
+
|
|
1279
|
+
// 移除 prompt part
|
|
1280
|
+
this.prompt.remove('my-prompt');
|
|
1281
|
+
```
|
|
1282
|
+
|
|
1283
|
+
#### 生命周期管理
|
|
1284
|
+
|
|
1285
|
+
| 操作 | 效果 |
|
|
1286
|
+
|------|------|
|
|
1287
|
+
| `disable` | 自动移除 prompt(保留注册记录) |
|
|
1288
|
+
| `enable` | 自动重新注册 prompt |
|
|
1289
|
+
| `reload` | 移除后重新注册 |
|
|
1290
|
+
| `uninstall` | 移除并清空注册记录 |
|
|
1291
|
+
|
|
1292
|
+
---
|
|
1293
|
+
|
|
1294
|
+
### 技能注册(skill.register)
|
|
1295
|
+
|
|
1296
|
+
Plugin 基类提供 `skill` 属性用于程序化管理技能。注册后自动以 `skill:<name>` 形式暴露为扩展,可通过 `ext_skill` + `ext_call` 统一调用。
|
|
1297
|
+
|
|
1298
|
+
```js
|
|
1299
|
+
// 注册技能
|
|
1300
|
+
this.skill.register('my-skill', '# 技能说明\n\n...内容', {
|
|
1301
|
+
description: '技能描述',
|
|
1302
|
+
'allowed-tools': 'tool1,tool2',
|
|
1303
|
+
}, {
|
|
1304
|
+
commands: [{
|
|
1305
|
+
name: 'do-something',
|
|
1306
|
+
description: '做某事',
|
|
1307
|
+
options: [
|
|
1308
|
+
{ flags: '-n, --name <name>', description: '姓名', required: true },
|
|
1309
|
+
{ flags: '-v, --verbose', description: '详细模式' },
|
|
1310
|
+
],
|
|
1311
|
+
execute: async (args) => {
|
|
1312
|
+
// args 是 commander.js 解析后的对象: { name: 'xxx', verbose: true }
|
|
1313
|
+
return { success: true, data: '处理结果' };
|
|
1314
|
+
},
|
|
1315
|
+
}],
|
|
1316
|
+
path: '/optional/path', // 可选:技能路径
|
|
1317
|
+
});
|
|
1318
|
+
|
|
1319
|
+
// 查询
|
|
1320
|
+
this.skill.has('my-skill'); // boolean
|
|
1321
|
+
this.skill.get('my-skill'); // 完整 skill 对象
|
|
1322
|
+
this.skill.details('my-skill'); // { name, description, content, commands, references, ... }
|
|
1323
|
+
this.skill.list(); // 所有技能数组
|
|
1324
|
+
this.skill.listOwned(); // 本插件注册的技能名
|
|
1325
|
+
|
|
1326
|
+
// 删除
|
|
1327
|
+
this.skill.remove('my-skill'); // boolean
|
|
1328
|
+
|
|
1329
|
+
// 直接执行(内部走 ext_call)
|
|
1330
|
+
await this.skill.execute('skill:my-skill', 'do-something', { command: '-n Claude --verbose' });
|
|
1331
|
+
```
|
|
1332
|
+
|
|
1333
|
+
#### 生命周期管理
|
|
1334
|
+
|
|
1335
|
+
| 操作 | 效果 |
|
|
1336
|
+
|------|------|
|
|
1337
|
+
| `disable` | 自动移除技能(保留注册记录) |
|
|
1338
|
+
| `enable` | 自动重新注册技能 |
|
|
1339
|
+
| `reload` | 移除后重新注册(`remove()` 后 reload 不会复活) |
|
|
1340
|
+
| `uninstall` | 移除并清空注册记录 |
|
|
1341
|
+
|
|
1342
|
+
---
|
|
1343
|
+
|
|
1344
|
+
## 扩展工具统一调用(ext_call / ext_skill)
|
|
1345
|
+
|
|
1346
|
+
所有"非 AI SDK 直调"的工具(普通扩展、MCP 服务器、Skill 命令)都通过 `ext_call` + `ext_skill` 统一调度:
|
|
1347
|
+
|
|
1348
|
+
```js
|
|
1349
|
+
// 1. 查询参数
|
|
1350
|
+
ext_skill({ plugin: "<extension_name>" })
|
|
1351
|
+
|
|
1352
|
+
// 2. 调用
|
|
1353
|
+
ext_call({
|
|
1354
|
+
plugin: "<extension_name>",
|
|
1355
|
+
tool: "<tool_name>",
|
|
1356
|
+
args: { /* 结构化参数 */ }
|
|
1357
|
+
})
|
|
1358
|
+
```
|
|
1359
|
+
|
|
1360
|
+
扩展命名空间:
|
|
1361
|
+
|
|
1362
|
+
| 扩展类型 | plugin 名格式 | 工具名格式 |
|
|
1363
|
+
|---|---|---|
|
|
1364
|
+
| 普通扩展(如 `gate-trading`) | `gate-trading` | `gate_get_balance` |
|
|
1365
|
+
| MCP 服务器 | `mcp:<servername>` | MCP 原始工具名(无前缀) |
|
|
1366
|
+
| Skill 命令 | `skill:<skillname>` | skill 命令名(无前缀) |
|
|
1367
|
+
|
|
1368
|
+
完整示例见 [`docs/usage.md` 的 Extensions 章节](#extensions-统一调用)。
|
|
1369
|
+
|
|
1114
1370
|
---
|
|
1115
1371
|
|
|
1116
1372
|
## 导出类型
|
package/docs/usage.md
CHANGED
|
@@ -166,32 +166,67 @@ skills/ → 子目录内有 SKILL.md → 加载为 skill
|
|
|
166
166
|
|
|
167
167
|
### 命令注册
|
|
168
168
|
|
|
169
|
-
如果 skill 目录下有 `index.js
|
|
169
|
+
如果 skill 目录下有 `index.js`,导出命令数组即可注册为可调用的扩展。**每个 skill 自动注册为 `skill:<skillname>` 扩展**,命令是扩展下的 tool。
|
|
170
170
|
|
|
171
171
|
```js
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
172
|
+
// index.js
|
|
173
|
+
module.exports = {
|
|
174
|
+
commands: [
|
|
175
|
+
{
|
|
176
|
+
name: 'greet',
|
|
177
|
+
description: '打招呼',
|
|
178
|
+
options: [
|
|
179
|
+
{ flags: '-n, --name <name>', description: '姓名', required: true },
|
|
180
|
+
{ flags: '-l, --lang <lang>', description: '语言', defaultValue: 'zh' },
|
|
181
|
+
{ flags: '-s, --shout', description: '是否大声喊' },
|
|
182
|
+
],
|
|
183
|
+
execute: async (args) => {
|
|
184
|
+
// args 是 commander.js 解析后的对象,无需自己解析命令字符串
|
|
185
|
+
const name = args.name || 'World';
|
|
186
|
+
const lang = args.lang || 'zh';
|
|
187
|
+
const shout = !!args.shout;
|
|
188
|
+
return `Hello, ${name}!` + (shout ? '!!!' : '');
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
],
|
|
192
|
+
};
|
|
184
193
|
```
|
|
185
194
|
|
|
186
|
-
|
|
195
|
+
#### 调用方式
|
|
196
|
+
|
|
197
|
+
```js
|
|
198
|
+
// 1. 查询参数
|
|
199
|
+
ext_skill({ plugin: "skill:<skillname>" })
|
|
200
|
+
|
|
201
|
+
// 2. 调用(传命令行字符串)
|
|
202
|
+
ext_call({
|
|
203
|
+
plugin: "skill:<skillname>",
|
|
204
|
+
tool: "greet",
|
|
205
|
+
args: { command: "-n Claude -l en --shout" },
|
|
206
|
+
})
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
#### 参数传递
|
|
210
|
+
|
|
211
|
+
Skill 命令参数通过 `args: { command: "..." }` 传递命令行字符串,由 Commander.js 解析后传给 handler:
|
|
212
|
+
|
|
213
|
+
| flags | 解析后 args 字段 |
|
|
214
|
+
|---|---|
|
|
215
|
+
| `-n, --name <name>` | `args.name` |
|
|
216
|
+
| `-l, --lang <lang>` | `args.lang` |
|
|
217
|
+
| `-s, --shout` | `args.shout` |
|
|
187
218
|
|
|
188
219
|
### 相关工具
|
|
189
220
|
|
|
190
|
-
- `skill_load({ skill: "name" })` —
|
|
221
|
+
- `skill_load({ skill: "name" })` — 获取技能内容(SKILL.md + 命令参考)
|
|
191
222
|
- `skill_reload` — 重载所有技能
|
|
192
223
|
- `skill_load_reference({ skill, reference })` — 加载技能的参考文档
|
|
193
224
|
- `skill_list_scripts` / `skill_load_script` — 技能脚本管理
|
|
194
225
|
|
|
226
|
+
### 程序化注册(不依赖文件)
|
|
227
|
+
|
|
228
|
+
可在 Plugin 中用 `this.skill.register(...)` 程序化创建技能,详见 [Plugin 基类的 skill accessor](#技能注册skillregister)。
|
|
229
|
+
|
|
195
230
|
## Workflows
|
|
196
231
|
|
|
197
232
|
### 结构化工作流
|
|
@@ -330,25 +365,67 @@ class MyPlugin extends Plugin {
|
|
|
330
365
|
this.system = false
|
|
331
366
|
}
|
|
332
367
|
|
|
333
|
-
|
|
334
|
-
//
|
|
335
|
-
|
|
368
|
+
onStart(framework) {
|
|
369
|
+
// 1. 注册 AI SDK 直调工具
|
|
370
|
+
this.tool.register({
|
|
336
371
|
name: 'my_tool',
|
|
337
372
|
description: 'My tool',
|
|
338
|
-
inputSchema: z.object({
|
|
339
|
-
|
|
373
|
+
inputSchema: framework.z.object({
|
|
374
|
+
param: framework.z.string().describe('参数')
|
|
375
|
+
}),
|
|
376
|
+
execute: async (args) => { /* ... */ }
|
|
377
|
+
})
|
|
378
|
+
|
|
379
|
+
// 2. 注册扩展工具(通过 ext_call 调用)
|
|
380
|
+
this.extension.register({
|
|
381
|
+
name: 'my_ext',
|
|
382
|
+
description: 'Extension tool',
|
|
383
|
+
inputSchema: framework.z.object({ /* ... */ }),
|
|
384
|
+
execute: async (args) => { /* ... */ }
|
|
340
385
|
})
|
|
386
|
+
|
|
387
|
+
// 3. 注册工作流
|
|
388
|
+
this.workflow.register('my-workflow', {
|
|
389
|
+
name: 'my-workflow',
|
|
390
|
+
steps: [/* ... */]
|
|
391
|
+
})
|
|
392
|
+
|
|
393
|
+
// 4. 注册子代理
|
|
394
|
+
this.agent.register({
|
|
395
|
+
name: 'helper',
|
|
396
|
+
role: '助手',
|
|
397
|
+
description: '辅助处理',
|
|
398
|
+
tools: {}
|
|
399
|
+
})
|
|
400
|
+
|
|
401
|
+
// 5. 注册 prompt part
|
|
402
|
+
this.prompt.register('my-rules', () => 'Rules content', {
|
|
403
|
+
scope: 'global',
|
|
404
|
+
priority: 50
|
|
405
|
+
})
|
|
406
|
+
|
|
407
|
+
// 6. 注册程序化 Skill(自动成为 skill:<name> 扩展)
|
|
408
|
+
this.skill.register('my-skill', '# My Skill\n\n...', {
|
|
409
|
+
description: 'My skill description'
|
|
410
|
+
}, {
|
|
411
|
+
commands: [{
|
|
412
|
+
name: 'do',
|
|
413
|
+
description: '...',
|
|
414
|
+
options: [{ flags: '-n, --name <name>', required: true }],
|
|
415
|
+
execute: async (args) => ({ success: true })
|
|
416
|
+
}]
|
|
417
|
+
})
|
|
418
|
+
|
|
341
419
|
framework.on('some:event', handler)
|
|
342
|
-
return this
|
|
343
420
|
}
|
|
344
421
|
|
|
345
|
-
|
|
346
|
-
//
|
|
347
|
-
return this
|
|
422
|
+
onStop() {
|
|
423
|
+
// 清理资源(工具/扩展/工作流/子代理/prompt/skill 基类自动处理)
|
|
348
424
|
}
|
|
349
425
|
|
|
350
426
|
reload(framework) {
|
|
351
|
-
//
|
|
427
|
+
// 声明式 prompts 自动清理/注册
|
|
428
|
+
// tool/extension/workflow/agent/prompt/skill 基类自动重新注册
|
|
352
429
|
}
|
|
353
430
|
|
|
354
431
|
async onCwdChanged(oldCwd, newCwd, framework) {
|
|
@@ -364,22 +441,37 @@ class MyPlugin extends Plugin {
|
|
|
364
441
|
module.exports = MyPlugin
|
|
365
442
|
```
|
|
366
443
|
|
|
444
|
+
#### 插件基类的 6 个 accessor 一览
|
|
445
|
+
|
|
446
|
+
| Accessor | 方法 | 用途 |
|
|
447
|
+
|---|---|---|
|
|
448
|
+
| `this.tool` | `register`/`remove`/`execute` | AI SDK 直接调用的工具 |
|
|
449
|
+
| `this.extension` | `register`/`remove`/`execute` | 扩展工具(通过 ext_call) |
|
|
450
|
+
| `this.workflow` | `register`/`remove`/`execute` | 工作流 |
|
|
451
|
+
| `this.agent` | `register`/`remove`/`get` | 子代理 |
|
|
452
|
+
| `this.prompt` | `register`/`remove` | 提示词 part |
|
|
453
|
+
| **`this.skill`** | `register`/`remove`/`get`/`has`/`list`/`details`/`listOwned`/`execute` | 技能(自动注册为 `skill:<name>` 扩展) |
|
|
454
|
+
|
|
367
455
|
### 生命周期
|
|
368
456
|
|
|
369
457
|
```
|
|
370
|
-
install() → load() → [start() + 注册工具]
|
|
458
|
+
install() → load() → [start() → onStart() + 注册工具]
|
|
371
459
|
↓
|
|
372
460
|
startAll() → [start() 再次调用]
|
|
373
461
|
↓
|
|
374
|
-
reload() →
|
|
462
|
+
reload() → 清理 + onStart()
|
|
463
|
+
↓
|
|
464
|
+
disable() → stop() → onStop()
|
|
465
|
+
↓
|
|
466
|
+
enable() → start() → onStart()
|
|
375
467
|
↓
|
|
376
|
-
uninstall() →
|
|
468
|
+
uninstall() → 清理 + 移除工具
|
|
377
469
|
```
|
|
378
470
|
|
|
379
471
|
**注意**:`start()` 会被调用两次(`load()` 和 `startAll()`),插件需通过 `_loaded` 标志或幂等设计来防止重复初始化。
|
|
380
472
|
|
|
381
473
|
### 放置位置
|
|
382
474
|
|
|
383
|
-
-
|
|
475
|
+
- 项目级:`.foliko/plugins/<name>/index.js`
|
|
384
476
|
- 全局:`~/.foliko/plugins/<name>.js` 或 `~/.foliko/plugins/<name>/index.js`
|
|
385
|
-
-
|
|
477
|
+
- 内置:`plugins/<name>/index.js`
|
package/package.json
CHANGED
|
@@ -23,7 +23,7 @@ class AuditPlugin extends Plugin {
|
|
|
23
23
|
this.config = {
|
|
24
24
|
maxLogs: config.maxLogs || 1000,
|
|
25
25
|
retentionDays: config.retentionDays || 30,
|
|
26
|
-
logDir: config.logDir || path.join(os.homedir(), '.
|
|
26
|
+
logDir: config.logDir || path.join(os.homedir(), '.foliko', 'logs', 'audit')
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
this._framework = null
|