@magnolia/skill-loader 0.1.0-preview.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 (43) hide show
  1. package/LICENSE.txt +27 -0
  2. package/README.md +354 -0
  3. package/dist/filter.d.ts +26 -0
  4. package/dist/filter.d.ts.map +1 -0
  5. package/dist/filter.js +160 -0
  6. package/dist/filter.js.map +1 -0
  7. package/dist/index.d.ts +35 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +38 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/loader.d.ts +81 -0
  12. package/dist/loader.d.ts.map +1 -0
  13. package/dist/loader.js +192 -0
  14. package/dist/loader.js.map +1 -0
  15. package/dist/manager.d.ts +131 -0
  16. package/dist/manager.d.ts.map +1 -0
  17. package/dist/manager.js +236 -0
  18. package/dist/manager.js.map +1 -0
  19. package/dist/parser.d.ts +25 -0
  20. package/dist/parser.d.ts.map +1 -0
  21. package/dist/parser.js +110 -0
  22. package/dist/parser.js.map +1 -0
  23. package/dist/sources/directory.d.ts +18 -0
  24. package/dist/sources/directory.d.ts.map +1 -0
  25. package/dist/sources/directory.js +57 -0
  26. package/dist/sources/directory.js.map +1 -0
  27. package/dist/sources/file.d.ts +15 -0
  28. package/dist/sources/file.d.ts.map +1 -0
  29. package/dist/sources/file.js +30 -0
  30. package/dist/sources/file.js.map +1 -0
  31. package/dist/sources/inline.d.ts +15 -0
  32. package/dist/sources/inline.d.ts.map +1 -0
  33. package/dist/sources/inline.js +21 -0
  34. package/dist/sources/inline.js.map +1 -0
  35. package/dist/sources/url.d.ts +20 -0
  36. package/dist/sources/url.d.ts.map +1 -0
  37. package/dist/sources/url.js +65 -0
  38. package/dist/sources/url.js.map +1 -0
  39. package/dist/types.d.ts +111 -0
  40. package/dist/types.d.ts.map +1 -0
  41. package/dist/types.js +21 -0
  42. package/dist/types.js.map +1 -0
  43. package/package.json +60 -0
package/LICENSE.txt ADDED
@@ -0,0 +1,27 @@
1
+ Copyright (c) 2026 Magnolia International Ltd.
2
+ (http://www.magnolia-cms.com). All rights reserved.
3
+
4
+
5
+ The software is dual-licensed under both the Magnolia
6
+ Network Agreement and the GNU General Public License.
7
+ You may elect to use one or the other of these licenses.
8
+
9
+ The software is distributed in the hope that it will be
10
+ useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
11
+ implied warranty of MERCHANTABILITY or FITNESS FOR A
12
+ PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
13
+ Redistribution, except as permitted by whichever of the GPL
14
+ or MNA you select, is prohibited.
15
+
16
+ 1. For the GPL license (GPL), you can redistribute and/or
17
+ modify this file under the terms of the GNU General
18
+ Public License, Version 3, as published by the Free Software
19
+ Foundation. You should have received a copy of the GNU
20
+ General Public License, Version 3 along with this program;
21
+ if not, write to the Free Software Foundation, Inc., 51
22
+ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
23
+
24
+ 2. For the Magnolia Network Agreement (MNA), this file
25
+ and the accompanying materials are made available under the
26
+ terms of the MNA which accompanies this distribution, and
27
+ is available at http://www.magnolia-cms.com/mna.html
package/README.md ADDED
@@ -0,0 +1,354 @@
1
+ # @magnolia/skill-loader
2
+
3
+ A Node.js library for loading, filtering, and managing AI prompt "skills" for use with LLMs.
4
+
5
+ ## Overview
6
+
7
+ Skills are structured prompts with metadata that can be conditionally included based on context (target platform, version constraints, detected features, etc.). This library provides a flexible, type-safe way to manage these prompts across different tools and applications.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install @magnolia/skill-loader
13
+ ```
14
+
15
+ ## Quick Start
16
+
17
+ ### Using SkillLoader (Low-level API)
18
+
19
+ ```typescript
20
+ import { SkillLoader } from '@magnolia/skill-loader';
21
+
22
+ // Create a loader with a directory of skill files
23
+ const loader = new SkillLoader()
24
+ .addDirectory('./skills');
25
+
26
+ // Load skills filtered by context
27
+ const skills = await loader.load({
28
+ target: 'freemarker',
29
+ version: '6.3.0',
30
+ detectedFieldTypes: ['textField', 'damLinkField'],
31
+ });
32
+
33
+ // Get combined prompt content
34
+ const prompt = await loader.getPrompt({
35
+ target: 'freemarker',
36
+ });
37
+ ```
38
+
39
+ ### Using SkillManager (High-level API with Priority Management)
40
+
41
+ ```typescript
42
+ import { SkillManager } from '@magnolia/skill-loader';
43
+
44
+ // Create a manager with priority-based directory loading
45
+ const manager = new SkillManager({
46
+ directories: [
47
+ { path: './plugin-skills', priority: 1 }, // Lowest priority
48
+ { path: '~/.app/skills', priority: 10 }, // Medium priority
49
+ { path: './project/skills', priority: 100 }, // Highest priority
50
+ ],
51
+ cacheTtl: 60000, // 1 minute cache
52
+ });
53
+
54
+ // Register additional directories dynamically
55
+ manager.registerSkillDirectory('./custom-skills', 50);
56
+
57
+ // Load and use skills
58
+ const prompt = await manager.getPrompt({ target: 'freemarker' });
59
+ ```
60
+
61
+ ## Skill File Format
62
+
63
+ Skills are Markdown files with YAML frontmatter:
64
+
65
+ ```markdown
66
+ ---
67
+ name: my-skill
68
+ description: A helpful skill for FreeMarker templates
69
+ targets: [freemarker]
70
+ version: ">=6.2"
71
+ tags: [ftl, generation]
72
+ requires: [damLinkField]
73
+ priority: 100
74
+ ---
75
+
76
+ # My Skill
77
+
78
+ Your prompt content here...
79
+ ```
80
+
81
+ ### Frontmatter Fields
82
+
83
+ | Field | Type | Description |
84
+ |---------------|----------|-------------------------------------------------------|
85
+ | `name` | string | Unique identifier (defaults to filename) |
86
+ | `description` | string | Human-readable description |
87
+ | `targets` | string[] | Target platforms (e.g., `freemarker`, `spa`, `react`) |
88
+ | `version` | string | Semver constraint (e.g., `>=6.2`, `^6.3.0`) |
89
+ | `tags` | string[] | Tags for categorization and filtering |
90
+ | `requires` | string[] | Field types that must be detected for inclusion |
91
+ | `priority` | number | Sort order (higher = earlier in output) |
92
+
93
+ ## API
94
+
95
+ ### SkillManager (Recommended)
96
+
97
+ The `SkillManager` provides a high-level API for managing skills from multiple directories with configurable priority-based loading. This is the recommended approach for applications that need to manage skills from multiple sources.
98
+
99
+ #### Constructor
100
+
101
+ ```typescript
102
+ const manager = new SkillManager(options?)
103
+
104
+ interface SkillManagerOptions {
105
+ directories?: SkillDirectory[]; // Directories to load, sorted by priority
106
+ enabled?: boolean; // Enable/disable skill loading (default: true)
107
+ cacheTtl?: number; // Cache TTL in milliseconds (default: 60000)
108
+ customFilter?: (skill, context) => boolean; // Custom filter function
109
+ customSort?: (a, b) => number; // Custom sort function
110
+ }
111
+
112
+ interface SkillDirectory {
113
+ path: string; // Absolute or relative path to skills directory
114
+ priority?: number; // Priority (higher = loaded later = overrides earlier)
115
+ }
116
+ ```
117
+
118
+ #### Methods
119
+
120
+ ```typescript
121
+ // Register a directory with optional priority
122
+ manager.registerSkillDirectory(path: string, priority?: number): void
123
+
124
+ // Load all skills without filtering
125
+ const all = await manager.loadAll(): Promise<Skill[]>
126
+
127
+ // Load skills filtered by context
128
+ const filtered = await manager.load(context: SkillContext): Promise<Skill[]>
129
+
130
+ // Get a single skill by name
131
+ const skill = await manager.get(name: string): Promise<Skill | undefined>
132
+
133
+ // Get combined prompt from filtered skills
134
+ const prompt = await manager.getPrompt(
135
+ context: SkillContext,
136
+ options?: PromptOptions
137
+ ): Promise<string>
138
+
139
+ // List all skills with metadata
140
+ const list = await manager.listSkills(): Promise<SkillInfo[]>
141
+
142
+ // Get registered directories with priorities
143
+ const dirs = manager.getDirectories(): Array<{ path: string; priority: number }>
144
+
145
+ // Get statistics
146
+ const stats = manager.getStats(): {
147
+ totalDirectories: number;
148
+ enabledDirectories: number;
149
+ enabled: boolean;
150
+ }
151
+
152
+ // Clear cache to force reload
153
+ manager.clearCache(): void
154
+ ```
155
+
156
+ #### Priority-Based Loading
157
+
158
+ Skills are loaded in priority order (lowest to highest). When multiple directories contain skills with the same name, the skill from the **higher priority** directory wins.
159
+
160
+ **Example:**
161
+
162
+ ```typescript
163
+ const manager = new SkillManager({
164
+ directories: [
165
+ { path: './built-in-skills', priority: 1 }, // Base skills
166
+ { path: './plugin-skills', priority: 10 }, // Plugin overrides
167
+ { path: './user-skills', priority: 100 }, // User overrides
168
+ { path: './project-skills', priority: 1000 }, // Project-specific (highest)
169
+ ],
170
+ });
171
+
172
+ // If all directories have a skill named "dialog-generation.prompt.md",
173
+ // the one from './project-skills' will be used (highest priority)
174
+ ```
175
+
176
+ #### Dynamic Registration
177
+
178
+ ```typescript
179
+ const manager = new SkillManager();
180
+
181
+ // Register directories dynamically
182
+ manager.registerSkillDirectory('./core-skills', 1);
183
+ manager.registerSkillDirectory('./plugin-a-skills', 10);
184
+ manager.registerSkillDirectory('./plugin-b-skills', 11);
185
+ manager.registerSkillDirectory('./user-skills', 100);
186
+
187
+ // Re-registering the same path updates its priority
188
+ manager.registerSkillDirectory('./user-skills', 200);
189
+ ```
190
+
191
+ #### Disabling Skill Loading
192
+
193
+ ```typescript
194
+ const manager = new SkillManager({ enabled: false });
195
+
196
+ // All methods return empty results when disabled
197
+ await manager.loadAll(); // Returns []
198
+ await manager.getPrompt({}); // Returns ""
199
+ ```
200
+
201
+ ### SkillLoader (Low-level API)
202
+
203
+ The `SkillLoader` provides direct control over skill sources and loading. Use this for simple use cases or when you need fine-grained control.
204
+
205
+ ```typescript
206
+ const loader = new SkillLoader(options?)
207
+ .addDirectory(path, pattern?) // Add a directory source
208
+ .addFile(path) // Add a single file
209
+ .addSkills(skills[]) // Add inline skills
210
+ .addUrl(url, headers?) // Add a remote URL source
211
+
212
+ // Load all skills
213
+ const all = await loader.loadAll();
214
+
215
+ // Load with filtering
216
+ const filtered = await loader.load(context);
217
+
218
+ // Get a single skill
219
+ const skill = await loader.get('skill-name');
220
+
221
+ // Get combined prompt
222
+ const prompt = await loader.getPrompt(context, options?);
223
+
224
+ // Clear cache
225
+ loader.clearCache();
226
+ ```
227
+
228
+ ### Context Filtering
229
+
230
+ ```typescript
231
+ interface SkillContext {
232
+ target?: string; // Platform: 'freemarker', 'spa', 'react', etc.
233
+ version?: string; // Version to match against constraints
234
+ detectedFieldTypes?: string[]; // Field types present in current context
235
+ requiredTags?: string[]; // Skills must have at least one of these
236
+ excludedTags?: string[]; // Skills with these tags are excluded
237
+ }
238
+ ```
239
+
240
+ ### Standalone Functions
241
+
242
+ ```typescript
243
+ import {
244
+ parseSkillFile,
245
+ createSkill,
246
+ filterSkills,
247
+ loadSkillsFromDirectory,
248
+ } from '@magnolia/skill-loader';
249
+
250
+ // Parse a skill file
251
+ const skill = parseSkillFile(content, filename);
252
+
253
+ // Create a skill programmatically
254
+ const skill = createSkill('name', 'content', { targets: ['spa'] });
255
+
256
+ // Filter skills
257
+ const filtered = filterSkills(skills, context);
258
+
259
+ // Load from directory
260
+ const skills = await loadSkillsFromDirectory('./skills', '*.prompt.md');
261
+ ```
262
+
263
+ ## Filtering Logic
264
+
265
+ ### Target Matching
266
+
267
+ Skills with `targets` are included only if the context `target` matches (case-insensitive). Skills without `targets` are always included.
268
+
269
+ ### Version Matching
270
+
271
+ Skills with `version` are included only if the context `version` satisfies the semver constraint. Uses the [semver](https://github.com/npm/node-semver) library.
272
+
273
+ ### Requires Matching
274
+
275
+ Skills with `requires` are only included when at least one required field type is in `detectedFieldTypes`.
276
+
277
+ ### Tag Filtering
278
+
279
+ - `requiredTags`: Skills must have at least one matching tag
280
+ - `excludedTags`: Skills with any matching tag are excluded
281
+
282
+ ## Use Cases
283
+
284
+ ### When to Use SkillManager
285
+
286
+ Use `SkillManager` when you need:
287
+
288
+ - **Multiple skill sources** with override capabilities (plugins, user configs, project-specific)
289
+ - **Priority-based loading** where later sources override earlier ones
290
+ - **Dynamic registration** of skill directories at runtime
291
+ - **Centralized management** of skills across an application
292
+ - **Easy enable/disable** of skill loading
293
+
294
+ **Example:** Plugin System
295
+
296
+ ```typescript
297
+ const manager = new SkillManager({
298
+ directories: [
299
+ { path: '~/.myapp/skills', priority: 100 },
300
+ { path: './project/skills', priority: 1000 },
301
+ ],
302
+ });
303
+
304
+ // Plugins register their skills dynamically
305
+ plugins.forEach((plugin, index) => {
306
+ if (plugin.skillsDir) {
307
+ manager.registerSkillDirectory(plugin.skillsDir, 1 + index);
308
+ }
309
+ });
310
+ ```
311
+
312
+ ### When to Use SkillLoader
313
+
314
+ Use `SkillLoader` when you need:
315
+
316
+ - **Simple, single-source** skill loading
317
+ - **Fine-grained control** over sources (files, URLs, inline)
318
+ - **Custom loading logic** without priority management
319
+ - **Lightweight** skill loading without extra abstractions
320
+
321
+ **Example:** Simple CLI Tool
322
+
323
+ ```typescript
324
+ const loader = new SkillLoader()
325
+ .addDirectory('./skills')
326
+ .addFile('./custom-skill.md');
327
+
328
+ const prompt = await loader.getPrompt({ target: 'react' });
329
+ ```
330
+
331
+ ## Development
332
+
333
+ ```bash
334
+ # Install dependencies
335
+ npm install
336
+
337
+ # Build
338
+ npm run build
339
+
340
+ # Run tests
341
+ npm test
342
+
343
+ # Watch mode
344
+ npm run dev
345
+ ```
346
+
347
+ ## License
348
+
349
+ See LICENSE.txt for license information.
350
+
351
+ ## Support
352
+
353
+ - [GitLab Issues](https://gitlab.magnolia-platform.com/ps/extensions/ai/dev-mcp/magnolia-skill-loader/issues) **Currently Internal Access Only**
354
+ - [Magnolia Documentation](https://docs.magnolia-cms.com)
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @magnolia/skill-loader - Filtering Logic
3
+ *
4
+ * Implements skill filtering based on context (target, version, requires, tags).
5
+ */
6
+ import { Skill, SkillContext } from './types.js';
7
+ /**
8
+ * Filter an array of skills by context.
9
+ *
10
+ * @param skills - Array of skills to filter
11
+ * @param context - Context to filter against
12
+ * @returns Filtered and sorted array of skills
13
+ */
14
+ export declare function filterSkills(skills: Skill[], context: SkillContext): Skill[];
15
+ /**
16
+ * Check if a skill matches the given context.
17
+ *
18
+ * A skill is included if ALL of the following are true:
19
+ * 1. Target matches (if skill has targets)
20
+ * 2. Version satisfies constraint (if skill has version)
21
+ * 3. At least one required field type is detected (if skill has requires)
22
+ * 4. Has at least one required tag (if context has requiredTags)
23
+ * 5. Has none of the excluded tags (if context has excludedTags)
24
+ */
25
+ export declare function matchesContext(skill: Skill, context: SkillContext): boolean;
26
+ //# sourceMappingURL=filter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../src/filter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEjD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,YAAY,GAAG,KAAK,EAAE,CAc5E;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CA6B3E"}
package/dist/filter.js ADDED
@@ -0,0 +1,160 @@
1
+ /**
2
+ * @magnolia/skill-loader - Filtering Logic
3
+ *
4
+ * Implements skill filtering based on context (target, version, requires, tags).
5
+ */
6
+ import { satisfies, valid, coerce } from 'semver';
7
+ /**
8
+ * Filter an array of skills by context.
9
+ *
10
+ * @param skills - Array of skills to filter
11
+ * @param context - Context to filter against
12
+ * @returns Filtered and sorted array of skills
13
+ */
14
+ export function filterSkills(skills, context) {
15
+ const filtered = skills.filter((skill) => matchesContext(skill, context));
16
+ // Sort by priority (higher first), then by name for stability
17
+ return filtered.sort((a, b) => {
18
+ const priorityA = a.metadata.priority ?? 0;
19
+ const priorityB = b.metadata.priority ?? 0;
20
+ if (priorityA !== priorityB) {
21
+ return priorityB - priorityA; // Higher priority first
22
+ }
23
+ return a.name.localeCompare(b.name);
24
+ });
25
+ }
26
+ /**
27
+ * Check if a skill matches the given context.
28
+ *
29
+ * A skill is included if ALL of the following are true:
30
+ * 1. Target matches (if skill has targets)
31
+ * 2. Version satisfies constraint (if skill has version)
32
+ * 3. At least one required field type is detected (if skill has requires)
33
+ * 4. Has at least one required tag (if context has requiredTags)
34
+ * 5. Has none of the excluded tags (if context has excludedTags)
35
+ */
36
+ export function matchesContext(skill, context) {
37
+ const { metadata } = skill;
38
+ // Check target matching
39
+ if (!matchesTarget(metadata.targets, context.target)) {
40
+ return false;
41
+ }
42
+ // Check version matching
43
+ if (!matchesVersion(metadata.version, context.version)) {
44
+ return false;
45
+ }
46
+ // Check requires matching
47
+ if (!matchesRequires(metadata.requires, context.detectedFieldTypes)) {
48
+ return false;
49
+ }
50
+ // Check required tags
51
+ if (!matchesRequiredTags(metadata.tags, context.requiredTags)) {
52
+ return false;
53
+ }
54
+ // Check excluded tags
55
+ if (!matchesExcludedTags(metadata.tags, context.excludedTags)) {
56
+ return false;
57
+ }
58
+ return true;
59
+ }
60
+ /**
61
+ * Check if skill targets match context target.
62
+ * Skills with no targets are included for all targets.
63
+ */
64
+ function matchesTarget(skillTargets, contextTarget) {
65
+ // No targets on skill = universal skill
66
+ if (!skillTargets || skillTargets.length === 0) {
67
+ return true;
68
+ }
69
+ // No target in context = include all skills
70
+ if (!contextTarget) {
71
+ return true;
72
+ }
73
+ // Check if context target is in skill targets (case-insensitive)
74
+ const normalizedContextTarget = contextTarget.toLowerCase();
75
+ return skillTargets.some((target) => target.toLowerCase() === normalizedContextTarget);
76
+ }
77
+ /**
78
+ * Check if context version satisfies skill version constraint.
79
+ * Skills with no version constraint are included for all versions.
80
+ */
81
+ function matchesVersion(skillVersion, contextVersion) {
82
+ // No version constraint on skill = include for all versions
83
+ if (!skillVersion) {
84
+ return true;
85
+ }
86
+ // No version in context = include skill (can't check constraint)
87
+ if (!contextVersion) {
88
+ return true;
89
+ }
90
+ // Try to coerce the context version to a valid semver
91
+ const coercedVersion = coerce(contextVersion);
92
+ if (!coercedVersion) {
93
+ // Can't parse context version, include the skill
94
+ return true;
95
+ }
96
+ // Check if version is a valid semver (might just be a simple string like "6.3")
97
+ const validVersion = valid(coercedVersion);
98
+ if (!validVersion) {
99
+ return true;
100
+ }
101
+ try {
102
+ return satisfies(validVersion, skillVersion);
103
+ }
104
+ catch {
105
+ // Invalid semver range, include the skill
106
+ return true;
107
+ }
108
+ }
109
+ /**
110
+ * Check if at least one required field type is detected.
111
+ * Skills with no requires are always included.
112
+ */
113
+ function matchesRequires(skillRequires, detectedFieldTypes) {
114
+ // No requires on skill = always include
115
+ if (!skillRequires || skillRequires.length === 0) {
116
+ return true;
117
+ }
118
+ // No detected field types = exclude skills with requires
119
+ if (!detectedFieldTypes || detectedFieldTypes.length === 0) {
120
+ return false;
121
+ }
122
+ // Check if at least one required field type is detected
123
+ const normalizedDetected = new Set(detectedFieldTypes.map((f) => f.toLowerCase()));
124
+ return skillRequires.some((required) => normalizedDetected.has(required.toLowerCase()));
125
+ }
126
+ /**
127
+ * Check if skill has at least one of the required tags.
128
+ * If no required tags in context, all skills pass.
129
+ */
130
+ function matchesRequiredTags(skillTags, requiredTags) {
131
+ // No required tags in context = all skills pass
132
+ if (!requiredTags || requiredTags.length === 0) {
133
+ return true;
134
+ }
135
+ // Required tags but skill has no tags = fail
136
+ if (!skillTags || skillTags.length === 0) {
137
+ return false;
138
+ }
139
+ // Check if skill has at least one required tag
140
+ const normalizedSkillTags = new Set(skillTags.map((t) => t.toLowerCase()));
141
+ return requiredTags.some((tag) => normalizedSkillTags.has(tag.toLowerCase()));
142
+ }
143
+ /**
144
+ * Check if skill has none of the excluded tags.
145
+ * If no excluded tags in context, all skills pass.
146
+ */
147
+ function matchesExcludedTags(skillTags, excludedTags) {
148
+ // No excluded tags in context = all skills pass
149
+ if (!excludedTags || excludedTags.length === 0) {
150
+ return true;
151
+ }
152
+ // No tags on skill = can't match excluded tags, so pass
153
+ if (!skillTags || skillTags.length === 0) {
154
+ return true;
155
+ }
156
+ // Check if skill has any excluded tag (if so, fail)
157
+ const normalizedSkillTags = new Set(skillTags.map((t) => t.toLowerCase()));
158
+ return !excludedTags.some((tag) => normalizedSkillTags.has(tag.toLowerCase()));
159
+ }
160
+ //# sourceMappingURL=filter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filter.js","sourceRoot":"","sources":["../src/filter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * @magnolia/skill-loader
3
+ *
4
+ * A Node.js library for loading, filtering, and managing AI prompt skills.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * import { SkillLoader, createSkill } from '@magnolia/skill-loader';
9
+ *
10
+ * const loader = new SkillLoader()
11
+ * .addDirectory('./skills');
12
+ *
13
+ * const skills = await loader.load({
14
+ * target: 'freemarker',
15
+ * version: '6.3.0',
16
+ * detectedFieldTypes: ['damLinkField'],
17
+ * });
18
+ *
19
+ * const prompt = await loader.getPrompt({ target: 'freemarker' });
20
+ * ```
21
+ *
22
+ * @packageDocumentation
23
+ */
24
+ export { SkillLoader, loadSkills } from './loader.js';
25
+ export { SkillManager } from './manager.js';
26
+ export type { Skill, SkillMetadata, SkillContext, SkillSource, SkillLoaderOptions, PromptOptions, } from './types.js';
27
+ export type { SkillManagerOptions, SkillDirectory, SkillInfo, SkillManagerLogger, } from './manager.js';
28
+ export { SkillLoaderError } from './types.js';
29
+ export { parseSkillFile, createSkill } from './parser.js';
30
+ export { filterSkills, matchesContext } from './filter.js';
31
+ export { loadSkillsFromDirectory } from './sources/directory.js';
32
+ export { loadSkillFromFile } from './sources/file.js';
33
+ export { loadSkillsFromUrl } from './sources/url.js';
34
+ export { processInlineSkills } from './sources/inline.js';
35
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAG5C,YAAY,EACV,KAAK,EACL,aAAa,EACb,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,aAAa,GACd,MAAM,YAAY,CAAC;AAEpB,YAAY,EACV,mBAAmB,EACnB,cAAc,EACd,SAAS,EACT,kBAAkB,GACnB,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAG9C,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG1D,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAG3D,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,38 @@
1
+ /**
2
+ * @magnolia/skill-loader
3
+ *
4
+ * A Node.js library for loading, filtering, and managing AI prompt skills.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * import { SkillLoader, createSkill } from '@magnolia/skill-loader';
9
+ *
10
+ * const loader = new SkillLoader()
11
+ * .addDirectory('./skills');
12
+ *
13
+ * const skills = await loader.load({
14
+ * target: 'freemarker',
15
+ * version: '6.3.0',
16
+ * detectedFieldTypes: ['damLinkField'],
17
+ * });
18
+ *
19
+ * const prompt = await loader.getPrompt({ target: 'freemarker' });
20
+ * ```
21
+ *
22
+ * @packageDocumentation
23
+ */
24
+ // Main classes
25
+ export { SkillLoader, loadSkills } from './loader.js';
26
+ export { SkillManager } from './manager.js';
27
+ // Error class (not a type-only export)
28
+ export { SkillLoaderError } from './types.js';
29
+ // Parser functions
30
+ export { parseSkillFile, createSkill } from './parser.js';
31
+ // Filter functions
32
+ export { filterSkills, matchesContext } from './filter.js';
33
+ // Source loaders (for advanced usage)
34
+ export { loadSkillsFromDirectory } from './sources/directory.js';
35
+ export { loadSkillFromFile } from './sources/file.js';
36
+ export { loadSkillsFromUrl } from './sources/url.js';
37
+ export { processInlineSkills } from './sources/inline.js';
38
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,eAAe;AACf,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAmB5C,uCAAuC;AACvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE9C,mBAAmB;AACnB,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1D,mBAAmB;AACnB,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE3D,sCAAsC;AACtC,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC"}