@johpaz/hive-skills 0.1.1
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 +21 -0
- package/src/bundled/browser_automation/SKILL.md +65 -0
- package/src/bundled/context_compact/SKILL.md +48 -0
- package/src/bundled/cron_manager/SKILL.md +59 -0
- package/src/bundled/file_manager/SKILL.md +47 -0
- package/src/bundled/http_client/SKILL.md +38 -0
- package/src/bundled/memory/SKILL.md +46 -0
- package/src/bundled/shell/SKILL.md +48 -0
- package/src/bundled/system_notify/SKILL.md +49 -0
- package/src/bundled/web_search/SKILL.md +40 -0
- package/src/index.ts +1 -0
- package/src/loader.ts +143 -0
package/package.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@johpaz/hive-skills",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Hive Skills — Official bundled skills for Hive",
|
|
5
|
+
"main": "./src/index.ts",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"files": [
|
|
8
|
+
"src/"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "bun test"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@johpaz/hive-core": "workspace:*",
|
|
15
|
+
"zod": "latest"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"typescript": "latest",
|
|
19
|
+
"@types/bun": "latest"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: browser_automation
|
|
3
|
+
description: "Control a web browser for automation tasks"
|
|
4
|
+
metadata:
|
|
5
|
+
hive:
|
|
6
|
+
emoji: "🌐"
|
|
7
|
+
bins: ["chromium", "chrome"]
|
|
8
|
+
userInvocable: true
|
|
9
|
+
requires:
|
|
10
|
+
config: []
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Browser Automation Skill
|
|
14
|
+
|
|
15
|
+
This skill enables the agent to control a web browser for automation tasks.
|
|
16
|
+
|
|
17
|
+
## Capabilities
|
|
18
|
+
|
|
19
|
+
- Navigate to URLs
|
|
20
|
+
- Click elements
|
|
21
|
+
- Fill forms
|
|
22
|
+
- Extract content
|
|
23
|
+
- Take screenshots
|
|
24
|
+
- Handle multiple tabs
|
|
25
|
+
|
|
26
|
+
## Configuration
|
|
27
|
+
|
|
28
|
+
Enable in CONFIG.yaml:
|
|
29
|
+
|
|
30
|
+
```yaml
|
|
31
|
+
tools:
|
|
32
|
+
browser:
|
|
33
|
+
enabled: true
|
|
34
|
+
headless: true
|
|
35
|
+
timeoutSeconds: 30
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Usage Examples
|
|
39
|
+
|
|
40
|
+
### Navigate and Extract
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
browser_navigate(url: "https://example.com")
|
|
44
|
+
browser_extract(selector: ".content")
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Fill Form
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
browser_fill(selector: "#email", value: "user@example.com")
|
|
51
|
+
browser_click(selector: "#submit")
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Best Practices
|
|
55
|
+
|
|
56
|
+
- Use headless mode for background tasks
|
|
57
|
+
- Set appropriate timeouts
|
|
58
|
+
- Close browser when done
|
|
59
|
+
- Handle dynamic content with waits
|
|
60
|
+
|
|
61
|
+
## Limitations
|
|
62
|
+
|
|
63
|
+
- Requires Chromium/Chrome installed
|
|
64
|
+
- Some sites may block automation
|
|
65
|
+
- Captchas cannot be bypassed
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: context_compact
|
|
3
|
+
description: "Manually trigger context compaction when conversation gets long"
|
|
4
|
+
metadata:
|
|
5
|
+
hive:
|
|
6
|
+
emoji: "📦"
|
|
7
|
+
bins: []
|
|
8
|
+
userInvocable: true
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Context Compact Skill
|
|
12
|
+
|
|
13
|
+
This skill allows manual triggering of context compaction.
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
### Via Slash Command
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
/compact
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### When to Use
|
|
24
|
+
|
|
25
|
+
- When you notice the agent is forgetting earlier context
|
|
26
|
+
- When responses become slower
|
|
27
|
+
- Before starting a new major topic
|
|
28
|
+
|
|
29
|
+
## How It Works
|
|
30
|
+
|
|
31
|
+
1. The agent summarizes the conversation history
|
|
32
|
+
2. Recent messages are preserved
|
|
33
|
+
3. A summary replaces older messages
|
|
34
|
+
4. Important information from memory is retained
|
|
35
|
+
|
|
36
|
+
## What Gets Preserved
|
|
37
|
+
|
|
38
|
+
- Last N messages (configurable)
|
|
39
|
+
- Pending tool calls
|
|
40
|
+
- Important facts saved to memory
|
|
41
|
+
|
|
42
|
+
## Automatic Compaction
|
|
43
|
+
|
|
44
|
+
The system automatically compacts when:
|
|
45
|
+
- Context reaches 80% of model's limit (configurable)
|
|
46
|
+
- Before critical operations
|
|
47
|
+
|
|
48
|
+
Use `/compact` for manual control when needed.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cron_manager
|
|
3
|
+
description: "Schedule and manage automated tasks"
|
|
4
|
+
metadata:
|
|
5
|
+
hive:
|
|
6
|
+
emoji: "⏰"
|
|
7
|
+
bins: []
|
|
8
|
+
userInvocable: true
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Cron Manager Skill
|
|
12
|
+
|
|
13
|
+
This skill enables the agent to schedule and manage automated tasks.
|
|
14
|
+
|
|
15
|
+
## Available Tools
|
|
16
|
+
|
|
17
|
+
- `cron_add`: Add a new scheduled task
|
|
18
|
+
- `cron_list`: List all scheduled tasks
|
|
19
|
+
- `cron_edit`: Edit an existing task
|
|
20
|
+
- `cron_remove`: Remove a scheduled task
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
### Add a Daily Task
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
cron_add(expression: "0 9 * * *", task: "Send daily report")
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### List All Tasks
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
cron_list()
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Remove a Task
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
cron_remove(jobId: "cron-1")
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Cron Expression Format
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
┌───────────── minute (0 - 59)
|
|
46
|
+
│ ┌───────────── hour (0 - 23)
|
|
47
|
+
│ │ ┌───────────── day of month (1 - 31)
|
|
48
|
+
│ │ │ ┌───────────── month (1 - 12)
|
|
49
|
+
│ │ │ │ ┌───────────── day of week (0 - 6) (Sunday = 0)
|
|
50
|
+
│ │ │ │ │
|
|
51
|
+
* * * * *
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Examples
|
|
55
|
+
|
|
56
|
+
- `0 9 * * *` - Every day at 9:00 AM
|
|
57
|
+
- `*/15 * * * *` - Every 15 minutes
|
|
58
|
+
- `0 9 * * 1` - Every Monday at 9:00 AM
|
|
59
|
+
- `0 0 1 * *` - First day of every month at midnight
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: file_manager
|
|
3
|
+
description: "Read, write, and manage files in the workspace"
|
|
4
|
+
metadata:
|
|
5
|
+
hive:
|
|
6
|
+
emoji: "📁"
|
|
7
|
+
bins: []
|
|
8
|
+
userInvocable: true
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# File Manager Skill
|
|
12
|
+
|
|
13
|
+
This skill enables the agent to manage files in the workspace.
|
|
14
|
+
|
|
15
|
+
## Available Tools
|
|
16
|
+
|
|
17
|
+
- `read`: Read file contents
|
|
18
|
+
- `write`: Create or overwrite files
|
|
19
|
+
- `edit`: Make targeted edits to existing files
|
|
20
|
+
- `apply_patch`: Apply diff/patch format changes
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
### Reading Files
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
read(path: "/path/to/file.txt")
|
|
28
|
+
read(path: "/path/to/file.txt", offset: 10, limit: 50)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Writing Files
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
write(path: "/path/to/file.txt", content: "Hello, World!")
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Editing Files
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
edit(path: "/path/to/file.txt", oldString: "old text", newString: "new text")
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Best Practices
|
|
44
|
+
|
|
45
|
+
- Always read a file before editing to understand its structure
|
|
46
|
+
- Use `offset` and `limit` for large files
|
|
47
|
+
- Create backups before major changes
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: http_client
|
|
3
|
+
description: "Make HTTP requests with custom headers and authentication"
|
|
4
|
+
metadata:
|
|
5
|
+
hive:
|
|
6
|
+
emoji: "🌐"
|
|
7
|
+
bins: []
|
|
8
|
+
userInvocable: true
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# HTTP Client Skill
|
|
12
|
+
|
|
13
|
+
This skill enables the agent to make HTTP requests to external APIs and services.
|
|
14
|
+
|
|
15
|
+
## Available Tools
|
|
16
|
+
|
|
17
|
+
- `web_fetch`: Fetch content from URLs
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
### Basic GET Request
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
web_fetch(url: "https://api.example.com/data")
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### With Custom Parameters
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
web_fetch(url: "https://api.example.com/data", maxLength: 5000)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Best Practices
|
|
34
|
+
|
|
35
|
+
- Always handle potential errors
|
|
36
|
+
- Respect rate limits
|
|
37
|
+
- Use appropriate timeouts
|
|
38
|
+
- Validate response data before processing
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: memory
|
|
3
|
+
description: "Store and retrieve persistent notes across sessions"
|
|
4
|
+
metadata:
|
|
5
|
+
hive:
|
|
6
|
+
emoji: "🧠"
|
|
7
|
+
bins: []
|
|
8
|
+
userInvocable: true
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Memory Skill
|
|
12
|
+
|
|
13
|
+
This skill enables the agent to maintain persistent memory across sessions.
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
Use memory to store important information that should persist between conversations.
|
|
18
|
+
|
|
19
|
+
## Available Operations
|
|
20
|
+
|
|
21
|
+
- `memory_write`: Save a note to memory
|
|
22
|
+
- `memory_read`: Retrieve a note from memory
|
|
23
|
+
- `memory_list`: List all saved notes
|
|
24
|
+
|
|
25
|
+
## Examples
|
|
26
|
+
|
|
27
|
+
1. Save a note:
|
|
28
|
+
```
|
|
29
|
+
memory_write(title: "User preferences", content: "Prefers brief responses, TypeScript developer")
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
2. Read a note:
|
|
33
|
+
```
|
|
34
|
+
memory_read(title: "User preferences")
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
3. List all notes:
|
|
38
|
+
```
|
|
39
|
+
memory_list()
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Best Practices
|
|
43
|
+
|
|
44
|
+
- Use descriptive titles for easy retrieval
|
|
45
|
+
- Update notes when information changes
|
|
46
|
+
- Don't store sensitive information in memory
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: shell
|
|
3
|
+
description: "Execute shell commands safely with allowlist control"
|
|
4
|
+
metadata:
|
|
5
|
+
hive:
|
|
6
|
+
emoji: "💻"
|
|
7
|
+
bins: [bash, sh]
|
|
8
|
+
userInvocable: true
|
|
9
|
+
requires:
|
|
10
|
+
config: []
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Shell Skill
|
|
14
|
+
|
|
15
|
+
This skill enables the agent to execute shell commands.
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
Use the `exec` tool to run shell commands. Commands are subject to allowlist/denylist restrictions.
|
|
20
|
+
|
|
21
|
+
## Safety
|
|
22
|
+
|
|
23
|
+
- Only commands in the allowlist can be executed
|
|
24
|
+
- Commands matching denylist patterns are always blocked
|
|
25
|
+
- Commands run with a configurable timeout
|
|
26
|
+
|
|
27
|
+
## Parameters
|
|
28
|
+
|
|
29
|
+
- `command` (required): The command to execute
|
|
30
|
+
- `timeout` (optional): Timeout in seconds (default: 30)
|
|
31
|
+
|
|
32
|
+
## Examples
|
|
33
|
+
|
|
34
|
+
1. List files:
|
|
35
|
+
```
|
|
36
|
+
exec(command: "ls -la")
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
2. Check git status:
|
|
40
|
+
```
|
|
41
|
+
exec(command: "git status")
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Best Practices
|
|
45
|
+
|
|
46
|
+
- Prefer read-only commands when possible
|
|
47
|
+
- Always check command output for errors
|
|
48
|
+
- Use absolute paths for reliability
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: system_notify
|
|
3
|
+
description: "Send system desktop notifications"
|
|
4
|
+
metadata:
|
|
5
|
+
hive:
|
|
6
|
+
emoji: "🔔"
|
|
7
|
+
bins: []
|
|
8
|
+
userInvocable: true
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# System Notify Skill
|
|
12
|
+
|
|
13
|
+
This skill enables the agent to send desktop notifications.
|
|
14
|
+
|
|
15
|
+
## Available Tools
|
|
16
|
+
|
|
17
|
+
- `notify`: Send a system notification
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
### Basic Notification
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
notify(title: "Task Complete", message: "Your file has been processed")
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### With Urgency Level
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
notify(title: "Important", message: "Server is down", urgency: "critical")
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Urgency Levels
|
|
34
|
+
|
|
35
|
+
- `low`: Low priority notification
|
|
36
|
+
- `normal`: Standard notification (default)
|
|
37
|
+
- `critical`: High priority, may stay on screen
|
|
38
|
+
|
|
39
|
+
## Platform Support
|
|
40
|
+
|
|
41
|
+
- **Linux**: Uses `notify-send` (libnotify)
|
|
42
|
+
- **macOS**: Uses AppleScript
|
|
43
|
+
- **Windows**: Not currently supported
|
|
44
|
+
|
|
45
|
+
## Best Practices
|
|
46
|
+
|
|
47
|
+
- Use appropriate urgency levels
|
|
48
|
+
- Keep messages concise
|
|
49
|
+
- Don't send too many notifications
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: web_search
|
|
3
|
+
description: "Search the web for current information using search engines"
|
|
4
|
+
metadata:
|
|
5
|
+
hive:
|
|
6
|
+
emoji: "🔍"
|
|
7
|
+
bins: []
|
|
8
|
+
userInvocable: true
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Web Search Skill
|
|
12
|
+
|
|
13
|
+
This skill enables the agent to search the web for current information.
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
Use the `web_search` tool to search for information on the internet. The search will return relevant results with titles, URLs, and snippets.
|
|
18
|
+
|
|
19
|
+
## Parameters
|
|
20
|
+
|
|
21
|
+
- `query` (required): The search query string
|
|
22
|
+
- `numResults` (optional): Number of results to return (default: 5)
|
|
23
|
+
|
|
24
|
+
## Examples
|
|
25
|
+
|
|
26
|
+
1. Search for recent news:
|
|
27
|
+
```
|
|
28
|
+
web_search(query: "latest AI developments 2024")
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
2. Search for documentation:
|
|
32
|
+
```
|
|
33
|
+
web_search(query: "TypeScript generic constraints examples")
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Best Practices
|
|
37
|
+
|
|
38
|
+
- Be specific with your search queries
|
|
39
|
+
- Use quotes for exact phrases
|
|
40
|
+
- Combine with `web_fetch` to get full content from results
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./loader.ts";
|
package/src/loader.ts
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import * as yaml from "js-yaml";
|
|
4
|
+
import type { Config } from "../config/loader.ts";
|
|
5
|
+
import { logger } from "../utils/logger.ts";
|
|
6
|
+
|
|
7
|
+
export interface SkillMetadata {
|
|
8
|
+
name: string;
|
|
9
|
+
description: string;
|
|
10
|
+
metadata?: {
|
|
11
|
+
hive?: {
|
|
12
|
+
emoji?: string;
|
|
13
|
+
bins?: string[];
|
|
14
|
+
userInvocable?: boolean;
|
|
15
|
+
requires?: {
|
|
16
|
+
config?: string[];
|
|
17
|
+
env?: string[];
|
|
18
|
+
};
|
|
19
|
+
install?: {
|
|
20
|
+
brew?: string;
|
|
21
|
+
apt?: string;
|
|
22
|
+
npm?: string;
|
|
23
|
+
};
|
|
24
|
+
os?: string[];
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface Skill {
|
|
30
|
+
name: string;
|
|
31
|
+
description: string;
|
|
32
|
+
content: string;
|
|
33
|
+
metadata: SkillMetadata["metadata"];
|
|
34
|
+
source: "bundled" | "managed" | "workspace";
|
|
35
|
+
path: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function parseFrontmatter(content: string): { frontmatter: Record<string, unknown>; body: string } {
|
|
39
|
+
const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
40
|
+
|
|
41
|
+
if (!match) {
|
|
42
|
+
return { frontmatter: {}, body: content };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
const frontmatter = yaml.load(match[1]!) as Record<string, unknown>;
|
|
47
|
+
const body = match[2]!;
|
|
48
|
+
return { frontmatter, body };
|
|
49
|
+
} catch {
|
|
50
|
+
return { frontmatter: {}, body: content };
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export class SkillLoader {
|
|
55
|
+
private config: Config;
|
|
56
|
+
private log = logger.child("skills");
|
|
57
|
+
private cache: Map<string, Skill> = new Map();
|
|
58
|
+
|
|
59
|
+
constructor(config: Config) {
|
|
60
|
+
this.config = config;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
private expandPath(p: string): string {
|
|
64
|
+
if (p.startsWith("~")) {
|
|
65
|
+
return path.join(process.env.HOME ?? "", p.slice(1));
|
|
66
|
+
}
|
|
67
|
+
return p;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
loadSkill(skillPath: string, source: Skill["source"]): Skill | null {
|
|
71
|
+
try {
|
|
72
|
+
const skillMdPath = path.join(skillPath, "SKILL.md");
|
|
73
|
+
|
|
74
|
+
if (!fs.existsSync(skillMdPath)) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const content = fs.readFileSync(skillMdPath, "utf-8");
|
|
79
|
+
const { frontmatter, body } = parseFrontmatter(content);
|
|
80
|
+
|
|
81
|
+
const metadata = frontmatter.metadata as SkillMetadata["metadata"];
|
|
82
|
+
const name = (frontmatter.name as string) ?? path.basename(skillPath);
|
|
83
|
+
const description = (frontmatter.description as string) ?? "";
|
|
84
|
+
|
|
85
|
+
const skill: Skill = {
|
|
86
|
+
name,
|
|
87
|
+
description,
|
|
88
|
+
content: body,
|
|
89
|
+
metadata,
|
|
90
|
+
source,
|
|
91
|
+
path: skillPath,
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
this.cache.set(name, skill);
|
|
95
|
+
return skill;
|
|
96
|
+
} catch (error) {
|
|
97
|
+
this.log.error(`Failed to load skill: ${skillPath}`, { error: (error as Error).message });
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
loadAllSkills(): Skill[] {
|
|
103
|
+
const skills: Map<string, Skill> = new Map();
|
|
104
|
+
|
|
105
|
+
const managedDir = this.expandPath(this.config.skills?.managedDir ?? "~/.hive/skills");
|
|
106
|
+
if (fs.existsSync(managedDir)) {
|
|
107
|
+
for (const entry of fs.readdirSync(managedDir, { withFileTypes: true })) {
|
|
108
|
+
if (entry.isDirectory()) {
|
|
109
|
+
const skill = this.loadSkill(path.join(managedDir, entry.name), "managed");
|
|
110
|
+
if (skill) {
|
|
111
|
+
skills.set(skill.name, skill);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const workspaceDir = "workspace/skills";
|
|
118
|
+
if (fs.existsSync(workspaceDir)) {
|
|
119
|
+
for (const entry of fs.readdirSync(workspaceDir, { withFileTypes: true })) {
|
|
120
|
+
if (entry.isDirectory()) {
|
|
121
|
+
const skill = this.loadSkill(path.join(workspaceDir, entry.name), "workspace");
|
|
122
|
+
if (skill) {
|
|
123
|
+
skills.set(skill.name, skill);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return Array.from(skills.values());
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
getSkill(name: string): Skill | undefined {
|
|
133
|
+
return this.cache.get(name);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
clearCache(): void {
|
|
137
|
+
this.cache.clear();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export function createSkillLoader(config: Config): SkillLoader {
|
|
142
|
+
return new SkillLoader(config);
|
|
143
|
+
}
|