frontmcp 1.0.0-beta.10 → 1.0.0-beta.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/commands/skills/catalog.d.ts +2 -0
- package/src/commands/skills/catalog.js +14 -2
- package/src/commands/skills/catalog.js.map +1 -1
- package/src/commands/skills/install.js +44 -0
- package/src/commands/skills/install.js.map +1 -1
- package/src/commands/skills/read.d.ts +4 -0
- package/src/commands/skills/read.js +126 -0
- package/src/commands/skills/read.js.map +1 -0
- package/src/commands/skills/register.js +8 -6
- package/src/commands/skills/register.js.map +1 -1
- package/src/commands/skills/search.js +1 -1
- package/src/commands/skills/search.js.map +1 -1
- package/src/core/colors.js +9 -1
- package/src/core/colors.js.map +1 -1
- package/src/core/help.d.ts +2 -2
- package/src/core/help.js +82 -41
- package/src/core/help.js.map +1 -1
- package/src/core/program.js +4 -1
- package/src/core/program.js.map +1 -1
- package/src/commands/skills/show.d.ts +0 -1
- package/src/commands/skills/show.js +0 -46
- package/src/commands/skills/show.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "frontmcp",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.12",
|
|
4
4
|
"description": "FrontMCP command line interface",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"homepage": "https://docs.agentfront.dev",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@clack/prompts": "^0.10.0",
|
|
33
|
-
"@frontmcp/utils": "1.0.0-beta.
|
|
33
|
+
"@frontmcp/utils": "1.0.0-beta.12",
|
|
34
34
|
"commander": "^13.0.0",
|
|
35
35
|
"tslib": "^2.3.0",
|
|
36
36
|
"vectoriadb": "^2.1.3",
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Uses vectoriadb's TFIDFVectoria for proper TF-IDF similarity search with
|
|
5
5
|
* weighted document fields: description 3x, tags 2x, name 1x, category 1x.
|
|
6
6
|
*/
|
|
7
|
+
import type { SkillReferenceEntry } from '@frontmcp/skills';
|
|
7
8
|
interface SkillEntry {
|
|
8
9
|
name: string;
|
|
9
10
|
category: string;
|
|
@@ -13,6 +14,7 @@ interface SkillEntry {
|
|
|
13
14
|
hasResources: boolean;
|
|
14
15
|
tags: string[];
|
|
15
16
|
bundle?: string[];
|
|
17
|
+
references?: SkillReferenceEntry[];
|
|
16
18
|
}
|
|
17
19
|
interface SkillManifest {
|
|
18
20
|
version: number;
|
|
@@ -169,7 +169,6 @@ function loadCatalog() {
|
|
|
169
169
|
function resolveManifestPath() {
|
|
170
170
|
// Primary: resolve directly from the @frontmcp/skills package
|
|
171
171
|
try {
|
|
172
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
173
172
|
return require.resolve('@frontmcp/skills/catalog/skills-manifest.json');
|
|
174
173
|
}
|
|
175
174
|
catch {
|
|
@@ -177,7 +176,6 @@ function resolveManifestPath() {
|
|
|
177
176
|
}
|
|
178
177
|
// Fallback: find the package root and navigate to catalog/
|
|
179
178
|
try {
|
|
180
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
181
179
|
const pkgJsonPath = require.resolve('@frontmcp/skills/package.json');
|
|
182
180
|
const pkgRoot = path.dirname(pkgJsonPath);
|
|
183
181
|
const manifestPath = path.join(pkgRoot, 'catalog', 'skills-manifest.json');
|
|
@@ -248,6 +246,20 @@ function buildSearchableText(skill) {
|
|
|
248
246
|
}
|
|
249
247
|
// Category (1x weight)
|
|
250
248
|
parts.push(skill.category);
|
|
249
|
+
// Reference names and descriptions (1x weight each)
|
|
250
|
+
if (skill.references) {
|
|
251
|
+
for (const ref of skill.references) {
|
|
252
|
+
const refNameParts = ref.name.split(/[-_.\s]/).filter(Boolean);
|
|
253
|
+
parts.push(...refNameParts);
|
|
254
|
+
if (ref.description) {
|
|
255
|
+
const refTerms = ref.description
|
|
256
|
+
.toLowerCase()
|
|
257
|
+
.split(/\s+/)
|
|
258
|
+
.filter((word) => word.length >= 4 && !STOP_WORDS.has(word));
|
|
259
|
+
parts.push(...refTerms);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
251
263
|
return parts.join(' ');
|
|
252
264
|
}
|
|
253
265
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../../../src/commands/skills/catalog.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Catalog loader and TF-IDF search engine for skills.\n *\n * Uses vectoriadb's TFIDFVectoria for proper TF-IDF similarity search with\n * weighted document fields: description 3x, tags 2x, name 1x, category 1x.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { TFIDFVectoria } from 'vectoriadb';\n\ninterface SkillEntry {\n name: string;\n category: string;\n description: string;\n path: string;\n targets: string[];\n hasResources: boolean;\n tags: string[];\n bundle?: string[];\n}\n\ninterface SkillManifest {\n version: number;\n skills: SkillEntry[];\n}\n\nexport interface SearchResult {\n skill: SkillEntry;\n score: number;\n}\n\ninterface SkillDocMetadata {\n id: string;\n skill: SkillEntry;\n}\n\nconst STOP_WORDS = new Set([\n // Articles & determiners\n 'the',\n 'a',\n 'an',\n 'this',\n 'that',\n 'these',\n 'those',\n 'each',\n 'every',\n 'some',\n 'any',\n 'no',\n // Conjunctions & prepositions\n 'and',\n 'or',\n 'but',\n 'nor',\n 'for',\n 'yet',\n 'so',\n 'with',\n 'from',\n 'into',\n 'onto',\n 'about',\n 'by',\n 'at',\n 'in',\n 'on',\n 'to',\n 'of',\n 'as',\n 'if',\n 'than',\n 'then',\n 'between',\n 'through',\n 'after',\n 'before',\n 'during',\n 'without',\n 'within',\n 'along',\n 'across',\n 'against',\n 'under',\n 'over',\n 'above',\n 'below',\n // Pronouns\n 'your',\n 'you',\n 'it',\n 'its',\n 'we',\n 'our',\n 'they',\n 'them',\n 'their',\n 'he',\n 'she',\n 'his',\n 'her',\n 'who',\n 'which',\n 'what',\n 'where',\n 'when',\n 'how',\n 'why',\n // Verbs (auxiliary / common)\n 'is',\n 'am',\n 'are',\n 'was',\n 'were',\n 'be',\n 'been',\n 'being',\n 'have',\n 'has',\n 'had',\n 'having',\n 'do',\n 'does',\n 'did',\n 'will',\n 'would',\n 'shall',\n 'should',\n 'may',\n 'might',\n 'must',\n 'can',\n 'could',\n 'need',\n 'use',\n 'using',\n 'used',\n // Adverbs & modifiers\n 'not',\n 'very',\n 'also',\n 'just',\n 'only',\n 'more',\n 'most',\n 'less',\n 'well',\n 'even',\n 'still',\n 'already',\n 'always',\n 'never',\n 'often',\n 'too',\n 'here',\n 'there',\n 'now',\n // Common filler\n 'all',\n 'both',\n 'other',\n 'another',\n 'such',\n 'like',\n 'get',\n 'set',\n 'new',\n 'make',\n 'see',\n 'way',\n 'etc',\n 'via',\n]);\n\nlet cachedManifest: SkillManifest | undefined;\nlet cachedIndex: TFIDFVectoria<SkillDocMetadata> | undefined;\n\n/**\n * Load the catalog manifest via the @frontmcp/skills package.\n * Works in both monorepo (workspace symlink) and installed (npx/npm) environments.\n */\nexport function loadCatalog(): SkillManifest {\n if (cachedManifest) return cachedManifest;\n\n const manifestPath = resolveManifestPath();\n cachedManifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8')) as SkillManifest;\n return cachedManifest;\n}\n\n/**\n * Resolve the path to skills-manifest.json from the @frontmcp/skills package.\n */\nfunction resolveManifestPath(): string {\n // Primary: resolve directly from the @frontmcp/skills package\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n return require.resolve('@frontmcp/skills/catalog/skills-manifest.json');\n } catch {\n // Not resolvable via subpath — try via package root\n }\n\n // Fallback: find the package root and navigate to catalog/\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const pkgJsonPath = require.resolve('@frontmcp/skills/package.json');\n const pkgRoot = path.dirname(pkgJsonPath);\n const manifestPath = path.join(pkgRoot, 'catalog', 'skills-manifest.json');\n if (fs.existsSync(manifestPath)) return manifestPath;\n } catch {\n // Package not found at all\n }\n\n // Monorepo dev fallback: walk up from __dirname to find libs/skills/catalog/\n let dir = __dirname;\n for (let i = 0; i < 8; i++) {\n const candidate = path.join(dir, 'libs', 'skills', 'catalog', 'skills-manifest.json');\n if (fs.existsSync(candidate)) return candidate;\n dir = path.dirname(dir);\n }\n\n throw new Error(\n 'Skills catalog not found. Make sure @frontmcp/skills is installed or you are in the FrontMCP monorepo.',\n );\n}\n\n/**\n * Resolve the catalog directory path.\n */\nexport function getCatalogDir(): string {\n return path.dirname(resolveManifestPath());\n}\n\n/**\n * Build and cache the TF-IDF search index from the catalog manifest.\n */\nfunction getSearchIndex(): TFIDFVectoria<SkillDocMetadata> {\n if (cachedIndex) return cachedIndex;\n\n const manifest = loadCatalog();\n cachedIndex = new TFIDFVectoria<SkillDocMetadata>({\n defaultTopK: 10,\n defaultSimilarityThreshold: 0.0,\n });\n\n const documents = manifest.skills.map((skill) => ({\n id: skill.name,\n text: buildSearchableText(skill),\n metadata: { id: skill.name, skill },\n }));\n\n cachedIndex.addDocuments(documents);\n cachedIndex.reindex();\n\n return cachedIndex;\n}\n\n/**\n * Build weighted searchable text for TF-IDF indexing.\n * Follows the same weighting pattern as the SDK's MemorySkillProvider.\n */\nfunction buildSearchableText(skill: SkillEntry): string {\n const parts: string[] = [];\n\n // Name tokens (1x)\n const nameParts = skill.name.split(/[-_.\\s]/).filter(Boolean);\n parts.push(...nameParts);\n\n // Description (3x weight — repeat for TF-IDF term frequency boost)\n if (skill.description) {\n parts.push(skill.description, skill.description, skill.description);\n\n // Extract key terms from description (additional boost for meaningful words)\n const keyTerms = skill.description\n .toLowerCase()\n .split(/\\s+/)\n .filter((word) => word.length >= 4 && !STOP_WORDS.has(word));\n parts.push(...keyTerms);\n }\n\n // Tags (2x weight)\n for (const tag of skill.tags) {\n parts.push(tag, tag);\n }\n\n // Category (1x weight)\n parts.push(skill.category);\n\n return parts.join(' ');\n}\n\n/**\n * Search skills using TF-IDF similarity via vectoriadb.\n */\nexport function searchCatalog(\n query: string,\n options?: { tag?: string; category?: string; limit?: number },\n): SearchResult[] {\n const index = getSearchIndex();\n const topK = options?.limit ?? 10;\n\n const filter = (metadata: SkillDocMetadata): boolean => {\n if (options?.tag && !metadata.skill.tags.includes(options.tag)) return false;\n if (options?.category && metadata.skill.category !== options.category) return false;\n return true;\n };\n\n const results = index.search(query, {\n topK,\n threshold: 0.01,\n filter,\n });\n\n return results.map((r) => ({\n skill: r.metadata.skill,\n score: r.score,\n }));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../../../src/commands/skills/catalog.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Catalog loader and TF-IDF search engine for skills.\n *\n * Uses vectoriadb's TFIDFVectoria for proper TF-IDF similarity search with\n * weighted document fields: description 3x, tags 2x, name 1x, category 1x.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { TFIDFVectoria } from 'vectoriadb';\nimport type { SkillReferenceEntry } from '@frontmcp/skills';\n\ninterface SkillEntry {\n name: string;\n category: string;\n description: string;\n path: string;\n targets: string[];\n hasResources: boolean;\n tags: string[];\n bundle?: string[];\n references?: SkillReferenceEntry[];\n}\n\ninterface SkillManifest {\n version: number;\n skills: SkillEntry[];\n}\n\nexport interface SearchResult {\n skill: SkillEntry;\n score: number;\n}\n\ninterface SkillDocMetadata {\n id: string;\n skill: SkillEntry;\n}\n\nconst STOP_WORDS = new Set([\n // Articles & determiners\n 'the',\n 'a',\n 'an',\n 'this',\n 'that',\n 'these',\n 'those',\n 'each',\n 'every',\n 'some',\n 'any',\n 'no',\n // Conjunctions & prepositions\n 'and',\n 'or',\n 'but',\n 'nor',\n 'for',\n 'yet',\n 'so',\n 'with',\n 'from',\n 'into',\n 'onto',\n 'about',\n 'by',\n 'at',\n 'in',\n 'on',\n 'to',\n 'of',\n 'as',\n 'if',\n 'than',\n 'then',\n 'between',\n 'through',\n 'after',\n 'before',\n 'during',\n 'without',\n 'within',\n 'along',\n 'across',\n 'against',\n 'under',\n 'over',\n 'above',\n 'below',\n // Pronouns\n 'your',\n 'you',\n 'it',\n 'its',\n 'we',\n 'our',\n 'they',\n 'them',\n 'their',\n 'he',\n 'she',\n 'his',\n 'her',\n 'who',\n 'which',\n 'what',\n 'where',\n 'when',\n 'how',\n 'why',\n // Verbs (auxiliary / common)\n 'is',\n 'am',\n 'are',\n 'was',\n 'were',\n 'be',\n 'been',\n 'being',\n 'have',\n 'has',\n 'had',\n 'having',\n 'do',\n 'does',\n 'did',\n 'will',\n 'would',\n 'shall',\n 'should',\n 'may',\n 'might',\n 'must',\n 'can',\n 'could',\n 'need',\n 'use',\n 'using',\n 'used',\n // Adverbs & modifiers\n 'not',\n 'very',\n 'also',\n 'just',\n 'only',\n 'more',\n 'most',\n 'less',\n 'well',\n 'even',\n 'still',\n 'already',\n 'always',\n 'never',\n 'often',\n 'too',\n 'here',\n 'there',\n 'now',\n // Common filler\n 'all',\n 'both',\n 'other',\n 'another',\n 'such',\n 'like',\n 'get',\n 'set',\n 'new',\n 'make',\n 'see',\n 'way',\n 'etc',\n 'via',\n]);\n\nlet cachedManifest: SkillManifest | undefined;\nlet cachedIndex: TFIDFVectoria<SkillDocMetadata> | undefined;\n\n/**\n * Load the catalog manifest via the @frontmcp/skills package.\n * Works in both monorepo (workspace symlink) and installed (npx/npm) environments.\n */\nexport function loadCatalog(): SkillManifest {\n if (cachedManifest) return cachedManifest;\n\n const manifestPath = resolveManifestPath();\n cachedManifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8')) as SkillManifest;\n return cachedManifest;\n}\n\n/**\n * Resolve the path to skills-manifest.json from the @frontmcp/skills package.\n */\nfunction resolveManifestPath(): string {\n // Primary: resolve directly from the @frontmcp/skills package\n try {\n return require.resolve('@frontmcp/skills/catalog/skills-manifest.json');\n } catch {\n // Not resolvable via subpath — try via package root\n }\n\n // Fallback: find the package root and navigate to catalog/\n try {\n const pkgJsonPath = require.resolve('@frontmcp/skills/package.json');\n const pkgRoot = path.dirname(pkgJsonPath);\n const manifestPath = path.join(pkgRoot, 'catalog', 'skills-manifest.json');\n if (fs.existsSync(manifestPath)) return manifestPath;\n } catch {\n // Package not found at all\n }\n\n // Monorepo dev fallback: walk up from __dirname to find libs/skills/catalog/\n let dir = __dirname;\n for (let i = 0; i < 8; i++) {\n const candidate = path.join(dir, 'libs', 'skills', 'catalog', 'skills-manifest.json');\n if (fs.existsSync(candidate)) return candidate;\n dir = path.dirname(dir);\n }\n\n throw new Error(\n 'Skills catalog not found. Make sure @frontmcp/skills is installed or you are in the FrontMCP monorepo.',\n );\n}\n\n/**\n * Resolve the catalog directory path.\n */\nexport function getCatalogDir(): string {\n return path.dirname(resolveManifestPath());\n}\n\n/**\n * Build and cache the TF-IDF search index from the catalog manifest.\n */\nfunction getSearchIndex(): TFIDFVectoria<SkillDocMetadata> {\n if (cachedIndex) return cachedIndex;\n\n const manifest = loadCatalog();\n cachedIndex = new TFIDFVectoria<SkillDocMetadata>({\n defaultTopK: 10,\n defaultSimilarityThreshold: 0.0,\n });\n\n const documents = manifest.skills.map((skill) => ({\n id: skill.name,\n text: buildSearchableText(skill),\n metadata: { id: skill.name, skill },\n }));\n\n cachedIndex.addDocuments(documents);\n cachedIndex.reindex();\n\n return cachedIndex;\n}\n\n/**\n * Build weighted searchable text for TF-IDF indexing.\n * Follows the same weighting pattern as the SDK's MemorySkillProvider.\n */\nfunction buildSearchableText(skill: SkillEntry): string {\n const parts: string[] = [];\n\n // Name tokens (1x)\n const nameParts = skill.name.split(/[-_.\\s]/).filter(Boolean);\n parts.push(...nameParts);\n\n // Description (3x weight — repeat for TF-IDF term frequency boost)\n if (skill.description) {\n parts.push(skill.description, skill.description, skill.description);\n\n // Extract key terms from description (additional boost for meaningful words)\n const keyTerms = skill.description\n .toLowerCase()\n .split(/\\s+/)\n .filter((word) => word.length >= 4 && !STOP_WORDS.has(word));\n parts.push(...keyTerms);\n }\n\n // Tags (2x weight)\n for (const tag of skill.tags) {\n parts.push(tag, tag);\n }\n\n // Category (1x weight)\n parts.push(skill.category);\n\n // Reference names and descriptions (1x weight each)\n if (skill.references) {\n for (const ref of skill.references) {\n const refNameParts = ref.name.split(/[-_.\\s]/).filter(Boolean);\n parts.push(...refNameParts);\n if (ref.description) {\n const refTerms = ref.description\n .toLowerCase()\n .split(/\\s+/)\n .filter((word) => word.length >= 4 && !STOP_WORDS.has(word));\n parts.push(...refTerms);\n }\n }\n }\n\n return parts.join(' ');\n}\n\n/**\n * Search skills using TF-IDF similarity via vectoriadb.\n */\nexport function searchCatalog(\n query: string,\n options?: { tag?: string; category?: string; limit?: number },\n): SearchResult[] {\n const index = getSearchIndex();\n const topK = options?.limit ?? 10;\n\n const filter = (metadata: SkillDocMetadata): boolean => {\n if (options?.tag && !metadata.skill.tags.includes(options.tag)) return false;\n if (options?.category && metadata.skill.category !== options.category) return false;\n return true;\n };\n\n const results = index.search(query, {\n topK,\n threshold: 0.01,\n filter,\n });\n\n return results.map((r) => ({\n skill: r.metadata.skill,\n score: r.score,\n }));\n}\n"]}
|
|
@@ -10,6 +10,46 @@ const PROVIDER_DIRS = {
|
|
|
10
10
|
claude: '.claude/skills',
|
|
11
11
|
codex: '.codex/skills',
|
|
12
12
|
};
|
|
13
|
+
/** The marker we look for in CLAUDE.md to know skills instructions are present. */
|
|
14
|
+
const SKILLS_MARKER = '# Skills and Tools';
|
|
15
|
+
/** Minimal CLAUDE.md content that instructs Claude to use installed skills. */
|
|
16
|
+
const CLAUDE_MD_SKILLS_SECTION = `# Skills and Tools
|
|
17
|
+
|
|
18
|
+
This project uses **FrontMCP skills** installed in \`.claude/skills/\`.
|
|
19
|
+
Before writing code, search the installed skills for relevant guidance:
|
|
20
|
+
|
|
21
|
+
- **Building components** (tools, resources, prompts, plugins, adapters) — check \`frontmcp-development\`
|
|
22
|
+
- **Testing** — check \`frontmcp-testing\`
|
|
23
|
+
- **Configuration** (auth, CORS, transport, sessions) — check \`frontmcp-config\`
|
|
24
|
+
- **Deployment** (Docker, Vercel, Lambda, Cloudflare) — check \`frontmcp-deployment\`
|
|
25
|
+
- **Production readiness** (security, performance, reliability) — check \`frontmcp-production-readiness\`
|
|
26
|
+
|
|
27
|
+
When you need to implement something, **read the matching skill first** — it contains patterns, examples, verification checklists, and common mistakes to avoid.
|
|
28
|
+
`;
|
|
29
|
+
/**
|
|
30
|
+
* Ensure CLAUDE.md exists and contains skills usage instructions.
|
|
31
|
+
* If the file doesn't exist, creates it with the skills section.
|
|
32
|
+
* If it exists but lacks the skills marker, prepends the section.
|
|
33
|
+
*/
|
|
34
|
+
async function ensureClaudeMdSkillsInstructions(cwd) {
|
|
35
|
+
const claudeMdPath = path.join(cwd, 'CLAUDE.md');
|
|
36
|
+
if (await (0, utils_1.fileExists)(claudeMdPath)) {
|
|
37
|
+
const content = await (0, utils_1.readFile)(claudeMdPath);
|
|
38
|
+
if (content.includes(SKILLS_MARKER)) {
|
|
39
|
+
// Already has skills instructions — nothing to do
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
// Exists but missing skills section — prepend it
|
|
43
|
+
const updated = CLAUDE_MD_SKILLS_SECTION + '\n' + content;
|
|
44
|
+
await (0, utils_1.writeFile)(claudeMdPath, updated);
|
|
45
|
+
console.log(`${(0, colors_1.c)('green', '✓')} Updated ${(0, colors_1.c)('cyan', 'CLAUDE.md')} with skills usage instructions`);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
// Create new CLAUDE.md with skills section
|
|
49
|
+
await (0, utils_1.writeFile)(claudeMdPath, CLAUDE_MD_SKILLS_SECTION);
|
|
50
|
+
console.log(`${(0, colors_1.c)('green', '✓')} Created ${(0, colors_1.c)('cyan', 'CLAUDE.md')} with skills usage instructions`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
13
53
|
async function installSkill(name, options) {
|
|
14
54
|
const manifest = (0, catalog_1.loadCatalog)();
|
|
15
55
|
const provider = options.provider ?? 'claude';
|
|
@@ -79,5 +119,9 @@ async function installSkill(name, options) {
|
|
|
79
119
|
if (skills.length > 1) {
|
|
80
120
|
console.log(`\n${(0, colors_1.c)('green', '✓')} Installed ${installed}/${skills.length} skills (provider: ${provider})`);
|
|
81
121
|
}
|
|
122
|
+
// For Claude provider: ensure CLAUDE.md has skills usage instructions
|
|
123
|
+
if (provider === 'claude') {
|
|
124
|
+
await ensureClaudeMdSkillsInstructions(process.cwd());
|
|
125
|
+
}
|
|
82
126
|
}
|
|
83
127
|
//# sourceMappingURL=install.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../../../src/commands/skills/install.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from 'path';\nimport { c } from '../../core/colors';\nimport { ensureDir, fileExists, cp } from '@frontmcp/utils';\nimport { loadCatalog, getCatalogDir } from './catalog';\n\nconst PROVIDER_DIRS: Record<string, string> = {\n claude: '.claude/skills',\n codex: '.codex/skills',\n};\n\nexport interface InstallOptions {\n provider?: 'claude' | 'codex';\n dir?: string;\n all?: boolean;\n tag?: string;\n category?: string;\n}\n\nexport async function installSkill(name: string | undefined, options: InstallOptions): Promise<void> {\n const manifest = loadCatalog();\n const provider = options.provider ?? 'claude';\n const targetBase = options.dir ?? path.resolve(process.cwd(), PROVIDER_DIRS[provider] ?? PROVIDER_DIRS['claude']);\n const catalogDir = getCatalogDir();\n\n // Validate that exactly one selector is supplied\n const selectorCount = [options.all, options.tag, options.category, name].filter(Boolean).length;\n if (selectorCount > 1) {\n console.error(c('red', 'Options --all, --tag, --category, and <name> are mutually exclusive.'));\n console.log(c('gray', 'Provide exactly one selector to choose which skills to install.'));\n process.exit(1);\n }\n\n // Determine which skills to install\n let skills = manifest.skills;\n\n if (options.all) {\n // Install all skills\n } else if (options.tag) {\n const tag = options.tag;\n skills = skills.filter((s) => s.tags.includes(tag));\n if (skills.length === 0) {\n console.error(c('red', `No skills found with tag \"${tag}\".`));\n console.log(c('gray', \"Use 'frontmcp skills list --tag <tag>' to see available tags.\"));\n process.exit(1);\n }\n } else if (options.category) {\n skills = skills.filter((s) => s.category === options.category);\n if (skills.length === 0) {\n console.error(c('red', `No skills found in category \"${options.category}\".`));\n console.log(c('gray', \"Use 'frontmcp skills list' to see available categories.\"));\n process.exit(1);\n }\n } else if (name) {\n // Single skill install\n const entry = skills.find((s) => s.name === name);\n if (!entry) {\n console.error(c('red', `Skill \"${name}\" not found in catalog.`));\n console.log(c('gray', \"Use 'frontmcp skills list' to see available skills.\"));\n process.exit(1);\n }\n skills = [entry];\n } else {\n console.error(c('red', 'Please specify a skill name, or use --all, --tag, or --category.'));\n process.exit(1);\n }\n\n // Install each skill\n let installed = 0;\n for (const entry of skills) {\n const targetDir = path.join(targetBase, entry.name);\n const sourceDir = path.join(catalogDir, entry.path);\n\n if (!(await fileExists(path.join(sourceDir, 'SKILL.md')))) {\n console.error(c('yellow', ` Skipped ${entry.name}: source SKILL.md not found`));\n continue;\n }\n\n await ensureDir(targetDir);\n await cp(sourceDir, targetDir, { recursive: true });\n installed++;\n\n console.log(\n `${c('green', '✓')} Installed ${c('bold', entry.name)} to ${c('cyan', path.relative(process.cwd(), targetDir))}`,\n );\n }\n\n if (installed === 0) {\n console.error(c('red', `No skills were installed (0/${skills.length} had valid SKILL.md files).`));\n process.exit(1);\n }\n\n if (skills.length > 1) {\n console.log(`\\n${c('green', '✓')} Installed ${installed}/${skills.length} skills (provider: ${provider})`);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../../../src/commands/skills/install.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from 'path';\nimport { c } from '../../core/colors';\nimport { ensureDir, fileExists, cp, readFile, writeFile } from '@frontmcp/utils';\nimport { loadCatalog, getCatalogDir } from './catalog';\n\nconst PROVIDER_DIRS: Record<string, string> = {\n claude: '.claude/skills',\n codex: '.codex/skills',\n};\n\n/** The marker we look for in CLAUDE.md to know skills instructions are present. */\nconst SKILLS_MARKER = '# Skills and Tools';\n\n/** Minimal CLAUDE.md content that instructs Claude to use installed skills. */\nconst CLAUDE_MD_SKILLS_SECTION = `# Skills and Tools\n\nThis project uses **FrontMCP skills** installed in \\`.claude/skills/\\`.\nBefore writing code, search the installed skills for relevant guidance:\n\n- **Building components** (tools, resources, prompts, plugins, adapters) — check \\`frontmcp-development\\`\n- **Testing** — check \\`frontmcp-testing\\`\n- **Configuration** (auth, CORS, transport, sessions) — check \\`frontmcp-config\\`\n- **Deployment** (Docker, Vercel, Lambda, Cloudflare) — check \\`frontmcp-deployment\\`\n- **Production readiness** (security, performance, reliability) — check \\`frontmcp-production-readiness\\`\n\nWhen you need to implement something, **read the matching skill first** — it contains patterns, examples, verification checklists, and common mistakes to avoid.\n`;\n\nexport interface InstallOptions {\n provider?: 'claude' | 'codex';\n dir?: string;\n all?: boolean;\n tag?: string;\n category?: string;\n}\n\n/**\n * Ensure CLAUDE.md exists and contains skills usage instructions.\n * If the file doesn't exist, creates it with the skills section.\n * If it exists but lacks the skills marker, prepends the section.\n */\nasync function ensureClaudeMdSkillsInstructions(cwd: string): Promise<void> {\n const claudeMdPath = path.join(cwd, 'CLAUDE.md');\n\n if (await fileExists(claudeMdPath)) {\n const content = await readFile(claudeMdPath);\n if (content.includes(SKILLS_MARKER)) {\n // Already has skills instructions — nothing to do\n return;\n }\n // Exists but missing skills section — prepend it\n const updated = CLAUDE_MD_SKILLS_SECTION + '\\n' + content;\n await writeFile(claudeMdPath, updated);\n console.log(`${c('green', '✓')} Updated ${c('cyan', 'CLAUDE.md')} with skills usage instructions`);\n } else {\n // Create new CLAUDE.md with skills section\n await writeFile(claudeMdPath, CLAUDE_MD_SKILLS_SECTION);\n console.log(`${c('green', '✓')} Created ${c('cyan', 'CLAUDE.md')} with skills usage instructions`);\n }\n}\n\nexport async function installSkill(name: string | undefined, options: InstallOptions): Promise<void> {\n const manifest = loadCatalog();\n const provider = options.provider ?? 'claude';\n const targetBase = options.dir ?? path.resolve(process.cwd(), PROVIDER_DIRS[provider] ?? PROVIDER_DIRS['claude']);\n const catalogDir = getCatalogDir();\n\n // Validate that exactly one selector is supplied\n const selectorCount = [options.all, options.tag, options.category, name].filter(Boolean).length;\n if (selectorCount > 1) {\n console.error(c('red', 'Options --all, --tag, --category, and <name> are mutually exclusive.'));\n console.log(c('gray', 'Provide exactly one selector to choose which skills to install.'));\n process.exit(1);\n }\n\n // Determine which skills to install\n let skills = manifest.skills;\n\n if (options.all) {\n // Install all skills\n } else if (options.tag) {\n const tag = options.tag;\n skills = skills.filter((s) => s.tags.includes(tag));\n if (skills.length === 0) {\n console.error(c('red', `No skills found with tag \"${tag}\".`));\n console.log(c('gray', \"Use 'frontmcp skills list --tag <tag>' to see available tags.\"));\n process.exit(1);\n }\n } else if (options.category) {\n skills = skills.filter((s) => s.category === options.category);\n if (skills.length === 0) {\n console.error(c('red', `No skills found in category \"${options.category}\".`));\n console.log(c('gray', \"Use 'frontmcp skills list' to see available categories.\"));\n process.exit(1);\n }\n } else if (name) {\n // Single skill install\n const entry = skills.find((s) => s.name === name);\n if (!entry) {\n console.error(c('red', `Skill \"${name}\" not found in catalog.`));\n console.log(c('gray', \"Use 'frontmcp skills list' to see available skills.\"));\n process.exit(1);\n }\n skills = [entry];\n } else {\n console.error(c('red', 'Please specify a skill name, or use --all, --tag, or --category.'));\n process.exit(1);\n }\n\n // Install each skill\n let installed = 0;\n for (const entry of skills) {\n const targetDir = path.join(targetBase, entry.name);\n const sourceDir = path.join(catalogDir, entry.path);\n\n if (!(await fileExists(path.join(sourceDir, 'SKILL.md')))) {\n console.error(c('yellow', ` Skipped ${entry.name}: source SKILL.md not found`));\n continue;\n }\n\n await ensureDir(targetDir);\n await cp(sourceDir, targetDir, { recursive: true });\n installed++;\n\n console.log(\n `${c('green', '✓')} Installed ${c('bold', entry.name)} to ${c('cyan', path.relative(process.cwd(), targetDir))}`,\n );\n }\n\n if (installed === 0) {\n console.error(c('red', `No skills were installed (0/${skills.length} had valid SKILL.md files).`));\n process.exit(1);\n }\n\n if (skills.length > 1) {\n console.log(`\\n${c('green', '✓')} Installed ${installed}/${skills.length} skills (provider: ${provider})`);\n }\n\n // For Claude provider: ensure CLAUDE.md has skills usage instructions\n if (provider === 'claude') {\n await ensureClaudeMdSkillsInstructions(process.cwd());\n }\n}\n"]}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.readSkill = readSkill;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const path = tslib_1.__importStar(require("path"));
|
|
6
|
+
const colors_1 = require("../../core/colors");
|
|
7
|
+
const utils_1 = require("@frontmcp/utils");
|
|
8
|
+
const catalog_1 = require("./catalog");
|
|
9
|
+
/**
|
|
10
|
+
* Strip YAML frontmatter from markdown content.
|
|
11
|
+
* Returns the body content after the closing `---`.
|
|
12
|
+
*/
|
|
13
|
+
function stripFrontmatter(content) {
|
|
14
|
+
if (!content.startsWith('---'))
|
|
15
|
+
return content;
|
|
16
|
+
const endIdx = content.indexOf('---', 3);
|
|
17
|
+
if (endIdx === -1)
|
|
18
|
+
return content;
|
|
19
|
+
return content.substring(endIdx + 3).trim();
|
|
20
|
+
}
|
|
21
|
+
async function readSkill(nameOrPath, options) {
|
|
22
|
+
// Support colon syntax: "skillName:path/to/file.ext"
|
|
23
|
+
let skillName = nameOrPath;
|
|
24
|
+
let filePath = options.reference;
|
|
25
|
+
if (!filePath && nameOrPath.includes(':')) {
|
|
26
|
+
const colonIdx = nameOrPath.indexOf(':');
|
|
27
|
+
skillName = nameOrPath.substring(0, colonIdx);
|
|
28
|
+
filePath = nameOrPath.substring(colonIdx + 1);
|
|
29
|
+
}
|
|
30
|
+
const manifest = (0, catalog_1.loadCatalog)();
|
|
31
|
+
const entry = manifest.skills.find((s) => s.name === skillName);
|
|
32
|
+
if (!entry) {
|
|
33
|
+
console.error((0, colors_1.c)('red', `Skill "${skillName}" not found in catalog.`));
|
|
34
|
+
console.log((0, colors_1.c)('gray', "Use 'frontmcp skills list' to see available skills."));
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
const catalogDir = (0, catalog_1.getCatalogDir)();
|
|
38
|
+
const skillDir = path.join(catalogDir, entry.path);
|
|
39
|
+
// Mode 1: List references
|
|
40
|
+
if (options.listRefs) {
|
|
41
|
+
const refs = entry.references ?? [];
|
|
42
|
+
if (refs.length === 0) {
|
|
43
|
+
console.log((0, colors_1.c)('yellow', `Skill "${skillName}" has no references.`));
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
console.log((0, colors_1.c)('bold', `\n References for ${skillName}:\n`));
|
|
47
|
+
for (const ref of refs) {
|
|
48
|
+
console.log(` ${(0, colors_1.c)('green', ref.name)}`);
|
|
49
|
+
if (ref.description) {
|
|
50
|
+
console.log(` ${(0, colors_1.c)('gray', ref.description)}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
console.log('');
|
|
54
|
+
console.log((0, colors_1.c)('gray', ` ${refs.length} reference(s). Read with: frontmcp skills read ${skillName} <reference>`));
|
|
55
|
+
console.log((0, colors_1.c)('gray', ` Or use colon syntax: frontmcp skills read ${skillName}:<reference>\n`));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
// Mode 2: Read a specific file (reference or any file in skill dir)
|
|
59
|
+
if (filePath) {
|
|
60
|
+
// Try exact path first, then references/<name>.md fallback
|
|
61
|
+
let targetPath = path.join(skillDir, filePath);
|
|
62
|
+
if (!(await (0, utils_1.fileExists)(targetPath))) {
|
|
63
|
+
// Try with .md extension in references/
|
|
64
|
+
const refPath = path.join(skillDir, 'references', `${filePath}.md`);
|
|
65
|
+
if (await (0, utils_1.fileExists)(refPath)) {
|
|
66
|
+
targetPath = refPath;
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
// Try with .md extension at the given path
|
|
70
|
+
const withMd = path.join(skillDir, `${filePath}.md`);
|
|
71
|
+
if (await (0, utils_1.fileExists)(withMd)) {
|
|
72
|
+
targetPath = withMd;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
console.error((0, colors_1.c)('red', `File "${filePath}" not found in skill "${skillName}".`));
|
|
76
|
+
if (entry.references && entry.references.length > 0) {
|
|
77
|
+
console.log((0, colors_1.c)('gray', `Available references: ${entry.references.map((r) => r.name).join(', ')}`));
|
|
78
|
+
}
|
|
79
|
+
console.log((0, colors_1.c)('gray', `Use 'frontmcp skills read ${skillName} --refs' to list all references.`));
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const content = await (0, utils_1.readFile)(targetPath);
|
|
85
|
+
const displayName = path.relative(skillDir, targetPath);
|
|
86
|
+
console.log((0, colors_1.c)('bold', `\n ${skillName} > ${displayName}`));
|
|
87
|
+
console.log((0, colors_1.c)('gray', ' ─────────────────────────────────────'));
|
|
88
|
+
console.log('');
|
|
89
|
+
// Strip frontmatter for .md files
|
|
90
|
+
if (targetPath.endsWith('.md')) {
|
|
91
|
+
console.log(stripFrontmatter(content));
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
console.log(content);
|
|
95
|
+
}
|
|
96
|
+
console.log('');
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
// Mode 3: Read main SKILL.md (default)
|
|
100
|
+
const skillMd = path.join(skillDir, 'SKILL.md');
|
|
101
|
+
if (!(await (0, utils_1.fileExists)(skillMd))) {
|
|
102
|
+
console.error((0, colors_1.c)('red', `SKILL.md not found at ${skillMd}`));
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
const content = await (0, utils_1.readFile)(skillMd);
|
|
106
|
+
console.log((0, colors_1.c)('bold', `\n ${entry.name}`));
|
|
107
|
+
console.log((0, colors_1.c)('gray', ` Category: ${entry.category}`));
|
|
108
|
+
console.log((0, colors_1.c)('gray', ` Tags: ${entry.tags.join(', ')}`));
|
|
109
|
+
console.log((0, colors_1.c)('gray', ` Targets: ${entry.targets.join(', ')}`));
|
|
110
|
+
console.log((0, colors_1.c)('gray', ` Bundle: ${entry.bundle?.join(', ') ?? 'none'}`));
|
|
111
|
+
console.log((0, colors_1.c)('gray', ` Has resources: ${entry.hasResources}`));
|
|
112
|
+
if (entry.references && entry.references.length > 0) {
|
|
113
|
+
console.log((0, colors_1.c)('gray', ` References: ${entry.references.length} (use --refs to list)`));
|
|
114
|
+
}
|
|
115
|
+
console.log('');
|
|
116
|
+
console.log((0, colors_1.c)('gray', ' ─────────────────────────────────────'));
|
|
117
|
+
console.log('');
|
|
118
|
+
// Print body (skip frontmatter)
|
|
119
|
+
console.log(stripFrontmatter(content));
|
|
120
|
+
console.log('');
|
|
121
|
+
console.log((0, colors_1.c)('gray', ` Install: frontmcp skills install ${skillName} --provider claude`));
|
|
122
|
+
if (entry.references && entry.references.length > 0) {
|
|
123
|
+
console.log((0, colors_1.c)('gray', ` References: frontmcp skills read ${skillName} --refs`));
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=read.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read.js","sourceRoot":"","sources":["../../../../src/commands/skills/read.ts"],"names":[],"mappings":";;AAgBA,8BAyHC;;AAzID,mDAA6B;AAC7B,8CAAsC;AACtC,2CAAuD;AACvD,uCAAuD;AAEvD;;;GAGG;AACH,SAAS,gBAAgB,CAAC,OAAe;IACvC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC;IAC/C,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACzC,IAAI,MAAM,KAAK,CAAC,CAAC;QAAE,OAAO,OAAO,CAAC;IAClC,OAAO,OAAO,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AAC9C,CAAC;AAEM,KAAK,UAAU,SAAS,CAC7B,UAAkB,EAClB,OAAmD;IAEnD,qDAAqD;IACrD,IAAI,SAAS,GAAG,UAAU,CAAC;IAC3B,IAAI,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC;IAEjC,IAAI,CAAC,QAAQ,IAAI,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1C,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACzC,SAAS,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;QAC9C,QAAQ,GAAG,UAAU,CAAC,SAAS,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;IAChD,CAAC;IAED,MAAM,QAAQ,GAAG,IAAA,qBAAW,GAAE,CAAC;IAC/B,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;IAEhE,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CAAC,IAAA,UAAC,EAAC,KAAK,EAAE,UAAU,SAAS,yBAAyB,CAAC,CAAC,CAAC;QACtE,OAAO,CAAC,GAAG,CAAC,IAAA,UAAC,EAAC,MAAM,EAAE,qDAAqD,CAAC,CAAC,CAAC;QAC9E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,UAAU,GAAG,IAAA,uBAAa,GAAE,CAAC;IACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAEnD,0BAA0B;IAC1B,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrB,MAAM,IAAI,GAAG,KAAK,CAAC,UAAU,IAAI,EAAE,CAAC;QACpC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,IAAA,UAAC,EAAC,QAAQ,EAAE,UAAU,SAAS,sBAAsB,CAAC,CAAC,CAAC;YACpE,OAAO;QACT,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,IAAA,UAAC,EAAC,MAAM,EAAE,sBAAsB,SAAS,KAAK,CAAC,CAAC,CAAC;QAC7D,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,OAAO,CAAC,GAAG,CAAC,KAAK,IAAA,UAAC,EAAC,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACzC,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;gBACpB,OAAO,CAAC,GAAG,CAAC,OAAO,IAAA,UAAC,EAAC,MAAM,EAAE,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;YACnD,CAAC;QACH,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,IAAA,UAAC,EAAC,MAAM,EAAE,KAAK,IAAI,CAAC,MAAM,kDAAkD,SAAS,cAAc,CAAC,CAAC,CAAC;QAClH,OAAO,CAAC,GAAG,CAAC,IAAA,UAAC,EAAC,MAAM,EAAE,+CAA+C,SAAS,gBAAgB,CAAC,CAAC,CAAC;QACjG,OAAO;IACT,CAAC;IAED,oEAAoE;IACpE,IAAI,QAAQ,EAAE,CAAC;QACb,2DAA2D;QAC3D,IAAI,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAE/C,IAAI,CAAC,CAAC,MAAM,IAAA,kBAAU,EAAC,UAAU,CAAC,CAAC,EAAE,CAAC;YACpC,wCAAwC;YACxC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,QAAQ,KAAK,CAAC,CAAC;YACpE,IAAI,MAAM,IAAA,kBAAU,EAAC,OAAO,CAAC,EAAE,CAAC;gBAC9B,UAAU,GAAG,OAAO,CAAC;YACvB,CAAC;iBAAM,CAAC;gBACN,2CAA2C;gBAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,QAAQ,KAAK,CAAC,CAAC;gBACrD,IAAI,MAAM,IAAA,kBAAU,EAAC,MAAM,CAAC,EAAE,CAAC;oBAC7B,UAAU,GAAG,MAAM,CAAC;gBACtB,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,KAAK,CAAC,IAAA,UAAC,EAAC,KAAK,EAAE,SAAS,QAAQ,yBAAyB,SAAS,IAAI,CAAC,CAAC,CAAC;oBACjF,IAAI,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBACpD,OAAO,CAAC,GAAG,CAAC,IAAA,UAAC,EAAC,MAAM,EAAE,yBAAyB,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;oBACpG,CAAC;oBACD,OAAO,CAAC,GAAG,CAAC,IAAA,UAAC,EAAC,MAAM,EAAE,6BAA6B,SAAS,kCAAkC,CAAC,CAAC,CAAC;oBACjG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAClB,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,IAAA,gBAAQ,EAAC,UAAU,CAAC,CAAC;QAC3C,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QAExD,OAAO,CAAC,GAAG,CAAC,IAAA,UAAC,EAAC,MAAM,EAAE,OAAO,SAAS,MAAM,WAAW,EAAE,CAAC,CAAC,CAAC;QAC5D,OAAO,CAAC,GAAG,CAAC,IAAA,UAAC,EAAC,MAAM,EAAE,yCAAyC,CAAC,CAAC,CAAC;QAClE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAEhB,kCAAkC;QAClC,IAAI,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAC/B,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC;QACzC,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACvB,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO;IACT,CAAC;IAED,uCAAuC;IACvC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IAEhD,IAAI,CAAC,CAAC,MAAM,IAAA,kBAAU,EAAC,OAAO,CAAC,CAAC,EAAE,CAAC;QACjC,OAAO,CAAC,KAAK,CAAC,IAAA,UAAC,EAAC,KAAK,EAAE,yBAAyB,OAAO,EAAE,CAAC,CAAC,CAAC;QAC5D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,IAAA,gBAAQ,EAAC,OAAO,CAAC,CAAC;IAExC,OAAO,CAAC,GAAG,CAAC,IAAA,UAAC,EAAC,MAAM,EAAE,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAC5C,OAAO,CAAC,GAAG,CAAC,IAAA,UAAC,EAAC,MAAM,EAAE,eAAe,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;IACxD,OAAO,CAAC,GAAG,CAAC,IAAA,UAAC,EAAC,MAAM,EAAE,WAAW,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IAC3D,OAAO,CAAC,GAAG,CAAC,IAAA,UAAC,EAAC,MAAM,EAAE,cAAc,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IACjE,OAAO,CAAC,GAAG,CAAC,IAAA,UAAC,EAAC,MAAM,EAAE,aAAa,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,MAAM,EAAE,CAAC,CAAC,CAAC;IAC1E,OAAO,CAAC,GAAG,CAAC,IAAA,UAAC,EAAC,MAAM,EAAE,oBAAoB,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC;IACjE,IAAI,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpD,OAAO,CAAC,GAAG,CAAC,IAAA,UAAC,EAAC,MAAM,EAAE,iBAAiB,KAAK,CAAC,UAAU,CAAC,MAAM,uBAAuB,CAAC,CAAC,CAAC;IAC1F,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,IAAA,UAAC,EAAC,MAAM,EAAE,yCAAyC,CAAC,CAAC,CAAC;IAClE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEhB,gCAAgC;IAChC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC;IAEvC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,IAAA,UAAC,EAAC,MAAM,EAAE,sCAAsC,SAAS,oBAAoB,CAAC,CAAC,CAAC;IAC5F,IAAI,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpD,OAAO,CAAC,GAAG,CAAC,IAAA,UAAC,EAAC,MAAM,EAAE,sCAAsC,SAAS,SAAS,CAAC,CAAC,CAAC;IACnF,CAAC;AACH,CAAC","sourcesContent":["import * as path from 'path';\nimport { c } from '../../core/colors';\nimport { fileExists, readFile } from '@frontmcp/utils';\nimport { loadCatalog, getCatalogDir } from './catalog';\n\n/**\n * Strip YAML frontmatter from markdown content.\n * Returns the body content after the closing `---`.\n */\nfunction stripFrontmatter(content: string): string {\n if (!content.startsWith('---')) return content;\n const endIdx = content.indexOf('---', 3);\n if (endIdx === -1) return content;\n return content.substring(endIdx + 3).trim();\n}\n\nexport async function readSkill(\n nameOrPath: string,\n options: { reference?: string; listRefs?: boolean },\n): Promise<void> {\n // Support colon syntax: \"skillName:path/to/file.ext\"\n let skillName = nameOrPath;\n let filePath = options.reference;\n\n if (!filePath && nameOrPath.includes(':')) {\n const colonIdx = nameOrPath.indexOf(':');\n skillName = nameOrPath.substring(0, colonIdx);\n filePath = nameOrPath.substring(colonIdx + 1);\n }\n\n const manifest = loadCatalog();\n const entry = manifest.skills.find((s) => s.name === skillName);\n\n if (!entry) {\n console.error(c('red', `Skill \"${skillName}\" not found in catalog.`));\n console.log(c('gray', \"Use 'frontmcp skills list' to see available skills.\"));\n process.exit(1);\n }\n\n const catalogDir = getCatalogDir();\n const skillDir = path.join(catalogDir, entry.path);\n\n // Mode 1: List references\n if (options.listRefs) {\n const refs = entry.references ?? [];\n if (refs.length === 0) {\n console.log(c('yellow', `Skill \"${skillName}\" has no references.`));\n return;\n }\n\n console.log(c('bold', `\\n References for ${skillName}:\\n`));\n for (const ref of refs) {\n console.log(` ${c('green', ref.name)}`);\n if (ref.description) {\n console.log(` ${c('gray', ref.description)}`);\n }\n }\n console.log('');\n console.log(c('gray', ` ${refs.length} reference(s). Read with: frontmcp skills read ${skillName} <reference>`));\n console.log(c('gray', ` Or use colon syntax: frontmcp skills read ${skillName}:<reference>\\n`));\n return;\n }\n\n // Mode 2: Read a specific file (reference or any file in skill dir)\n if (filePath) {\n // Try exact path first, then references/<name>.md fallback\n let targetPath = path.join(skillDir, filePath);\n\n if (!(await fileExists(targetPath))) {\n // Try with .md extension in references/\n const refPath = path.join(skillDir, 'references', `${filePath}.md`);\n if (await fileExists(refPath)) {\n targetPath = refPath;\n } else {\n // Try with .md extension at the given path\n const withMd = path.join(skillDir, `${filePath}.md`);\n if (await fileExists(withMd)) {\n targetPath = withMd;\n } else {\n console.error(c('red', `File \"${filePath}\" not found in skill \"${skillName}\".`));\n if (entry.references && entry.references.length > 0) {\n console.log(c('gray', `Available references: ${entry.references.map((r) => r.name).join(', ')}`));\n }\n console.log(c('gray', `Use 'frontmcp skills read ${skillName} --refs' to list all references.`));\n process.exit(1);\n }\n }\n }\n\n const content = await readFile(targetPath);\n const displayName = path.relative(skillDir, targetPath);\n\n console.log(c('bold', `\\n ${skillName} > ${displayName}`));\n console.log(c('gray', ' ─────────────────────────────────────'));\n console.log('');\n\n // Strip frontmatter for .md files\n if (targetPath.endsWith('.md')) {\n console.log(stripFrontmatter(content));\n } else {\n console.log(content);\n }\n console.log('');\n return;\n }\n\n // Mode 3: Read main SKILL.md (default)\n const skillMd = path.join(skillDir, 'SKILL.md');\n\n if (!(await fileExists(skillMd))) {\n console.error(c('red', `SKILL.md not found at ${skillMd}`));\n process.exit(1);\n }\n\n const content = await readFile(skillMd);\n\n console.log(c('bold', `\\n ${entry.name}`));\n console.log(c('gray', ` Category: ${entry.category}`));\n console.log(c('gray', ` Tags: ${entry.tags.join(', ')}`));\n console.log(c('gray', ` Targets: ${entry.targets.join(', ')}`));\n console.log(c('gray', ` Bundle: ${entry.bundle?.join(', ') ?? 'none'}`));\n console.log(c('gray', ` Has resources: ${entry.hasResources}`));\n if (entry.references && entry.references.length > 0) {\n console.log(c('gray', ` References: ${entry.references.length} (use --refs to list)`));\n }\n console.log('');\n console.log(c('gray', ' ─────────────────────────────────────'));\n console.log('');\n\n // Print body (skip frontmatter)\n console.log(stripFrontmatter(content));\n\n console.log('');\n console.log(c('gray', ` Install: frontmcp skills install ${skillName} --provider claude`));\n if (entry.references && entry.references.length > 0) {\n console.log(c('gray', ` References: frontmcp skills read ${skillName} --refs`));\n }\n}\n"]}
|
|
@@ -54,12 +54,14 @@ function registerSkillsCommands(program) {
|
|
|
54
54
|
});
|
|
55
55
|
});
|
|
56
56
|
skills
|
|
57
|
-
.command('
|
|
58
|
-
.description('
|
|
59
|
-
.argument('<
|
|
60
|
-
.
|
|
61
|
-
|
|
62
|
-
|
|
57
|
+
.command('read')
|
|
58
|
+
.description('Read a skill, its references, or any file in the skill directory')
|
|
59
|
+
.argument('<nameOrPath>', 'Skill name or skill:filepath (e.g., frontmcp-dev:references/create-tool.md)')
|
|
60
|
+
.argument('[reference]', 'Reference name to read (e.g., create-tool)')
|
|
61
|
+
.option('--refs', 'List all available references for the skill')
|
|
62
|
+
.action(async (name, reference, options) => {
|
|
63
|
+
const { readSkill } = await import('./read.js');
|
|
64
|
+
await readSkill(name, { reference, listRefs: options.refs });
|
|
63
65
|
});
|
|
64
66
|
}
|
|
65
67
|
//# sourceMappingURL=register.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"register.js","sourceRoot":"","sources":["../../../../src/commands/skills/register.ts"],"names":[],"mappings":";;AAEA,
|
|
1
|
+
{"version":3,"file":"register.js","sourceRoot":"","sources":["../../../../src/commands/skills/register.ts"],"names":[],"mappings":"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","sourcesContent":["import { Command } from 'commander';\n\nexport function registerSkillsCommands(program: Command): void {\n const skills = program.command('skills').description('Search, list, and install skills from the FrontMCP catalog');\n\n skills\n .command('search')\n .description('Search the skills catalog using semantic text matching')\n .argument('<query>', 'Search text (matches descriptions, tags, and names)')\n .option('-n, --limit <count>', 'Maximum results to return', '10')\n .option('-t, --tag <tag>', 'Filter by tag')\n .option('-c, --category <category>', 'Filter by category')\n .action(async (query: string, options: { limit?: string; tag?: string; category?: string }) => {\n const { searchSkills } = await import('./search.js');\n await searchSkills(query, {\n limit: Math.max(1, Number(options.limit) || 10),\n tag: options.tag,\n category: options.category,\n });\n });\n\n skills\n .command('list')\n .description('List all available skills in the catalog')\n .option('-c, --category <category>', 'Filter by category')\n .option('-t, --tag <tag>', 'Filter by tag')\n .option('-b, --bundle <bundle>', 'Filter by bundle (recommended, minimal, full)')\n .action(async (options: { category?: string; tag?: string; bundle?: string }) => {\n const { listSkills } = await import('./list.js');\n await listSkills(options);\n });\n\n skills\n .command('install')\n .description('Install skill(s) to a provider directory (.claude/skills or .codex/skills)')\n .argument('[name]', 'Skill name to install (optional with --all, --tag, or --category)')\n .option('-p, --provider <provider>', 'Target provider: claude, codex (default: claude)', 'claude')\n .option('-d, --dir <directory>', 'Custom install directory (overrides provider default)')\n .option('-a, --all', 'Install all skills from the catalog')\n .option('-t, --tag <tag>', 'Install all skills matching a tag')\n .option('-c, --category <category>', 'Install all skills in a category')\n .action(\n async (\n name: string | undefined,\n options: { provider?: string; dir?: string; all?: boolean; tag?: string; category?: string },\n ) => {\n const validProviders = ['claude', 'codex'] as const;\n type Provider = (typeof validProviders)[number];\n const raw = options.provider;\n if (raw && !validProviders.includes(raw as Provider)) {\n console.error(`Invalid provider \"${raw}\". Valid providers: ${validProviders.join(', ')}`);\n process.exit(1);\n }\n const { installSkill } = await import('./install.js');\n await installSkill(name, {\n provider: raw as Provider | undefined,\n dir: options.dir,\n all: options.all,\n tag: options.tag,\n category: options.category,\n });\n },\n );\n\n skills\n .command('read')\n .description('Read a skill, its references, or any file in the skill directory')\n .argument('<nameOrPath>', 'Skill name or skill:filepath (e.g., frontmcp-dev:references/create-tool.md)')\n .argument('[reference]', 'Reference name to read (e.g., create-tool)')\n .option('--refs', 'List all available references for the skill')\n .action(async (name: string, reference: string | undefined, options: { refs?: boolean }) => {\n const { readSkill } = await import('./read.js');\n await readSkill(name, { reference, listRefs: options.refs });\n });\n}\n"]}
|
|
@@ -18,7 +18,7 @@ async function searchSkills(query, options) {
|
|
|
18
18
|
console.log(` ${(0, colors_1.c)('gray', `tags: ${tags}`)}`);
|
|
19
19
|
console.log('');
|
|
20
20
|
}
|
|
21
|
-
console.log((0, colors_1.c)('gray', ` ${results.length} result(s). Use 'frontmcp skills
|
|
21
|
+
console.log((0, colors_1.c)('gray', ` ${results.length} result(s). Use 'frontmcp skills read <name>' for full details.`));
|
|
22
22
|
console.log((0, colors_1.c)('gray', ` Install: 'frontmcp skills install <name> --provider claude'\n`));
|
|
23
23
|
}
|
|
24
24
|
//# sourceMappingURL=search.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../../../src/commands/skills/search.ts"],"names":[],"mappings":";;AAGA,oCAwBC;AA3BD,8CAAsC;AACtC,uCAA0C;AAEnC,KAAK,UAAU,YAAY,CAChC,KAAa,EACb,OAA2D;IAE3D,MAAM,OAAO,GAAG,IAAA,uBAAa,EAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAE9C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,IAAA,UAAC,EAAC,QAAQ,EAAE,6BAA6B,KAAK,IAAI,CAAC,CAAC,CAAC;QACjE,OAAO,CAAC,GAAG,CAAC,IAAA,UAAC,EAAC,MAAM,EAAE,4CAA4C,CAAC,CAAC,CAAC;QACrE,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,IAAA,UAAC,EAAC,MAAM,EAAE,wBAAwB,KAAK,MAAM,CAAC,CAAC,CAAC;IAE5D,KAAK,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,OAAO,EAAE,CAAC;QACvC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/C,OAAO,CAAC,GAAG,CAAC,KAAK,IAAA,UAAC,EAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,IAAA,UAAC,EAAC,MAAM,EAAE,IAAI,KAAK,CAAC,QAAQ,GAAG,CAAC,IAAI,IAAA,UAAC,EAAC,MAAM,EAAE,SAAS,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;QAC9G,OAAO,CAAC,GAAG,CAAC,OAAO,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC/D,OAAO,CAAC,GAAG,CAAC,OAAO,IAAA,UAAC,EAAC,MAAM,EAAE,SAAS,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;QACjD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,IAAA,UAAC,EAAC,MAAM,EAAE,KAAK,OAAO,CAAC,MAAM,iEAAiE,CAAC,CAAC,CAAC;IAC7G,OAAO,CAAC,GAAG,CAAC,IAAA,UAAC,EAAC,MAAM,EAAE,iEAAiE,CAAC,CAAC,CAAC;AAC5F,CAAC","sourcesContent":["import { c } from '../../core/colors';\nimport { searchCatalog } from './catalog';\n\nexport async function searchSkills(\n query: string,\n options: { limit: number; tag?: string; category?: string },\n): Promise<void> {\n const results = searchCatalog(query, options);\n\n if (results.length === 0) {\n console.log(c('yellow', `No skills found matching \"${query}\".`));\n console.log(c('gray', 'Try: frontmcp skills list --category setup'));\n return;\n }\n\n console.log(c('bold', `\\n Skills matching \"${query}\":\\n`));\n\n for (const { skill, score } of results) {\n const tags = skill.tags.slice(0, 3).join(', ');\n console.log(` ${c('green', skill.name)} ${c('gray', `[${skill.category}]`)} ${c('gray', `score:${score}`)}`);\n console.log(` ${skill.description.split('. Use when')[0]}`);\n console.log(` ${c('gray', `tags: ${tags}`)}`);\n console.log('');\n }\n\n console.log(c('gray', ` ${results.length} result(s). Use 'frontmcp skills
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../../../src/commands/skills/search.ts"],"names":[],"mappings":";;AAGA,oCAwBC;AA3BD,8CAAsC;AACtC,uCAA0C;AAEnC,KAAK,UAAU,YAAY,CAChC,KAAa,EACb,OAA2D;IAE3D,MAAM,OAAO,GAAG,IAAA,uBAAa,EAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAE9C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,IAAA,UAAC,EAAC,QAAQ,EAAE,6BAA6B,KAAK,IAAI,CAAC,CAAC,CAAC;QACjE,OAAO,CAAC,GAAG,CAAC,IAAA,UAAC,EAAC,MAAM,EAAE,4CAA4C,CAAC,CAAC,CAAC;QACrE,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,IAAA,UAAC,EAAC,MAAM,EAAE,wBAAwB,KAAK,MAAM,CAAC,CAAC,CAAC;IAE5D,KAAK,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,OAAO,EAAE,CAAC;QACvC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/C,OAAO,CAAC,GAAG,CAAC,KAAK,IAAA,UAAC,EAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,IAAA,UAAC,EAAC,MAAM,EAAE,IAAI,KAAK,CAAC,QAAQ,GAAG,CAAC,IAAI,IAAA,UAAC,EAAC,MAAM,EAAE,SAAS,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;QAC9G,OAAO,CAAC,GAAG,CAAC,OAAO,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC/D,OAAO,CAAC,GAAG,CAAC,OAAO,IAAA,UAAC,EAAC,MAAM,EAAE,SAAS,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;QACjD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,IAAA,UAAC,EAAC,MAAM,EAAE,KAAK,OAAO,CAAC,MAAM,iEAAiE,CAAC,CAAC,CAAC;IAC7G,OAAO,CAAC,GAAG,CAAC,IAAA,UAAC,EAAC,MAAM,EAAE,iEAAiE,CAAC,CAAC,CAAC;AAC5F,CAAC","sourcesContent":["import { c } from '../../core/colors';\nimport { searchCatalog } from './catalog';\n\nexport async function searchSkills(\n query: string,\n options: { limit: number; tag?: string; category?: string },\n): Promise<void> {\n const results = searchCatalog(query, options);\n\n if (results.length === 0) {\n console.log(c('yellow', `No skills found matching \"${query}\".`));\n console.log(c('gray', 'Try: frontmcp skills list --category setup'));\n return;\n }\n\n console.log(c('bold', `\\n Skills matching \"${query}\":\\n`));\n\n for (const { skill, score } of results) {\n const tags = skill.tags.slice(0, 3).join(', ');\n console.log(` ${c('green', skill.name)} ${c('gray', `[${skill.category}]`)} ${c('gray', `score:${score}`)}`);\n console.log(` ${skill.description.split('. Use when')[0]}`);\n console.log(` ${c('gray', `tags: ${tags}`)}`);\n console.log('');\n }\n\n console.log(c('gray', ` ${results.length} result(s). Use 'frontmcp skills read <name>' for full details.`));\n console.log(c('gray', ` Install: 'frontmcp skills install <name> --provider claude'\\n`));\n}\n"]}
|
package/src/core/colors.js
CHANGED
|
@@ -12,6 +12,14 @@ exports.COLORS = {
|
|
|
12
12
|
cyan: '\x1b[36m',
|
|
13
13
|
gray: '\x1b[90m',
|
|
14
14
|
};
|
|
15
|
-
|
|
15
|
+
function colorsEnabled() {
|
|
16
|
+
if (process.env['NO_COLOR'] !== undefined)
|
|
17
|
+
return false;
|
|
18
|
+
const fc = process.env['FORCE_COLOR'];
|
|
19
|
+
if (fc !== undefined)
|
|
20
|
+
return fc !== '0' && fc.toLowerCase() !== 'false';
|
|
21
|
+
return process.stdout?.isTTY === true;
|
|
22
|
+
}
|
|
23
|
+
const c = (color, s) => colorsEnabled() ? exports.COLORS[color] + s + exports.COLORS.reset : s;
|
|
16
24
|
exports.c = c;
|
|
17
25
|
//# sourceMappingURL=colors.js.map
|
package/src/core/colors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"colors.js","sourceRoot":"","sources":["../../../src/core/colors.ts"],"names":[],"mappings":";;;AAAa,QAAA,MAAM,GAAG;IACpB,KAAK,EAAE,SAAS;IAChB,IAAI,EAAE,SAAS;IACf,GAAG,EAAE,SAAS;IACd,GAAG,EAAE,UAAU;IACf,KAAK,EAAE,UAAU;IACjB,MAAM,EAAE,UAAU;IAClB,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,UAAU;CACR,CAAC;
|
|
1
|
+
{"version":3,"file":"colors.js","sourceRoot":"","sources":["../../../src/core/colors.ts"],"names":[],"mappings":";;;AAAa,QAAA,MAAM,GAAG;IACpB,KAAK,EAAE,SAAS;IAChB,IAAI,EAAE,SAAS;IACf,GAAG,EAAE,SAAS;IACd,GAAG,EAAE,UAAU;IACf,KAAK,EAAE,UAAU;IACjB,MAAM,EAAE,UAAU;IAClB,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,UAAU;CACR,CAAC;AAEX,SAAS,aAAa;IACpB,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACxD,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IACtC,IAAI,EAAE,KAAK,SAAS;QAAE,OAAO,EAAE,KAAK,GAAG,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,OAAO,CAAC;IACxE,OAAO,OAAO,CAAC,MAAM,EAAE,KAAK,KAAK,IAAI,CAAC;AACxC,CAAC;AAEM,MAAM,CAAC,GAAG,CAAC,KAA0B,EAAE,CAAS,EAAU,EAAE,CACjE,aAAa,EAAE,CAAC,CAAC,CAAC,cAAM,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,cAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAD5C,QAAA,CAAC,KAC2C","sourcesContent":["export const COLORS = {\n reset: '\\x1b[0m',\n bold: '\\x1b[1m',\n dim: '\\x1b[2m',\n red: '\\x1b[31m',\n green: '\\x1b[32m',\n yellow: '\\x1b[33m',\n blue: '\\x1b[34m',\n cyan: '\\x1b[36m',\n gray: '\\x1b[90m',\n} as const;\n\nfunction colorsEnabled(): boolean {\n if (process.env['NO_COLOR'] !== undefined) return false;\n const fc = process.env['FORCE_COLOR'];\n if (fc !== undefined) return fc !== '0' && fc.toLowerCase() !== 'false';\n return process.stdout?.isTTY === true;\n}\n\nexport const c = (color: keyof typeof COLORS, s: string): string =>\n colorsEnabled() ? COLORS[color] + s + COLORS.reset : s;\n"]}
|
package/src/core/help.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
/**
|
|
3
3
|
* Apply custom help formatting to the top-level program so that
|
|
4
|
-
* `frontmcp --help` groups commands under section headers
|
|
5
|
-
*
|
|
4
|
+
* `frontmcp --help` groups commands under section headers, shows skills
|
|
5
|
+
* subcommands inline, and appends a concise Examples block.
|
|
6
6
|
*/
|
|
7
7
|
export declare function customizeHelp(program: Command): void;
|
package/src/core/help.js
CHANGED
|
@@ -2,23 +2,69 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.customizeHelp = customizeHelp;
|
|
4
4
|
const colors_1 = require("./colors");
|
|
5
|
-
/**
|
|
5
|
+
/**
|
|
6
|
+
* Command groups in display order, mapped to the command names they contain.
|
|
7
|
+
* The `skills` group is handled separately to show subcommands inline.
|
|
8
|
+
*/
|
|
6
9
|
const GROUPS = [
|
|
7
|
-
['
|
|
8
|
-
['
|
|
9
|
-
['Process Manager', ['start', 'stop', 'restart', 'status', 'list', 'logs', 'service']],
|
|
10
|
+
['Getting Started', ['create', 'init', 'doctor']],
|
|
11
|
+
['Development', ['dev', 'build', 'test', 'inspector']],
|
|
12
|
+
['Process Manager', ['start', 'stop', 'restart', 'status', 'list', 'logs', 'socket', 'service']],
|
|
10
13
|
['Package Manager', ['install', 'uninstall', 'configure']],
|
|
11
14
|
];
|
|
15
|
+
const EXAMPLES = [
|
|
16
|
+
'npx frontmcp create my-mcp # Scaffold a new project',
|
|
17
|
+
'frontmcp dev # Start dev server with hot-reload',
|
|
18
|
+
'frontmcp build --target node # Build for Node.js deployment',
|
|
19
|
+
'frontmcp start my-app --port 3005 # Start managed server',
|
|
20
|
+
'frontmcp install @company/my-mcp # Install from npm registry',
|
|
21
|
+
'frontmcp skills search "openapi" # Find skills in catalog',
|
|
22
|
+
];
|
|
23
|
+
/** Format a top-level command line with cyan name and dim arg placeholders. */
|
|
24
|
+
function formatCommandLine(sub, padWidth) {
|
|
25
|
+
const rawName = sub.name();
|
|
26
|
+
const rawArgs = sub.registeredArguments.map((a) => (a.required ? `<${a.name()}>` : `[${a.name()}]`)).join(' ');
|
|
27
|
+
const rawTerm = rawArgs ? `${rawName} ${rawArgs}` : rawName;
|
|
28
|
+
const name = (0, colors_1.c)('cyan', rawName);
|
|
29
|
+
const args = sub.registeredArguments.map((a) => (0, colors_1.c)('dim', a.required ? `<${a.name()}>` : `[${a.name()}]`)).join(' ');
|
|
30
|
+
const term = args ? `${name} ${args}` : name;
|
|
31
|
+
const padding = ' '.repeat(Math.max(2, padWidth - rawTerm.length + 2));
|
|
32
|
+
return ` ${term}${padding}${sub.description()}`;
|
|
33
|
+
}
|
|
34
|
+
/** Format a skills subcommand as "skills <subname> <args>". */
|
|
35
|
+
function formatSkillsLine(sub, padWidth) {
|
|
36
|
+
const rawPrefix = `skills ${sub.name()}`;
|
|
37
|
+
const rawArgs = sub.registeredArguments.map((a) => (a.required ? `<${a.name()}>` : `[${a.name()}]`)).join(' ');
|
|
38
|
+
const rawTerm = rawArgs ? `${rawPrefix} ${rawArgs}` : rawPrefix;
|
|
39
|
+
const prefix = (0, colors_1.c)('cyan', rawPrefix);
|
|
40
|
+
const args = sub.registeredArguments.map((a) => (0, colors_1.c)('dim', a.required ? `<${a.name()}>` : `[${a.name()}]`)).join(' ');
|
|
41
|
+
const term = args ? `${prefix} ${args}` : prefix;
|
|
42
|
+
const padding = ' '.repeat(Math.max(2, padWidth - rawTerm.length + 2));
|
|
43
|
+
return ` ${term}${padding}${sub.description()}`;
|
|
44
|
+
}
|
|
12
45
|
/**
|
|
13
46
|
* Apply custom help formatting to the top-level program so that
|
|
14
|
-
* `frontmcp --help` groups commands under section headers
|
|
15
|
-
*
|
|
47
|
+
* `frontmcp --help` groups commands under section headers, shows skills
|
|
48
|
+
* subcommands inline, and appends a concise Examples block.
|
|
16
49
|
*/
|
|
17
50
|
function customizeHelp(program) {
|
|
18
51
|
program.configureHelp({
|
|
19
52
|
formatHelp(cmd, helper) {
|
|
20
|
-
|
|
53
|
+
let termWidth = helper.padWidth(cmd, helper);
|
|
21
54
|
const lines = [];
|
|
55
|
+
// Adjust padWidth to account for skills subcommand terms (e.g. "skills search <query>")
|
|
56
|
+
const allCommands = helper.visibleCommands(cmd);
|
|
57
|
+
const skillsCmd = allCommands.find((c) => c.name() === 'skills');
|
|
58
|
+
const skillsSubs = skillsCmd ? helper.visibleCommands(skillsCmd) : [];
|
|
59
|
+
if (skillsCmd) {
|
|
60
|
+
for (const sub of skillsSubs) {
|
|
61
|
+
const rawArgs = sub.registeredArguments
|
|
62
|
+
.map((a) => (a.required ? `<${a.name()}>` : `[${a.name()}]`))
|
|
63
|
+
.join(' ');
|
|
64
|
+
const rawTerm = rawArgs ? `skills ${sub.name()} ${rawArgs}` : `skills ${sub.name()}`;
|
|
65
|
+
termWidth = Math.max(termWidth, rawTerm.length);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
22
68
|
// Description
|
|
23
69
|
const desc = helper.commandDescription(cmd);
|
|
24
70
|
if (desc)
|
|
@@ -27,18 +73,31 @@ function customizeHelp(program) {
|
|
|
27
73
|
lines.push((0, colors_1.c)('bold', 'Usage'));
|
|
28
74
|
lines.push(` ${helper.commandUsage(cmd)}`, '');
|
|
29
75
|
// Grouped commands
|
|
30
|
-
const allCommands = cmd.commands;
|
|
31
76
|
for (const [label, names] of GROUPS) {
|
|
32
77
|
const matching = names.map((n) => allCommands.find((c) => c.name() === n)).filter(Boolean);
|
|
33
78
|
if (matching.length === 0)
|
|
34
79
|
continue;
|
|
35
80
|
lines.push((0, colors_1.c)('bold', label));
|
|
36
81
|
for (const sub of matching) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
82
|
+
lines.push(formatCommandLine(sub, termWidth));
|
|
83
|
+
}
|
|
84
|
+
lines.push('');
|
|
85
|
+
}
|
|
86
|
+
// Skills — show subcommands inline
|
|
87
|
+
if (skillsCmd && skillsSubs.length > 0) {
|
|
88
|
+
lines.push((0, colors_1.c)('bold', 'Skills'));
|
|
89
|
+
for (const sub of skillsSubs) {
|
|
90
|
+
lines.push(formatSkillsLine(sub, termWidth));
|
|
91
|
+
}
|
|
92
|
+
lines.push('');
|
|
93
|
+
}
|
|
94
|
+
// Other commands not in any group
|
|
95
|
+
const renderedNames = new Set([...GROUPS.flatMap(([, names]) => names), 'skills']);
|
|
96
|
+
const other = allCommands.filter((sc) => !renderedNames.has(sc.name()));
|
|
97
|
+
if (other.length > 0) {
|
|
98
|
+
lines.push((0, colors_1.c)('bold', 'Other'));
|
|
99
|
+
for (const sub of other) {
|
|
100
|
+
lines.push(formatCommandLine(sub, termWidth));
|
|
42
101
|
}
|
|
43
102
|
lines.push('');
|
|
44
103
|
}
|
|
@@ -56,33 +115,15 @@ function customizeHelp(program) {
|
|
|
56
115
|
return lines.join('\n');
|
|
57
116
|
},
|
|
58
117
|
});
|
|
59
|
-
program.addHelpText('after',
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
npx frontmcp create # Interactive mode
|
|
70
|
-
npx frontmcp create my-mcp --yes # Use defaults
|
|
71
|
-
npx frontmcp create my-mcp --target vercel # Vercel deployment
|
|
72
|
-
frontmcp socket ./src/main.ts --socket /tmp/my-app.sock
|
|
73
|
-
frontmcp start my-app --entry ./src/main.ts --port 3005
|
|
74
|
-
frontmcp stop my-app
|
|
75
|
-
frontmcp logs my-app --follow
|
|
76
|
-
frontmcp service install my-app
|
|
77
|
-
frontmcp skills list
|
|
78
|
-
frontmcp skills search "openapi adapter"
|
|
79
|
-
frontmcp skills install frontmcp-development -p claude
|
|
80
|
-
frontmcp skills install --all -p claude
|
|
81
|
-
frontmcp install @company/my-mcp --registry https://npm.company.com
|
|
82
|
-
frontmcp install ./my-local-app
|
|
83
|
-
frontmcp install github:user/repo
|
|
84
|
-
frontmcp configure my-app
|
|
85
|
-
frontmcp uninstall my-app
|
|
86
|
-
`);
|
|
118
|
+
program.addHelpText('after', () => {
|
|
119
|
+
const lines = [
|
|
120
|
+
(0, colors_1.c)('bold', 'Examples'),
|
|
121
|
+
...EXAMPLES.map((ex) => ` ${ex}`),
|
|
122
|
+
'',
|
|
123
|
+
(0, colors_1.c)('dim', `Use ${(0, colors_1.c)('cyan', 'frontmcp <command> --help')} for detailed usage of any command.`),
|
|
124
|
+
'',
|
|
125
|
+
];
|
|
126
|
+
return '\n' + lines.join('\n');
|
|
127
|
+
});
|
|
87
128
|
}
|
|
88
129
|
//# sourceMappingURL=help.js.map
|
package/src/core/help.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"help.js","sourceRoot":"","sources":["../../../src/core/help.ts"],"names":[],"mappings":"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","sourcesContent":["import { Command } from 'commander';\nimport { c } from './colors';\n\n/** Group labels in display order, mapped to the command names they contain. */\nconst GROUPS: [label: string, commands: string[]][] = [\n ['Development', ['dev', 'build', 'test', 'init', 'doctor', 'inspector', 'create', 'socket']],\n ['Skills', ['skills']],\n ['Process Manager', ['start', 'stop', 'restart', 'status', 'list', 'logs', 'service']],\n ['Package Manager', ['install', 'uninstall', 'configure']],\n];\n\n/**\n * Apply custom help formatting to the top-level program so that\n * `frontmcp --help` groups commands under section headers and appends\n * an Examples block.\n */\nexport function customizeHelp(program: Command): void {\n program.configureHelp({\n formatHelp(cmd, helper) {\n const termWidth = helper.padWidth(cmd, helper);\n const lines: string[] = [];\n\n // Description\n const desc = helper.commandDescription(cmd);\n if (desc) lines.push(desc, '');\n\n // Usage\n lines.push(c('bold', 'Usage'));\n lines.push(` ${helper.commandUsage(cmd)}`, '');\n\n // Grouped commands\n const allCommands = cmd.commands;\n for (const [label, names] of GROUPS) {\n const matching = names.map((n) => allCommands.find((c) => c.name() === n)).filter(Boolean) as Command[];\n if (matching.length === 0) continue;\n\n lines.push(c('bold', label));\n for (const sub of matching) {\n const name = sub.name();\n const args = sub.registeredArguments.map((a) => (a.required ? `<${a.name()}>` : `[${a.name()}]`)).join(' ');\n const term = args ? `${name} ${args}` : name;\n const padding = ' '.repeat(Math.max(2, termWidth - term.length + 2));\n lines.push(` ${term}${padding}${sub.description()}`);\n }\n lines.push('');\n }\n\n // Global options\n const opts = helper.visibleOptions(cmd);\n if (opts.length > 0) {\n lines.push(c('bold', 'Options'));\n for (const opt of opts) {\n const term = helper.optionTerm(opt);\n const padding = ' '.repeat(Math.max(2, termWidth - term.length + 2));\n lines.push(` ${term}${padding}${helper.optionDescription(opt)}`);\n }\n lines.push('');\n }\n\n return lines.join('\\n');\n },\n });\n\n program.addHelpText(\n 'after',\n `\n${c('bold', 'Examples')}\n frontmcp dev\n frontmcp build --target node\n frontmcp build --target cli\n frontmcp build --target cli --js\n frontmcp test --runInBand\n frontmcp init\n frontmcp doctor\n frontmcp inspector\n npx frontmcp create # Interactive mode\n npx frontmcp create my-mcp --yes # Use defaults\n npx frontmcp create my-mcp --target vercel # Vercel deployment\n frontmcp socket ./src/main.ts --socket /tmp/my-app.sock\n frontmcp start my-app --entry ./src/main.ts --port 3005\n frontmcp stop my-app\n frontmcp logs my-app --follow\n frontmcp service install my-app\n frontmcp skills list\n frontmcp skills search \"openapi adapter\"\n frontmcp skills install frontmcp-development -p claude\n frontmcp skills install --all -p claude\n frontmcp install @company/my-mcp --registry https://npm.company.com\n frontmcp install ./my-local-app\n frontmcp install github:user/repo\n frontmcp configure my-app\n frontmcp uninstall my-app\n`,\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"help.js","sourceRoot":"","sources":["../../../src/core/help.ts"],"names":[],"mappings":"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","sourcesContent":["import { Command } from 'commander';\nimport { c } from './colors';\n\n/**\n * Command groups in display order, mapped to the command names they contain.\n * The `skills` group is handled separately to show subcommands inline.\n */\nconst GROUPS: [label: string, commands: string[]][] = [\n ['Getting Started', ['create', 'init', 'doctor']],\n ['Development', ['dev', 'build', 'test', 'inspector']],\n ['Process Manager', ['start', 'stop', 'restart', 'status', 'list', 'logs', 'socket', 'service']],\n ['Package Manager', ['install', 'uninstall', 'configure']],\n];\n\nconst EXAMPLES: string[] = [\n 'npx frontmcp create my-mcp # Scaffold a new project',\n 'frontmcp dev # Start dev server with hot-reload',\n 'frontmcp build --target node # Build for Node.js deployment',\n 'frontmcp start my-app --port 3005 # Start managed server',\n 'frontmcp install @company/my-mcp # Install from npm registry',\n 'frontmcp skills search \"openapi\" # Find skills in catalog',\n];\n\n/** Format a top-level command line with cyan name and dim arg placeholders. */\nfunction formatCommandLine(sub: Command, padWidth: number): string {\n const rawName = sub.name();\n const rawArgs = sub.registeredArguments.map((a) => (a.required ? `<${a.name()}>` : `[${a.name()}]`)).join(' ');\n const rawTerm = rawArgs ? `${rawName} ${rawArgs}` : rawName;\n\n const name = c('cyan', rawName);\n const args = sub.registeredArguments.map((a) => c('dim', a.required ? `<${a.name()}>` : `[${a.name()}]`)).join(' ');\n const term = args ? `${name} ${args}` : name;\n\n const padding = ' '.repeat(Math.max(2, padWidth - rawTerm.length + 2));\n return ` ${term}${padding}${sub.description()}`;\n}\n\n/** Format a skills subcommand as \"skills <subname> <args>\". */\nfunction formatSkillsLine(sub: Command, padWidth: number): string {\n const rawPrefix = `skills ${sub.name()}`;\n const rawArgs = sub.registeredArguments.map((a) => (a.required ? `<${a.name()}>` : `[${a.name()}]`)).join(' ');\n const rawTerm = rawArgs ? `${rawPrefix} ${rawArgs}` : rawPrefix;\n\n const prefix = c('cyan', rawPrefix);\n const args = sub.registeredArguments.map((a) => c('dim', a.required ? `<${a.name()}>` : `[${a.name()}]`)).join(' ');\n const term = args ? `${prefix} ${args}` : prefix;\n\n const padding = ' '.repeat(Math.max(2, padWidth - rawTerm.length + 2));\n return ` ${term}${padding}${sub.description()}`;\n}\n\n/**\n * Apply custom help formatting to the top-level program so that\n * `frontmcp --help` groups commands under section headers, shows skills\n * subcommands inline, and appends a concise Examples block.\n */\nexport function customizeHelp(program: Command): void {\n program.configureHelp({\n formatHelp(cmd, helper) {\n let termWidth = helper.padWidth(cmd, helper);\n const lines: string[] = [];\n\n // Adjust padWidth to account for skills subcommand terms (e.g. \"skills search <query>\")\n const allCommands = helper.visibleCommands(cmd);\n const skillsCmd = allCommands.find((c) => c.name() === 'skills');\n const skillsSubs = skillsCmd ? helper.visibleCommands(skillsCmd) : [];\n if (skillsCmd) {\n for (const sub of skillsSubs) {\n const rawArgs = sub.registeredArguments\n .map((a) => (a.required ? `<${a.name()}>` : `[${a.name()}]`))\n .join(' ');\n const rawTerm = rawArgs ? `skills ${sub.name()} ${rawArgs}` : `skills ${sub.name()}`;\n termWidth = Math.max(termWidth, rawTerm.length);\n }\n }\n\n // Description\n const desc = helper.commandDescription(cmd);\n if (desc) lines.push(desc, '');\n\n // Usage\n lines.push(c('bold', 'Usage'));\n lines.push(` ${helper.commandUsage(cmd)}`, '');\n\n // Grouped commands\n for (const [label, names] of GROUPS) {\n const matching = names.map((n) => allCommands.find((c) => c.name() === n)).filter(Boolean) as Command[];\n if (matching.length === 0) continue;\n\n lines.push(c('bold', label));\n for (const sub of matching) {\n lines.push(formatCommandLine(sub, termWidth));\n }\n lines.push('');\n }\n\n // Skills — show subcommands inline\n if (skillsCmd && skillsSubs.length > 0) {\n lines.push(c('bold', 'Skills'));\n for (const sub of skillsSubs) {\n lines.push(formatSkillsLine(sub, termWidth));\n }\n lines.push('');\n }\n\n // Other commands not in any group\n const renderedNames = new Set([...GROUPS.flatMap(([, names]) => names), 'skills']);\n const other = allCommands.filter((sc) => !renderedNames.has(sc.name()));\n if (other.length > 0) {\n lines.push(c('bold', 'Other'));\n for (const sub of other) {\n lines.push(formatCommandLine(sub, termWidth));\n }\n lines.push('');\n }\n\n // Global options\n const opts = helper.visibleOptions(cmd);\n if (opts.length > 0) {\n lines.push(c('bold', 'Options'));\n for (const opt of opts) {\n const term = helper.optionTerm(opt);\n const padding = ' '.repeat(Math.max(2, termWidth - term.length + 2));\n lines.push(` ${term}${padding}${helper.optionDescription(opt)}`);\n }\n lines.push('');\n }\n\n return lines.join('\\n');\n },\n });\n\n program.addHelpText('after', () => {\n const lines = [\n c('bold', 'Examples'),\n ...EXAMPLES.map((ex) => ` ${ex}`),\n '',\n c('dim', `Use ${c('cyan', 'frontmcp <command> --help')} for detailed usage of any command.`),\n '',\n ];\n return '\\n' + lines.join('\\n');\n });\n}\n"]}
|
package/src/core/program.js
CHANGED
|
@@ -12,7 +12,10 @@ const register_6 = require("../commands/skills/register");
|
|
|
12
12
|
const help_1 = require("./help");
|
|
13
13
|
function createProgram() {
|
|
14
14
|
const program = new commander_1.Command();
|
|
15
|
-
program
|
|
15
|
+
program
|
|
16
|
+
.name('frontmcp')
|
|
17
|
+
.description('Build, test, and deploy MCP servers with FrontMCP')
|
|
18
|
+
.version((0, version_1.getSelfVersion)(), '-V, --version');
|
|
16
19
|
(0, register_1.registerDevCommands)(program);
|
|
17
20
|
(0, register_2.registerBuildCommands)(program);
|
|
18
21
|
(0, register_3.registerScaffoldCommands)(program);
|
package/src/core/program.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"program.js","sourceRoot":"","sources":["../../../src/core/program.ts"],"names":[],"mappings":";;AAUA,
|
|
1
|
+
{"version":3,"file":"program.js","sourceRoot":"","sources":["../../../src/core/program.ts"],"names":[],"mappings":";;AAUA,sCAiBC;AA3BD,yCAAoC;AACpC,uCAA2C;AAC3C,uDAA+D;AAC/D,yDAAmE;AACnE,4DAAyE;AACzE,sDAA6D;AAC7D,2DAAuE;AACvE,0DAAqE;AACrE,iCAAuC;AAEvC,SAAgB,aAAa;IAC3B,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,UAAU,CAAC;SAChB,WAAW,CAAC,mDAAmD,CAAC;SAChE,OAAO,CAAC,IAAA,wBAAc,GAAE,EAAE,eAAe,CAAC,CAAC;IAE9C,IAAA,8BAAmB,EAAC,OAAO,CAAC,CAAC;IAC7B,IAAA,gCAAqB,EAAC,OAAO,CAAC,CAAC;IAC/B,IAAA,mCAAwB,EAAC,OAAO,CAAC,CAAC;IAClC,IAAA,6BAAkB,EAAC,OAAO,CAAC,CAAC;IAC5B,IAAA,kCAAuB,EAAC,OAAO,CAAC,CAAC;IACjC,IAAA,iCAAsB,EAAC,OAAO,CAAC,CAAC;IAChC,IAAA,oBAAa,EAAC,OAAO,CAAC,CAAC;IAEvB,OAAO,OAAO,CAAC;AACjB,CAAC","sourcesContent":["import { Command } from 'commander';\nimport { getSelfVersion } from './version';\nimport { registerDevCommands } from '../commands/dev/register';\nimport { registerBuildCommands } from '../commands/build/register';\nimport { registerScaffoldCommands } from '../commands/scaffold/register';\nimport { registerPmCommands } from '../commands/pm/register';\nimport { registerPackageCommands } from '../commands/package/register';\nimport { registerSkillsCommands } from '../commands/skills/register';\nimport { customizeHelp } from './help';\n\nexport function createProgram(): Command {\n const program = new Command();\n\n program\n .name('frontmcp')\n .description('Build, test, and deploy MCP servers with FrontMCP')\n .version(getSelfVersion(), '-V, --version');\n\n registerDevCommands(program);\n registerBuildCommands(program);\n registerScaffoldCommands(program);\n registerPmCommands(program);\n registerPackageCommands(program);\n registerSkillsCommands(program);\n customizeHelp(program);\n\n return program;\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function showSkill(name: string): Promise<void>;
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.showSkill = showSkill;
|
|
4
|
-
const tslib_1 = require("tslib");
|
|
5
|
-
const path = tslib_1.__importStar(require("path"));
|
|
6
|
-
const colors_1 = require("../../core/colors");
|
|
7
|
-
const utils_1 = require("@frontmcp/utils");
|
|
8
|
-
const catalog_1 = require("./catalog");
|
|
9
|
-
async function showSkill(name) {
|
|
10
|
-
const manifest = (0, catalog_1.loadCatalog)();
|
|
11
|
-
const entry = manifest.skills.find((s) => s.name === name);
|
|
12
|
-
if (!entry) {
|
|
13
|
-
console.error((0, colors_1.c)('red', `Skill "${name}" not found in catalog.`));
|
|
14
|
-
console.log((0, colors_1.c)('gray', "Use 'frontmcp skills list' to see available skills."));
|
|
15
|
-
process.exit(1);
|
|
16
|
-
}
|
|
17
|
-
const catalogDir = (0, catalog_1.getCatalogDir)();
|
|
18
|
-
const skillDir = path.join(catalogDir, entry.path);
|
|
19
|
-
const skillMd = path.join(skillDir, 'SKILL.md');
|
|
20
|
-
if (!(await (0, utils_1.fileExists)(skillMd))) {
|
|
21
|
-
console.error((0, colors_1.c)('red', `SKILL.md not found at ${skillMd}`));
|
|
22
|
-
process.exit(1);
|
|
23
|
-
}
|
|
24
|
-
const content = await (0, utils_1.readFile)(skillMd);
|
|
25
|
-
console.log((0, colors_1.c)('bold', `\n ${entry.name}`));
|
|
26
|
-
console.log((0, colors_1.c)('gray', ` Category: ${entry.category}`));
|
|
27
|
-
console.log((0, colors_1.c)('gray', ` Tags: ${entry.tags.join(', ')}`));
|
|
28
|
-
console.log((0, colors_1.c)('gray', ` Targets: ${entry.targets.join(', ')}`));
|
|
29
|
-
console.log((0, colors_1.c)('gray', ` Bundle: ${entry.bundle?.join(', ') ?? 'none'}`));
|
|
30
|
-
console.log((0, colors_1.c)('gray', ` Has resources: ${entry.hasResources}`));
|
|
31
|
-
console.log('');
|
|
32
|
-
console.log((0, colors_1.c)('gray', ' ─────────────────────────────────────'));
|
|
33
|
-
console.log('');
|
|
34
|
-
// Print body (skip frontmatter)
|
|
35
|
-
const bodyStart = content.indexOf('---', 3);
|
|
36
|
-
if (bodyStart !== -1) {
|
|
37
|
-
const body = content.substring(bodyStart + 3).trim();
|
|
38
|
-
console.log(body);
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
console.log(content);
|
|
42
|
-
}
|
|
43
|
-
console.log('');
|
|
44
|
-
console.log((0, colors_1.c)('gray', ` Install: frontmcp skills install ${name} --provider claude`));
|
|
45
|
-
}
|
|
46
|
-
//# sourceMappingURL=show.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"show.js","sourceRoot":"","sources":["../../../../src/commands/skills/show.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from 'path';\nimport { c } from '../../core/colors';\nimport { fileExists, readFile } from '@frontmcp/utils';\nimport { loadCatalog, getCatalogDir } from './catalog';\n\nexport async function showSkill(name: string): Promise<void> {\n const manifest = loadCatalog();\n const entry = manifest.skills.find((s) => s.name === name);\n\n if (!entry) {\n console.error(c('red', `Skill \"${name}\" not found in catalog.`));\n console.log(c('gray', \"Use 'frontmcp skills list' to see available skills.\"));\n process.exit(1);\n }\n\n const catalogDir = getCatalogDir();\n const skillDir = path.join(catalogDir, entry.path);\n const skillMd = path.join(skillDir, 'SKILL.md');\n\n if (!(await fileExists(skillMd))) {\n console.error(c('red', `SKILL.md not found at ${skillMd}`));\n process.exit(1);\n }\n\n const content = await readFile(skillMd);\n\n console.log(c('bold', `\\n ${entry.name}`));\n console.log(c('gray', ` Category: ${entry.category}`));\n console.log(c('gray', ` Tags: ${entry.tags.join(', ')}`));\n console.log(c('gray', ` Targets: ${entry.targets.join(', ')}`));\n console.log(c('gray', ` Bundle: ${entry.bundle?.join(', ') ?? 'none'}`));\n console.log(c('gray', ` Has resources: ${entry.hasResources}`));\n console.log('');\n console.log(c('gray', ' ─────────────────────────────────────'));\n console.log('');\n\n // Print body (skip frontmatter)\n const bodyStart = content.indexOf('---', 3);\n if (bodyStart !== -1) {\n const body = content.substring(bodyStart + 3).trim();\n console.log(body);\n } else {\n console.log(content);\n }\n\n console.log('');\n console.log(c('gray', ` Install: frontmcp skills install ${name} --provider claude`));\n}\n"]}
|