@framers/agentos-skills 0.2.0 → 0.3.0
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/README.md +64 -94
- package/dist/SkillLoader.d.ts +50 -0
- package/dist/SkillLoader.d.ts.map +1 -0
- package/dist/SkillLoader.js +291 -0
- package/dist/SkillLoader.js.map +1 -0
- package/dist/SkillRegistry.d.ts +135 -0
- package/dist/SkillRegistry.d.ts.map +1 -0
- package/dist/SkillRegistry.js +455 -0
- package/dist/SkillRegistry.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/paths.d.ts +35 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +71 -0
- package/dist/paths.js.map +1 -0
- package/dist/types.d.ts +231 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +21 -0
- package/dist/types.js.map +1 -0
- package/package.json +31 -13
- package/registry/community/.gitkeep +0 -0
- package/registry/curated/1password/SKILL.md +0 -53
- package/registry/curated/apple-notes/SKILL.md +0 -45
- package/registry/curated/apple-reminders/SKILL.md +0 -46
- package/registry/curated/coding-agent/SKILL.md +0 -40
- package/registry/curated/discord-helper/SKILL.md +0 -43
- package/registry/curated/git/SKILL.md +0 -39
- package/registry/curated/github/SKILL.md +0 -54
- package/registry/curated/healthcheck/SKILL.md +0 -43
- package/registry/curated/image-gen/SKILL.md +0 -44
- package/registry/curated/notion/SKILL.md +0 -43
- package/registry/curated/obsidian/SKILL.md +0 -42
- package/registry/curated/slack-helper/SKILL.md +0 -42
- package/registry/curated/spotify-player/SKILL.md +0 -44
- package/registry/curated/summarize/SKILL.md +0 -40
- package/registry/curated/trello/SKILL.md +0 -43
- package/registry/curated/weather/SKILL.md +0 -37
- package/registry/curated/whisper-transcribe/SKILL.md +0 -58
- package/registry.json +0 -363
- package/types.d.ts +0 -77
package/README.md
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://agentos.sh"><img src="logos/agentos-primary-no-tagline-transparent-2x.png" alt="AgentOS" height="56" /></a>
|
|
3
|
+
|
|
4
|
+
<a href="https://frame.dev"><img src="logos/frame-logo-green-no-tagline.svg" alt="Frame.dev" height="36" /></a>
|
|
5
|
+
</p>
|
|
6
|
+
|
|
1
7
|
# @framers/agentos-skills
|
|
2
8
|
|
|
3
|
-
|
|
9
|
+
Skills runtime for the [AgentOS](https://github.com/framersai/agentos) ecosystem -- loads, parses, and manages SKILL.md prompt modules.
|
|
4
10
|
|
|
5
11
|
[](https://www.npmjs.com/package/@framers/agentos-skills)
|
|
6
12
|
|
|
@@ -10,117 +16,81 @@ npm install @framers/agentos-skills
|
|
|
10
16
|
|
|
11
17
|
## What's Inside
|
|
12
18
|
|
|
13
|
-
This package is
|
|
19
|
+
This package is the **runtime** for the AgentOS skills system. It provides:
|
|
14
20
|
|
|
15
|
-
|
|
|
16
|
-
|
|
|
17
|
-
| `
|
|
18
|
-
| `
|
|
19
|
-
| `
|
|
21
|
+
| Module | Description |
|
|
22
|
+
| ------------------- | ------------------------------------------------------------------------ |
|
|
23
|
+
| `SkillLoader` | Loads and parses SKILL.md files with YAML frontmatter |
|
|
24
|
+
| `SkillRegistry` | Runtime registry for managing, querying, and filtering loaded skills |
|
|
25
|
+
| `paths` | Path resolution utilities for discovering default skill directories |
|
|
26
|
+
| `types` | Full TypeScript type definitions for skills, metadata, and configuration |
|
|
20
27
|
|
|
21
|
-
|
|
28
|
+
## Usage
|
|
22
29
|
|
|
23
|
-
|
|
30
|
+
```typescript
|
|
31
|
+
import {
|
|
32
|
+
SkillRegistry,
|
|
33
|
+
loadSkillFromDir,
|
|
34
|
+
loadSkillsFromDir,
|
|
35
|
+
resolveDefaultSkillsDirs,
|
|
36
|
+
} from '@framers/agentos-skills';
|
|
24
37
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
| **Information** | weather, summarize |
|
|
28
|
-
| **Developer Tools** | github, coding-agent |
|
|
29
|
-
| **Communication** | slack-helper, discord-helper |
|
|
30
|
-
| **Productivity** | notion, obsidian, trello, apple-notes, apple-reminders |
|
|
31
|
-
| **DevOps** | healthcheck |
|
|
32
|
-
| **Media** | spotify-player, whisper-transcribe |
|
|
33
|
-
| **Security** | 1password |
|
|
34
|
-
| **Creative** | image-gen |
|
|
38
|
+
// Discover default skill directories
|
|
39
|
+
const dirs = resolveDefaultSkillsDirs();
|
|
35
40
|
|
|
36
|
-
|
|
41
|
+
// Create a registry and load skills
|
|
42
|
+
const registry = new SkillRegistry();
|
|
43
|
+
await registry.loadFromDirs(dirs);
|
|
37
44
|
|
|
38
|
-
|
|
45
|
+
console.log(`Loaded ${registry.size} skills`);
|
|
39
46
|
|
|
40
|
-
|
|
41
|
-
|
|
47
|
+
// Build a snapshot for LLM context
|
|
48
|
+
const snapshot = registry.buildSnapshot({ platform: 'darwin', strict: true });
|
|
49
|
+
console.log(snapshot.prompt);
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Relationship to Other Packages
|
|
42
53
|
|
|
43
|
-
|
|
44
|
-
|
|
54
|
+
```
|
|
55
|
+
@framers/agentos-skills <-- You are here (runtime: SkillLoader, SkillRegistry, types)
|
|
56
|
+
@framers/agentos-skills-registry (catalog: 40+ curated SKILL.md files + JSON index)
|
|
57
|
+
@framers/agentos (full cognitive runtime, re-exports skills from here)
|
|
45
58
|
```
|
|
46
59
|
|
|
47
|
-
|
|
60
|
+
| Package | What | Runtime Code | Dependencies |
|
|
61
|
+
| ------------------------------------ | ----------------------------------------- | :----------: | --------------- |
|
|
62
|
+
| **@framers/agentos-skills** | SkillLoader, SkillRegistry, path utils | Yes | `yaml` |
|
|
63
|
+
| **@framers/agentos-skills-registry** | 40+ SKILL.md files + JSON index + catalog | No | `yaml` |
|
|
64
|
+
| **@framers/agentos** | Full cognitive runtime | Yes | Many |
|
|
48
65
|
|
|
49
|
-
|
|
66
|
+
## API
|
|
50
67
|
|
|
51
|
-
|
|
52
|
-
npm install @framers/agentos-skills-registry
|
|
53
|
-
```
|
|
68
|
+
### SkillLoader
|
|
54
69
|
|
|
55
|
-
|
|
56
|
-
|
|
70
|
+
- `parseSkillFrontmatter(content)` -- Parse YAML frontmatter from SKILL.md content
|
|
71
|
+
- `extractMetadata(frontmatter)` -- Extract typed SkillMetadata from parsed frontmatter
|
|
72
|
+
- `loadSkillFromDir(dir)` -- Load a single skill from a directory containing SKILL.md
|
|
73
|
+
- `loadSkillsFromDir(dir)` -- Load all skills from a parent directory
|
|
74
|
+
- `filterByPlatform(entries, platform)` -- Filter skill entries by OS platform
|
|
75
|
+
- `filterByEligibility(entries, context)` -- Filter by full eligibility context
|
|
76
|
+
- `checkBinaryRequirements(entry, hasBin)` -- Check if binary requirements are met
|
|
57
77
|
|
|
58
|
-
|
|
59
|
-
const matches = searchSkills('github');
|
|
60
|
-
```
|
|
78
|
+
### SkillRegistry
|
|
61
79
|
|
|
62
|
-
|
|
80
|
+
- `register(entry)` / `unregister(name)` -- Add/remove skills
|
|
81
|
+
- `loadFromDir(dir)` / `loadFromDirs(dirs)` / `reload(options)` -- Bulk loading
|
|
82
|
+
- `getByName(name)` / `listAll()` / `has(name)` / `size` -- Queries
|
|
83
|
+
- `filterByPlatform(platform)` / `filterByEligibility(context)` -- Filtering
|
|
84
|
+
- `getUserInvocableSkills()` / `getModelInvocableSkills()` -- Invocation filtering
|
|
85
|
+
- `buildSnapshot(options)` -- Build LLM context snapshot
|
|
86
|
+
- `buildPrompt(entries)` -- Format skills into prompt text
|
|
87
|
+
- `buildCommandSpecs(options)` -- Generate CLI command specs
|
|
63
88
|
|
|
64
|
-
|
|
65
|
-
@framers/agentos-skills ← You are here (data: SKILL.md files + JSON index)
|
|
66
|
-
└── @framers/agentos-skills-registry (SDK: typed catalog, query helpers, registry factories)
|
|
67
|
-
└── @framers/agentos (optional peer: live SkillRegistry + snapshots)
|
|
68
|
-
```
|
|
89
|
+
### Path Utilities
|
|
69
90
|
|
|
70
|
-
|
|
71
|
-
| ------------------------------------ | ----------------------------------------- | :----------: | -------------------------------------- |
|
|
72
|
-
| **@framers/agentos-skills** | Raw SKILL.md files + JSON index | No | Zero |
|
|
73
|
-
| **@framers/agentos-skills-registry** | Typed catalog + query helpers + factories | Yes | `agentos-skills`, optionally `agentos` |
|
|
74
|
-
| **@framers/agentos** | Full cognitive runtime with SkillRegistry | Yes | Many |
|
|
75
|
-
|
|
76
|
-
## Contributing a Skill
|
|
77
|
-
|
|
78
|
-
1. **Fork** the [agentos-skills](https://github.com/framersai/agentos-skills) repository.
|
|
79
|
-
2. **Create** a `SKILL.md` file in `registry/community/<your-skill>/`.
|
|
80
|
-
3. **Open a PR** against `main`.
|
|
81
|
-
|
|
82
|
-
See [`CONTRIBUTING.md`](https://github.com/framersai/agentos-skills/blob/main/CONTRIBUTING.md) for the full SKILL.md format spec and submission process.
|
|
83
|
-
|
|
84
|
-
## Community vs Curated
|
|
85
|
-
|
|
86
|
-
Skills ship in two tiers, all bundled in this single package:
|
|
87
|
-
|
|
88
|
-
| Tier | Namespace | Maintained By | Verified |
|
|
89
|
-
| ------------- | ------------ | ------------- | :------: |
|
|
90
|
-
| **Curated** | `wunderland` | Core staff | Yes |
|
|
91
|
-
| **Community** | `community` | PR contributors | No |
|
|
92
|
-
|
|
93
|
-
Curated skills live in `registry/curated/` and are maintained and tested by the AgentOS team. Community skills live in `registry/community/` and are submitted via pull request from the community.
|
|
94
|
-
|
|
95
|
-
## Skill Format Quick Reference
|
|
96
|
-
|
|
97
|
-
```yaml
|
|
98
|
-
---
|
|
99
|
-
name: my-skill
|
|
100
|
-
description: Short description of what this skill does
|
|
101
|
-
namespace: community # or 'wunderland' for curated
|
|
102
|
-
category: productivity # information | developer-tools | communication | productivity | devops | media | security | creative
|
|
103
|
-
tags: [example, template]
|
|
104
|
-
metadata:
|
|
105
|
-
openclaw:
|
|
106
|
-
emoji: "\U0001F4A1"
|
|
107
|
-
primaryEnv: MY_API_KEY # optional
|
|
108
|
-
os: [darwin, linux] # optional platform restriction
|
|
109
|
-
requires:
|
|
110
|
-
bins: [my-tool] # all must exist
|
|
111
|
-
install:
|
|
112
|
-
- id: brew
|
|
113
|
-
kind: brew
|
|
114
|
-
formula: my-tool
|
|
115
|
-
bins: [my-tool]
|
|
116
|
-
label: "Install via Homebrew"
|
|
117
|
-
---
|
|
118
|
-
|
|
119
|
-
# My Skill
|
|
120
|
-
|
|
121
|
-
Instructions injected into the agent's system prompt go here.
|
|
122
|
-
```
|
|
91
|
+
- `resolveDefaultSkillsDirs(options)` -- Resolve default skill directories to scan
|
|
123
92
|
|
|
124
93
|
## License
|
|
125
94
|
|
|
126
95
|
MIT
|
|
96
|
+
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Skill Loader for AgentOS
|
|
3
|
+
* @module @framers/agentos-skills/SkillLoader
|
|
4
|
+
*
|
|
5
|
+
* Loads skills from directories by parsing SKILL.md files with YAML frontmatter.
|
|
6
|
+
* Skills are modular capabilities that extend agent functionality.
|
|
7
|
+
*/
|
|
8
|
+
import type { SkillEntry, SkillMetadata, SkillEligibilityContext, ParsedSkillFrontmatter } from './types.js';
|
|
9
|
+
/**
|
|
10
|
+
* Parse YAML frontmatter from SKILL.md content.
|
|
11
|
+
* Supports the standard `---` delimited format.
|
|
12
|
+
*/
|
|
13
|
+
export declare function parseSkillFrontmatter(content: string): {
|
|
14
|
+
frontmatter: ParsedSkillFrontmatter;
|
|
15
|
+
body: string;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Extract SkillMetadata from parsed frontmatter.
|
|
19
|
+
*/
|
|
20
|
+
export declare function extractMetadata(frontmatter: ParsedSkillFrontmatter): SkillMetadata | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* Load a single skill from a directory.
|
|
23
|
+
*
|
|
24
|
+
* @param skillDir - Path to skill directory (should contain SKILL.md)
|
|
25
|
+
* @returns SkillEntry or null if invalid
|
|
26
|
+
*/
|
|
27
|
+
export declare function loadSkillFromDir(skillDir: string): Promise<SkillEntry | null>;
|
|
28
|
+
/**
|
|
29
|
+
* Load all skills from a directory.
|
|
30
|
+
*
|
|
31
|
+
* @param dir - Parent directory containing skill subdirectories
|
|
32
|
+
* @returns Array of SkillEntry objects
|
|
33
|
+
*/
|
|
34
|
+
export declare function loadSkillsFromDir(dir: string): Promise<SkillEntry[]>;
|
|
35
|
+
/**
|
|
36
|
+
* Filter skill entries by platform.
|
|
37
|
+
*/
|
|
38
|
+
export declare function filterByPlatform(entries: SkillEntry[], platform: string): SkillEntry[];
|
|
39
|
+
/**
|
|
40
|
+
* Filter skill entries by eligibility context.
|
|
41
|
+
*/
|
|
42
|
+
export declare function filterByEligibility(entries: SkillEntry[], context: SkillEligibilityContext): SkillEntry[];
|
|
43
|
+
/**
|
|
44
|
+
* Check if all binary requirements for a skill are met.
|
|
45
|
+
*/
|
|
46
|
+
export declare function checkBinaryRequirements(entry: SkillEntry, hasBin: (bin: string) => boolean): {
|
|
47
|
+
met: boolean;
|
|
48
|
+
missing: string[];
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=SkillLoader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SkillLoader.d.ts","sourceRoot":"","sources":["../src/SkillLoader.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,KAAK,EAEV,UAAU,EACV,aAAa,EACb,uBAAuB,EACvB,sBAAsB,EAEvB,MAAM,YAAY,CAAC;AAQpB;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG;IACtD,WAAW,EAAE,sBAAsB,CAAC;IACpC,IAAI,EAAE,MAAM,CAAC;CACd,CAkCA;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,sBAAsB,GAAG,aAAa,GAAG,SAAS,CAoC9F;AAiED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAyCnF;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAuB1E;AAMD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,EAAE,CAStF;AAaD;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,UAAU,EAAE,EACrB,OAAO,EAAE,uBAAuB,GAC/B,UAAU,EAAE,CA+Bd;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,GAC/B;IAAE,GAAG,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAgBrC"}
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Skill Loader for AgentOS
|
|
3
|
+
* @module @framers/agentos-skills/SkillLoader
|
|
4
|
+
*
|
|
5
|
+
* Loads skills from directories by parsing SKILL.md files with YAML frontmatter.
|
|
6
|
+
* Skills are modular capabilities that extend agent functionality.
|
|
7
|
+
*/
|
|
8
|
+
import * as fs from 'fs';
|
|
9
|
+
import * as path from 'path';
|
|
10
|
+
import YAML from 'yaml';
|
|
11
|
+
const fsp = fs.promises;
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// FRONTMATTER PARSING
|
|
14
|
+
// ============================================================================
|
|
15
|
+
/**
|
|
16
|
+
* Parse YAML frontmatter from SKILL.md content.
|
|
17
|
+
* Supports the standard `---` delimited format.
|
|
18
|
+
*/
|
|
19
|
+
export function parseSkillFrontmatter(content) {
|
|
20
|
+
const normalized = content.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
|
21
|
+
const lines = normalized.split('\n');
|
|
22
|
+
// Check for frontmatter start
|
|
23
|
+
if (lines[0]?.trim() !== '---') {
|
|
24
|
+
return { frontmatter: {}, body: normalized.trim() };
|
|
25
|
+
}
|
|
26
|
+
// Find frontmatter end
|
|
27
|
+
let endIndex = -1;
|
|
28
|
+
for (let i = 1; i < lines.length; i++) {
|
|
29
|
+
if (lines[i]?.trim() === '---') {
|
|
30
|
+
endIndex = i;
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (endIndex === -1) {
|
|
35
|
+
return { frontmatter: {}, body: normalized.trim() };
|
|
36
|
+
}
|
|
37
|
+
const frontmatterBlock = lines.slice(1, endIndex).join('\n');
|
|
38
|
+
const body = lines.slice(endIndex + 1).join('\n').trim();
|
|
39
|
+
try {
|
|
40
|
+
const parsed = YAML.parse(frontmatterBlock);
|
|
41
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
42
|
+
return { frontmatter: {}, body };
|
|
43
|
+
}
|
|
44
|
+
return { frontmatter: parsed, body };
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return { frontmatter: {}, body };
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Extract SkillMetadata from parsed frontmatter.
|
|
52
|
+
*/
|
|
53
|
+
export function extractMetadata(frontmatter) {
|
|
54
|
+
const metadataValue = frontmatter.metadata;
|
|
55
|
+
let meta = undefined;
|
|
56
|
+
if (metadataValue && typeof metadataValue === 'object') {
|
|
57
|
+
const mObj = metadataValue;
|
|
58
|
+
meta = mObj.openclaw ?? mObj.wunderland ?? mObj.agentos ?? mObj;
|
|
59
|
+
}
|
|
60
|
+
else if (typeof metadataValue === 'string' && metadataValue.trim()) {
|
|
61
|
+
// Support OpenClaw-style metadata serialization (JSON-ish string in YAML).
|
|
62
|
+
try {
|
|
63
|
+
meta = JSON.parse(metadataValue);
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
meta = undefined;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (!meta) {
|
|
70
|
+
meta = frontmatter;
|
|
71
|
+
}
|
|
72
|
+
if (!meta || typeof meta !== 'object') {
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
const m = meta;
|
|
76
|
+
return {
|
|
77
|
+
always: m.always === true,
|
|
78
|
+
skillKey: typeof m.skillKey === 'string' ? m.skillKey : undefined,
|
|
79
|
+
primaryEnv: typeof m.primaryEnv === 'string' ? m.primaryEnv : undefined,
|
|
80
|
+
emoji: typeof m.emoji === 'string' ? m.emoji : undefined,
|
|
81
|
+
homepage: typeof m.homepage === 'string' ? m.homepage : undefined,
|
|
82
|
+
os: Array.isArray(m.os) ? m.os : undefined,
|
|
83
|
+
requires: m.requires,
|
|
84
|
+
install: Array.isArray(m.install) ? m.install : undefined,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Extract skill description from body content.
|
|
89
|
+
*/
|
|
90
|
+
function extractDescription(body) {
|
|
91
|
+
// Skip markdown title and get first paragraph
|
|
92
|
+
const lines = body.split('\n');
|
|
93
|
+
let inParagraph = false;
|
|
94
|
+
const paragraphLines = [];
|
|
95
|
+
for (const line of lines) {
|
|
96
|
+
const trimmed = line.trim();
|
|
97
|
+
// Skip headings
|
|
98
|
+
if (trimmed.startsWith('#')) {
|
|
99
|
+
if (inParagraph)
|
|
100
|
+
break;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
// Skip empty lines before paragraph
|
|
104
|
+
if (!trimmed && !inParagraph) {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
// Empty line ends paragraph
|
|
108
|
+
if (!trimmed && inParagraph) {
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
inParagraph = true;
|
|
112
|
+
paragraphLines.push(trimmed);
|
|
113
|
+
}
|
|
114
|
+
return paragraphLines.join(' ').slice(0, 200);
|
|
115
|
+
}
|
|
116
|
+
function coerceBoolean(value) {
|
|
117
|
+
if (typeof value === 'boolean')
|
|
118
|
+
return value;
|
|
119
|
+
if (typeof value === 'string') {
|
|
120
|
+
const lowered = value.trim().toLowerCase();
|
|
121
|
+
if (lowered === 'true')
|
|
122
|
+
return true;
|
|
123
|
+
if (lowered === 'false')
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
128
|
+
function resolveSkillInvocationPolicy(frontmatter) {
|
|
129
|
+
const userInvocable = coerceBoolean(frontmatter['user-invocable']) ??
|
|
130
|
+
coerceBoolean(frontmatter.userInvocable) ??
|
|
131
|
+
true;
|
|
132
|
+
const disableModelInvocation = coerceBoolean(frontmatter['disable-model-invocation']) ??
|
|
133
|
+
coerceBoolean(frontmatter.disableModelInvocation) ??
|
|
134
|
+
false;
|
|
135
|
+
return { userInvocable, disableModelInvocation };
|
|
136
|
+
}
|
|
137
|
+
// ============================================================================
|
|
138
|
+
// SKILL LOADING
|
|
139
|
+
// ============================================================================
|
|
140
|
+
/**
|
|
141
|
+
* Load a single skill from a directory.
|
|
142
|
+
*
|
|
143
|
+
* @param skillDir - Path to skill directory (should contain SKILL.md)
|
|
144
|
+
* @returns SkillEntry or null if invalid
|
|
145
|
+
*/
|
|
146
|
+
export async function loadSkillFromDir(skillDir) {
|
|
147
|
+
const skillPath = path.join(skillDir, 'SKILL.md');
|
|
148
|
+
try {
|
|
149
|
+
const stat = await fsp.stat(skillPath);
|
|
150
|
+
if (!stat.isFile()) {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
const content = await fsp.readFile(skillPath, 'utf-8');
|
|
154
|
+
const { frontmatter, body } = parseSkillFrontmatter(content);
|
|
155
|
+
const name = (typeof frontmatter.name === 'string' && frontmatter.name.trim())
|
|
156
|
+
? frontmatter.name.trim()
|
|
157
|
+
: path.basename(skillDir);
|
|
158
|
+
const description = (typeof frontmatter.description === 'string' && frontmatter.description.trim())
|
|
159
|
+
? frontmatter.description.trim()
|
|
160
|
+
: extractDescription(body);
|
|
161
|
+
const skill = {
|
|
162
|
+
name,
|
|
163
|
+
description,
|
|
164
|
+
content: body,
|
|
165
|
+
};
|
|
166
|
+
const metadata = extractMetadata(frontmatter);
|
|
167
|
+
const invocation = resolveSkillInvocationPolicy(frontmatter);
|
|
168
|
+
return {
|
|
169
|
+
skill,
|
|
170
|
+
frontmatter,
|
|
171
|
+
metadata,
|
|
172
|
+
invocation,
|
|
173
|
+
sourcePath: skillDir,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
// Skill doesn't exist or is invalid
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Load all skills from a directory.
|
|
183
|
+
*
|
|
184
|
+
* @param dir - Parent directory containing skill subdirectories
|
|
185
|
+
* @returns Array of SkillEntry objects
|
|
186
|
+
*/
|
|
187
|
+
export async function loadSkillsFromDir(dir) {
|
|
188
|
+
const entries = [];
|
|
189
|
+
try {
|
|
190
|
+
const items = await fsp.readdir(dir, { withFileTypes: true });
|
|
191
|
+
for (const item of items) {
|
|
192
|
+
if (!item.isDirectory())
|
|
193
|
+
continue;
|
|
194
|
+
if (item.name.startsWith('.'))
|
|
195
|
+
continue;
|
|
196
|
+
const skillDir = path.join(dir, item.name);
|
|
197
|
+
const entry = await loadSkillFromDir(skillDir);
|
|
198
|
+
if (entry) {
|
|
199
|
+
entries.push(entry);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
catch (err) {
|
|
204
|
+
// Directory doesn't exist or is inaccessible
|
|
205
|
+
console.warn(`[SkillLoader] Failed to load skills from ${dir}:`, err);
|
|
206
|
+
}
|
|
207
|
+
return entries;
|
|
208
|
+
}
|
|
209
|
+
// ============================================================================
|
|
210
|
+
// FILTERING
|
|
211
|
+
// ============================================================================
|
|
212
|
+
/**
|
|
213
|
+
* Filter skill entries by platform.
|
|
214
|
+
*/
|
|
215
|
+
export function filterByPlatform(entries, platform) {
|
|
216
|
+
return entries.filter((entry) => {
|
|
217
|
+
const os = entry.metadata?.os;
|
|
218
|
+
if (!os || os.length === 0)
|
|
219
|
+
return true;
|
|
220
|
+
// Normalize platform names
|
|
221
|
+
const normalizedPlatform = normalizeOSName(platform);
|
|
222
|
+
return os.some((p) => normalizeOSName(p) === normalizedPlatform);
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Normalize OS name for comparison.
|
|
227
|
+
*/
|
|
228
|
+
function normalizeOSName(name) {
|
|
229
|
+
const lower = name.toLowerCase();
|
|
230
|
+
if (lower === 'darwin' || lower === 'macos' || lower === 'mac')
|
|
231
|
+
return 'darwin';
|
|
232
|
+
if (lower === 'win32' || lower === 'windows')
|
|
233
|
+
return 'win32';
|
|
234
|
+
if (lower === 'linux')
|
|
235
|
+
return 'linux';
|
|
236
|
+
return lower;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Filter skill entries by eligibility context.
|
|
240
|
+
*/
|
|
241
|
+
export function filterByEligibility(entries, context) {
|
|
242
|
+
return entries.filter((entry) => {
|
|
243
|
+
const requires = entry.metadata?.requires;
|
|
244
|
+
if (!requires)
|
|
245
|
+
return true;
|
|
246
|
+
// Check required binaries
|
|
247
|
+
if (requires.bins && requires.bins.length > 0) {
|
|
248
|
+
const allBins = requires.bins.every((bin) => context.hasBin(bin));
|
|
249
|
+
if (!allBins)
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
// Check any-of binaries
|
|
253
|
+
if (requires.anyBins && requires.anyBins.length > 0) {
|
|
254
|
+
const anyBin = context.hasAnyBin(requires.anyBins);
|
|
255
|
+
if (!anyBin)
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
// Check environment variables
|
|
259
|
+
if (requires.env && requires.env.length > 0 && context.hasEnv) {
|
|
260
|
+
const allEnv = requires.env.every((env) => context.hasEnv(env));
|
|
261
|
+
if (!allEnv)
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
// Platform check
|
|
265
|
+
for (const platform of context.platforms) {
|
|
266
|
+
const filtered = filterByPlatform([entry], platform);
|
|
267
|
+
if (filtered.length === 0)
|
|
268
|
+
return false;
|
|
269
|
+
}
|
|
270
|
+
return true;
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Check if all binary requirements for a skill are met.
|
|
275
|
+
*/
|
|
276
|
+
export function checkBinaryRequirements(entry, hasBin) {
|
|
277
|
+
const requires = entry.metadata?.requires;
|
|
278
|
+
const missing = [];
|
|
279
|
+
if (requires?.bins) {
|
|
280
|
+
for (const bin of requires.bins) {
|
|
281
|
+
if (!hasBin(bin)) {
|
|
282
|
+
missing.push(bin);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return {
|
|
287
|
+
met: missing.length === 0,
|
|
288
|
+
missing,
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
//# sourceMappingURL=SkillLoader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SkillLoader.js","sourceRoot":"","sources":["../src/SkillLoader.ts"],"names":[],"mappings":"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"}
|