foliko 1.0.74 → 1.0.75
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/.shared/ui-ux-pro-max/data/charts.csv +26 -0
- package/.agent/.shared/ui-ux-pro-max/data/colors.csv +97 -0
- package/.agent/.shared/ui-ux-pro-max/data/icons.csv +101 -0
- package/.agent/.shared/ui-ux-pro-max/data/landing.csv +31 -0
- package/.agent/.shared/ui-ux-pro-max/data/products.csv +97 -0
- package/.agent/.shared/ui-ux-pro-max/data/prompts.csv +24 -0
- package/.agent/.shared/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/.agent/.shared/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/.agent/.shared/ui-ux-pro-max/data/styles.csv +59 -0
- package/.agent/.shared/ui-ux-pro-max/data/typography.csv +58 -0
- package/.agent/.shared/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
- package/.agent/.shared/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/.agent/.shared/ui-ux-pro-max/data/web-interface.csv +31 -0
- package/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/core.cpython-313.pyc +0 -0
- package/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-313.pyc +0 -0
- package/.agent/.shared/ui-ux-pro-max/scripts/core.py +258 -0
- package/.agent/.shared/ui-ux-pro-max/scripts/design_system.py +1067 -0
- package/.agent/.shared/ui-ux-pro-max/scripts/search.py +106 -0
- package/.agent/ARCHITECTURE.md +288 -0
- package/.agent/agents/ambient-agent.md +57 -0
- package/.agent/agents/debugger.md +55 -0
- package/.agent/agents/email-assistant.md +49 -0
- package/.agent/agents/file-manager.md +42 -0
- package/.agent/agents/python-developer.md +60 -0
- package/.agent/agents/scheduler.md +59 -0
- package/.agent/agents/web-developer.md +45 -0
- package/.agent/data/default.json +29 -0
- package/.agent/data/plugins-state.json +255 -0
- package/.agent/mcp_config.json +4 -0
- package/.agent/mcp_config_updated.json +12 -0
- package/.agent/plugins.json +5 -0
- package/.agent/rules/GEMINI.md +273 -0
- package/.agent/rules/allow-rule.md +77 -0
- package/.agent/rules/log-rule.md +83 -0
- package/.agent/rules/security-rule.md +93 -0
- package/.agent/scripts/auto_preview.py +148 -0
- package/.agent/scripts/checklist.py +217 -0
- package/.agent/scripts/session_manager.py +120 -0
- package/.agent/scripts/verify_all.py +327 -0
- package/.agent/skills/api-patterns/SKILL.md +81 -0
- package/.agent/skills/api-patterns/api-style.md +42 -0
- package/.agent/skills/api-patterns/auth.md +24 -0
- package/.agent/skills/api-patterns/documentation.md +26 -0
- package/.agent/skills/api-patterns/graphql.md +41 -0
- package/.agent/skills/api-patterns/rate-limiting.md +31 -0
- package/.agent/skills/api-patterns/response.md +37 -0
- package/.agent/skills/api-patterns/rest.md +40 -0
- package/.agent/skills/api-patterns/scripts/api_validator.py +211 -0
- package/.agent/skills/api-patterns/security-testing.md +122 -0
- package/.agent/skills/api-patterns/trpc.md +41 -0
- package/.agent/skills/api-patterns/versioning.md +22 -0
- package/.agent/skills/app-builder/SKILL.md +75 -0
- package/.agent/skills/app-builder/agent-coordination.md +71 -0
- package/.agent/skills/app-builder/feature-building.md +53 -0
- package/.agent/skills/app-builder/project-detection.md +34 -0
- package/.agent/skills/app-builder/scaffolding.md +118 -0
- package/.agent/skills/app-builder/tech-stack.md +40 -0
- package/.agent/skills/app-builder/templates/SKILL.md +39 -0
- package/.agent/skills/app-builder/templates/astro-static/TEMPLATE.md +76 -0
- package/.agent/skills/app-builder/templates/chrome-extension/TEMPLATE.md +92 -0
- package/.agent/skills/app-builder/templates/cli-tool/TEMPLATE.md +88 -0
- package/.agent/skills/app-builder/templates/electron-desktop/TEMPLATE.md +88 -0
- package/.agent/skills/app-builder/templates/express-api/TEMPLATE.md +83 -0
- package/.agent/skills/app-builder/templates/flutter-app/TEMPLATE.md +90 -0
- package/.agent/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +90 -0
- package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +122 -0
- package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +122 -0
- package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +169 -0
- package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +134 -0
- package/.agent/skills/app-builder/templates/python-fastapi/TEMPLATE.md +83 -0
- package/.agent/skills/app-builder/templates/react-native-app/TEMPLATE.md +119 -0
- package/.agent/skills/architecture/SKILL.md +55 -0
- package/.agent/skills/architecture/context-discovery.md +43 -0
- package/.agent/skills/architecture/examples.md +94 -0
- package/.agent/skills/architecture/pattern-selection.md +68 -0
- package/.agent/skills/architecture/patterns-reference.md +50 -0
- package/.agent/skills/architecture/trade-off-analysis.md +77 -0
- package/.agent/skills/clean-code/SKILL.md +201 -0
- package/.agent/skills/doc.md +177 -0
- package/.agent/skills/frontend-design/SKILL.md +418 -0
- package/.agent/skills/frontend-design/animation-guide.md +331 -0
- package/.agent/skills/frontend-design/color-system.md +311 -0
- package/.agent/skills/frontend-design/decision-trees.md +418 -0
- package/.agent/skills/frontend-design/motion-graphics.md +306 -0
- package/.agent/skills/frontend-design/scripts/accessibility_checker.py +183 -0
- package/.agent/skills/frontend-design/scripts/ux_audit.py +722 -0
- package/.agent/skills/frontend-design/typography-system.md +345 -0
- package/.agent/skills/frontend-design/ux-psychology.md +1116 -0
- package/.agent/skills/frontend-design/visual-effects.md +383 -0
- package/.agent/skills/i18n-localization/SKILL.md +154 -0
- package/.agent/skills/i18n-localization/scripts/i18n_checker.py +241 -0
- package/.agent/skills/mcp-builder/SKILL.md +176 -0
- package/.agent/skills/web-design-guidelines/SKILL.md +57 -0
- package/.agent/workflows/brainstorm.md +113 -0
- package/.agent/workflows/create.md +59 -0
- package/.agent/workflows/debug.md +103 -0
- package/.agent/workflows/deploy.md +176 -0
- package/.agent/workflows/enhance.md +63 -0
- package/.agent/workflows/orchestrate.md +237 -0
- package/.agent/workflows/plan.md +89 -0
- package/.agent/workflows/preview.md +81 -0
- package/.agent/workflows/simple-test.md +42 -0
- package/.agent/workflows/status.md +86 -0
- package/.agent/workflows/structured-orchestrate.md +180 -0
- package/.agent/workflows/test.md +144 -0
- package/.agent/workflows/ui-ux-pro-max.md +296 -0
- package/.claude/settings.local.json +157 -149
- package/.editorconfig +56 -0
- package/.husky/pre-commit +4 -0
- package/.lintstagedrc +7 -0
- package/.prettierignore +29 -0
- package/.prettierrc +11 -0
- package/CLAUDE.md +2 -0
- package/README.md +64 -55
- package/SPEC.md +102 -61
- package/cli/bin/foliko.js +4 -4
- package/cli/src/commands/chat.js +53 -51
- package/cli/src/commands/list.js +40 -37
- package/cli/src/index.js +18 -18
- package/cli/src/ui/chat-ui.js +78 -76
- package/cli/src/utils/ansi.js +15 -15
- package/cli/src/utils/markdown.js +112 -116
- package/docker-compose.yml +1 -1
- package/docs/ai-sdk-optimization.md +655 -643
- package/docs/features.md +80 -80
- package/docs/quick-reference.md +49 -46
- package/docs/user-manual.md +411 -380
- package/examples/ambient-example.js +95 -97
- package/examples/basic.js +115 -110
- package/examples/bootstrap.js +52 -43
- package/examples/mcp-example.js +56 -53
- package/examples/skill-example.js +49 -49
- package/examples/test-chat.js +60 -58
- package/examples/test-mcp.js +49 -43
- package/examples/test-reload.js +38 -40
- package/examples/test-telegram.js +3 -3
- package/examples/test-tg-bot.js +7 -4
- package/examples/test-tg-simple.js +4 -3
- package/examples/test-tg.js +3 -3
- package/examples/test-think.js +13 -7
- package/examples/test-web-plugin.js +61 -56
- package/examples/test-weixin-feishu.js +40 -37
- package/examples/workflow.js +49 -49
- package/foliko-1.0.75.tgz +0 -0
- package/package.json +37 -3
- package/plugins/ai-plugin.js +7 -5
- package/plugins/ambient-agent/EventWatcher.js +113 -0
- package/plugins/ambient-agent/ExplorerLoop.js +640 -0
- package/plugins/ambient-agent/GoalManager.js +197 -0
- package/plugins/ambient-agent/Reflector.js +95 -0
- package/plugins/ambient-agent/StateStore.js +90 -0
- package/plugins/ambient-agent/constants.js +101 -0
- package/plugins/ambient-agent/index.js +579 -0
- package/plugins/default-plugins.js +62 -49
- package/plugins/email/constants.js +64 -0
- package/plugins/email/handlers.js +461 -0
- package/plugins/email/index.js +278 -0
- package/plugins/email/monitor.js +269 -0
- package/plugins/email/parser.js +138 -0
- package/plugins/email/reply.js +151 -0
- package/plugins/email/utils.js +124 -0
- package/plugins/feishu-plugin.js +23 -19
- package/plugins/file-system-plugin.js +456 -106
- package/plugins/install-plugin.js +6 -4
- package/plugins/python-executor-plugin.js +3 -1
- package/plugins/python-plugin-loader.js +10 -8
- package/plugins/rules-plugin.js +5 -3
- package/plugins/scheduler-plugin.js +18 -16
- package/plugins/session-plugin.js +3 -1
- package/plugins/storage-plugin.js +5 -3
- package/plugins/subagent-plugin.js +152 -92
- package/plugins/telegram-plugin.js +26 -19
- package/plugins/think-plugin.js +4 -2
- package/plugins/tools-plugin.js +3 -1
- package/plugins/web-plugin.js +15 -13
- package/plugins/weixin-plugin.js +43 -36
- package/reports/system-health-report-20260401.md +79 -0
- package/skills/ambient-agent/SKILL.md +49 -39
- package/skills/foliko-dev/AGENTS.md +64 -61
- package/skills/foliko-dev/SKILL.md +125 -119
- package/skills/mcp-usage/SKILL.md +19 -17
- package/skills/python-plugin-dev/SKILL.md +16 -15
- package/skills/skill-guide/SKILL.md +12 -12
- package/skills/subagent-guide/SKILL.md +237 -0
- package/skills/workflow-guide/SKILL.md +90 -45
- package/skills/workflow-troubleshooting/DEBUGGING.md +36 -21
- package/skills/workflow-troubleshooting/SKILL.md +156 -79
- package/src/capabilities/index.js +4 -4
- package/src/capabilities/skill-manager.js +211 -197
- package/src/capabilities/workflow-engine.js +461 -547
- package/src/core/agent-chat.js +426 -279
- package/src/core/agent.js +453 -249
- package/src/core/framework.js +183 -149
- package/src/core/index.js +8 -8
- package/src/core/plugin-base.js +52 -52
- package/src/core/plugin-manager.js +377 -281
- package/src/core/provider.js +35 -32
- package/src/core/sub-agent-config.js +264 -0
- package/src/core/system-prompt-builder.js +120 -0
- package/src/core/tool-registry.js +416 -33
- package/src/core/tool-router.js +149 -68
- package/src/executors/executor-base.js +58 -58
- package/src/executors/mcp-executor.js +269 -257
- package/src/index.js +5 -17
- package/src/utils/circuit-breaker.js +301 -0
- package/src/utils/error-boundary.js +363 -0
- package/src/utils/error.js +374 -0
- package/src/utils/event-emitter.js +20 -20
- package/src/utils/id.js +133 -0
- package/src/utils/index.js +217 -3
- package/src/utils/logger.js +181 -0
- package/src/utils/plugin-helpers.js +90 -0
- package/src/utils/retry.js +122 -0
- package/src/utils/sandbox.js +292 -0
- package/test/tool-registry-validation.test.js +218 -0
- package/test_report.md +70 -0
- package/website/docs/api.html +169 -107
- package/website/docs/configuration.html +296 -144
- package/website/docs/plugin-development.html +154 -85
- package/website/docs/project-structure.html +110 -109
- package/website/docs/skill-development.html +117 -61
- package/website/index.html +209 -205
- package/website/script.js +20 -17
- package/website/styles.css +1 -1
- package/plugins/ambient-agent-plugin.js +0 -1565
- package/plugins/email.js +0 -1142
|
@@ -3,82 +3,93 @@
|
|
|
3
3
|
* 加载和管理 Skill
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
const fs = require('fs')
|
|
7
|
-
const path = require('path')
|
|
8
|
-
const { Plugin } = require('../core/plugin-base')
|
|
9
|
-
const {
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const { Plugin } = require('../core/plugin-base');
|
|
9
|
+
const { logger } = require('../utils/logger');
|
|
10
|
+
const log = logger.child('SkillManager');
|
|
11
|
+
const { z } = require('zod');
|
|
10
12
|
|
|
11
13
|
/**
|
|
12
14
|
* 验证 skill 名称
|
|
13
15
|
* 1-64字符,字母数字、下划线和连字符,不能以连字符或下划线开头或结尾
|
|
14
16
|
*/
|
|
15
17
|
function isValidSkillName(name) {
|
|
16
|
-
if (!name || name.length < 1 || name.length > 64) return false
|
|
17
|
-
if (!/^[a-zA-Z0-9_-]+$/.test(name)) return false
|
|
18
|
-
if (name.startsWith('-') || name.startsWith('_') || name.endsWith('-') || name.endsWith('_'))
|
|
19
|
-
|
|
20
|
-
return
|
|
18
|
+
if (!name || name.length < 1 || name.length > 64) return false;
|
|
19
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(name)) return false;
|
|
20
|
+
if (name.startsWith('-') || name.startsWith('_') || name.endsWith('-') || name.endsWith('_'))
|
|
21
|
+
return false;
|
|
22
|
+
if (/--/.test(name) || /__/.test(name)) return false;
|
|
23
|
+
return true;
|
|
21
24
|
}
|
|
22
25
|
|
|
23
26
|
/**
|
|
24
27
|
* 解析 YAML frontmatter
|
|
25
28
|
*/
|
|
26
29
|
function parseFrontmatter(content) {
|
|
27
|
-
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/)
|
|
28
|
-
if (!match) return null
|
|
30
|
+
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
31
|
+
if (!match) return null;
|
|
29
32
|
|
|
30
|
-
const frontmatter = {}
|
|
31
|
-
const lines = match[1].split('\n')
|
|
32
|
-
let currentKey = null
|
|
33
|
+
const frontmatter = {};
|
|
34
|
+
const lines = match[1].split('\n');
|
|
35
|
+
let currentKey = null;
|
|
33
36
|
|
|
34
37
|
for (const line of lines) {
|
|
35
38
|
// 处理 metadata 嵌套
|
|
36
39
|
if (currentKey === 'metadata') {
|
|
37
40
|
if (line.match(/^ {2}[a-zA-Z]/)) {
|
|
38
|
-
const colonIndex = line.indexOf(':')
|
|
41
|
+
const colonIndex = line.indexOf(':');
|
|
39
42
|
if (colonIndex > 0) {
|
|
40
|
-
const key = line.substring(2, colonIndex).trim()
|
|
41
|
-
const value = line
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
const key = line.substring(2, colonIndex).trim();
|
|
44
|
+
const value = line
|
|
45
|
+
.substring(colonIndex + 1)
|
|
46
|
+
.trim()
|
|
47
|
+
.replace(/^["']|["']$/g, '');
|
|
48
|
+
frontmatter[currentKey][key] = value;
|
|
49
|
+
continue;
|
|
44
50
|
}
|
|
45
51
|
} else if (line.match(/^[a-zA-Z]/)) {
|
|
46
|
-
currentKey = null
|
|
47
|
-
continue
|
|
52
|
+
currentKey = null;
|
|
53
|
+
continue;
|
|
48
54
|
}
|
|
49
55
|
}
|
|
50
56
|
|
|
51
|
-
const colonIndex = line.indexOf(':')
|
|
52
|
-
if (colonIndex === -1) continue
|
|
57
|
+
const colonIndex = line.indexOf(':');
|
|
58
|
+
if (colonIndex === -1) continue;
|
|
53
59
|
|
|
54
|
-
const key = line.substring(0, colonIndex).trim()
|
|
55
|
-
let value = line.substring(colonIndex + 1).trim()
|
|
60
|
+
const key = line.substring(0, colonIndex).trim();
|
|
61
|
+
let value = line.substring(colonIndex + 1).trim();
|
|
56
62
|
|
|
57
63
|
// 移除引号
|
|
58
|
-
if (
|
|
59
|
-
|
|
60
|
-
value
|
|
64
|
+
if (
|
|
65
|
+
(value.startsWith('"') && value.endsWith('"')) ||
|
|
66
|
+
(value.startsWith("'") && value.endsWith("'"))
|
|
67
|
+
) {
|
|
68
|
+
value = value.slice(1, -1);
|
|
61
69
|
}
|
|
62
70
|
|
|
63
71
|
if (key === 'metadata') {
|
|
64
|
-
currentKey = 'metadata'
|
|
65
|
-
frontmatter.metadata = {}
|
|
72
|
+
currentKey = 'metadata';
|
|
73
|
+
frontmatter.metadata = {};
|
|
66
74
|
} else if (key === 'allowed-tools') {
|
|
67
|
-
frontmatter[key] = value.split(',').map(t => t.trim().replace(/^["']|["']$/g, '')).filter(t => t)
|
|
68
|
-
} else {
|
|
69
75
|
frontmatter[key] = value
|
|
76
|
+
.split(',')
|
|
77
|
+
.map((t) => t.trim().replace(/^["']|["']$/g, ''))
|
|
78
|
+
.filter((t) => t);
|
|
79
|
+
} else {
|
|
80
|
+
frontmatter[key] = value;
|
|
70
81
|
}
|
|
71
82
|
}
|
|
72
83
|
|
|
73
|
-
return frontmatter
|
|
84
|
+
return frontmatter;
|
|
74
85
|
}
|
|
75
86
|
|
|
76
87
|
/**
|
|
77
88
|
* 移除 frontmatter,获取正文
|
|
78
89
|
*/
|
|
79
90
|
function stripFrontmatter(content) {
|
|
80
|
-
const match = content.match(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/)
|
|
81
|
-
return match ? content.slice(match[0].length).trim() : content.trim()
|
|
91
|
+
const match = content.match(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/);
|
|
92
|
+
return match ? content.slice(match[0].length).trim() : content.trim();
|
|
82
93
|
}
|
|
83
94
|
|
|
84
95
|
/**
|
|
@@ -86,12 +97,12 @@ function stripFrontmatter(content) {
|
|
|
86
97
|
*/
|
|
87
98
|
class SkillMetadata {
|
|
88
99
|
constructor(data) {
|
|
89
|
-
this.name = data.name || ''
|
|
90
|
-
this.description = data.description || ''
|
|
91
|
-
this.license = data.license || null
|
|
92
|
-
this.compatibility = data.compatibility || null
|
|
93
|
-
this.metadata = data.metadata || {}
|
|
94
|
-
this.allowedTools = data.allowedTools || []
|
|
100
|
+
this.name = data.name || '';
|
|
101
|
+
this.description = data.description || '';
|
|
102
|
+
this.license = data.license || null;
|
|
103
|
+
this.compatibility = data.compatibility || null;
|
|
104
|
+
this.metadata = data.metadata || {};
|
|
105
|
+
this.allowedTools = data.allowedTools || [];
|
|
95
106
|
}
|
|
96
107
|
}
|
|
97
108
|
|
|
@@ -100,24 +111,24 @@ class SkillMetadata {
|
|
|
100
111
|
*/
|
|
101
112
|
class Skill {
|
|
102
113
|
constructor(metadata, content) {
|
|
103
|
-
this.metadata = metadata
|
|
104
|
-
this.content = content
|
|
105
|
-
this._framework = null
|
|
114
|
+
this.metadata = metadata;
|
|
115
|
+
this.content = content;
|
|
116
|
+
this._framework = null;
|
|
106
117
|
}
|
|
107
118
|
|
|
108
119
|
/**
|
|
109
120
|
* 安装 skill
|
|
110
121
|
*/
|
|
111
122
|
install(framework) {
|
|
112
|
-
this._framework = framework
|
|
113
|
-
return this
|
|
123
|
+
this._framework = framework;
|
|
124
|
+
return this;
|
|
114
125
|
}
|
|
115
126
|
|
|
116
127
|
/**
|
|
117
128
|
* 获取工具定义
|
|
118
129
|
*/
|
|
119
130
|
getTools() {
|
|
120
|
-
return []
|
|
131
|
+
return [];
|
|
121
132
|
}
|
|
122
133
|
}
|
|
123
134
|
|
|
@@ -126,48 +137,50 @@ class Skill {
|
|
|
126
137
|
*/
|
|
127
138
|
class SkillManagerPlugin extends Plugin {
|
|
128
139
|
constructor(config = {}) {
|
|
129
|
-
super()
|
|
130
|
-
this.name = 'skill-manager'
|
|
131
|
-
this.version = '1.0.0'
|
|
132
|
-
this.description = '技能管理器,加载和管理 Skill'
|
|
133
|
-
this.priority = 5
|
|
134
|
-
this.system = true
|
|
135
|
-
|
|
136
|
-
this._framework = null
|
|
137
|
-
this._skillsDirs = Array.isArray(config.skillsDirs)
|
|
138
|
-
|
|
139
|
-
|
|
140
|
+
super();
|
|
141
|
+
this.name = 'skill-manager';
|
|
142
|
+
this.version = '1.0.0';
|
|
143
|
+
this.description = '技能管理器,加载和管理 Skill';
|
|
144
|
+
this.priority = 5;
|
|
145
|
+
this.system = true;
|
|
146
|
+
|
|
147
|
+
this._framework = null;
|
|
148
|
+
this._skillsDirs = Array.isArray(config.skillsDirs)
|
|
149
|
+
? config.skillsDirs
|
|
150
|
+
: [config.skillsDir || '.agent/skills', 'skills'];
|
|
151
|
+
this._skills = new Map();
|
|
152
|
+
this._loaded = false;
|
|
140
153
|
}
|
|
141
154
|
|
|
142
155
|
install(framework) {
|
|
143
|
-
this._framework = framework
|
|
144
|
-
return this
|
|
156
|
+
this._framework = framework;
|
|
157
|
+
return this;
|
|
145
158
|
}
|
|
146
159
|
|
|
147
160
|
start(framework) {
|
|
148
|
-
this._loadAllSkills()
|
|
161
|
+
this._loadAllSkills();
|
|
149
162
|
|
|
150
163
|
// 注册 loadSkill 工具
|
|
151
164
|
framework.registerTool({
|
|
152
165
|
name: 'loadSkill',
|
|
153
166
|
description: '加载指定技能,获取技能的使用指南和内容',
|
|
154
167
|
inputSchema: z.object({
|
|
155
|
-
skill: z.string().describe('技能名称')
|
|
168
|
+
skill: z.string().describe('技能名称'),
|
|
156
169
|
}),
|
|
157
170
|
execute: async (args) => {
|
|
158
|
-
const skillName = args.skill
|
|
159
|
-
const skill = this.getSkill(skillName)
|
|
171
|
+
const skillName = args.skill;
|
|
172
|
+
const skill = this.getSkill(skillName);
|
|
160
173
|
if (!skill) {
|
|
161
|
-
return { success: false, error: `Skill '${skillName}' not found` }
|
|
174
|
+
return { success: false, error: `Skill '${skillName}' not found` };
|
|
162
175
|
}
|
|
163
176
|
return {
|
|
164
177
|
success: true,
|
|
165
178
|
name: skill.name,
|
|
166
179
|
description: skill.metadata?.description || '',
|
|
167
|
-
content: skill.content
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
})
|
|
180
|
+
content: skill.content,
|
|
181
|
+
};
|
|
182
|
+
},
|
|
183
|
+
});
|
|
171
184
|
|
|
172
185
|
// 注册 reloadSkills 工具
|
|
173
186
|
framework.registerTool({
|
|
@@ -175,14 +188,14 @@ class SkillManagerPlugin extends Plugin {
|
|
|
175
188
|
description: '重载所有技能,当用户添加新技能或修改技能后调用此工具',
|
|
176
189
|
inputSchema: z.object({}),
|
|
177
190
|
execute: async () => {
|
|
178
|
-
this.reload(this._framework)
|
|
191
|
+
this.reload(this._framework);
|
|
179
192
|
return {
|
|
180
193
|
success: true,
|
|
181
194
|
message: `Skills reloaded. Total: ${this._skills.size}`,
|
|
182
|
-
skills: Array.from(this._skills.keys())
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
})
|
|
195
|
+
skills: Array.from(this._skills.keys()),
|
|
196
|
+
};
|
|
197
|
+
},
|
|
198
|
+
});
|
|
186
199
|
|
|
187
200
|
// 注册 loadReference 工具(按需加载 skill 的附加文档)
|
|
188
201
|
framework.registerTool({
|
|
@@ -191,51 +204,51 @@ class SkillManagerPlugin extends Plugin {
|
|
|
191
204
|
inputSchema: z.object({
|
|
192
205
|
skill: z.string().describe('技能名称'),
|
|
193
206
|
reference: z.string().describe('参考文档名称(不含 .md 后缀)'),
|
|
194
|
-
list: z.boolean().optional().describe('如果为 true,列出该技能的所有可用的 reference 文件')
|
|
207
|
+
list: z.boolean().optional().describe('如果为 true,列出该技能的所有可用的 reference 文件'),
|
|
195
208
|
}),
|
|
196
209
|
execute: async (args) => {
|
|
197
210
|
if (args.list) {
|
|
198
211
|
// 列出该技能的所有 reference
|
|
199
|
-
const refs = this.listReferences(args.skill)
|
|
212
|
+
const refs = this.listReferences(args.skill);
|
|
200
213
|
return {
|
|
201
214
|
success: true,
|
|
202
215
|
skill: args.skill,
|
|
203
|
-
references: refs
|
|
204
|
-
}
|
|
216
|
+
references: refs,
|
|
217
|
+
};
|
|
205
218
|
}
|
|
206
219
|
|
|
207
|
-
const content = this.loadReference(args.skill, args.reference)
|
|
220
|
+
const content = this.loadReference(args.skill, args.reference);
|
|
208
221
|
if (content === null) {
|
|
209
222
|
return {
|
|
210
223
|
success: false,
|
|
211
|
-
error: `Reference '${args.reference}' not found in skill '${args.skill}'
|
|
212
|
-
}
|
|
224
|
+
error: `Reference '${args.reference}' not found in skill '${args.skill}'`,
|
|
225
|
+
};
|
|
213
226
|
}
|
|
214
227
|
return {
|
|
215
228
|
success: true,
|
|
216
229
|
skill: args.skill,
|
|
217
230
|
reference: args.reference,
|
|
218
|
-
content
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
})
|
|
231
|
+
content,
|
|
232
|
+
};
|
|
233
|
+
},
|
|
234
|
+
});
|
|
222
235
|
|
|
223
236
|
// 注册 listScripts 工具(列出 skill 的脚本)
|
|
224
237
|
framework.registerTool({
|
|
225
238
|
name: 'listScripts',
|
|
226
239
|
description: '列出指定技能下的所有可执行脚本',
|
|
227
240
|
inputSchema: z.object({
|
|
228
|
-
skill: z.string().describe('技能名称')
|
|
241
|
+
skill: z.string().describe('技能名称'),
|
|
229
242
|
}),
|
|
230
243
|
execute: async (args) => {
|
|
231
|
-
const scripts = this.listScripts(args.skill)
|
|
244
|
+
const scripts = this.listScripts(args.skill);
|
|
232
245
|
return {
|
|
233
246
|
success: true,
|
|
234
247
|
skill: args.skill,
|
|
235
|
-
scripts
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
})
|
|
248
|
+
scripts,
|
|
249
|
+
};
|
|
250
|
+
},
|
|
251
|
+
});
|
|
239
252
|
|
|
240
253
|
// 注册 loadScript 工具(读取脚本内容)
|
|
241
254
|
framework.registerTool({
|
|
@@ -243,74 +256,74 @@ class SkillManagerPlugin extends Plugin {
|
|
|
243
256
|
description: '读取指定技能下脚本文件的内容',
|
|
244
257
|
inputSchema: z.object({
|
|
245
258
|
skill: z.string().describe('技能名称'),
|
|
246
|
-
script: z.string().describe('脚本名称(包含扩展名)')
|
|
259
|
+
script: z.string().describe('脚本名称(包含扩展名)'),
|
|
247
260
|
}),
|
|
248
261
|
execute: async (args) => {
|
|
249
|
-
const content = this.loadScript(args.skill, args.script)
|
|
262
|
+
const content = this.loadScript(args.skill, args.script);
|
|
250
263
|
if (content === null) {
|
|
251
264
|
return {
|
|
252
265
|
success: false,
|
|
253
|
-
error: `Script '${args.script}' not found in skill '${args.skill}'
|
|
254
|
-
}
|
|
266
|
+
error: `Script '${args.script}' not found in skill '${args.skill}'`,
|
|
267
|
+
};
|
|
255
268
|
}
|
|
256
269
|
return {
|
|
257
270
|
success: true,
|
|
258
271
|
skill: args.skill,
|
|
259
272
|
script: args.script,
|
|
260
|
-
content
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
})
|
|
273
|
+
content,
|
|
274
|
+
};
|
|
275
|
+
},
|
|
276
|
+
});
|
|
264
277
|
|
|
265
|
-
return this
|
|
278
|
+
return this;
|
|
266
279
|
}
|
|
267
280
|
|
|
268
281
|
/**
|
|
269
282
|
* 加载所有 skills
|
|
270
283
|
*/
|
|
271
284
|
_loadAllSkills() {
|
|
272
|
-
if (this._loaded) return
|
|
285
|
+
if (this._loaded) return;
|
|
273
286
|
|
|
274
|
-
let totalLoaded = 0
|
|
287
|
+
let totalLoaded = 0;
|
|
275
288
|
|
|
276
289
|
for (const skillsDir of this._skillsDirs) {
|
|
277
|
-
const resolvedDir = path.resolve(process.cwd(), skillsDir)
|
|
290
|
+
const resolvedDir = path.resolve(process.cwd(), skillsDir);
|
|
278
291
|
|
|
279
292
|
if (!fs.existsSync(resolvedDir)) {
|
|
280
|
-
continue
|
|
293
|
+
continue;
|
|
281
294
|
}
|
|
282
295
|
|
|
283
296
|
try {
|
|
284
|
-
const entries = fs.readdirSync(resolvedDir, { withFileTypes: true })
|
|
297
|
+
const entries = fs.readdirSync(resolvedDir, { withFileTypes: true });
|
|
285
298
|
|
|
286
299
|
for (const entry of entries) {
|
|
287
|
-
if (!entry.isDirectory()) continue
|
|
300
|
+
if (!entry.isDirectory()) continue;
|
|
288
301
|
|
|
289
|
-
const skillPath = path.join(resolvedDir, entry.name)
|
|
302
|
+
const skillPath = path.join(resolvedDir, entry.name);
|
|
290
303
|
|
|
291
304
|
if (!isValidSkillName(entry.name)) {
|
|
292
|
-
continue
|
|
305
|
+
continue;
|
|
293
306
|
}
|
|
294
307
|
|
|
295
308
|
// 跳过已加载的 skill
|
|
296
309
|
if (this._skills.has(entry.name)) {
|
|
297
|
-
continue
|
|
310
|
+
continue;
|
|
298
311
|
}
|
|
299
312
|
|
|
300
313
|
try {
|
|
301
|
-
this._loadSkill(entry.name, skillPath)
|
|
302
|
-
totalLoaded
|
|
314
|
+
this._loadSkill(entry.name, skillPath);
|
|
315
|
+
totalLoaded++;
|
|
303
316
|
} catch (err) {
|
|
304
|
-
|
|
317
|
+
log.error(` Failed to load skill '${entry.name}':`, err.message);
|
|
305
318
|
}
|
|
306
319
|
}
|
|
307
320
|
} catch (err) {
|
|
308
|
-
|
|
321
|
+
log.error('Failed to load skills from:', skillsDir, err.message);
|
|
309
322
|
}
|
|
310
323
|
}
|
|
311
324
|
|
|
312
|
-
|
|
313
|
-
this._loaded = true
|
|
325
|
+
log.info(` Loaded ${this._skills.size} skills`);
|
|
326
|
+
this._loaded = true;
|
|
314
327
|
}
|
|
315
328
|
|
|
316
329
|
/**
|
|
@@ -320,35 +333,35 @@ class SkillManagerPlugin extends Plugin {
|
|
|
320
333
|
*/
|
|
321
334
|
_findSkillMarkdown(dir) {
|
|
322
335
|
if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory()) {
|
|
323
|
-
return null
|
|
336
|
+
return null;
|
|
324
337
|
}
|
|
325
338
|
|
|
326
|
-
const entries = fs.readdirSync(dir, { withFileTypes: true })
|
|
339
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
327
340
|
|
|
328
341
|
// 第一遍:优先查找 SKILL.MD
|
|
329
342
|
for (const entry of entries) {
|
|
330
343
|
if (entry.isFile() && entry.name.toUpperCase() === 'SKILL.MD') {
|
|
331
|
-
return path.join(dir, entry.name)
|
|
344
|
+
return path.join(dir, entry.name);
|
|
332
345
|
}
|
|
333
346
|
}
|
|
334
347
|
|
|
335
348
|
// 第二遍:查找 AGENTS.MD
|
|
336
349
|
for (const entry of entries) {
|
|
337
350
|
if (entry.isFile() && entry.name.toUpperCase() === 'AGENTS.MD') {
|
|
338
|
-
return path.join(dir, entry.name)
|
|
351
|
+
return path.join(dir, entry.name);
|
|
339
352
|
}
|
|
340
353
|
}
|
|
341
354
|
|
|
342
355
|
// 如果没找到,递归搜索子目录(排除 node_modules)
|
|
343
356
|
for (const entry of entries) {
|
|
344
357
|
if (entry.isDirectory() && entry.name !== 'node_modules') {
|
|
345
|
-
const subPath = path.join(dir, entry.name)
|
|
346
|
-
const found = this._findSkillMarkdown(subPath)
|
|
347
|
-
if (found) return found
|
|
358
|
+
const subPath = path.join(dir, entry.name);
|
|
359
|
+
const found = this._findSkillMarkdown(subPath);
|
|
360
|
+
if (found) return found;
|
|
348
361
|
}
|
|
349
362
|
}
|
|
350
363
|
|
|
351
|
-
return null
|
|
364
|
+
return null;
|
|
352
365
|
}
|
|
353
366
|
|
|
354
367
|
/**
|
|
@@ -356,17 +369,17 @@ class SkillManagerPlugin extends Plugin {
|
|
|
356
369
|
*/
|
|
357
370
|
_loadSkill(name, skillPath) {
|
|
358
371
|
// 查找 markdown 文件,优先加载 SKILL.md 或 AGENTS.md(支持多层嵌套)
|
|
359
|
-
const skillMdPath = this._findSkillMarkdown(skillPath)
|
|
372
|
+
const skillMdPath = this._findSkillMarkdown(skillPath);
|
|
360
373
|
if (!skillMdPath) {
|
|
361
|
-
throw new Error('No markdown file found')
|
|
374
|
+
throw new Error('No markdown file found');
|
|
362
375
|
}
|
|
363
376
|
|
|
364
|
-
const mainFile = skillMdPath
|
|
365
|
-
const content = fs.readFileSync(mainFile, 'utf-8')
|
|
366
|
-
const frontmatter = parseFrontmatter(content)
|
|
377
|
+
const mainFile = skillMdPath;
|
|
378
|
+
const content = fs.readFileSync(mainFile, 'utf-8');
|
|
379
|
+
const frontmatter = parseFrontmatter(content);
|
|
367
380
|
|
|
368
381
|
if (!frontmatter) {
|
|
369
|
-
throw new Error('No valid frontmatter found')
|
|
382
|
+
throw new Error('No valid frontmatter found');
|
|
370
383
|
}
|
|
371
384
|
|
|
372
385
|
const metadata = new SkillMetadata({
|
|
@@ -375,17 +388,17 @@ class SkillManagerPlugin extends Plugin {
|
|
|
375
388
|
license: frontmatter.license,
|
|
376
389
|
compatibility: frontmatter.compatibility,
|
|
377
390
|
metadata: frontmatter.metadata || {},
|
|
378
|
-
allowedTools: frontmatter['allowed-tools'] || []
|
|
379
|
-
})
|
|
391
|
+
allowedTools: frontmatter['allowed-tools'] || [],
|
|
392
|
+
});
|
|
380
393
|
|
|
381
|
-
const skill = new Skill(metadata, stripFrontmatter(content))
|
|
382
|
-
skill.install(this._framework)
|
|
394
|
+
const skill = new Skill(metadata, stripFrontmatter(content));
|
|
395
|
+
skill.install(this._framework);
|
|
383
396
|
|
|
384
397
|
// 扫描 references 子目录(按需加载的附加文档)
|
|
385
|
-
const references = this._scanReferences(skillPath)
|
|
398
|
+
const references = this._scanReferences(skillPath);
|
|
386
399
|
|
|
387
400
|
// 扫描 scripts 子目录(可执行脚本)
|
|
388
|
-
const scripts = this._scanScripts(skillPath)
|
|
401
|
+
const scripts = this._scanScripts(skillPath);
|
|
389
402
|
|
|
390
403
|
this._skills.set(name, {
|
|
391
404
|
name,
|
|
@@ -394,12 +407,12 @@ class SkillManagerPlugin extends Plugin {
|
|
|
394
407
|
instance: skill,
|
|
395
408
|
path: skillPath,
|
|
396
409
|
references,
|
|
397
|
-
scripts
|
|
398
|
-
})
|
|
410
|
+
scripts,
|
|
411
|
+
});
|
|
399
412
|
|
|
400
|
-
const refsInfo = references.size > 0 ? `, ${references.size} refs` : ''
|
|
401
|
-
const scriptsInfo = scripts.size > 0 ? `, ${scripts.size} scripts` : ''
|
|
402
|
-
//
|
|
413
|
+
const refsInfo = references.size > 0 ? `, ${references.size} refs` : '';
|
|
414
|
+
const scriptsInfo = scripts.size > 0 ? `, ${scripts.size} scripts` : '';
|
|
415
|
+
//log.info(` Loaded skill: ${name}${refsInfo}${scriptsInfo}`)
|
|
403
416
|
}
|
|
404
417
|
|
|
405
418
|
/**
|
|
@@ -408,30 +421,30 @@ class SkillManagerPlugin extends Plugin {
|
|
|
408
421
|
* @returns {Map} references 文件映射 { filename: { path, content } }
|
|
409
422
|
*/
|
|
410
423
|
_scanReferences(skillPath) {
|
|
411
|
-
const references = new Map()
|
|
412
|
-
const refsDir = path.join(skillPath, 'references')
|
|
424
|
+
const references = new Map();
|
|
425
|
+
const refsDir = path.join(skillPath, 'references');
|
|
413
426
|
|
|
414
427
|
if (!fs.existsSync(refsDir) || !fs.statSync(refsDir).isDirectory()) {
|
|
415
|
-
return references
|
|
428
|
+
return references;
|
|
416
429
|
}
|
|
417
430
|
|
|
418
431
|
try {
|
|
419
|
-
const entries = fs.readdirSync(refsDir, { withFileTypes: true })
|
|
432
|
+
const entries = fs.readdirSync(refsDir, { withFileTypes: true });
|
|
420
433
|
for (const entry of entries) {
|
|
421
434
|
if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
422
|
-
const refPath = path.join(refsDir, entry.name)
|
|
423
|
-
const refName = entry.name.replace('.md', '')
|
|
435
|
+
const refPath = path.join(refsDir, entry.name);
|
|
436
|
+
const refName = entry.name.replace('.md', '');
|
|
424
437
|
references.set(refName, {
|
|
425
438
|
path: refPath,
|
|
426
|
-
content: null
|
|
427
|
-
})
|
|
439
|
+
content: null, // 延迟加载
|
|
440
|
+
});
|
|
428
441
|
}
|
|
429
442
|
}
|
|
430
443
|
} catch (err) {
|
|
431
|
-
|
|
444
|
+
log.warn(` Failed to scan references for ${skillPath}:`, err.message);
|
|
432
445
|
}
|
|
433
446
|
|
|
434
|
-
return references
|
|
447
|
+
return references;
|
|
435
448
|
}
|
|
436
449
|
|
|
437
450
|
/**
|
|
@@ -440,34 +453,35 @@ class SkillManagerPlugin extends Plugin {
|
|
|
440
453
|
* @returns {Map} scripts 映射 { filename: { path, isExecutable } }
|
|
441
454
|
*/
|
|
442
455
|
_scanScripts(skillPath) {
|
|
443
|
-
const scripts = new Map()
|
|
444
|
-
const scriptsDir = path.join(skillPath, 'scripts')
|
|
456
|
+
const scripts = new Map();
|
|
457
|
+
const scriptsDir = path.join(skillPath, 'scripts');
|
|
445
458
|
|
|
446
459
|
if (!fs.existsSync(scriptsDir) || !fs.statSync(scriptsDir).isDirectory()) {
|
|
447
|
-
return scripts
|
|
460
|
+
return scripts;
|
|
448
461
|
}
|
|
449
462
|
|
|
450
463
|
try {
|
|
451
|
-
const entries = fs.readdirSync(scriptsDir, { withFileTypes: true })
|
|
464
|
+
const entries = fs.readdirSync(scriptsDir, { withFileTypes: true });
|
|
452
465
|
for (const entry of entries) {
|
|
453
466
|
if (entry.isFile()) {
|
|
454
|
-
const scriptPath = path.join(scriptsDir, entry.name)
|
|
467
|
+
const scriptPath = path.join(scriptsDir, entry.name);
|
|
455
468
|
// 检查文件是否有执行权限(或检查扩展名)
|
|
456
|
-
const isExecutable =
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
469
|
+
const isExecutable =
|
|
470
|
+
entry.name.endsWith('.sh') ||
|
|
471
|
+
entry.name.endsWith('.js') ||
|
|
472
|
+
entry.name.endsWith('.py') ||
|
|
473
|
+
entry.name.endsWith('.ts');
|
|
460
474
|
scripts.set(entry.name, {
|
|
461
475
|
path: scriptPath,
|
|
462
|
-
isExecutable
|
|
463
|
-
})
|
|
476
|
+
isExecutable,
|
|
477
|
+
});
|
|
464
478
|
}
|
|
465
479
|
}
|
|
466
480
|
} catch (err) {
|
|
467
|
-
|
|
481
|
+
log.warn(` Failed to scan scripts for ${skillPath}:`, err.message);
|
|
468
482
|
}
|
|
469
483
|
|
|
470
|
-
return scripts
|
|
484
|
+
return scripts;
|
|
471
485
|
}
|
|
472
486
|
|
|
473
487
|
/**
|
|
@@ -477,22 +491,22 @@ class SkillManagerPlugin extends Plugin {
|
|
|
477
491
|
* @returns {string|null} 文件内容
|
|
478
492
|
*/
|
|
479
493
|
loadReference(skillName, refName) {
|
|
480
|
-
const skill = this._skills.get(skillName)
|
|
494
|
+
const skill = this._skills.get(skillName);
|
|
481
495
|
if (!skill || !skill.references.has(refName)) {
|
|
482
|
-
return null
|
|
496
|
+
return null;
|
|
483
497
|
}
|
|
484
498
|
|
|
485
|
-
const ref = skill.references.get(refName)
|
|
499
|
+
const ref = skill.references.get(refName);
|
|
486
500
|
if (!ref.content) {
|
|
487
501
|
try {
|
|
488
|
-
ref.content = fs.readFileSync(ref.path, 'utf-8')
|
|
502
|
+
ref.content = fs.readFileSync(ref.path, 'utf-8');
|
|
489
503
|
} catch (err) {
|
|
490
|
-
|
|
491
|
-
return null
|
|
504
|
+
log.error(` Failed to load reference ${skillName}/${refName}:`, err.message);
|
|
505
|
+
return null;
|
|
492
506
|
}
|
|
493
507
|
}
|
|
494
508
|
|
|
495
|
-
return ref.content
|
|
509
|
+
return ref.content;
|
|
496
510
|
}
|
|
497
511
|
|
|
498
512
|
/**
|
|
@@ -501,9 +515,9 @@ class SkillManagerPlugin extends Plugin {
|
|
|
501
515
|
* @returns {string[]} reference 文件名列表
|
|
502
516
|
*/
|
|
503
517
|
listReferences(skillName) {
|
|
504
|
-
const skill = this._skills.get(skillName)
|
|
505
|
-
if (!skill) return []
|
|
506
|
-
return Array.from(skill.references.keys())
|
|
518
|
+
const skill = this._skills.get(skillName);
|
|
519
|
+
if (!skill) return [];
|
|
520
|
+
return Array.from(skill.references.keys());
|
|
507
521
|
}
|
|
508
522
|
|
|
509
523
|
/**
|
|
@@ -512,13 +526,13 @@ class SkillManagerPlugin extends Plugin {
|
|
|
512
526
|
* @returns {Object[]} script 信息列表 [{ name, path, isExecutable }]
|
|
513
527
|
*/
|
|
514
528
|
listScripts(skillName) {
|
|
515
|
-
const skill = this._skills.get(skillName)
|
|
516
|
-
if (!skill) return []
|
|
529
|
+
const skill = this._skills.get(skillName);
|
|
530
|
+
if (!skill) return [];
|
|
517
531
|
return Array.from(skill.scripts.entries()).map(([name, info]) => ({
|
|
518
532
|
name,
|
|
519
533
|
path: info.path,
|
|
520
|
-
isExecutable: info.isExecutable
|
|
521
|
-
}))
|
|
534
|
+
isExecutable: info.isExecutable,
|
|
535
|
+
}));
|
|
522
536
|
}
|
|
523
537
|
|
|
524
538
|
/**
|
|
@@ -528,17 +542,17 @@ class SkillManagerPlugin extends Plugin {
|
|
|
528
542
|
* @returns {string|null}
|
|
529
543
|
*/
|
|
530
544
|
loadScript(skillName, scriptName) {
|
|
531
|
-
const skill = this._skills.get(skillName)
|
|
545
|
+
const skill = this._skills.get(skillName);
|
|
532
546
|
if (!skill || !skill.scripts.has(scriptName)) {
|
|
533
|
-
return null
|
|
547
|
+
return null;
|
|
534
548
|
}
|
|
535
549
|
|
|
536
|
-
const script = skill.scripts.get(scriptName)
|
|
550
|
+
const script = skill.scripts.get(scriptName);
|
|
537
551
|
try {
|
|
538
|
-
return fs.readFileSync(script.path, 'utf-8')
|
|
552
|
+
return fs.readFileSync(script.path, 'utf-8');
|
|
539
553
|
} catch (err) {
|
|
540
|
-
|
|
541
|
-
return null
|
|
554
|
+
log.error(` Failed to load script ${skillName}/${scriptName}:`, err.message);
|
|
555
|
+
return null;
|
|
542
556
|
}
|
|
543
557
|
}
|
|
544
558
|
|
|
@@ -546,42 +560,42 @@ class SkillManagerPlugin extends Plugin {
|
|
|
546
560
|
* 获取所有 skills
|
|
547
561
|
*/
|
|
548
562
|
getAllSkills() {
|
|
549
|
-
return Array.from(this._skills.values())
|
|
563
|
+
return Array.from(this._skills.values());
|
|
550
564
|
}
|
|
551
565
|
|
|
552
566
|
/**
|
|
553
567
|
* 获取 skill
|
|
554
568
|
*/
|
|
555
569
|
getSkill(name) {
|
|
556
|
-
return this._skills.get(name)
|
|
570
|
+
return this._skills.get(name);
|
|
557
571
|
}
|
|
558
572
|
|
|
559
573
|
/**
|
|
560
574
|
* 检查 skill 是否存在
|
|
561
575
|
*/
|
|
562
576
|
hasSkill(name) {
|
|
563
|
-
return this._skills.has(name)
|
|
577
|
+
return this._skills.has(name);
|
|
564
578
|
}
|
|
565
579
|
|
|
566
580
|
/**
|
|
567
581
|
* 获取 skill 数量
|
|
568
582
|
*/
|
|
569
583
|
size() {
|
|
570
|
-
return this._skills.size
|
|
584
|
+
return this._skills.size;
|
|
571
585
|
}
|
|
572
586
|
|
|
573
587
|
reload(framework) {
|
|
574
|
-
|
|
575
|
-
this._skills.clear()
|
|
576
|
-
this._loaded = false
|
|
577
|
-
this._framework = framework
|
|
578
|
-
this._loadAllSkills()
|
|
588
|
+
log.info(' Reloading...');
|
|
589
|
+
this._skills.clear();
|
|
590
|
+
this._loaded = false;
|
|
591
|
+
this._framework = framework;
|
|
592
|
+
this._loadAllSkills();
|
|
579
593
|
}
|
|
580
594
|
|
|
581
595
|
uninstall(framework) {
|
|
582
|
-
this._skills.clear()
|
|
583
|
-
this._framework = null
|
|
584
|
-
this._loaded = false
|
|
596
|
+
this._skills.clear();
|
|
597
|
+
this._framework = null;
|
|
598
|
+
this._loaded = false;
|
|
585
599
|
}
|
|
586
600
|
}
|
|
587
601
|
|
|
@@ -591,5 +605,5 @@ module.exports = {
|
|
|
591
605
|
SkillMetadata,
|
|
592
606
|
isValidSkillName,
|
|
593
607
|
parseFrontmatter,
|
|
594
|
-
stripFrontmatter
|
|
595
|
-
}
|
|
608
|
+
stripFrontmatter,
|
|
609
|
+
};
|