@johpaz/hive-skills 1.0.6 → 1.0.8
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 +2 -3
- package/src/loader.ts +111 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@johpaz/hive-skills",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "Hive Skills — Official bundled skills for Hive",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"license": "MIT",
|
|
@@ -11,8 +11,7 @@
|
|
|
11
11
|
"test": "bun test"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"
|
|
15
|
-
"zod": "latest"
|
|
14
|
+
"js-yaml": "latest"
|
|
16
15
|
},
|
|
17
16
|
"devDependencies": {
|
|
18
17
|
"typescript": "latest",
|
package/src/loader.ts
CHANGED
|
@@ -1,8 +1,35 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import * as yaml from "js-yaml";
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
|
|
5
|
+
export interface SkillsConfig {
|
|
6
|
+
allowBundled?: string[];
|
|
7
|
+
managedDir?: string;
|
|
8
|
+
extraDirs?: string[];
|
|
9
|
+
hotReload?: boolean;
|
|
10
|
+
maxSkillSizeKB?: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface Config {
|
|
14
|
+
skills?: SkillsConfig;
|
|
15
|
+
workspacePath?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface Logger {
|
|
19
|
+
debug: (msg: string, ...args: unknown[]) => void;
|
|
20
|
+
info: (msg: string, ...args: unknown[]) => void;
|
|
21
|
+
warn: (msg: string, ...args: unknown[]) => void;
|
|
22
|
+
error: (msg: string, ...args: unknown[]) => void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function createLogger(): Logger {
|
|
26
|
+
return {
|
|
27
|
+
debug: (msg, ...args) => console.debug(`[skills] ${msg}`, ...args),
|
|
28
|
+
info: (msg, ...args) => console.info(`[skills] ${msg}`, ...args),
|
|
29
|
+
warn: (msg, ...args) => console.warn(`[skills] ${msg}`, ...args),
|
|
30
|
+
error: (msg, ...args) => console.error(`[skills] ${msg}`, ...args),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
6
33
|
|
|
7
34
|
export interface SkillMetadata {
|
|
8
35
|
name: string;
|
|
@@ -30,6 +57,7 @@ export interface Skill {
|
|
|
30
57
|
name: string;
|
|
31
58
|
description: string;
|
|
32
59
|
content: string;
|
|
60
|
+
raw: string;
|
|
33
61
|
metadata: SkillMetadata["metadata"];
|
|
34
62
|
source: "bundled" | "managed" | "workspace";
|
|
35
63
|
path: string;
|
|
@@ -37,7 +65,7 @@ export interface Skill {
|
|
|
37
65
|
|
|
38
66
|
function parseFrontmatter(content: string): { frontmatter: Record<string, unknown>; body: string } {
|
|
39
67
|
const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
40
|
-
|
|
68
|
+
|
|
41
69
|
if (!match) {
|
|
42
70
|
return { frontmatter: {}, body: content };
|
|
43
71
|
}
|
|
@@ -53,11 +81,14 @@ function parseFrontmatter(content: string): { frontmatter: Record<string, unknow
|
|
|
53
81
|
|
|
54
82
|
export class SkillLoader {
|
|
55
83
|
private config: Config;
|
|
56
|
-
private log
|
|
84
|
+
private log: Logger;
|
|
57
85
|
private cache: Map<string, Skill> = new Map();
|
|
86
|
+
private bundledDir: string;
|
|
58
87
|
|
|
59
88
|
constructor(config: Config) {
|
|
60
89
|
this.config = config;
|
|
90
|
+
this.log = createLogger();
|
|
91
|
+
this.bundledDir = path.join(__dirname, "bundled");
|
|
61
92
|
}
|
|
62
93
|
|
|
63
94
|
private expandPath(p: string): string {
|
|
@@ -70,7 +101,7 @@ export class SkillLoader {
|
|
|
70
101
|
loadSkill(skillPath: string, source: Skill["source"]): Skill | null {
|
|
71
102
|
try {
|
|
72
103
|
const skillMdPath = path.join(skillPath, "SKILL.md");
|
|
73
|
-
|
|
104
|
+
|
|
74
105
|
if (!fs.existsSync(skillMdPath)) {
|
|
75
106
|
return null;
|
|
76
107
|
}
|
|
@@ -86,6 +117,7 @@ export class SkillLoader {
|
|
|
86
117
|
name,
|
|
87
118
|
description,
|
|
88
119
|
content: body,
|
|
120
|
+
raw: content,
|
|
89
121
|
metadata,
|
|
90
122
|
source,
|
|
91
123
|
path: skillPath,
|
|
@@ -99,9 +131,41 @@ export class SkillLoader {
|
|
|
99
131
|
}
|
|
100
132
|
}
|
|
101
133
|
|
|
134
|
+
loadBundledSkills(): Skill[] {
|
|
135
|
+
const skills: Map<string, Skill> = new Map();
|
|
136
|
+
|
|
137
|
+
if (!fs.existsSync(this.bundledDir)) {
|
|
138
|
+
this.log.debug(`Bundled skills directory not found: ${this.bundledDir}`);
|
|
139
|
+
return [];
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
for (const entry of fs.readdirSync(this.bundledDir, { withFileTypes: true })) {
|
|
143
|
+
if (entry.isDirectory()) {
|
|
144
|
+
const skill = this.loadSkill(path.join(this.bundledDir, entry.name), "bundled");
|
|
145
|
+
if (skill) {
|
|
146
|
+
skills.set(skill.name, skill);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
this.log.debug(`Loaded ${skills.size} bundled skills`);
|
|
152
|
+
return Array.from(skills.values());
|
|
153
|
+
}
|
|
154
|
+
|
|
102
155
|
loadAllSkills(): Skill[] {
|
|
103
156
|
const skills: Map<string, Skill> = new Map();
|
|
157
|
+
const allowBundled = this.config.skills?.allowBundled;
|
|
158
|
+
|
|
159
|
+
// 1. Load bundled skills (lowest priority)
|
|
160
|
+
const bundledSkills = this.loadBundledSkills();
|
|
161
|
+
for (const skill of bundledSkills) {
|
|
162
|
+
// If allowBundled is undefined, empty, or contains the skill name, include it
|
|
163
|
+
if (!allowBundled || allowBundled.length === 0 || allowBundled.includes(skill.name)) {
|
|
164
|
+
skills.set(skill.name, skill);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
104
167
|
|
|
168
|
+
// 2. Load managed skills (medium priority)
|
|
105
169
|
const managedDir = this.expandPath(this.config.skills?.managedDir ?? "~/.hive/skills");
|
|
106
170
|
if (fs.existsSync(managedDir)) {
|
|
107
171
|
for (const entry of fs.readdirSync(managedDir, { withFileTypes: true })) {
|
|
@@ -114,11 +178,29 @@ export class SkillLoader {
|
|
|
114
178
|
}
|
|
115
179
|
}
|
|
116
180
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
181
|
+
// 3. Load extra directories
|
|
182
|
+
const extraDirs = this.config.skills?.extraDirs ?? [];
|
|
183
|
+
for (const extraDir of extraDirs) {
|
|
184
|
+
const expandedDir = this.expandPath(extraDir);
|
|
185
|
+
if (fs.existsSync(expandedDir)) {
|
|
186
|
+
for (const entry of fs.readdirSync(expandedDir, { withFileTypes: true })) {
|
|
187
|
+
if (entry.isDirectory()) {
|
|
188
|
+
const skill = this.loadSkill(path.join(expandedDir, entry.name), "managed");
|
|
189
|
+
if (skill) {
|
|
190
|
+
skills.set(skill.name, skill);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// 4. Load workspace skills (highest priority)
|
|
198
|
+
const workspacePath = this.config.workspacePath ?? process.cwd();
|
|
199
|
+
const workspaceSkillsDir = path.join(workspacePath, "skills");
|
|
200
|
+
if (fs.existsSync(workspaceSkillsDir)) {
|
|
201
|
+
for (const entry of fs.readdirSync(workspaceSkillsDir, { withFileTypes: true })) {
|
|
120
202
|
if (entry.isDirectory()) {
|
|
121
|
-
const skill = this.loadSkill(path.join(
|
|
203
|
+
const skill = this.loadSkill(path.join(workspaceSkillsDir, entry.name), "workspace");
|
|
122
204
|
if (skill) {
|
|
123
205
|
skills.set(skill.name, skill);
|
|
124
206
|
}
|
|
@@ -126,6 +208,7 @@ export class SkillLoader {
|
|
|
126
208
|
}
|
|
127
209
|
}
|
|
128
210
|
|
|
211
|
+
this.log.info(`Loaded ${skills.size} total skills`);
|
|
129
212
|
return Array.from(skills.values());
|
|
130
213
|
}
|
|
131
214
|
|
|
@@ -133,6 +216,10 @@ export class SkillLoader {
|
|
|
133
216
|
return this.cache.get(name);
|
|
134
217
|
}
|
|
135
218
|
|
|
219
|
+
listSkills(): string[] {
|
|
220
|
+
return Array.from(this.cache.keys());
|
|
221
|
+
}
|
|
222
|
+
|
|
136
223
|
clearCache(): void {
|
|
137
224
|
this.cache.clear();
|
|
138
225
|
}
|
|
@@ -141,3 +228,18 @@ export class SkillLoader {
|
|
|
141
228
|
export function createSkillLoader(config: Config): SkillLoader {
|
|
142
229
|
return new SkillLoader(config);
|
|
143
230
|
}
|
|
231
|
+
|
|
232
|
+
// Export all bundled skill names for convenience
|
|
233
|
+
export const BUNDLED_SKILL_NAMES = [
|
|
234
|
+
"web_search",
|
|
235
|
+
"shell",
|
|
236
|
+
"file_manager",
|
|
237
|
+
"http_client",
|
|
238
|
+
"memory",
|
|
239
|
+
"cron_manager",
|
|
240
|
+
"system_notify",
|
|
241
|
+
"browser_automation",
|
|
242
|
+
"context_compact",
|
|
243
|
+
] as const;
|
|
244
|
+
|
|
245
|
+
export type BundledSkillName = typeof BUNDLED_SKILL_NAMES[number];
|