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.
Files changed (93) hide show
  1. package/.claude/settings.local.json +4 -1
  2. package/.cli_default_systemPrompt.md +291 -0
  3. package/CLAUDE.md +3 -0
  4. package/README.md +20 -3
  5. package/docs/architecture.md +34 -2
  6. package/docs/extensions.md +199 -0
  7. package/docs/migration.md +100 -0
  8. package/docs/public-api.md +280 -24
  9. package/docs/usage.md +122 -30
  10. package/package.json +1 -1
  11. package/plugins/core/audit/index.js +1 -1
  12. package/plugins/core/default/bootstrap.js +44 -19
  13. package/plugins/core/python-loader/index.js +43 -25
  14. package/plugins/core/scheduler/index.js +1 -0
  15. package/plugins/core/skill-manager/PROMPT.md +6 -0
  16. package/plugins/core/skill-manager/index.js +402 -115
  17. package/plugins/core/sub-agent/PROMPT.md +10 -0
  18. package/plugins/core/sub-agent/index.js +36 -3
  19. package/plugins/core/think/index.js +1 -0
  20. package/plugins/core/workflow/context.js +941 -0
  21. package/plugins/core/workflow/engine.js +66 -0
  22. package/plugins/core/workflow/examples/01-basic.js +42 -0
  23. package/plugins/core/workflow/examples/01-basic.json +30 -0
  24. package/plugins/core/workflow/examples/02-choice.js +75 -0
  25. package/plugins/core/workflow/examples/02-choice.json +59 -0
  26. package/plugins/core/workflow/examples/03-chain-style.js +114 -0
  27. package/plugins/core/workflow/examples/03-each.json +41 -0
  28. package/plugins/core/workflow/examples/04-parallel.js +52 -0
  29. package/plugins/core/workflow/examples/04-parallel.json +51 -0
  30. package/plugins/core/workflow/examples/05-chain-style.json +68 -0
  31. package/plugins/core/workflow/examples/05-each.js +65 -0
  32. package/plugins/core/workflow/examples/06-script.js +82 -0
  33. package/plugins/core/workflow/examples/07-module-export.js +43 -0
  34. package/plugins/core/workflow/examples/08-default-export.js +29 -0
  35. package/plugins/core/workflow/examples/09-next-with-args.js +50 -0
  36. package/plugins/core/workflow/examples/10-logger.js +34 -0
  37. package/plugins/core/workflow/examples/11-storage.js +68 -0
  38. package/plugins/core/workflow/examples/simple.js +77 -0
  39. package/plugins/core/workflow/examples/simple.json +75 -0
  40. package/plugins/core/workflow/index.js +204 -78
  41. package/plugins/core/workflow/js-runner.js +318 -0
  42. package/plugins/core/workflow/json-runner.js +323 -0
  43. package/plugins/core/workflow/stages/action.js +211 -0
  44. package/plugins/core/workflow/stages/choice.js +74 -0
  45. package/plugins/core/workflow/stages/delay.js +73 -0
  46. package/plugins/core/workflow/stages/each.js +123 -0
  47. package/plugins/core/workflow/stages/parallel.js +69 -0
  48. package/plugins/core/workflow/stages/try.js +142 -0
  49. package/plugins/executors/data-splitter/PROMPT.md +13 -0
  50. package/plugins/executors/data-splitter/index.js +8 -6
  51. package/plugins/executors/extension/extension-registry.js +145 -0
  52. package/plugins/executors/extension/index.js +405 -437
  53. package/plugins/executors/extension/prompt-builder.js +359 -0
  54. package/plugins/executors/extension/skill-helper.js +143 -0
  55. package/plugins/messaging/feishu/index.js +5 -3
  56. package/plugins/messaging/qq/index.js +6 -4
  57. package/plugins/messaging/telegram/index.js +6 -3
  58. package/plugins/messaging/weixin/index.js +5 -3
  59. package/plugins/tools/PROMPT.md +26 -0
  60. package/plugins/tools/index.js +6 -5
  61. package/sandbox/check-context.js +5 -0
  62. package/sandbox/test-context.js +27 -0
  63. package/sandbox/test-fixes.js +40 -0
  64. package/sandbox/test-hello-js.js +46 -0
  65. package/skills/foliko/AGENTS.md +196 -43
  66. package/skills/foliko/SKILL.md +157 -28
  67. package/skills/mcp/SKILL.md +77 -118
  68. package/skills/plugins/SKILL.md +89 -3
  69. package/skills/python/SKILL.md +57 -39
  70. package/skills/skill-guide/SKILL.md +42 -34
  71. package/skills/workflows/SKILL.md +753 -436
  72. package/src/agent/chat.js +56 -28
  73. package/src/agent/main.js +39 -14
  74. package/src/agent/prompt-registry.js +56 -16
  75. package/src/agent/prompts/PROMPT.md +3 -0
  76. package/src/agent/sub.js +1 -1
  77. package/src/cli/ui/chat-ui-old.js +5 -2
  78. package/src/cli/ui/chat-ui.js +9 -5
  79. package/src/common/constants.js +12 -0
  80. package/src/common/error-capture.js +91 -0
  81. package/src/common/json-safe.js +20 -0
  82. package/src/common/logger.js +2 -2
  83. package/src/context/compressor.js +6 -2
  84. package/src/executors/mcp-executor.js +105 -125
  85. package/src/framework/framework.js +78 -12
  86. package/src/index.js +4 -0
  87. package/src/plugin/base.js +908 -5
  88. package/src/plugin/manager.js +124 -9
  89. package/src/tool/schema.js +32 -9
  90. package/src/utils/sandbox.js +1 -1
  91. package/website/index.html +821 -0
  92. package/skills/workflows/workflow-troubleshooting/DEBUGGING.md +0 -197
  93. 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)` | 直接执行 |
@@ -486,10 +486,10 @@ framework.skills.listCommands('my-skill');
486
486
 
487
487
  // 获取单个命令详情
488
488
  framework.skills.getCommand('my-skill', 'run');
489
- // { name: 'my-skill:run', description: '...', options: [...], inputSchema: {...} }
489
+ // { name: 'run', description: '...', options: [...], inputSchema: {...} }
490
490
 
491
491
  // 调用命令(通过 extension 执行)
492
- await framework.extensions.execute('skill', 'my-skill:run', { command: '--arg value' });
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', 'my-skill:hello', { command: '-n Alice' });
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
- | `mcp_call` | 调用 MCP 服务器工具 |
1022
- | `mcp_tool_schema` | 获取工具调用示例 |
1023
- | `mcp_set_enabled` | 动态开启/关闭服务器 |
1024
- | `mcp_reload` | 重载 MCP 配置 |
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
- install(framework) {
1084
- // 注册工具
1085
- framework.tools.tool({
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
- // 注册 Prompt Part
1093
- framework.prompts.register('my-plugin', 'my-rules', () => {
1094
- return '## 我的规则';
1095
- }, { scope: 'global', priority: 50 });
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
- start(framework) {
1099
- // 声明式 prompts 在此自动注册
1103
+ onStop() {
1104
+ // 自定义清理逻辑(工具/扩展基类自动处理)
1100
1105
  }
1106
+ }
1101
1107
 
1102
- reload(framework) {
1103
- // prompts 会自动清理并重新注册
1104
- }
1108
+ module.exports = MyPlugin;
1109
+ ```
1105
1110
 
1106
- uninstall(framework) {
1107
- // prompts 会自动清理
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
- module.exports = MyPlugin;
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`,导出命令数组即可注册为可调用的 slash 命令:
169
+ 如果 skill 目录下有 `index.js`,导出命令数组即可注册为可调用的扩展。**每个 skill 自动注册为 `skill:<skillname>` 扩展**,命令是扩展下的 tool。
170
170
 
171
171
  ```js
172
- module.exports = [
173
- {
174
- name: 'greet',
175
- description: '打招呼',
176
- options: [
177
- { flags: '-n, --name <value>', description: '姓名' }
178
- ],
179
- execute: async (parsedArgs, ctx) => {
180
- return `Hello, ${parsedArgs.name || 'World'}!`
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
- 命令通过 `ext_call({ plugin: "skill", tool: "skill-name:command-name", args: { command: "..." } })` 调用。
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
- install(framework) {
334
- // 注册工具、监听事件
335
- framework.registerTool({
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
- execute: async (args) => { ... }
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
- start(framework) {
346
- // 初始化逻辑,start() 可能会被调用多次
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
- - 项目级:`plugins/<name>/index.js`
475
+ - 项目级:`.foliko/plugins/<name>/index.js`
384
476
  - 全局:`~/.foliko/plugins/<name>.js` 或 `~/.foliko/plugins/<name>/index.js`
385
- - 通过 `pluginLinks` 指定任意路径
477
+ - 内置:`plugins/<name>/index.js`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foliko",
3
- "version": "2.0.5",
3
+ "version": "2.0.7",
4
4
  "description": "简约的插件化 Agent 框架",
5
5
  "main": "src/index.js",
6
6
  "type": "commonjs",
@@ -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(), '.vb-agent', 'logs', 'audit')
26
+ logDir: config.logDir || path.join(os.homedir(), '.foliko', 'logs', 'audit')
27
27
  }
28
28
 
29
29
  this._framework = null