@frontmcp/skills 0.0.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/LICENSE +201 -0
- package/README.md +135 -0
- package/catalog/TEMPLATE.md +49 -0
- package/catalog/adapters/create-adapter/SKILL.md +127 -0
- package/catalog/adapters/official-adapters/SKILL.md +136 -0
- package/catalog/auth/configure-auth/SKILL.md +250 -0
- package/catalog/auth/configure-auth/references/auth-modes.md +77 -0
- package/catalog/auth/configure-session/SKILL.md +201 -0
- package/catalog/config/configure-elicitation/SKILL.md +136 -0
- package/catalog/config/configure-http/SKILL.md +167 -0
- package/catalog/config/configure-throttle/SKILL.md +189 -0
- package/catalog/config/configure-throttle/references/guard-config.md +68 -0
- package/catalog/config/configure-transport/SKILL.md +151 -0
- package/catalog/config/configure-transport/references/protocol-presets.md +57 -0
- package/catalog/deployment/build-for-browser/SKILL.md +95 -0
- package/catalog/deployment/build-for-cli/SKILL.md +100 -0
- package/catalog/deployment/build-for-sdk/SKILL.md +218 -0
- package/catalog/deployment/deploy-to-cloudflare/SKILL.md +192 -0
- package/catalog/deployment/deploy-to-lambda/SKILL.md +304 -0
- package/catalog/deployment/deploy-to-node/SKILL.md +229 -0
- package/catalog/deployment/deploy-to-node/references/Dockerfile.example +45 -0
- package/catalog/deployment/deploy-to-vercel/SKILL.md +196 -0
- package/catalog/deployment/deploy-to-vercel/references/vercel.json.example +60 -0
- package/catalog/development/create-agent/SKILL.md +563 -0
- package/catalog/development/create-agent/references/llm-config.md +46 -0
- package/catalog/development/create-job/SKILL.md +566 -0
- package/catalog/development/create-prompt/SKILL.md +400 -0
- package/catalog/development/create-provider/SKILL.md +233 -0
- package/catalog/development/create-resource/SKILL.md +437 -0
- package/catalog/development/create-skill/SKILL.md +526 -0
- package/catalog/development/create-skill-with-tools/SKILL.md +579 -0
- package/catalog/development/create-tool/SKILL.md +418 -0
- package/catalog/development/create-tool/references/output-schema-types.md +56 -0
- package/catalog/development/create-tool/references/tool-annotations.md +34 -0
- package/catalog/development/create-workflow/SKILL.md +709 -0
- package/catalog/development/decorators-guide/SKILL.md +598 -0
- package/catalog/plugins/create-plugin/SKILL.md +336 -0
- package/catalog/plugins/create-plugin-hooks/SKILL.md +282 -0
- package/catalog/plugins/official-plugins/SKILL.md +667 -0
- package/catalog/setup/frontmcp-skills-usage/SKILL.md +200 -0
- package/catalog/setup/multi-app-composition/SKILL.md +358 -0
- package/catalog/setup/nx-workflow/SKILL.md +357 -0
- package/catalog/setup/project-structure-nx/SKILL.md +186 -0
- package/catalog/setup/project-structure-standalone/SKILL.md +153 -0
- package/catalog/setup/setup-project/SKILL.md +493 -0
- package/catalog/setup/setup-redis/SKILL.md +385 -0
- package/catalog/setup/setup-sqlite/SKILL.md +359 -0
- package/catalog/skills-manifest.json +414 -0
- package/catalog/testing/setup-testing/SKILL.md +539 -0
- package/catalog/testing/setup-testing/references/test-auth.md +88 -0
- package/catalog/testing/setup-testing/references/test-browser-build.md +57 -0
- package/catalog/testing/setup-testing/references/test-cli-binary.md +48 -0
- package/catalog/testing/setup-testing/references/test-direct-client.md +62 -0
- package/catalog/testing/setup-testing/references/test-e2e-handler.md +51 -0
- package/catalog/testing/setup-testing/references/test-tool-unit.md +41 -0
- package/package.json +34 -0
- package/src/index.d.ts +3 -0
- package/src/index.js +16 -0
- package/src/index.js.map +1 -0
- package/src/loader.d.ts +46 -0
- package/src/loader.js +75 -0
- package/src/loader.js.map +1 -0
- package/src/manifest.d.ts +81 -0
- package/src/manifest.js +26 -0
- package/src/manifest.js.map +1 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Testing CLI Binary / SEA Build
|
|
2
|
+
|
|
3
|
+
After building with `frontmcp build --target cli`, test the binary:
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
import { execSync, spawn } from 'child_process';
|
|
7
|
+
import * as path from 'path';
|
|
8
|
+
|
|
9
|
+
const BINARY = path.resolve(__dirname, '../dist/my-server');
|
|
10
|
+
|
|
11
|
+
describe('CLI Binary', () => {
|
|
12
|
+
it('should start and respond to health check', async () => {
|
|
13
|
+
const child = spawn(BINARY, [], {
|
|
14
|
+
env: { ...process.env, PORT: '0' },
|
|
15
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
// Wait for server to start
|
|
19
|
+
await new Promise<void>((resolve) => {
|
|
20
|
+
child.stdout.on('data', (data: Buffer) => {
|
|
21
|
+
if (data.toString().includes('listening')) resolve();
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Test health endpoint
|
|
26
|
+
const res = await fetch('http://localhost:3001/health');
|
|
27
|
+
expect(res.ok).toBe(true);
|
|
28
|
+
|
|
29
|
+
child.kill();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should exit with code 0 on --help', () => {
|
|
33
|
+
const output = execSync(`${BINARY} --help`, { encoding: 'utf-8' });
|
|
34
|
+
expect(output).toContain('Usage');
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Testing JS Bundle
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
describe('JS Bundle', () => {
|
|
43
|
+
it('should be importable', async () => {
|
|
44
|
+
const mod = await import('../dist/my-server.cjs.js');
|
|
45
|
+
expect(mod).toBeDefined();
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
```
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Testing with Direct Client (No HTTP)
|
|
2
|
+
|
|
3
|
+
Uses `connect()` or `create()` for in-memory testing without HTTP overhead.
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
import { create, connectOpenAI } from '@frontmcp/sdk';
|
|
7
|
+
import { tool } from '@frontmcp/sdk';
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
|
|
10
|
+
const AddTool = tool({
|
|
11
|
+
name: 'add',
|
|
12
|
+
description: 'Add numbers',
|
|
13
|
+
inputSchema: { a: z.number(), b: z.number() },
|
|
14
|
+
outputSchema: { sum: z.number() },
|
|
15
|
+
})((input) => ({ sum: input.a + input.b }));
|
|
16
|
+
|
|
17
|
+
describe('Direct Client Testing', () => {
|
|
18
|
+
it('should call tools via create()', async () => {
|
|
19
|
+
const server = await create({
|
|
20
|
+
info: { name: 'test', version: '1.0.0' },
|
|
21
|
+
tools: [AddTool],
|
|
22
|
+
cacheKey: 'test-direct',
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const result = await server.callTool('add', { a: 2, b: 3 });
|
|
26
|
+
expect(result.content[0].text).toContain('5');
|
|
27
|
+
|
|
28
|
+
await server.dispose();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should return OpenAI-formatted tools', async () => {
|
|
32
|
+
const client = await connectOpenAI({
|
|
33
|
+
info: { name: 'test', version: '1.0.0' },
|
|
34
|
+
tools: [AddTool],
|
|
35
|
+
serve: false,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const tools = await client.listTools();
|
|
39
|
+
// OpenAI format: [{ type: 'function', function: { name, parameters } }]
|
|
40
|
+
expect(tools[0].type).toBe('function');
|
|
41
|
+
expect(tools[0].function.name).toBe('add');
|
|
42
|
+
|
|
43
|
+
await client.close();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should return Claude-formatted tools', async () => {
|
|
47
|
+
const { connectClaude } = await import('@frontmcp/sdk');
|
|
48
|
+
const client = await connectClaude({
|
|
49
|
+
info: { name: 'test', version: '1.0.0' },
|
|
50
|
+
tools: [AddTool],
|
|
51
|
+
serve: false,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const tools = await client.listTools();
|
|
55
|
+
// Claude format: [{ name, description, input_schema }]
|
|
56
|
+
expect(tools[0].name).toBe('add');
|
|
57
|
+
expect(tools[0].input_schema).toBeDefined();
|
|
58
|
+
|
|
59
|
+
await client.close();
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
```
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# E2E Testing with McpTestClient (HTTP Handler)
|
|
2
|
+
|
|
3
|
+
Tests the full MCP protocol over HTTP — validates tools, resources, prompts end-to-end.
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
import { McpTestClient, TestServer } from '@frontmcp/testing';
|
|
7
|
+
import Server from '../src/main';
|
|
8
|
+
|
|
9
|
+
describe('Server E2E', () => {
|
|
10
|
+
let client: McpTestClient;
|
|
11
|
+
let server: TestServer;
|
|
12
|
+
|
|
13
|
+
beforeAll(async () => {
|
|
14
|
+
server = await TestServer.create(Server);
|
|
15
|
+
client = await server.connect();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
afterAll(async () => {
|
|
19
|
+
await client.close();
|
|
20
|
+
await server.dispose();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('should list all tools', async () => {
|
|
24
|
+
const { tools } = await client.listTools();
|
|
25
|
+
expect(tools.length).toBeGreaterThan(0);
|
|
26
|
+
expect(tools).toContainTool('add_numbers');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('should call a tool and get result', async () => {
|
|
30
|
+
const result = await client.callTool('add_numbers', { a: 5, b: 3 });
|
|
31
|
+
expect(result).toBeSuccessful();
|
|
32
|
+
expect(result.content[0].text).toContain('8');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should return error for invalid input', async () => {
|
|
36
|
+
const result = await client.callTool('add_numbers', { a: 'bad' });
|
|
37
|
+
expect(result.isError).toBe(true);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should list resources', async () => {
|
|
41
|
+
const { resources } = await client.listResources();
|
|
42
|
+
expect(resources.length).toBeGreaterThanOrEqual(0);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('should get a prompt', async () => {
|
|
46
|
+
const result = await client.getPrompt('summarize', { topic: 'testing' });
|
|
47
|
+
expect(result.messages).toBeDefined();
|
|
48
|
+
expect(result.messages.length).toBeGreaterThan(0);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
```
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Unit Testing a Tool
|
|
2
|
+
|
|
3
|
+
```typescript
|
|
4
|
+
import { ToolContext } from '@frontmcp/sdk';
|
|
5
|
+
import { AddTool } from '../tools/add.tool';
|
|
6
|
+
|
|
7
|
+
describe('AddTool', () => {
|
|
8
|
+
it('should add two numbers', async () => {
|
|
9
|
+
// Create mock context
|
|
10
|
+
const ctx = {
|
|
11
|
+
get: jest.fn(),
|
|
12
|
+
tryGet: jest.fn(),
|
|
13
|
+
fail: jest.fn((err) => {
|
|
14
|
+
throw err;
|
|
15
|
+
}),
|
|
16
|
+
mark: jest.fn(),
|
|
17
|
+
notify: jest.fn(),
|
|
18
|
+
respondProgress: jest.fn(),
|
|
19
|
+
} as unknown as ToolContext;
|
|
20
|
+
|
|
21
|
+
const tool = new AddTool();
|
|
22
|
+
Object.assign(tool, ctx);
|
|
23
|
+
|
|
24
|
+
const result = await tool.execute({ a: 2, b: 3 });
|
|
25
|
+
expect(result).toEqual({ sum: 5 });
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('should handle negative numbers', async () => {
|
|
29
|
+
const tool = new AddTool();
|
|
30
|
+
const result = await tool.execute({ a: -1, b: -2 });
|
|
31
|
+
expect(result).toEqual({ sum: -3 });
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should throw on invalid input', async () => {
|
|
35
|
+
const tool = new AddTool();
|
|
36
|
+
// Zod validates before execute — test the schema separately
|
|
37
|
+
const schema = z.object({ a: z.number(), b: z.number() });
|
|
38
|
+
expect(() => schema.parse({ a: 'not-a-number' })).toThrow();
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
```
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@frontmcp/skills",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Curated skills catalog for FrontMCP projects",
|
|
5
|
+
"author": "AgentFront <info@agentfront.dev>",
|
|
6
|
+
"homepage": "https://docs.agentfront.dev",
|
|
7
|
+
"license": "Apache-2.0",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"skills",
|
|
10
|
+
"mcp",
|
|
11
|
+
"agentfront",
|
|
12
|
+
"frontmcp",
|
|
13
|
+
"catalog",
|
|
14
|
+
"agent-skills",
|
|
15
|
+
"typescript"
|
|
16
|
+
],
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/agentfront/frontmcp.git",
|
|
20
|
+
"directory": "libs/skills"
|
|
21
|
+
},
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/agentfront/frontmcp/issues"
|
|
24
|
+
},
|
|
25
|
+
"main": "./src/index.js",
|
|
26
|
+
"types": "./index.d.js",
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=22.0.0"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"tslib": "^2.3.0"
|
|
32
|
+
},
|
|
33
|
+
"type": "commonjs"
|
|
34
|
+
}
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export type { SkillCatalogEntry, SkillManifest, SkillTarget, SkillCategory, SkillBundle, SkillDestination, SkillMergeStrategy, SkillInstallConfig, } from './manifest';
|
|
2
|
+
export { VALID_TARGETS, VALID_CATEGORIES, VALID_BUNDLES } from './manifest';
|
|
3
|
+
export { loadManifest, getSkillsByTarget, getSkillsByCategory, getSkillsByBundle, getInstructionOnlySkills, getResourceSkills, resolveSkillPath, } from './loader';
|
package/src/index.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveSkillPath = exports.getResourceSkills = exports.getInstructionOnlySkills = exports.getSkillsByBundle = exports.getSkillsByCategory = exports.getSkillsByTarget = exports.loadManifest = exports.VALID_BUNDLES = exports.VALID_CATEGORIES = exports.VALID_TARGETS = void 0;
|
|
4
|
+
var manifest_1 = require("./manifest");
|
|
5
|
+
Object.defineProperty(exports, "VALID_TARGETS", { enumerable: true, get: function () { return manifest_1.VALID_TARGETS; } });
|
|
6
|
+
Object.defineProperty(exports, "VALID_CATEGORIES", { enumerable: true, get: function () { return manifest_1.VALID_CATEGORIES; } });
|
|
7
|
+
Object.defineProperty(exports, "VALID_BUNDLES", { enumerable: true, get: function () { return manifest_1.VALID_BUNDLES; } });
|
|
8
|
+
var loader_1 = require("./loader");
|
|
9
|
+
Object.defineProperty(exports, "loadManifest", { enumerable: true, get: function () { return loader_1.loadManifest; } });
|
|
10
|
+
Object.defineProperty(exports, "getSkillsByTarget", { enumerable: true, get: function () { return loader_1.getSkillsByTarget; } });
|
|
11
|
+
Object.defineProperty(exports, "getSkillsByCategory", { enumerable: true, get: function () { return loader_1.getSkillsByCategory; } });
|
|
12
|
+
Object.defineProperty(exports, "getSkillsByBundle", { enumerable: true, get: function () { return loader_1.getSkillsByBundle; } });
|
|
13
|
+
Object.defineProperty(exports, "getInstructionOnlySkills", { enumerable: true, get: function () { return loader_1.getInstructionOnlySkills; } });
|
|
14
|
+
Object.defineProperty(exports, "getResourceSkills", { enumerable: true, get: function () { return loader_1.getResourceSkills; } });
|
|
15
|
+
Object.defineProperty(exports, "resolveSkillPath", { enumerable: true, get: function () { return loader_1.resolveSkillPath; } });
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
package/src/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAWA,uCAA4E;AAAnE,yGAAA,aAAa,OAAA;AAAE,4GAAA,gBAAgB,OAAA;AAAE,yGAAA,aAAa,OAAA;AAEvD,mCAQkB;AAPhB,sGAAA,YAAY,OAAA;AACZ,2GAAA,iBAAiB,OAAA;AACjB,6GAAA,mBAAmB,OAAA;AACnB,2GAAA,iBAAiB,OAAA;AACjB,kHAAA,wBAAwB,OAAA;AACxB,2GAAA,iBAAiB,OAAA;AACjB,0GAAA,gBAAgB,OAAA","sourcesContent":["export type {\n SkillCatalogEntry,\n SkillManifest,\n SkillTarget,\n SkillCategory,\n SkillBundle,\n SkillDestination,\n SkillMergeStrategy,\n SkillInstallConfig,\n} from './manifest';\n\nexport { VALID_TARGETS, VALID_CATEGORIES, VALID_BUNDLES } from './manifest';\n\nexport {\n loadManifest,\n getSkillsByTarget,\n getSkillsByCategory,\n getSkillsByBundle,\n getInstructionOnlySkills,\n getResourceSkills,\n resolveSkillPath,\n} from './loader';\n"]}
|
package/src/loader.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skills catalog loader and filtering helpers.
|
|
3
|
+
*
|
|
4
|
+
* Provides functions to query the catalog manifest by target, category, and bundle.
|
|
5
|
+
*
|
|
6
|
+
* @module skills/loader
|
|
7
|
+
*/
|
|
8
|
+
import type { SkillCatalogEntry, SkillManifest } from './manifest';
|
|
9
|
+
/**
|
|
10
|
+
* Load the skills manifest from the catalog directory.
|
|
11
|
+
*
|
|
12
|
+
* @param catalogDir - Absolute path to the catalog directory. Defaults to the bundled catalog.
|
|
13
|
+
* @returns The parsed skills manifest
|
|
14
|
+
*/
|
|
15
|
+
export declare function loadManifest(catalogDir?: string): SkillManifest;
|
|
16
|
+
/**
|
|
17
|
+
* Filter skills by deployment target.
|
|
18
|
+
* Returns skills that include the given target or 'all'.
|
|
19
|
+
*/
|
|
20
|
+
export declare function getSkillsByTarget(skills: SkillCatalogEntry[], target: string): SkillCatalogEntry[];
|
|
21
|
+
/**
|
|
22
|
+
* Filter skills by category.
|
|
23
|
+
*/
|
|
24
|
+
export declare function getSkillsByCategory(skills: SkillCatalogEntry[], category: string): SkillCatalogEntry[];
|
|
25
|
+
/**
|
|
26
|
+
* Filter skills by bundle membership.
|
|
27
|
+
*/
|
|
28
|
+
export declare function getSkillsByBundle(skills: SkillCatalogEntry[], bundle: string): SkillCatalogEntry[];
|
|
29
|
+
/**
|
|
30
|
+
* Get only instruction-only skills (no scripts/, references/, or assets/ directories).
|
|
31
|
+
* These are safe to use with `instructions: { file: ... }` wrappers.
|
|
32
|
+
*/
|
|
33
|
+
export declare function getInstructionOnlySkills(skills: SkillCatalogEntry[]): SkillCatalogEntry[];
|
|
34
|
+
/**
|
|
35
|
+
* Get only resource-carrying skills (have scripts/, references/, or assets/).
|
|
36
|
+
* These need full directory loading via `skillDir()`.
|
|
37
|
+
*/
|
|
38
|
+
export declare function getResourceSkills(skills: SkillCatalogEntry[]): SkillCatalogEntry[];
|
|
39
|
+
/**
|
|
40
|
+
* Resolve the absolute path to a skill directory.
|
|
41
|
+
*
|
|
42
|
+
* @param entry - The catalog entry
|
|
43
|
+
* @param catalogDir - Absolute path to the catalog directory
|
|
44
|
+
* @returns Absolute path to the skill directory
|
|
45
|
+
*/
|
|
46
|
+
export declare function resolveSkillPath(entry: SkillCatalogEntry, catalogDir?: string): string;
|
package/src/loader.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Skills catalog loader and filtering helpers.
|
|
4
|
+
*
|
|
5
|
+
* Provides functions to query the catalog manifest by target, category, and bundle.
|
|
6
|
+
*
|
|
7
|
+
* @module skills/loader
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.loadManifest = loadManifest;
|
|
11
|
+
exports.getSkillsByTarget = getSkillsByTarget;
|
|
12
|
+
exports.getSkillsByCategory = getSkillsByCategory;
|
|
13
|
+
exports.getSkillsByBundle = getSkillsByBundle;
|
|
14
|
+
exports.getInstructionOnlySkills = getInstructionOnlySkills;
|
|
15
|
+
exports.getResourceSkills = getResourceSkills;
|
|
16
|
+
exports.resolveSkillPath = resolveSkillPath;
|
|
17
|
+
const tslib_1 = require("tslib");
|
|
18
|
+
const path = tslib_1.__importStar(require("node:path"));
|
|
19
|
+
/**
|
|
20
|
+
* Load the skills manifest from the catalog directory.
|
|
21
|
+
*
|
|
22
|
+
* @param catalogDir - Absolute path to the catalog directory. Defaults to the bundled catalog.
|
|
23
|
+
* @returns The parsed skills manifest
|
|
24
|
+
*/
|
|
25
|
+
function loadManifest(catalogDir) {
|
|
26
|
+
const dir = catalogDir ?? path.resolve(__dirname, '..', 'catalog');
|
|
27
|
+
const manifestPath = path.join(dir, 'skills-manifest.json');
|
|
28
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
29
|
+
return require(manifestPath);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Filter skills by deployment target.
|
|
33
|
+
* Returns skills that include the given target or 'all'.
|
|
34
|
+
*/
|
|
35
|
+
function getSkillsByTarget(skills, target) {
|
|
36
|
+
return skills.filter((s) => s.targets.includes('all') || s.targets.includes(target));
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Filter skills by category.
|
|
40
|
+
*/
|
|
41
|
+
function getSkillsByCategory(skills, category) {
|
|
42
|
+
return skills.filter((s) => s.category === category);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Filter skills by bundle membership.
|
|
46
|
+
*/
|
|
47
|
+
function getSkillsByBundle(skills, bundle) {
|
|
48
|
+
return skills.filter((s) => s.bundle?.includes(bundle));
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Get only instruction-only skills (no scripts/, references/, or assets/ directories).
|
|
52
|
+
* These are safe to use with `instructions: { file: ... }` wrappers.
|
|
53
|
+
*/
|
|
54
|
+
function getInstructionOnlySkills(skills) {
|
|
55
|
+
return skills.filter((s) => !s.hasResources);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Get only resource-carrying skills (have scripts/, references/, or assets/).
|
|
59
|
+
* These need full directory loading via `skillDir()`.
|
|
60
|
+
*/
|
|
61
|
+
function getResourceSkills(skills) {
|
|
62
|
+
return skills.filter((s) => s.hasResources);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Resolve the absolute path to a skill directory.
|
|
66
|
+
*
|
|
67
|
+
* @param entry - The catalog entry
|
|
68
|
+
* @param catalogDir - Absolute path to the catalog directory
|
|
69
|
+
* @returns Absolute path to the skill directory
|
|
70
|
+
*/
|
|
71
|
+
function resolveSkillPath(entry, catalogDir) {
|
|
72
|
+
const dir = catalogDir ?? path.resolve(__dirname, '..', 'catalog');
|
|
73
|
+
return path.resolve(dir, entry.path);
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/loader.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;AAWH,oCAKC;AAMD,8CAIC;AAKD,kDAEC;AAKD,8CAIC;AAMD,4DAEC;AAMD,8CAEC;AASD,4CAGC;;AApED,wDAAkC;AAGlC;;;;;GAKG;AACH,SAAgB,YAAY,CAAC,UAAmB;IAC9C,MAAM,GAAG,GAAG,UAAU,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;IACnE,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,sBAAsB,CAAC,CAAC;IAC5D,iEAAiE;IACjE,OAAO,OAAO,CAAC,YAAY,CAAkB,CAAC;AAChD,CAAC;AAED;;;GAGG;AACH,SAAgB,iBAAiB,CAAC,MAA2B,EAAE,MAAc;IAC3E,OAAO,MAAM,CAAC,MAAM,CAClB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,MAA8C,CAAC,CACvG,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAgB,mBAAmB,CAAC,MAA2B,EAAE,QAAgB;IAC/E,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC;AACvD,CAAC;AAED;;GAEG;AACH,SAAgB,iBAAiB,CAAC,MAA2B,EAAE,MAAc;IAC3E,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CACzB,CAAC,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAiF,CAAC,CACtG,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAgB,wBAAwB,CAAC,MAA2B;IAClE,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;AAC/C,CAAC;AAED;;;GAGG;AACH,SAAgB,iBAAiB,CAAC,MAA2B;IAC3D,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;AAC9C,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,gBAAgB,CAAC,KAAwB,EAAE,UAAmB;IAC5E,MAAM,GAAG,GAAG,UAAU,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;IACnE,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;AACvC,CAAC","sourcesContent":["/**\n * Skills catalog loader and filtering helpers.\n *\n * Provides functions to query the catalog manifest by target, category, and bundle.\n *\n * @module skills/loader\n */\n\nimport * as path from 'node:path';\nimport type { SkillCatalogEntry, SkillManifest } from './manifest';\n\n/**\n * Load the skills manifest from the catalog directory.\n *\n * @param catalogDir - Absolute path to the catalog directory. Defaults to the bundled catalog.\n * @returns The parsed skills manifest\n */\nexport function loadManifest(catalogDir?: string): SkillManifest {\n const dir = catalogDir ?? path.resolve(__dirname, '..', 'catalog');\n const manifestPath = path.join(dir, 'skills-manifest.json');\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n return require(manifestPath) as SkillManifest;\n}\n\n/**\n * Filter skills by deployment target.\n * Returns skills that include the given target or 'all'.\n */\nexport function getSkillsByTarget(skills: SkillCatalogEntry[], target: string): SkillCatalogEntry[] {\n return skills.filter(\n (s) => s.targets.includes('all') || s.targets.includes(target as SkillCatalogEntry['targets'][number]),\n );\n}\n\n/**\n * Filter skills by category.\n */\nexport function getSkillsByCategory(skills: SkillCatalogEntry[], category: string): SkillCatalogEntry[] {\n return skills.filter((s) => s.category === category);\n}\n\n/**\n * Filter skills by bundle membership.\n */\nexport function getSkillsByBundle(skills: SkillCatalogEntry[], bundle: string): SkillCatalogEntry[] {\n return skills.filter((s) =>\n s.bundle?.includes(bundle as SkillCatalogEntry['bundle'] extends (infer U)[] | undefined ? U : never),\n );\n}\n\n/**\n * Get only instruction-only skills (no scripts/, references/, or assets/ directories).\n * These are safe to use with `instructions: { file: ... }` wrappers.\n */\nexport function getInstructionOnlySkills(skills: SkillCatalogEntry[]): SkillCatalogEntry[] {\n return skills.filter((s) => !s.hasResources);\n}\n\n/**\n * Get only resource-carrying skills (have scripts/, references/, or assets/).\n * These need full directory loading via `skillDir()`.\n */\nexport function getResourceSkills(skills: SkillCatalogEntry[]): SkillCatalogEntry[] {\n return skills.filter((s) => s.hasResources);\n}\n\n/**\n * Resolve the absolute path to a skill directory.\n *\n * @param entry - The catalog entry\n * @param catalogDir - Absolute path to the catalog directory\n * @returns Absolute path to the skill directory\n */\nexport function resolveSkillPath(entry: SkillCatalogEntry, catalogDir?: string): string {\n const dir = catalogDir ?? path.resolve(__dirname, '..', 'catalog');\n return path.resolve(dir, entry.path);\n}\n"]}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skills catalog manifest types.
|
|
3
|
+
*
|
|
4
|
+
* Defines the contract between the catalog, scaffold tooling, and future installer.
|
|
5
|
+
*
|
|
6
|
+
* @module skills/manifest
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Supported deployment targets for skill filtering.
|
|
10
|
+
*/
|
|
11
|
+
export type SkillTarget = 'node' | 'vercel' | 'lambda' | 'cloudflare' | 'all';
|
|
12
|
+
/**
|
|
13
|
+
* Skill categories for organizing the catalog.
|
|
14
|
+
*/
|
|
15
|
+
export type SkillCategory = 'setup' | 'deployment' | 'development' | 'config' | 'auth' | 'plugins' | 'adapters' | 'testing';
|
|
16
|
+
/**
|
|
17
|
+
* Bundle membership for curated scaffold presets.
|
|
18
|
+
*/
|
|
19
|
+
export type SkillBundle = 'recommended' | 'minimal' | 'full';
|
|
20
|
+
/**
|
|
21
|
+
* Install destination types for future provider wiring.
|
|
22
|
+
*/
|
|
23
|
+
export type SkillDestination = 'project-local' | '.claude/skills' | 'codex' | 'gemini';
|
|
24
|
+
/**
|
|
25
|
+
* Merge strategy when installing a skill that already exists at the destination.
|
|
26
|
+
*/
|
|
27
|
+
export type SkillMergeStrategy = 'overwrite' | 'skip-existing';
|
|
28
|
+
/**
|
|
29
|
+
* Install configuration for a catalog skill.
|
|
30
|
+
*/
|
|
31
|
+
export interface SkillInstallConfig {
|
|
32
|
+
/** Where this skill can be installed */
|
|
33
|
+
destinations: SkillDestination[];
|
|
34
|
+
/** How to handle existing skills at the destination */
|
|
35
|
+
mergeStrategy: SkillMergeStrategy;
|
|
36
|
+
/** Other skills this depends on (by name) */
|
|
37
|
+
dependencies?: string[];
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* A single entry in the skills catalog manifest.
|
|
41
|
+
*
|
|
42
|
+
* This is the core contract connecting SKILL.md files to scaffolding,
|
|
43
|
+
* future installation, and provider-specific destinations.
|
|
44
|
+
*/
|
|
45
|
+
export interface SkillCatalogEntry {
|
|
46
|
+
/** Unique skill name — matches SKILL.md frontmatter `name` */
|
|
47
|
+
name: string;
|
|
48
|
+
/** Skill category for organization */
|
|
49
|
+
category: SkillCategory;
|
|
50
|
+
/** Short description */
|
|
51
|
+
description: string;
|
|
52
|
+
/** Path to the skill directory, relative to catalog/ */
|
|
53
|
+
path: string;
|
|
54
|
+
/** Deployment targets this skill applies to */
|
|
55
|
+
targets: SkillTarget[];
|
|
56
|
+
/** Whether the skill has scripts/, references/, or assets/ directories */
|
|
57
|
+
hasResources: boolean;
|
|
58
|
+
/** Target-specific storage defaults (e.g., { node: 'redis-docker', vercel: 'vercel-kv' }) */
|
|
59
|
+
storageDefault?: Record<string, string>;
|
|
60
|
+
/** Tags for secondary filtering and search */
|
|
61
|
+
tags: string[];
|
|
62
|
+
/** Bundle membership for scaffold presets */
|
|
63
|
+
bundle?: SkillBundle[];
|
|
64
|
+
/** Install configuration for future distribution */
|
|
65
|
+
install: SkillInstallConfig;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* The skills catalog manifest — single source of truth for scaffold and install tooling.
|
|
69
|
+
*/
|
|
70
|
+
export interface SkillManifest {
|
|
71
|
+
/** Manifest schema version */
|
|
72
|
+
version: 1;
|
|
73
|
+
/** All catalog skills */
|
|
74
|
+
skills: SkillCatalogEntry[];
|
|
75
|
+
}
|
|
76
|
+
/** Valid deployment targets for manifest validation */
|
|
77
|
+
export declare const VALID_TARGETS: readonly SkillTarget[];
|
|
78
|
+
/** Valid categories for manifest validation */
|
|
79
|
+
export declare const VALID_CATEGORIES: readonly SkillCategory[];
|
|
80
|
+
/** Valid bundles for manifest validation */
|
|
81
|
+
export declare const VALID_BUNDLES: readonly SkillBundle[];
|
package/src/manifest.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Skills catalog manifest types.
|
|
4
|
+
*
|
|
5
|
+
* Defines the contract between the catalog, scaffold tooling, and future installer.
|
|
6
|
+
*
|
|
7
|
+
* @module skills/manifest
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.VALID_BUNDLES = exports.VALID_CATEGORIES = exports.VALID_TARGETS = void 0;
|
|
11
|
+
/** Valid deployment targets for manifest validation */
|
|
12
|
+
exports.VALID_TARGETS = ['node', 'vercel', 'lambda', 'cloudflare', 'all'];
|
|
13
|
+
/** Valid categories for manifest validation */
|
|
14
|
+
exports.VALID_CATEGORIES = [
|
|
15
|
+
'setup',
|
|
16
|
+
'deployment',
|
|
17
|
+
'development',
|
|
18
|
+
'config',
|
|
19
|
+
'auth',
|
|
20
|
+
'plugins',
|
|
21
|
+
'adapters',
|
|
22
|
+
'testing',
|
|
23
|
+
];
|
|
24
|
+
/** Valid bundles for manifest validation */
|
|
25
|
+
exports.VALID_BUNDLES = ['recommended', 'minimal', 'full'];
|
|
26
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/manifest.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AAsFH,uDAAuD;AAC1C,QAAA,aAAa,GAA2B,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,KAAK,CAAC,CAAC;AAEvG,+CAA+C;AAClC,QAAA,gBAAgB,GAA6B;IACxD,OAAO;IACP,YAAY;IACZ,aAAa;IACb,QAAQ;IACR,MAAM;IACN,SAAS;IACT,UAAU;IACV,SAAS;CACV,CAAC;AAEF,4CAA4C;AAC/B,QAAA,aAAa,GAA2B,CAAC,aAAa,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC","sourcesContent":["/**\n * Skills catalog manifest types.\n *\n * Defines the contract between the catalog, scaffold tooling, and future installer.\n *\n * @module skills/manifest\n */\n\n/**\n * Supported deployment targets for skill filtering.\n */\nexport type SkillTarget = 'node' | 'vercel' | 'lambda' | 'cloudflare' | 'all';\n\n/**\n * Skill categories for organizing the catalog.\n */\nexport type SkillCategory =\n | 'setup'\n | 'deployment'\n | 'development'\n | 'config'\n | 'auth'\n | 'plugins'\n | 'adapters'\n | 'testing';\n\n/**\n * Bundle membership for curated scaffold presets.\n */\nexport type SkillBundle = 'recommended' | 'minimal' | 'full';\n\n/**\n * Install destination types for future provider wiring.\n */\nexport type SkillDestination = 'project-local' | '.claude/skills' | 'codex' | 'gemini';\n\n/**\n * Merge strategy when installing a skill that already exists at the destination.\n */\nexport type SkillMergeStrategy = 'overwrite' | 'skip-existing';\n\n/**\n * Install configuration for a catalog skill.\n */\nexport interface SkillInstallConfig {\n /** Where this skill can be installed */\n destinations: SkillDestination[];\n /** How to handle existing skills at the destination */\n mergeStrategy: SkillMergeStrategy;\n /** Other skills this depends on (by name) */\n dependencies?: string[];\n}\n\n/**\n * A single entry in the skills catalog manifest.\n *\n * This is the core contract connecting SKILL.md files to scaffolding,\n * future installation, and provider-specific destinations.\n */\nexport interface SkillCatalogEntry {\n /** Unique skill name — matches SKILL.md frontmatter `name` */\n name: string;\n /** Skill category for organization */\n category: SkillCategory;\n /** Short description */\n description: string;\n /** Path to the skill directory, relative to catalog/ */\n path: string;\n /** Deployment targets this skill applies to */\n targets: SkillTarget[];\n /** Whether the skill has scripts/, references/, or assets/ directories */\n hasResources: boolean;\n /** Target-specific storage defaults (e.g., { node: 'redis-docker', vercel: 'vercel-kv' }) */\n storageDefault?: Record<string, string>;\n /** Tags for secondary filtering and search */\n tags: string[];\n /** Bundle membership for scaffold presets */\n bundle?: SkillBundle[];\n /** Install configuration for future distribution */\n install: SkillInstallConfig;\n}\n\n/**\n * The skills catalog manifest — single source of truth for scaffold and install tooling.\n */\nexport interface SkillManifest {\n /** Manifest schema version */\n version: 1;\n /** All catalog skills */\n skills: SkillCatalogEntry[];\n}\n\n/** Valid deployment targets for manifest validation */\nexport const VALID_TARGETS: readonly SkillTarget[] = ['node', 'vercel', 'lambda', 'cloudflare', 'all'];\n\n/** Valid categories for manifest validation */\nexport const VALID_CATEGORIES: readonly SkillCategory[] = [\n 'setup',\n 'deployment',\n 'development',\n 'config',\n 'auth',\n 'plugins',\n 'adapters',\n 'testing',\n];\n\n/** Valid bundles for manifest validation */\nexport const VALID_BUNDLES: readonly SkillBundle[] = ['recommended', 'minimal', 'full'];\n"]}
|