@framers/agentos-skills 0.3.0 → 0.4.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.
Files changed (100) hide show
  1. package/CONTRIBUTING.md +231 -0
  2. package/README.md +93 -58
  3. package/package.json +19 -31
  4. package/registry/community/.gitkeep +0 -0
  5. package/registry/curated/1password/SKILL.md +53 -0
  6. package/registry/curated/account-manager/SKILL.md +60 -0
  7. package/registry/curated/agent-config/SKILL.md +22 -0
  8. package/registry/curated/amazon-polly/SKILL.md +74 -0
  9. package/registry/curated/apple-notes/SKILL.md +45 -0
  10. package/registry/curated/apple-reminders/SKILL.md +46 -0
  11. package/registry/curated/audio-generation/SKILL.md +231 -0
  12. package/registry/curated/blog-publisher/SKILL.md +110 -0
  13. package/registry/curated/bluesky-bot/SKILL.md +93 -0
  14. package/registry/curated/cli-tools/SKILL.md +137 -0
  15. package/registry/curated/cloud-ops/SKILL.md +124 -0
  16. package/registry/curated/code-safety/SKILL.md +42 -0
  17. package/registry/curated/coding-agent/SKILL.md +40 -0
  18. package/registry/curated/company-research/SKILL.md +46 -0
  19. package/registry/curated/content-creator/SKILL.md +53 -0
  20. package/registry/curated/deep-research/SKILL.md +56 -0
  21. package/registry/curated/diarization/SKILL.md +83 -0
  22. package/registry/curated/discord-helper/SKILL.md +43 -0
  23. package/registry/curated/document-export/SKILL.md +54 -0
  24. package/registry/curated/email-intelligence/SKILL.md +41 -0
  25. package/registry/curated/emergent-tools/SKILL.md +225 -0
  26. package/registry/curated/endpoint-semantic/SKILL.md +72 -0
  27. package/registry/curated/facebook-bot/SKILL.md +94 -0
  28. package/registry/curated/git/SKILL.md +49 -0
  29. package/registry/curated/github/SKILL.md +142 -0
  30. package/registry/curated/google-cloud-stt/SKILL.md +71 -0
  31. package/registry/curated/google-cloud-tts/SKILL.md +71 -0
  32. package/registry/curated/grounding-guard/SKILL.md +38 -0
  33. package/registry/curated/healthcheck/SKILL.md +43 -0
  34. package/registry/curated/image-editing/SKILL.md +25 -0
  35. package/registry/curated/image-gen/SKILL.md +141 -0
  36. package/registry/curated/instagram-bot/SKILL.md +60 -0
  37. package/registry/curated/interactive-widgets/SKILL.md +85 -0
  38. package/registry/curated/linkedin-bot/SKILL.md +86 -0
  39. package/registry/curated/mastodon-bot/SKILL.md +104 -0
  40. package/registry/curated/memory-manager/SKILL.md +127 -0
  41. package/registry/curated/ml-content-classifier/SKILL.md +38 -0
  42. package/registry/curated/movie-lookup/SKILL.md +48 -0
  43. package/registry/curated/multimodal-rag/SKILL.md +153 -0
  44. package/registry/curated/notion/SKILL.md +43 -0
  45. package/registry/curated/obsidian/SKILL.md +42 -0
  46. package/registry/curated/openwakeword/SKILL.md +75 -0
  47. package/registry/curated/pii-redaction/SKILL.md +56 -0
  48. package/registry/curated/pinterest-bot/SKILL.md +45 -0
  49. package/registry/curated/piper/SKILL.md +72 -0
  50. package/registry/curated/porcupine/SKILL.md +74 -0
  51. package/registry/curated/reddit-bot/SKILL.md +74 -0
  52. package/registry/curated/seo-campaign/SKILL.md +51 -0
  53. package/registry/curated/site-deploy/SKILL.md +119 -0
  54. package/registry/curated/slack-helper/SKILL.md +43 -0
  55. package/registry/curated/social-broadcast/SKILL.md +145 -0
  56. package/registry/curated/spotify-player/SKILL.md +45 -0
  57. package/registry/curated/streaming-stt-deepgram/SKILL.md +84 -0
  58. package/registry/curated/streaming-stt-whisper/SKILL.md +82 -0
  59. package/registry/curated/streaming-tts-elevenlabs/SKILL.md +84 -0
  60. package/registry/curated/streaming-tts-openai/SKILL.md +83 -0
  61. package/registry/curated/structured-output/SKILL.md +22 -0
  62. package/registry/curated/summarize/SKILL.md +40 -0
  63. package/registry/curated/threads-bot/SKILL.md +82 -0
  64. package/registry/curated/tiktok-bot/SKILL.md +104 -0
  65. package/registry/curated/topicality/SKILL.md +37 -0
  66. package/registry/curated/trello/SKILL.md +44 -0
  67. package/registry/curated/twitter-bot/SKILL.md +63 -0
  68. package/registry/curated/video-generation/SKILL.md +225 -0
  69. package/registry/curated/vision-ocr/SKILL.md +82 -0
  70. package/registry/curated/voice-conversation/SKILL.md +65 -0
  71. package/registry/curated/vosk/SKILL.md +74 -0
  72. package/registry/curated/weather/SKILL.md +37 -0
  73. package/registry/curated/web-scraper/SKILL.md +60 -0
  74. package/registry/curated/web-search/SKILL.md +49 -0
  75. package/registry/curated/whisper-transcribe/SKILL.md +58 -0
  76. package/registry/curated/youtube-bot/SKILL.md +104 -0
  77. package/registry.json +2446 -0
  78. package/scripts/update-registry.mjs +126 -0
  79. package/scripts/validate-skill.mjs +304 -0
  80. package/types.d.ts +160 -0
  81. package/dist/SkillLoader.d.ts +0 -50
  82. package/dist/SkillLoader.d.ts.map +0 -1
  83. package/dist/SkillLoader.js +0 -291
  84. package/dist/SkillLoader.js.map +0 -1
  85. package/dist/SkillRegistry.d.ts +0 -135
  86. package/dist/SkillRegistry.d.ts.map +0 -1
  87. package/dist/SkillRegistry.js +0 -455
  88. package/dist/SkillRegistry.js.map +0 -1
  89. package/dist/index.d.ts +0 -13
  90. package/dist/index.d.ts.map +0 -1
  91. package/dist/index.js +0 -13
  92. package/dist/index.js.map +0 -1
  93. package/dist/paths.d.ts +0 -35
  94. package/dist/paths.d.ts.map +0 -1
  95. package/dist/paths.js +0 -71
  96. package/dist/paths.js.map +0 -1
  97. package/dist/types.d.ts +0 -231
  98. package/dist/types.d.ts.map +0 -1
  99. package/dist/types.js +0 -21
  100. package/dist/types.js.map +0 -1
@@ -0,0 +1,126 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Regenerate skills registry.json from SKILL.md files.
5
+ */
6
+
7
+ import fs from 'node:fs';
8
+ import path from 'node:path';
9
+ import { fileURLToPath } from 'node:url';
10
+ import YAML from 'yaml';
11
+
12
+ const __filename = fileURLToPath(import.meta.url);
13
+ const __dirname = path.dirname(__filename);
14
+ const packageRoot = path.join(__dirname, '..');
15
+ const registryPath = path.join(packageRoot, 'registry.json');
16
+ const curatedRoot = path.join(packageRoot, 'registry', 'curated');
17
+ const communityRoot = path.join(packageRoot, 'registry', 'community');
18
+
19
+ function readFrontmatter(filePath) {
20
+ const content = fs.readFileSync(filePath, 'utf8');
21
+ const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
22
+ if (!match) return {};
23
+ try {
24
+ const parsed = YAML.parse(match[1]);
25
+ return parsed && typeof parsed === 'object' ? parsed : {};
26
+ } catch {
27
+ return {};
28
+ }
29
+ }
30
+
31
+ function listSkillDirs(root) {
32
+ if (!fs.existsSync(root)) return [];
33
+ return fs
34
+ .readdirSync(root, { withFileTypes: true })
35
+ .filter((d) => d.isDirectory() && fs.existsSync(path.join(root, d.name, 'SKILL.md')))
36
+ .map((d) => d.name)
37
+ .sort();
38
+ }
39
+
40
+ function cleanObject(obj) {
41
+ const out = {};
42
+ for (const [k, v] of Object.entries(obj)) {
43
+ if (v === undefined) continue;
44
+ if (Array.isArray(v) && v.length === 0) continue;
45
+ if (v && typeof v === 'object' && !Array.isArray(v) && Object.keys(v).length === 0) continue;
46
+ out[k] = v;
47
+ }
48
+ return out;
49
+ }
50
+
51
+ function toStringArray(value) {
52
+ if (!Array.isArray(value)) return [];
53
+ return value.filter((v) => typeof v === 'string' && v.trim().length > 0);
54
+ }
55
+
56
+ function slugToDisplayName(slug) {
57
+ return slug
58
+ .split(/[-_]/g)
59
+ .filter(Boolean)
60
+ .map((part) => part[0].toUpperCase() + part.slice(1))
61
+ .join(' ');
62
+ }
63
+
64
+ function buildEntry(name, source, updatedAt) {
65
+ const skillPath = path.join(packageRoot, 'registry', source, name, 'SKILL.md');
66
+ const fm = readFrontmatter(skillPath);
67
+ const metadata = fm?.metadata?.agentos && typeof fm.metadata.agentos === 'object'
68
+ ? fm.metadata.agentos
69
+ : undefined;
70
+
71
+ return cleanObject({
72
+ id: source === 'curated' ? `com.framers.skill.${name}` : `com.community.skill.${name}`,
73
+ name,
74
+ displayName:
75
+ typeof fm.name === 'string' && fm.name.trim().length > 0
76
+ ? fm.name
77
+ : slugToDisplayName(name),
78
+ version: typeof fm.version === 'string' && fm.version ? fm.version : '1.0.0',
79
+ path: `registry/${source}/${name}`,
80
+ description: typeof fm.description === 'string' ? fm.description : '',
81
+ category: typeof fm.category === 'string' && fm.category ? fm.category : 'uncategorized',
82
+ namespace: typeof fm.namespace === 'string' && fm.namespace ? fm.namespace : 'wunderland',
83
+ verified: source === 'curated',
84
+ source,
85
+ verifiedAt: source === 'curated' ? updatedAt : undefined,
86
+ keywords: toStringArray(fm.tags),
87
+ requiredSecrets: toStringArray(fm.requires_secrets),
88
+ requiredTools: toStringArray(fm.requires_tools),
89
+ metadata: metadata && typeof metadata === 'object' ? metadata : undefined,
90
+ });
91
+ }
92
+
93
+ function generateRegistry() {
94
+ const updated = new Date().toISOString();
95
+ const curatedNames = listSkillDirs(curatedRoot);
96
+ const communityNames = listSkillDirs(communityRoot);
97
+
98
+ const curated = curatedNames.map((name) => buildEntry(name, 'curated', updated));
99
+ const community = communityNames.map((name) => buildEntry(name, 'community', updated));
100
+
101
+ return {
102
+ version: '1.0.0',
103
+ updated,
104
+ categories: {
105
+ curated: curatedNames,
106
+ community: communityNames,
107
+ },
108
+ skills: {
109
+ curated,
110
+ community,
111
+ },
112
+ stats: {
113
+ totalSkills: curated.length + community.length,
114
+ curatedCount: curated.length,
115
+ communityCount: community.length,
116
+ },
117
+ };
118
+ }
119
+
120
+ const registry = generateRegistry();
121
+ fs.writeFileSync(registryPath, `${JSON.stringify(registry, null, 2)}\n`);
122
+
123
+ console.log('✅ Skills registry updated');
124
+ console.log(` curated: ${registry.stats.curatedCount}`);
125
+ console.log(` community: ${registry.stats.communityCount}`);
126
+ console.log(` total: ${registry.stats.totalSkills}`);
@@ -0,0 +1,304 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * SKILL.md validator for @framers/agentos-skills
5
+ *
6
+ * Usage:
7
+ * node scripts/validate-skill.mjs registry/community/my-skill/SKILL.md
8
+ * node scripts/validate-skill.mjs # validates ALL skills
9
+ *
10
+ * Exit code 0 on pass, 1 on fail.
11
+ * Zero external dependencies — uses only Node.js built-ins.
12
+ */
13
+
14
+ import { readFileSync, readdirSync, existsSync, statSync } from 'node:fs';
15
+ import { resolve, basename, dirname, join } from 'node:path';
16
+
17
+ // ---------------------------------------------------------------------------
18
+ // Constants
19
+ // ---------------------------------------------------------------------------
20
+
21
+ const VALID_CATEGORIES = new Set([
22
+ 'automation',
23
+ 'communication',
24
+ 'content',
25
+ 'creative',
26
+ 'developer-tools',
27
+ 'devops',
28
+ 'information',
29
+ 'infrastructure',
30
+ 'marketing',
31
+ 'media',
32
+ 'productivity',
33
+ 'research',
34
+ 'security',
35
+ 'social-automation',
36
+ ]);
37
+
38
+ const VALID_NAMESPACES = new Set(['wunderland', 'community']);
39
+
40
+ const REQUIRED_FIELDS = ['name', 'version', 'description', 'author', 'namespace', 'category', 'tags'];
41
+
42
+ const MAX_DESCRIPTION_LENGTH = 200;
43
+
44
+ /** Patterns that suggest accidentally-committed secrets. */
45
+ const SECRET_PATTERNS = [
46
+ /(?:api[_-]?key|apikey)\s*[:=]\s*["']?[A-Za-z0-9_\-]{16,}/i,
47
+ /(?:secret|token|password|passwd|pwd)\s*[:=]\s*["']?[A-Za-z0-9_\-]{16,}/i,
48
+ /sk-[A-Za-z0-9]{20,}/, // OpenAI-style keys
49
+ /ghp_[A-Za-z0-9]{36,}/, // GitHub personal access tokens
50
+ /gho_[A-Za-z0-9]{36,}/, // GitHub OAuth tokens
51
+ /xox[bpors]-[A-Za-z0-9\-]{10,}/, // Slack tokens
52
+ /AKIA[0-9A-Z]{16}/, // AWS access key IDs
53
+ /-----BEGIN\s+(RSA\s+)?PRIVATE\s+KEY-----/, // Private keys
54
+ /Bearer\s+[A-Za-z0-9_\-\.]{20,}/, // Bearer tokens
55
+ ];
56
+
57
+ // ---------------------------------------------------------------------------
58
+ // Simple YAML frontmatter parser (no dependencies)
59
+ // ---------------------------------------------------------------------------
60
+
61
+ /**
62
+ * Parse basic YAML key-value pairs from frontmatter lines.
63
+ * Handles:
64
+ * key: value -> string
65
+ * key: 'value' -> string (strip quotes)
66
+ * key: "value" -> string (strip quotes)
67
+ * key: [a, b, c] -> string[]
68
+ * key: [] -> string[] (empty)
69
+ *
70
+ * Nested keys (like metadata.agentos.emoji) are ignored — only top-level
71
+ * keys matter for required-field validation.
72
+ */
73
+ function parseSimpleYaml(yamlText) {
74
+ const result = {};
75
+ const lines = yamlText.split('\n');
76
+
77
+ for (const line of lines) {
78
+ // Skip blank lines and comments
79
+ const trimmed = line.trimStart();
80
+ if (!trimmed || trimmed.startsWith('#')) continue;
81
+
82
+ // Only parse top-level keys (no leading whitespace)
83
+ if (line[0] === ' ' || line[0] === '\t') continue;
84
+
85
+ const colonIndex = trimmed.indexOf(':');
86
+ if (colonIndex === -1) continue;
87
+
88
+ const key = trimmed.slice(0, colonIndex).trim();
89
+ let value = trimmed.slice(colonIndex + 1).trim();
90
+
91
+ if (!key) continue;
92
+
93
+ // Inline array: [a, b, c]
94
+ if (value.startsWith('[') && value.endsWith(']')) {
95
+ const inner = value.slice(1, -1).trim();
96
+ if (inner === '') {
97
+ result[key] = [];
98
+ } else {
99
+ result[key] = inner.split(',').map((s) => s.trim().replace(/^['"]|['"]$/g, ''));
100
+ }
101
+ continue;
102
+ }
103
+
104
+ // Strip surrounding quotes
105
+ if ((value.startsWith("'") && value.endsWith("'")) || (value.startsWith('"') && value.endsWith('"'))) {
106
+ value = value.slice(1, -1);
107
+ }
108
+
109
+ result[key] = value;
110
+ }
111
+
112
+ return result;
113
+ }
114
+
115
+ // ---------------------------------------------------------------------------
116
+ // Validation
117
+ // ---------------------------------------------------------------------------
118
+
119
+ /**
120
+ * Validate a single SKILL.md file. Returns an object with:
121
+ * { path, passed, errors[] }
122
+ */
123
+ function validateSkill(filePath) {
124
+ const errors = [];
125
+ const absolutePath = resolve(filePath);
126
+
127
+ // --- Read file --------------------------------------------------------
128
+
129
+ let content;
130
+ try {
131
+ content = readFileSync(absolutePath, 'utf-8');
132
+ } catch (err) {
133
+ return { path: absolutePath, passed: false, errors: [`Cannot read file: ${err.message}`] };
134
+ }
135
+
136
+ // --- Split frontmatter / body ----------------------------------------
137
+
138
+ const fmRegex = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/;
139
+ const match = content.match(fmRegex);
140
+
141
+ if (!match) {
142
+ return {
143
+ path: absolutePath,
144
+ passed: false,
145
+ errors: ['File does not contain valid YAML frontmatter (expected --- delimiters).'],
146
+ };
147
+ }
148
+
149
+ const yamlText = match[1];
150
+ const markdownBody = match[2];
151
+
152
+ // --- Parse YAML -------------------------------------------------------
153
+
154
+ const meta = parseSimpleYaml(yamlText);
155
+
156
+ // --- Required fields --------------------------------------------------
157
+
158
+ for (const field of REQUIRED_FIELDS) {
159
+ if (meta[field] === undefined || meta[field] === '') {
160
+ errors.push(`Missing required field: ${field}`);
161
+ }
162
+ }
163
+
164
+ // --- Category ---------------------------------------------------------
165
+
166
+ if (meta.category && !VALID_CATEGORIES.has(meta.category)) {
167
+ errors.push(
168
+ `Invalid category "${meta.category}". Must be one of: ${[...VALID_CATEGORIES].join(', ')}`,
169
+ );
170
+ }
171
+
172
+ // --- Namespace --------------------------------------------------------
173
+
174
+ if (meta.namespace && !VALID_NAMESPACES.has(meta.namespace)) {
175
+ errors.push(
176
+ `Invalid namespace "${meta.namespace}". Must be one of: ${[...VALID_NAMESPACES].join(', ')}`,
177
+ );
178
+ }
179
+
180
+ // --- Description length -----------------------------------------------
181
+
182
+ if (meta.description && typeof meta.description === 'string' && meta.description.length > MAX_DESCRIPTION_LENGTH) {
183
+ errors.push(
184
+ `Description is ${meta.description.length} characters (max ${MAX_DESCRIPTION_LENGTH}).`,
185
+ );
186
+ }
187
+
188
+ // --- Tags -------------------------------------------------------------
189
+
190
+ if (meta.tags !== undefined) {
191
+ if (!Array.isArray(meta.tags)) {
192
+ errors.push('tags must be an array.');
193
+ } else if (meta.tags.length === 0) {
194
+ errors.push('tags array must contain at least 1 tag.');
195
+ }
196
+ }
197
+
198
+ // --- Name matches directory -------------------------------------------
199
+
200
+ const dirName = basename(dirname(absolutePath));
201
+ if (meta.name && meta.name !== dirName) {
202
+ errors.push(
203
+ `Skill name "${meta.name}" does not match directory name "${dirName}".`,
204
+ );
205
+ }
206
+
207
+ // --- Markdown body not empty ------------------------------------------
208
+
209
+ if (!markdownBody || markdownBody.trim().length === 0) {
210
+ errors.push('Markdown body is empty. Include usage instructions, Examples, and Constraints.');
211
+ }
212
+
213
+ // --- Secret pattern scan ----------------------------------------------
214
+
215
+ for (const pattern of SECRET_PATTERNS) {
216
+ if (pattern.test(content)) {
217
+ errors.push(`Possible secret or credential detected (pattern: ${pattern.source}). Remove it before submitting.`);
218
+ }
219
+ }
220
+
221
+ return { path: absolutePath, passed: errors.length === 0, errors };
222
+ }
223
+
224
+ // ---------------------------------------------------------------------------
225
+ // Discover all SKILL.md files
226
+ // ---------------------------------------------------------------------------
227
+
228
+ function discoverSkills(rootDir) {
229
+ const skills = [];
230
+ const tiers = ['curated', 'community'];
231
+
232
+ for (const tier of tiers) {
233
+ const tierDir = join(rootDir, 'registry', tier);
234
+ if (!existsSync(tierDir)) continue;
235
+
236
+ for (const entry of readdirSync(tierDir)) {
237
+ const skillDir = join(tierDir, entry);
238
+ if (!statSync(skillDir).isDirectory()) continue;
239
+
240
+ const skillFile = join(skillDir, 'SKILL.md');
241
+ if (existsSync(skillFile)) {
242
+ skills.push(skillFile);
243
+ }
244
+ }
245
+ }
246
+
247
+ return skills;
248
+ }
249
+
250
+ // ---------------------------------------------------------------------------
251
+ // Main
252
+ // ---------------------------------------------------------------------------
253
+
254
+ function main() {
255
+ const args = process.argv.slice(2);
256
+
257
+ let filesToValidate;
258
+
259
+ if (args.length === 0) {
260
+ // Validate all skills
261
+ const rootDir = resolve(dirname(new URL(import.meta.url).pathname), '..');
262
+ filesToValidate = discoverSkills(rootDir);
263
+ if (filesToValidate.length === 0) {
264
+ console.log('No SKILL.md files found in registry/curated/ or registry/community/.');
265
+ process.exit(0);
266
+ }
267
+ console.log(`Validating ${filesToValidate.length} skill(s)...\n`);
268
+ } else {
269
+ filesToValidate = [resolve(args[0])];
270
+ }
271
+
272
+ let allPassed = true;
273
+
274
+ for (const filePath of filesToValidate) {
275
+ const result = validateSkill(filePath);
276
+
277
+ if (result.passed) {
278
+ console.log(` PASS ${result.path}`);
279
+ } else {
280
+ allPassed = false;
281
+ console.log(` FAIL ${result.path}`);
282
+ for (const err of result.errors) {
283
+ console.log(` - ${err}`);
284
+ }
285
+ }
286
+ }
287
+
288
+ console.log('');
289
+
290
+ if (allPassed) {
291
+ console.log(`All ${filesToValidate.length} skill(s) passed validation.`);
292
+ process.exit(0);
293
+ } else {
294
+ const failCount = filesToValidate.length - filesToValidate.filter((_, i) => {
295
+ // Re-validate to count (cheap for small set)
296
+ return validateSkill(filesToValidate[i]).passed;
297
+ }).length;
298
+ // Simpler: just fail
299
+ console.log('Validation failed. Fix the errors above and re-run.');
300
+ process.exit(1);
301
+ }
302
+ }
303
+
304
+ main();
package/types.d.ts ADDED
@@ -0,0 +1,160 @@
1
+ /**
2
+ * Type declarations for the `@framers/agentos-skills` content package.
3
+ *
4
+ * Describes the shape of `registry.json` — the machine-readable index of all
5
+ * bundled SKILL.md prompt modules. These types are consumed by
6
+ * `@framers/agentos-skills-registry` (the catalog SDK) and any tooling that
7
+ * reads the registry directly.
8
+ *
9
+ * @module @framers/agentos-skills
10
+ */
11
+
12
+ /** Supported package-manager / install strategies for skill prerequisites. */
13
+ export type SkillInstallKind = 'brew' | 'apt' | 'node' | 'go' | 'uv' | 'download';
14
+
15
+ /**
16
+ * Describes how to install a single prerequisite binary for a skill.
17
+ *
18
+ * Each install spec maps to a concrete command the agent or user can run
19
+ * (e.g. `brew install gh`, `npm install -g typescript`).
20
+ */
21
+ export interface SkillInstallSpec {
22
+ /** Unique ID for this install option (e.g. 'brew-gh') */
23
+ id?: string;
24
+ /** Package manager or install strategy */
25
+ kind: SkillInstallKind;
26
+ /** Human-readable label for the install option */
27
+ label?: string;
28
+ /** Binary names this install provides (used for verification) */
29
+ bins?: string[];
30
+ /** OS restrictions — only show this option on matching platforms */
31
+ os?: readonly string[];
32
+ /** Homebrew formula name */
33
+ formula?: string;
34
+ /** npm / pip / go package name */
35
+ package?: string;
36
+ /** Node module name (for `npx`-style invocation) */
37
+ module?: string;
38
+ /** Direct download URL */
39
+ url?: string;
40
+ /** Archive filename within the download */
41
+ archive?: string;
42
+ /** Whether to extract the download */
43
+ extract?: boolean;
44
+ /** Number of directory levels to strip when extracting */
45
+ stripComponents?: number;
46
+ /** Target directory for the extracted/downloaded binary */
47
+ targetDir?: string;
48
+ }
49
+
50
+ /**
51
+ * Binary, environment variable, and config requirements that must be met
52
+ * before a skill is eligible to run.
53
+ */
54
+ export interface SkillRequirements {
55
+ /** All of these binaries must be on PATH */
56
+ bins?: string[];
57
+ /** At least one of these binaries must be on PATH */
58
+ anyBins?: string[];
59
+ /** All of these environment variables must be set */
60
+ env?: string[];
61
+ /** All of these config file paths must exist */
62
+ config?: string[];
63
+ }
64
+
65
+ /**
66
+ * Structured metadata extracted from the `metadata.agentos` block in SKILL.md
67
+ * frontmatter. Controls eligibility, discoverability, and installation UX.
68
+ */
69
+ export interface SkillMetadata {
70
+ /** If true, skill is always included in agent context (no opt-in needed) */
71
+ always?: boolean;
72
+ /** Override key used for per-skill config in agent.config.json */
73
+ skillKey?: string;
74
+ /** Primary environment variable this skill needs (e.g. 'GITHUB_TOKEN') */
75
+ primaryEnv?: string;
76
+ /** Emoji icon for display in catalogs and CLI */
77
+ emoji?: string;
78
+ /** URL to the skill's homepage or docs */
79
+ homepage?: string;
80
+ /** OS restrictions — skill only available on these platforms */
81
+ os?: readonly string[];
82
+ /** Binary and env requirements for eligibility checking */
83
+ requires?: SkillRequirements;
84
+ /** Installation options for missing prerequisites */
85
+ install?: SkillInstallSpec[];
86
+ }
87
+
88
+ /**
89
+ * Shape of a single skill entry in `registry.json`.
90
+ *
91
+ * Each entry maps to one `registry/curated/{name}/SKILL.md` file and includes
92
+ * all metadata needed for catalog queries without reading the file from disk.
93
+ */
94
+ export interface SkillRegistryEntry {
95
+ /** Fully-qualified ID (e.g. 'com.framers.skill.github') */
96
+ id: string;
97
+ /** Unique slug matching the directory name under registry/curated/ */
98
+ name: string;
99
+ /** Human-readable display name (e.g. 'GitHub') */
100
+ displayName?: string;
101
+ /** Semantic version from the SKILL.md frontmatter */
102
+ version: string;
103
+ /** Relative path from package root to the skill directory */
104
+ path: string;
105
+ /** Brief description of the skill's capabilities */
106
+ description: string;
107
+ /** Grouping category (e.g. 'developer', 'social', 'voice') */
108
+ category?: string;
109
+ /** Namespace used for registry scoping */
110
+ namespace?: string;
111
+ /** Whether this skill has been staff-verified */
112
+ verified: boolean;
113
+ /** Provenance: curated (staff-maintained) or community-submitted */
114
+ source?: 'curated' | 'community';
115
+ /** ISO timestamp of last verification */
116
+ verifiedAt?: string;
117
+ /** Searchable keywords */
118
+ keywords?: string[];
119
+ /** Secret identifiers the skill requires (e.g. 'github.token') */
120
+ requiredSecrets?: string[];
121
+ /** Tool identifiers the skill depends on */
122
+ requiredTools?: string[];
123
+ /** Structured metadata from the SKILL.md frontmatter */
124
+ metadata?: SkillMetadata;
125
+ }
126
+
127
+ /** Aggregate counts for the registry. */
128
+ export interface SkillsRegistryStats {
129
+ totalSkills: number;
130
+ curatedCount: number;
131
+ communityCount: number;
132
+ }
133
+
134
+ /**
135
+ * Shape of the full `registry.json` file.
136
+ *
137
+ * Auto-generated by `scripts/update-registry.mjs` from the SKILL.md files
138
+ * in `registry/curated/` and `registry/community/`.
139
+ */
140
+ export interface SkillsRegistry {
141
+ /** Schema version */
142
+ version: string;
143
+ /** ISO timestamp of last regeneration */
144
+ updated: string;
145
+ /** Category names present in each source */
146
+ categories: {
147
+ curated: string[];
148
+ community: string[];
149
+ };
150
+ /** Skill entries grouped by source */
151
+ skills: {
152
+ curated: SkillRegistryEntry[];
153
+ community: SkillRegistryEntry[];
154
+ };
155
+ /** Aggregate statistics */
156
+ stats: SkillsRegistryStats;
157
+ }
158
+
159
+ declare const registry: SkillsRegistry;
160
+ export default registry;
@@ -1,50 +0,0 @@
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
@@ -1 +0,0 @@
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"}