frontmcp 1.2.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/package.json +4 -4
  2. package/src/commands/build/exec/bin-meta.d.ts +49 -0
  3. package/src/commands/build/exec/bin-meta.js +68 -0
  4. package/src/commands/build/exec/bin-meta.js.map +1 -0
  5. package/src/commands/build/exec/cli-runtime/generate-cli-entry.js +195 -3
  6. package/src/commands/build/exec/cli-runtime/generate-cli-entry.js.map +1 -1
  7. package/src/commands/build/exec/cli-runtime/plugin-emitter.d.ts +160 -0
  8. package/src/commands/build/exec/cli-runtime/plugin-emitter.js +512 -0
  9. package/src/commands/build/exec/cli-runtime/plugin-emitter.js.map +1 -0
  10. package/src/commands/build/exec/cli-runtime/schema-extractor.d.ts +13 -1
  11. package/src/commands/build/exec/cli-runtime/schema-extractor.js +29 -3
  12. package/src/commands/build/exec/cli-runtime/schema-extractor.js.map +1 -1
  13. package/src/commands/build/exec/cli-runtime/skill-md-compose.d.ts +25 -0
  14. package/src/commands/build/exec/cli-runtime/skill-md-compose.js +63 -0
  15. package/src/commands/build/exec/cli-runtime/skill-md-compose.js.map +1 -0
  16. package/src/commands/build/exec/index.js +26 -0
  17. package/src/commands/build/exec/index.js.map +1 -1
  18. package/src/commands/dev/bridge/child-supervisor.d.ts +48 -0
  19. package/src/commands/dev/bridge/child-supervisor.js +228 -0
  20. package/src/commands/dev/bridge/child-supervisor.js.map +1 -0
  21. package/src/commands/dev/bridge/errors.d.ts +23 -0
  22. package/src/commands/dev/bridge/errors.js +34 -0
  23. package/src/commands/dev/bridge/errors.js.map +1 -0
  24. package/src/commands/dev/bridge/index.d.ts +30 -0
  25. package/src/commands/dev/bridge/index.js +220 -0
  26. package/src/commands/dev/bridge/index.js.map +1 -0
  27. package/src/commands/dev/bridge/log.d.ts +29 -0
  28. package/src/commands/dev/bridge/log.js +82 -0
  29. package/src/commands/dev/bridge/log.js.map +1 -0
  30. package/src/commands/dev/bridge/state-machine.d.ts +56 -0
  31. package/src/commands/dev/bridge/state-machine.js +245 -0
  32. package/src/commands/dev/bridge/state-machine.js.map +1 -0
  33. package/src/commands/dev/bridge/stdio-framer.d.ts +47 -0
  34. package/src/commands/dev/bridge/stdio-framer.js +128 -0
  35. package/src/commands/dev/bridge/stdio-framer.js.map +1 -0
  36. package/src/commands/dev/bridge/upstream-client.d.ts +49 -0
  37. package/src/commands/dev/bridge/upstream-client.js +159 -0
  38. package/src/commands/dev/bridge/upstream-client.js.map +1 -0
  39. package/src/commands/dev/bridge/watcher.d.ts +30 -0
  40. package/src/commands/dev/bridge/watcher.js +87 -0
  41. package/src/commands/dev/bridge/watcher.js.map +1 -0
  42. package/src/commands/dev/dev.d.ts +18 -1
  43. package/src/commands/dev/dev.js +134 -14
  44. package/src/commands/dev/dev.js.map +1 -1
  45. package/src/commands/dev/inspector.d.ts +13 -1
  46. package/src/commands/dev/inspector.js +77 -3
  47. package/src/commands/dev/inspector.js.map +1 -1
  48. package/src/commands/dev/port.d.ts +23 -0
  49. package/src/commands/dev/port.js +87 -0
  50. package/src/commands/dev/port.js.map +1 -0
  51. package/src/commands/dev/register.d.ts +1 -1
  52. package/src/commands/dev/register.js +28 -4
  53. package/src/commands/dev/register.js.map +1 -1
  54. package/src/commands/dev/test.d.ts +26 -1
  55. package/src/commands/dev/test.js +181 -64
  56. package/src/commands/dev/test.js.map +1 -1
  57. package/src/commands/eject/mcp-client.d.ts +25 -0
  58. package/src/commands/eject/mcp-client.js +74 -0
  59. package/src/commands/eject/mcp-client.js.map +1 -0
  60. package/src/commands/eject/register.d.ts +9 -0
  61. package/src/commands/eject/register.js +56 -0
  62. package/src/commands/eject/register.js.map +1 -0
  63. package/src/commands/install/install-claude-plugin.d.ts +13 -0
  64. package/src/commands/install/install-claude-plugin.js +327 -0
  65. package/src/commands/install/install-claude-plugin.js.map +1 -0
  66. package/src/commands/install/register.d.ts +16 -0
  67. package/src/commands/install/register.js +70 -0
  68. package/src/commands/install/register.js.map +1 -0
  69. package/src/commands/scaffold/create.js +44 -0
  70. package/src/commands/scaffold/create.js.map +1 -1
  71. package/src/commands/skills/from-entry.d.ts +31 -0
  72. package/src/commands/skills/from-entry.js +68 -0
  73. package/src/commands/skills/from-entry.js.map +1 -0
  74. package/src/commands/skills/install.d.ts +12 -0
  75. package/src/commands/skills/install.js +173 -8
  76. package/src/commands/skills/install.js.map +1 -1
  77. package/src/commands/skills/register.js +7 -3
  78. package/src/commands/skills/register.js.map +1 -1
  79. package/src/config/frontmcp-config.loader.d.ts +28 -0
  80. package/src/config/frontmcp-config.loader.js +146 -67
  81. package/src/config/frontmcp-config.loader.js.map +1 -1
  82. package/src/config/frontmcp-config.resolve.d.ts +67 -0
  83. package/src/config/frontmcp-config.resolve.js +118 -0
  84. package/src/config/frontmcp-config.resolve.js.map +1 -0
  85. package/src/config/frontmcp-config.schema.d.ts +207 -0
  86. package/src/config/frontmcp-config.schema.js +217 -1
  87. package/src/config/frontmcp-config.schema.js.map +1 -1
  88. package/src/config/frontmcp-config.types.d.ts +133 -0
  89. package/src/config/frontmcp-config.types.js.map +1 -1
  90. package/src/config/index.d.ts +2 -1
  91. package/src/config/index.js +3 -1
  92. package/src/config/index.js.map +1 -1
  93. package/src/core/args.d.ts +13 -0
  94. package/src/core/args.js.map +1 -1
  95. package/src/core/bridge.js +39 -0
  96. package/src/core/bridge.js.map +1 -1
  97. package/src/core/cli.d.ts +0 -6
  98. package/src/core/cli.js +23 -3
  99. package/src/core/cli.js.map +1 -1
  100. package/src/core/help.d.ts +1 -1
  101. package/src/core/help.js +27 -6
  102. package/src/core/help.js.map +1 -1
  103. package/src/core/program.d.ts +1 -1
  104. package/src/core/program.js +56 -12
  105. package/src/core/program.js.map +1 -1
  106. package/src/core/project-commands.d.ts +44 -0
  107. package/src/core/project-commands.js +216 -0
  108. package/src/core/project-commands.js.map +1 -0
@@ -5,10 +5,14 @@ exports.ensureClaudeMdSkillsInstructions = ensureClaudeMdSkillsInstructions;
5
5
  exports.installSkill = installSkill;
6
6
  const tslib_1 = require("tslib");
7
7
  const path = tslib_1.__importStar(require("path"));
8
+ const utils_1 = require("@frontmcp/utils");
8
9
  const colors_1 = require("../../core/colors");
9
10
  const version_1 = require("../../core/version");
10
- const utils_1 = require("@frontmcp/utils");
11
+ const fs_1 = require("../../shared/fs");
12
+ const plugin_emitter_1 = require("../build/exec/cli-runtime/plugin-emitter");
13
+ const skill_md_compose_1 = require("../build/exec/cli-runtime/skill-md-compose");
11
14
  const catalog_1 = require("./catalog");
15
+ const from_entry_1 = require("./from-entry");
12
16
  const PROVIDER_DIRS = {
13
17
  claude: '.claude/skills',
14
18
  codex: '.codex/skills',
@@ -68,13 +72,12 @@ function buildSkillsSection(version, skills) {
68
72
  * - If file doesn't exist: creates it with the block.
69
73
  */
70
74
  async function ensureClaudeMdSkillsInstructions(cwd) {
71
- const manifest = (0, catalog_1.loadCatalog)();
72
75
  const version = (0, version_1.getSelfVersion)();
73
- // Only include skills that are actually installed (not the full catalog)
74
- const installedSkills = (await Promise.all(manifest.skills.map(async (skill) => {
75
- const skillMdPath = path.join(cwd, '.claude', 'skills', skill.name, 'SKILL.md');
76
- return (await (0, utils_1.fileExists)(skillMdPath)) ? { name: skill.name, description: skill.description } : undefined;
77
- }))).filter((s) => s !== undefined);
76
+ // Scan the actual `.claude/skills/<name>/SKILL.md` tree rather than
77
+ // filtering against the framework catalog project-defined skills
78
+ // (installed via `--from-entry` / `--from-package`) live in the same
79
+ // directory and must also be listed in the CLAUDE.md block.
80
+ const installedSkills = await scanInstalledSkills(path.join(cwd, '.claude', 'skills'));
78
81
  const section = buildSkillsSection(version, installedSkills);
79
82
  const claudeMdPath = path.join(cwd, 'CLAUDE.md');
80
83
  if (await (0, utils_1.fileExists)(claudeMdPath)) {
@@ -117,9 +120,17 @@ async function ensureClaudeMdSkillsInstructions(cwd) {
117
120
  }
118
121
  }
119
122
  async function installSkill(name, options) {
120
- const manifest = (0, catalog_1.loadCatalog)();
121
123
  const provider = options.provider ?? 'claude';
122
124
  const targetBase = options.dir ?? path.resolve(process.cwd(), PROVIDER_DIRS[provider] ?? PROVIDER_DIRS['claude']);
125
+ if (options.fromEntry && options.fromPackage) {
126
+ console.error((0, colors_1.c)('red', 'Options --from-entry and --from-package are mutually exclusive.'));
127
+ process.exit(1);
128
+ }
129
+ if (options.fromEntry || options.fromPackage) {
130
+ await installFromProject({ name, options, provider, targetBase });
131
+ return;
132
+ }
133
+ const manifest = (0, catalog_1.loadCatalog)();
123
134
  const catalogDir = (0, catalog_1.getCatalogDir)();
124
135
  // Validate that exactly one selector is supplied
125
136
  const selectorCount = [options.all, options.tag, options.category, name].filter(Boolean).length;
@@ -190,4 +201,158 @@ async function installSkill(name, options) {
190
201
  await ensureClaudeMdSkillsInstructions(process.cwd());
191
202
  }
192
203
  }
204
+ async function installFromProject(args) {
205
+ const { name, options, provider, targetBase } = args;
206
+ const selectorCount = [options.all, name].filter(Boolean).length;
207
+ if (selectorCount > 1) {
208
+ console.error((0, colors_1.c)('red', 'Options --all and <name> are mutually exclusive.'));
209
+ process.exit(1);
210
+ }
211
+ if (selectorCount === 0) {
212
+ console.error((0, colors_1.c)('red', 'Specify a skill name or --all when using --from-entry/--from-package.'));
213
+ process.exit(1);
214
+ }
215
+ if (options.tag || options.category) {
216
+ console.error((0, colors_1.c)('red', '--tag and --category are not supported with --from-entry/--from-package yet.'));
217
+ process.exit(1);
218
+ }
219
+ const cwd = process.cwd();
220
+ let entry;
221
+ if (options.fromPackage) {
222
+ try {
223
+ entry = (0, from_entry_1.resolvePackageEntry)(options.fromPackage, cwd);
224
+ }
225
+ catch (err) {
226
+ console.error((0, colors_1.c)('red', `Could not resolve package "${options.fromPackage}" from ${cwd}: ${err.message}`));
227
+ process.exit(1);
228
+ }
229
+ }
230
+ else {
231
+ entry = await (0, fs_1.resolveEntry)(cwd, options.fromEntry);
232
+ }
233
+ let assets;
234
+ try {
235
+ assets = await (0, from_entry_1.extractProjectSkills)({ entry, cwd });
236
+ }
237
+ catch (err) {
238
+ console.error((0, colors_1.c)('red', `Could not enumerate @Skill entries from ${entry}: ${err.message}`));
239
+ process.exit(1);
240
+ }
241
+ if (assets.length === 0) {
242
+ console.error((0, colors_1.c)('yellow', `No @Skill-decorated entries found in ${path.relative(cwd, entry) || entry}.`));
243
+ process.exit(1);
244
+ }
245
+ let selected = assets;
246
+ if (name) {
247
+ const match = assets.find((a) => a.skillName === name);
248
+ if (!match) {
249
+ console.error((0, colors_1.c)('red', `Skill "${name}" not found in ${options.fromPackage ?? path.relative(cwd, entry)}.`));
250
+ console.log((0, colors_1.c)('gray', ` Available: ${assets.map((a) => a.skillName).join(', ')}`));
251
+ process.exit(1);
252
+ }
253
+ selected = [match];
254
+ }
255
+ let installed = 0;
256
+ for (const asset of selected) {
257
+ // Validate the skill name BEFORE it lands in a filesystem path or
258
+ // the synthesized SKILL.md frontmatter. Same rules as plugin names
259
+ // (issue #411 security pass) — a malicious `@Skill({ name: '../x' })`
260
+ // would otherwise escape `targetBase` via `path.join`.
261
+ try {
262
+ (0, plugin_emitter_1.assertValidPluginName)(asset.skillName, 'skills install --from-entry');
263
+ }
264
+ catch (err) {
265
+ console.error((0, colors_1.c)('yellow', ` Skipped: ${err.message}`));
266
+ continue;
267
+ }
268
+ const targetDir = path.join(targetBase, asset.skillName);
269
+ try {
270
+ await materializeProjectSkill(asset, targetDir);
271
+ installed++;
272
+ console.log(`${(0, colors_1.c)('green', '✓')} Installed ${(0, colors_1.c)('bold', asset.skillName)} to ${(0, colors_1.c)('cyan', path.relative(cwd, targetDir))}`);
273
+ }
274
+ catch (err) {
275
+ console.error((0, colors_1.c)('yellow', ` Skipped ${asset.skillName}: ${err.message}`));
276
+ }
277
+ }
278
+ if (installed === 0) {
279
+ console.error((0, colors_1.c)('red', `No skills were installed (0/${selected.length}).`));
280
+ process.exit(1);
281
+ }
282
+ if (selected.length > 1) {
283
+ console.log(`\n${(0, colors_1.c)('green', '✓')} Installed ${installed}/${selected.length} skills (provider: ${provider})`);
284
+ }
285
+ if (provider === 'claude') {
286
+ await ensureClaudeMdSkillsInstructions(cwd);
287
+ }
288
+ }
289
+ async function materializeProjectSkill(asset, targetDir) {
290
+ await (0, utils_1.ensureDir)(targetDir);
291
+ const body = asset.instructionFile && (await (0, utils_1.fileExists)(asset.instructionFile)) ? await (0, utils_1.readFile)(asset.instructionFile) : '';
292
+ const skillMd = (0, skill_md_compose_1.composeSkillMd)({ name: asset.skillName, description: asset.description, tags: asset.tags, license: asset.license }, body);
293
+ await (0, utils_1.writeFile)(path.join(targetDir, 'SKILL.md'), skillMd);
294
+ for (const kind of ['references', 'examples', 'scripts', 'assets']) {
295
+ const src = asset.resourceDirs?.[kind];
296
+ if (!src)
297
+ continue;
298
+ if (!(await (0, utils_1.fileExists)(src)))
299
+ continue;
300
+ const dest = path.join(targetDir, kind);
301
+ await (0, utils_1.cp)(src, dest, { recursive: true });
302
+ }
303
+ }
304
+ /**
305
+ * Walk `<base>/<skill>/SKILL.md` and read the frontmatter `name` / `description`
306
+ * for each. Used by `ensureClaudeMdSkillsInstructions` to list both catalog
307
+ * and project-defined skills in the auto-generated block.
308
+ */
309
+ async function scanInstalledSkills(base) {
310
+ if (!(await (0, utils_1.fileExists)(base)))
311
+ return [];
312
+ const catalog = (0, catalog_1.loadCatalog)();
313
+ const catalogByName = new Map(catalog.skills.map((s) => [s.name, s]));
314
+ let entries;
315
+ try {
316
+ entries = await (0, utils_1.readdir)(base);
317
+ }
318
+ catch {
319
+ return [];
320
+ }
321
+ const summaries = [];
322
+ for (const entry of entries.sort()) {
323
+ const skillMdPath = path.join(base, entry, 'SKILL.md');
324
+ if (!(await (0, utils_1.fileExists)(skillMdPath)))
325
+ continue;
326
+ const fromCatalog = catalogByName.get(entry);
327
+ if (fromCatalog) {
328
+ summaries.push({ name: fromCatalog.name, description: fromCatalog.description });
329
+ continue;
330
+ }
331
+ // Project-defined skill — read frontmatter for description.
332
+ const content = await (0, utils_1.readFile)(skillMdPath);
333
+ summaries.push({ name: entry, description: extractFrontmatterDescription(content) ?? `${entry} skill` });
334
+ }
335
+ return summaries;
336
+ }
337
+ function extractFrontmatterDescription(content) {
338
+ if (!(0, skill_md_compose_1.hasFrontmatter)(content))
339
+ return undefined;
340
+ const end = content.indexOf('\n---', 4);
341
+ if (end < 0)
342
+ return undefined;
343
+ const frontmatter = content.slice(4, end);
344
+ const match = frontmatter.match(/^description:\s*(.+)$/m);
345
+ if (!match)
346
+ return undefined;
347
+ const raw = match[1].trim();
348
+ if ((raw.startsWith('"') && raw.endsWith('"')) || (raw.startsWith("'") && raw.endsWith("'"))) {
349
+ try {
350
+ return JSON.parse(raw.replace(/^'/, '"').replace(/'$/, '"'));
351
+ }
352
+ catch {
353
+ return raw.slice(1, -1);
354
+ }
355
+ }
356
+ return raw;
357
+ }
193
358
  //# 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 { getSelfVersion } from '../../core/version';\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/** Start marker for the auto-generated skills block (version is appended). */\nconst SKILLS_BLOCK_START = '<!-- frontmcp:skills-start';\n/** End marker for the auto-generated skills block. */\nconst SKILLS_BLOCK_END = '<!-- frontmcp:skills-end -->';\n/** Legacy marker from older versions (used for migration). */\nconst LEGACY_SKILLS_MARKER = '# Skills and Tools';\n\n/**\n * Build a short summary from a skill description.\n * Takes the first sentence or truncates at ~80 chars.\n */\nfunction summarizeDescription(description: string): string {\n // Take text before the first period that ends a sentence\n const firstSentence = description.replace(/\\. .+$/, '');\n // Remove the \"Use when you want to\" / \"Use when you need to\" prefix\n const cleaned = firstSentence\n .replace(/^Use when you (?:want|need) to\\s+/i, '')\n .replace(/^Use (?:before|when)\\s+/i, '');\n // Truncate if still long\n if (cleaned.length > 90) {\n return cleaned.slice(0, 87) + '...';\n }\n return cleaned;\n}\n\n/**\n * Build the skills CLAUDE.md section dynamically from the manifest.\n */\nexport function buildSkillsSection(version: string, skills: { name: string; description: string }[]): string {\n const lines: string[] = [];\n\n lines.push(`${SKILLS_BLOCK_START} v${version} -->`);\n lines.push('# Skills and Tools');\n lines.push('');\n lines.push(`> Auto-generated by \\`frontmcp skills install\\` (v${version}) — do not edit manually.`);\n lines.push('');\n lines.push('This project uses **FrontMCP skills** installed in `.claude/skills/`.');\n lines.push('Before writing code, search the installed skills for relevant guidance:');\n lines.push('');\n\n for (const skill of skills) {\n const summary = summarizeDescription(skill.description);\n lines.push(`- **${skill.name}** — ${summary}`);\n }\n\n lines.push('');\n lines.push(\n 'When you need to implement something, **read the matching skill first** — it contains patterns, examples, and common mistakes to avoid.',\n );\n lines.push(SKILLS_BLOCK_END);\n lines.push('');\n\n return lines.join('\\n');\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 an up-to-date skills section.\n *\n * - If markers exist: replaces the block between them (handles version updates).\n * - If legacy `# Skills and Tools` header exists (no markers): replaces it.\n * - If neither exists: prepends the block.\n * - If file doesn't exist: creates it with the block.\n */\nexport async function ensureClaudeMdSkillsInstructions(cwd: string): Promise<void> {\n const manifest = loadCatalog();\n const version = getSelfVersion();\n // Only include skills that are actually installed (not the full catalog)\n const installedSkills = (\n await Promise.all(\n manifest.skills.map(async (skill) => {\n const skillMdPath = path.join(cwd, '.claude', 'skills', skill.name, 'SKILL.md');\n return (await fileExists(skillMdPath)) ? { name: skill.name, description: skill.description } : undefined;\n }),\n )\n ).filter((s): s is { name: string; description: string } => s !== undefined);\n const section = buildSkillsSection(version, installedSkills);\n const claudeMdPath = path.join(cwd, 'CLAUDE.md');\n\n if (await fileExists(claudeMdPath)) {\n let content = await readFile(claudeMdPath);\n\n if (content.includes(SKILLS_BLOCK_START)) {\n // Replace existing marker-bounded block\n const startIdx = content.indexOf(SKILLS_BLOCK_START);\n const endIdx = content.indexOf(SKILLS_BLOCK_END, startIdx);\n if (endIdx !== -1) {\n const before = content.slice(0, startIdx);\n const after = content.slice(endIdx + SKILLS_BLOCK_END.length);\n // Trim leading newlines from after to avoid accumulating blank lines\n content = before + section + after.replace(/^\\n+/, '\\n');\n } else {\n // Malformed: start marker without end — replace from start marker to end of file section\n content = content.slice(0, startIdx) + section + '\\n';\n }\n } else if (content.includes(LEGACY_SKILLS_MARKER)) {\n // Migrate legacy format: replace from the legacy header to the next markdown heading\n const legacyIdx = content.indexOf(LEGACY_SKILLS_MARKER);\n const before = content.slice(0, legacyIdx);\n const afterLegacy = content.slice(legacyIdx + LEGACY_SKILLS_MARKER.length);\n // Find the next markdown heading (# at start of line) after the legacy header\n const nextHeadingMatch = afterLegacy.match(/\\n(?=#{1,6}\\s)/);\n const after =\n nextHeadingMatch && nextHeadingMatch.index !== undefined ? afterLegacy.slice(nextHeadingMatch.index) : '';\n content = before + section + after;\n } else {\n // No existing skills section — prepend\n content = section + '\\n' + content;\n }\n\n await writeFile(claudeMdPath, content);\n console.log(`${c('green', '✓')} Updated ${c('cyan', 'CLAUDE.md')} with skills usage instructions`);\n } else {\n await writeFile(claudeMdPath, 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"]}
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';\n\nimport { cp, ensureDir, fileExists, readdir, readFile, writeFile } from '@frontmcp/utils';\n\nimport { c } from '../../core/colors';\nimport { getSelfVersion } from '../../core/version';\nimport { resolveEntry } from '../../shared/fs';\nimport { assertValidPluginName } from '../build/exec/cli-runtime/plugin-emitter';\nimport type { ExtractedSkillAsset } from '../build/exec/cli-runtime/schema-extractor';\nimport { composeSkillMd, hasFrontmatter } from '../build/exec/cli-runtime/skill-md-compose';\nimport { getCatalogDir, loadCatalog } from './catalog';\nimport { extractProjectSkills, resolvePackageEntry } from './from-entry';\n\nconst PROVIDER_DIRS: Record<string, string> = {\n claude: '.claude/skills',\n codex: '.codex/skills',\n};\n\n/** Start marker for the auto-generated skills block (version is appended). */\nconst SKILLS_BLOCK_START = '<!-- frontmcp:skills-start';\n/** End marker for the auto-generated skills block. */\nconst SKILLS_BLOCK_END = '<!-- frontmcp:skills-end -->';\n/** Legacy marker from older versions (used for migration). */\nconst LEGACY_SKILLS_MARKER = '# Skills and Tools';\n\n/**\n * Build a short summary from a skill description.\n * Takes the first sentence or truncates at ~80 chars.\n */\nfunction summarizeDescription(description: string): string {\n // Take text before the first period that ends a sentence\n const firstSentence = description.replace(/\\. .+$/, '');\n // Remove the \"Use when you want to\" / \"Use when you need to\" prefix\n const cleaned = firstSentence\n .replace(/^Use when you (?:want|need) to\\s+/i, '')\n .replace(/^Use (?:before|when)\\s+/i, '');\n // Truncate if still long\n if (cleaned.length > 90) {\n return cleaned.slice(0, 87) + '...';\n }\n return cleaned;\n}\n\n/**\n * Build the skills CLAUDE.md section dynamically from the manifest.\n */\nexport function buildSkillsSection(version: string, skills: { name: string; description: string }[]): string {\n const lines: string[] = [];\n\n lines.push(`${SKILLS_BLOCK_START} v${version} -->`);\n lines.push('# Skills and Tools');\n lines.push('');\n lines.push(`> Auto-generated by \\`frontmcp skills install\\` (v${version}) — do not edit manually.`);\n lines.push('');\n lines.push('This project uses **FrontMCP skills** installed in `.claude/skills/`.');\n lines.push('Before writing code, search the installed skills for relevant guidance:');\n lines.push('');\n\n for (const skill of skills) {\n const summary = summarizeDescription(skill.description);\n lines.push(`- **${skill.name}** — ${summary}`);\n }\n\n lines.push('');\n lines.push(\n 'When you need to implement something, **read the matching skill first** — it contains patterns, examples, and common mistakes to avoid.',\n );\n lines.push(SKILLS_BLOCK_END);\n lines.push('');\n\n return lines.join('\\n');\n}\n\nexport interface InstallOptions {\n provider?: 'claude' | 'codex';\n dir?: string;\n all?: boolean;\n tag?: string;\n category?: string;\n /**\n * Install skills from a project's `@Skill`-decorated entries instead of\n * the bundled framework catalog. Bundles the entry via esbuild and\n * enumerates skills through the same path the per-bin install uses.\n */\n fromEntry?: string;\n /**\n * Install skills from a published package's `@Skill`-decorated entries.\n * The package must be installed under the project's `node_modules/` so\n * Node's module resolution can locate it.\n */\n fromPackage?: string;\n}\n\n/**\n * Ensure CLAUDE.md exists and contains an up-to-date skills section.\n *\n * - If markers exist: replaces the block between them (handles version updates).\n * - If legacy `# Skills and Tools` header exists (no markers): replaces it.\n * - If neither exists: prepends the block.\n * - If file doesn't exist: creates it with the block.\n */\nexport async function ensureClaudeMdSkillsInstructions(cwd: string): Promise<void> {\n const version = getSelfVersion();\n // Scan the actual `.claude/skills/<name>/SKILL.md` tree rather than\n // filtering against the framework catalog — project-defined skills\n // (installed via `--from-entry` / `--from-package`) live in the same\n // directory and must also be listed in the CLAUDE.md block.\n const installedSkills = await scanInstalledSkills(path.join(cwd, '.claude', 'skills'));\n const section = buildSkillsSection(version, installedSkills);\n const claudeMdPath = path.join(cwd, 'CLAUDE.md');\n\n if (await fileExists(claudeMdPath)) {\n let content = await readFile(claudeMdPath);\n\n if (content.includes(SKILLS_BLOCK_START)) {\n // Replace existing marker-bounded block\n const startIdx = content.indexOf(SKILLS_BLOCK_START);\n const endIdx = content.indexOf(SKILLS_BLOCK_END, startIdx);\n if (endIdx !== -1) {\n const before = content.slice(0, startIdx);\n const after = content.slice(endIdx + SKILLS_BLOCK_END.length);\n // Trim leading newlines from after to avoid accumulating blank lines\n content = before + section + after.replace(/^\\n+/, '\\n');\n } else {\n // Malformed: start marker without end — replace from start marker to end of file section\n content = content.slice(0, startIdx) + section + '\\n';\n }\n } else if (content.includes(LEGACY_SKILLS_MARKER)) {\n // Migrate legacy format: replace from the legacy header to the next markdown heading\n const legacyIdx = content.indexOf(LEGACY_SKILLS_MARKER);\n const before = content.slice(0, legacyIdx);\n const afterLegacy = content.slice(legacyIdx + LEGACY_SKILLS_MARKER.length);\n // Find the next markdown heading (# at start of line) after the legacy header\n const nextHeadingMatch = afterLegacy.match(/\\n(?=#{1,6}\\s)/);\n const after =\n nextHeadingMatch && nextHeadingMatch.index !== undefined ? afterLegacy.slice(nextHeadingMatch.index) : '';\n content = before + section + after;\n } else {\n // No existing skills section — prepend\n content = section + '\\n' + content;\n }\n\n await writeFile(claudeMdPath, content);\n console.log(`${c('green', '✓')} Updated ${c('cyan', 'CLAUDE.md')} with skills usage instructions`);\n } else {\n await writeFile(claudeMdPath, 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 provider = options.provider ?? 'claude';\n const targetBase = options.dir ?? path.resolve(process.cwd(), PROVIDER_DIRS[provider] ?? PROVIDER_DIRS['claude']);\n\n if (options.fromEntry && options.fromPackage) {\n console.error(c('red', 'Options --from-entry and --from-package are mutually exclusive.'));\n process.exit(1);\n }\n\n if (options.fromEntry || options.fromPackage) {\n await installFromProject({ name, options, provider, targetBase });\n return;\n }\n\n const manifest = loadCatalog();\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\ninterface InstallFromProjectArgs {\n name: string | undefined;\n options: InstallOptions;\n provider: 'claude' | 'codex';\n targetBase: string;\n}\n\nasync function installFromProject(args: InstallFromProjectArgs): Promise<void> {\n const { name, options, provider, targetBase } = args;\n\n const selectorCount = [options.all, name].filter(Boolean).length;\n if (selectorCount > 1) {\n console.error(c('red', 'Options --all and <name> are mutually exclusive.'));\n process.exit(1);\n }\n if (selectorCount === 0) {\n console.error(c('red', 'Specify a skill name or --all when using --from-entry/--from-package.'));\n process.exit(1);\n }\n if (options.tag || options.category) {\n console.error(c('red', '--tag and --category are not supported with --from-entry/--from-package yet.'));\n process.exit(1);\n }\n\n const cwd = process.cwd();\n let entry: string;\n if (options.fromPackage) {\n try {\n entry = resolvePackageEntry(options.fromPackage, cwd);\n } catch (err) {\n console.error(\n c('red', `Could not resolve package \"${options.fromPackage}\" from ${cwd}: ${(err as Error).message}`),\n );\n process.exit(1);\n }\n } else {\n entry = await resolveEntry(cwd, options.fromEntry);\n }\n\n let assets: ExtractedSkillAsset[];\n try {\n assets = await extractProjectSkills({ entry, cwd });\n } catch (err) {\n console.error(c('red', `Could not enumerate @Skill entries from ${entry}: ${(err as Error).message}`));\n process.exit(1);\n }\n\n if (assets.length === 0) {\n console.error(c('yellow', `No @Skill-decorated entries found in ${path.relative(cwd, entry) || entry}.`));\n process.exit(1);\n }\n\n let selected = assets;\n if (name) {\n const match = assets.find((a) => a.skillName === name);\n if (!match) {\n console.error(c('red', `Skill \"${name}\" not found in ${options.fromPackage ?? path.relative(cwd, entry)}.`));\n console.log(c('gray', ` Available: ${assets.map((a) => a.skillName).join(', ')}`));\n process.exit(1);\n }\n selected = [match];\n }\n\n let installed = 0;\n for (const asset of selected) {\n // Validate the skill name BEFORE it lands in a filesystem path or\n // the synthesized SKILL.md frontmatter. Same rules as plugin names\n // (issue #411 security pass) — a malicious `@Skill({ name: '../x' })`\n // would otherwise escape `targetBase` via `path.join`.\n try {\n assertValidPluginName(asset.skillName, 'skills install --from-entry');\n } catch (err) {\n console.error(c('yellow', ` Skipped: ${(err as Error).message}`));\n continue;\n }\n const targetDir = path.join(targetBase, asset.skillName);\n try {\n await materializeProjectSkill(asset, targetDir);\n installed++;\n console.log(\n `${c('green', '✓')} Installed ${c('bold', asset.skillName)} to ${c('cyan', path.relative(cwd, targetDir))}`,\n );\n } catch (err) {\n console.error(c('yellow', ` Skipped ${asset.skillName}: ${(err as Error).message}`));\n }\n }\n\n if (installed === 0) {\n console.error(c('red', `No skills were installed (0/${selected.length}).`));\n process.exit(1);\n }\n\n if (selected.length > 1) {\n console.log(`\\n${c('green', '✓')} Installed ${installed}/${selected.length} skills (provider: ${provider})`);\n }\n\n if (provider === 'claude') {\n await ensureClaudeMdSkillsInstructions(cwd);\n }\n}\n\nasync function materializeProjectSkill(asset: ExtractedSkillAsset, targetDir: string): Promise<void> {\n await ensureDir(targetDir);\n\n const body =\n asset.instructionFile && (await fileExists(asset.instructionFile)) ? await readFile(asset.instructionFile) : '';\n const skillMd = composeSkillMd(\n { name: asset.skillName, description: asset.description, tags: asset.tags, license: asset.license },\n body,\n );\n await writeFile(path.join(targetDir, 'SKILL.md'), skillMd);\n\n for (const kind of ['references', 'examples', 'scripts', 'assets'] as const) {\n const src = asset.resourceDirs?.[kind];\n if (!src) continue;\n if (!(await fileExists(src))) continue;\n const dest = path.join(targetDir, kind);\n await cp(src, dest, { recursive: true });\n }\n}\n\ninterface InstalledSkillSummary {\n name: string;\n description: string;\n}\n\n/**\n * Walk `<base>/<skill>/SKILL.md` and read the frontmatter `name` / `description`\n * for each. Used by `ensureClaudeMdSkillsInstructions` to list both catalog\n * and project-defined skills in the auto-generated block.\n */\nasync function scanInstalledSkills(base: string): Promise<InstalledSkillSummary[]> {\n if (!(await fileExists(base))) return [];\n const catalog = loadCatalog();\n const catalogByName = new Map(catalog.skills.map((s) => [s.name, s] as const));\n\n let entries: string[];\n try {\n entries = await readdir(base);\n } catch {\n return [];\n }\n\n const summaries: InstalledSkillSummary[] = [];\n for (const entry of entries.sort()) {\n const skillMdPath = path.join(base, entry, 'SKILL.md');\n if (!(await fileExists(skillMdPath))) continue;\n\n const fromCatalog = catalogByName.get(entry);\n if (fromCatalog) {\n summaries.push({ name: fromCatalog.name, description: fromCatalog.description });\n continue;\n }\n\n // Project-defined skill — read frontmatter for description.\n const content = await readFile(skillMdPath);\n summaries.push({ name: entry, description: extractFrontmatterDescription(content) ?? `${entry} skill` });\n }\n return summaries;\n}\n\nfunction extractFrontmatterDescription(content: string): string | undefined {\n if (!hasFrontmatter(content)) return undefined;\n const end = content.indexOf('\\n---', 4);\n if (end < 0) return undefined;\n const frontmatter = content.slice(4, end);\n const match = frontmatter.match(/^description:\\s*(.+)$/m);\n if (!match) return undefined;\n const raw = match[1].trim();\n if ((raw.startsWith('\"') && raw.endsWith('\"')) || (raw.startsWith(\"'\") && raw.endsWith(\"'\"))) {\n try {\n return JSON.parse(raw.replace(/^'/, '\"').replace(/'$/, '\"'));\n } catch {\n return raw.slice(1, -1);\n }\n }\n return raw;\n}\n"]}
@@ -34,9 +34,11 @@ function registerSkillsCommands(program) {
34
34
  .argument('[name]', 'Skill name to install (optional with --all, --tag, or --category)')
35
35
  .option('-p, --provider <provider>', 'Target provider: claude, codex (default: claude)', 'claude')
36
36
  .option('-d, --dir <directory>', 'Custom install directory (overrides provider default)')
37
- .option('-a, --all', 'Install all skills from the catalog')
38
- .option('-t, --tag <tag>', 'Install all skills matching a tag')
39
- .option('-c, --category <category>', 'Install all skills in a category')
37
+ .option('-a, --all', 'Install all skills from the catalog (or all @Skill entries when --from-entry/--from-package is set)')
38
+ .option('-t, --tag <tag>', 'Install all skills matching a tag (catalog only)')
39
+ .option('-c, --category <category>', 'Install all skills in a category (catalog only)')
40
+ .option('--from-entry <path>', 'Install @Skill entries from a local project entry file instead of the framework catalog')
41
+ .option('--from-package <pkg>', "Install @Skill entries from a published package's main entry instead of the framework catalog")
40
42
  .action(async (name, options) => {
41
43
  const validProviders = ['claude', 'codex'];
42
44
  const raw = options.provider;
@@ -51,6 +53,8 @@ function registerSkillsCommands(program) {
51
53
  all: options.all,
52
54
  tag: options.tag,
53
55
  category: options.category,
56
+ fromEntry: options.fromEntry,
57
+ fromPackage: options.fromPackage,
54
58
  });
55
59
  });
56
60
  skills
@@ -1 +1 @@
1
- {"version":3,"file":"register.js","sourceRoot":"","sources":["../../../../src/commands/skills/register.ts"],"names":[],"mappings":"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","sourcesContent":["import { type 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('export')\n .description('Convert a catalog skill into a Cursor / Windsurf / Copilot rule file in the current directory')\n .option('-t, --target <target>', 'Target IDE: cursor | windsurf | copilot', 'cursor')\n .option('-n, --name <name>', 'Skill name to export (required unless --all is set)')\n .option('-a, --all', 'Export every skill in the catalog')\n .option('-d, --out <directory>', 'Output directory (default: cwd)')\n .action(async (options: { target?: string; name?: string; all?: boolean; out?: string }) => {\n const validTargets = ['cursor', 'windsurf', 'copilot'] as const;\n type Target = (typeof validTargets)[number];\n const t = (options.target ?? 'cursor') as Target;\n if (!validTargets.includes(t)) {\n console.error(`Invalid target \"${options.target}\". Valid targets: ${validTargets.join(', ')}`);\n process.exit(1);\n }\n const { exportSkills } = await import('./export.js');\n await exportSkills({\n target: t,\n name: options.name,\n all: options.all,\n outDir: options.out,\n });\n });\n\n skills\n .command('publish')\n .description('Publish a skill to a public marketplace (Smithery or Glama)')\n .argument('<name>', 'Skill name to publish')\n .option('-t, --target <target>', 'Marketplace target: smithery | glama', 'smithery')\n .option('--token <token>', 'API token (defaults to SMITHERY_TOKEN / GLAMA_TOKEN env)')\n .option('--repository <url>', 'Repository URL to advertise on the marketplace')\n .option('--dry-run', 'Print the payload + endpoint without submitting')\n .action(\n async (name: string, options: { target?: string; token?: string; repository?: string; dryRun?: boolean }) => {\n const validTargets = ['smithery', 'glama'] as const;\n type Target = (typeof validTargets)[number];\n const t = (options.target ?? 'smithery') as Target;\n if (!validTargets.includes(t)) {\n console.error(`Invalid target \"${options.target}\". Valid targets: ${validTargets.join(', ')}`);\n process.exit(1);\n }\n const { publishSkill } = await import('./publish.js');\n await publishSkill({\n target: t,\n name,\n token: options.token,\n repository: options.repository,\n dryRun: options.dryRun,\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 .option('--examples [reference]', 'List examples for the skill, optionally filtered by reference name')\n .action(\n async (name: string, reference: string | undefined, options: { refs?: boolean; examples?: boolean | string }) => {\n const { readSkill } = await import('./read.js');\n await readSkill(name, {\n reference,\n listRefs: options.refs,\n listExamples: options.examples === true ? true : undefined,\n examplesForRef: typeof options.examples === 'string' ? options.examples : undefined,\n });\n },\n );\n}\n"]}
1
+ {"version":3,"file":"register.js","sourceRoot":"","sources":["../../../../src/commands/skills/register.ts"],"names":[],"mappings":";;AAEA,wDAyJC;AAzJD,SAAgB,sBAAsB,CAAC,OAAgB;IACrD,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,4DAA4D,CAAC,CAAC;IAEnH,MAAM;SACH,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,wDAAwD,CAAC;SACrE,QAAQ,CAAC,SAAS,EAAE,qDAAqD,CAAC;SAC1E,MAAM,CAAC,qBAAqB,EAAE,2BAA2B,EAAE,IAAI,CAAC;SAChE,MAAM,CAAC,iBAAiB,EAAE,eAAe,CAAC;SAC1C,MAAM,CAAC,2BAA2B,EAAE,oBAAoB,CAAC;SACzD,MAAM,CAAC,KAAK,EAAE,KAAa,EAAE,OAA4D,EAAE,EAAE;QAC5F,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;QACrD,MAAM,YAAY,CAAC,KAAK,EAAE;YACxB,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;YAC/C,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,QAAQ,EAAE,OAAO,CAAC,QAAQ;SAC3B,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEL,MAAM;SACH,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,0CAA0C,CAAC;SACvD,MAAM,CAAC,2BAA2B,EAAE,oBAAoB,CAAC;SACzD,MAAM,CAAC,iBAAiB,EAAE,eAAe,CAAC;SAC1C,MAAM,CAAC,uBAAuB,EAAE,+CAA+C,CAAC;SAChF,MAAM,CAAC,KAAK,EAAE,OAA6D,EAAE,EAAE;QAC9E,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;QACjD,MAAM,UAAU,CAAC,OAAO,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEL,MAAM;SACH,OAAO,CAAC,SAAS,CAAC;SAClB,WAAW,CAAC,4EAA4E,CAAC;SACzF,QAAQ,CAAC,QAAQ,EAAE,mEAAmE,CAAC;SACvF,MAAM,CAAC,2BAA2B,EAAE,kDAAkD,EAAE,QAAQ,CAAC;SACjG,MAAM,CAAC,uBAAuB,EAAE,uDAAuD,CAAC;SACxF,MAAM,CACL,WAAW,EACX,qGAAqG,CACtG;SACA,MAAM,CAAC,iBAAiB,EAAE,kDAAkD,CAAC;SAC7E,MAAM,CAAC,2BAA2B,EAAE,iDAAiD,CAAC;SACtF,MAAM,CACL,qBAAqB,EACrB,yFAAyF,CAC1F;SACA,MAAM,CACL,sBAAsB,EACtB,+FAA+F,CAChG;SACA,MAAM,CACL,KAAK,EACH,IAAwB,EACxB,OAQC,EACD,EAAE;QACF,MAAM,cAAc,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAU,CAAC;QAEpD,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC;QAC7B,IAAI,GAAG,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,GAAe,CAAC,EAAE,CAAC;YACrD,OAAO,CAAC,KAAK,CAAC,qBAAqB,GAAG,uBAAuB,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC1F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;QACtD,MAAM,YAAY,CAAC,IAAI,EAAE;YACvB,QAAQ,EAAE,GAA2B;YACrC,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,WAAW,EAAE,OAAO,CAAC,WAAW;SACjC,CAAC,CAAC;IACL,CAAC,CACF,CAAC;IAEJ,MAAM;SACH,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,+FAA+F,CAAC;SAC5G,MAAM,CAAC,uBAAuB,EAAE,yCAAyC,EAAE,QAAQ,CAAC;SACpF,MAAM,CAAC,mBAAmB,EAAE,qDAAqD,CAAC;SAClF,MAAM,CAAC,WAAW,EAAE,mCAAmC,CAAC;SACxD,MAAM,CAAC,uBAAuB,EAAE,iCAAiC,CAAC;SAClE,MAAM,CAAC,KAAK,EAAE,OAAwE,EAAE,EAAE;QACzF,MAAM,YAAY,GAAG,CAAC,QAAQ,EAAE,UAAU,EAAE,SAAS,CAAU,CAAC;QAEhE,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,IAAI,QAAQ,CAAW,CAAC;QACjD,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9B,OAAO,CAAC,KAAK,CAAC,mBAAmB,OAAO,CAAC,MAAM,qBAAqB,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC/F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;QACrD,MAAM,YAAY,CAAC;YACjB,MAAM,EAAE,CAAC;YACT,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,MAAM,EAAE,OAAO,CAAC,GAAG;SACpB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEL,MAAM;SACH,OAAO,CAAC,SAAS,CAAC;SAClB,WAAW,CAAC,6DAA6D,CAAC;SAC1E,QAAQ,CAAC,QAAQ,EAAE,uBAAuB,CAAC;SAC3C,MAAM,CAAC,uBAAuB,EAAE,sCAAsC,EAAE,UAAU,CAAC;SACnF,MAAM,CAAC,iBAAiB,EAAE,0DAA0D,CAAC;SACrF,MAAM,CAAC,oBAAoB,EAAE,gDAAgD,CAAC;SAC9E,MAAM,CAAC,WAAW,EAAE,iDAAiD,CAAC;SACtE,MAAM,CACL,KAAK,EAAE,IAAY,EAAE,OAAmF,EAAE,EAAE;QAC1G,MAAM,YAAY,GAAG,CAAC,UAAU,EAAE,OAAO,CAAU,CAAC;QAEpD,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,IAAI,UAAU,CAAW,CAAC;QACnD,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9B,OAAO,CAAC,KAAK,CAAC,mBAAmB,OAAO,CAAC,MAAM,qBAAqB,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC/F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;QACtD,MAAM,YAAY,CAAC;YACjB,MAAM,EAAE,CAAC;YACT,IAAI;YACJ,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,UAAU,EAAE,OAAO,CAAC,UAAU;YAC9B,MAAM,EAAE,OAAO,CAAC,MAAM;SACvB,CAAC,CAAC;IACL,CAAC,CACF,CAAC;IAEJ,MAAM;SACH,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,kEAAkE,CAAC;SAC/E,QAAQ,CAAC,cAAc,EAAE,6EAA6E,CAAC;SACvG,QAAQ,CAAC,aAAa,EAAE,4CAA4C,CAAC;SACrE,MAAM,CAAC,QAAQ,EAAE,6CAA6C,CAAC;SAC/D,MAAM,CAAC,wBAAwB,EAAE,oEAAoE,CAAC;SACtG,MAAM,CACL,KAAK,EAAE,IAAY,EAAE,SAA6B,EAAE,OAAwD,EAAE,EAAE;QAC9G,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;QAChD,MAAM,SAAS,CAAC,IAAI,EAAE;YACpB,SAAS;YACT,QAAQ,EAAE,OAAO,CAAC,IAAI;YACtB,YAAY,EAAE,OAAO,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;YAC1D,cAAc,EAAE,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;SACpF,CAAC,CAAC;IACL,CAAC,CACF,CAAC;AACN,CAAC","sourcesContent":["import { type 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(\n '-a, --all',\n 'Install all skills from the catalog (or all @Skill entries when --from-entry/--from-package is set)',\n )\n .option('-t, --tag <tag>', 'Install all skills matching a tag (catalog only)')\n .option('-c, --category <category>', 'Install all skills in a category (catalog only)')\n .option(\n '--from-entry <path>',\n 'Install @Skill entries from a local project entry file instead of the framework catalog',\n )\n .option(\n '--from-package <pkg>',\n \"Install @Skill entries from a published package's main entry instead of the framework catalog\",\n )\n .action(\n async (\n name: string | undefined,\n options: {\n provider?: string;\n dir?: string;\n all?: boolean;\n tag?: string;\n category?: string;\n fromEntry?: string;\n fromPackage?: string;\n },\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 fromEntry: options.fromEntry,\n fromPackage: options.fromPackage,\n });\n },\n );\n\n skills\n .command('export')\n .description('Convert a catalog skill into a Cursor / Windsurf / Copilot rule file in the current directory')\n .option('-t, --target <target>', 'Target IDE: cursor | windsurf | copilot', 'cursor')\n .option('-n, --name <name>', 'Skill name to export (required unless --all is set)')\n .option('-a, --all', 'Export every skill in the catalog')\n .option('-d, --out <directory>', 'Output directory (default: cwd)')\n .action(async (options: { target?: string; name?: string; all?: boolean; out?: string }) => {\n const validTargets = ['cursor', 'windsurf', 'copilot'] as const;\n type Target = (typeof validTargets)[number];\n const t = (options.target ?? 'cursor') as Target;\n if (!validTargets.includes(t)) {\n console.error(`Invalid target \"${options.target}\". Valid targets: ${validTargets.join(', ')}`);\n process.exit(1);\n }\n const { exportSkills } = await import('./export.js');\n await exportSkills({\n target: t,\n name: options.name,\n all: options.all,\n outDir: options.out,\n });\n });\n\n skills\n .command('publish')\n .description('Publish a skill to a public marketplace (Smithery or Glama)')\n .argument('<name>', 'Skill name to publish')\n .option('-t, --target <target>', 'Marketplace target: smithery | glama', 'smithery')\n .option('--token <token>', 'API token (defaults to SMITHERY_TOKEN / GLAMA_TOKEN env)')\n .option('--repository <url>', 'Repository URL to advertise on the marketplace')\n .option('--dry-run', 'Print the payload + endpoint without submitting')\n .action(\n async (name: string, options: { target?: string; token?: string; repository?: string; dryRun?: boolean }) => {\n const validTargets = ['smithery', 'glama'] as const;\n type Target = (typeof validTargets)[number];\n const t = (options.target ?? 'smithery') as Target;\n if (!validTargets.includes(t)) {\n console.error(`Invalid target \"${options.target}\". Valid targets: ${validTargets.join(', ')}`);\n process.exit(1);\n }\n const { publishSkill } = await import('./publish.js');\n await publishSkill({\n target: t,\n name,\n token: options.token,\n repository: options.repository,\n dryRun: options.dryRun,\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 .option('--examples [reference]', 'List examples for the skill, optionally filtered by reference name')\n .action(\n async (name: string, reference: string | undefined, options: { refs?: boolean; examples?: boolean | string }) => {\n const { readSkill } = await import('./read.js');\n await readSkill(name, {\n reference,\n listRefs: options.refs,\n listExamples: options.examples === true ? true : undefined,\n examplesForRef: typeof options.examples === 'string' ? options.examples : undefined,\n });\n },\n );\n}\n"]}
@@ -18,6 +18,26 @@ import type { DeploymentTarget } from './frontmcp-config.types';
18
18
  * 6. Derive from package.json (minimal config with 'node' target)
19
19
  */
20
20
  export declare function loadFrontMcpConfig(cwd: string): Promise<FrontMcpConfigParsed>;
21
+ /**
22
+ * Load a specific config file by absolute or cwd-relative path. Used by the
23
+ * `--config <path>` flag and the `FRONTMCP_CONFIG` env var (issue #400).
24
+ *
25
+ * Unlike `loadFrontMcpConfig`, this doesn't search `CONFIG_FILENAMES` — the
26
+ * caller already named the file, so a missing-file error is a hard failure
27
+ * (no silent fallback to `deriveFromPackageJson`).
28
+ */
29
+ export declare function loadFrontMcpConfigFromFile(configPath: string): Promise<FrontMcpConfigParsed>;
30
+ /**
31
+ * Locate the nearest `frontmcp.config.*` file by walking upward from `cwd`.
32
+ *
33
+ * Issue #400 — monorepo nested apps no longer require `cd <repo-root>`
34
+ * before invoking the CLI. The walk caps at 10 levels to avoid pathological
35
+ * symlink loops.
36
+ *
37
+ * Returns the directory containing the config (so callers can pass it to
38
+ * `loadFrontMcpConfig(dir)`), or `undefined` if nothing was found.
39
+ */
40
+ export declare function findConfigDir(startDir: string, maxLevels?: number): Promise<string | undefined>;
21
41
  /**
22
42
  * Variant that load-errors propagate (parse failures in `frontmcp.config.ts`,
23
43
  * missing dependencies, etc.) but schema-validation errors return `undefined`.
@@ -38,6 +58,14 @@ export declare function loadFrontMcpConfig(cwd: string): Promise<FrontMcpConfigP
38
58
  * regressions.
39
59
  */
40
60
  export declare function tryLoadFrontMcpConfig(cwd: string): Promise<FrontMcpConfigParsed | undefined>;
61
+ /**
62
+ * Explicit-path counterpart of {@link tryLoadFrontMcpConfig}. Used by
63
+ * `resolveConfig` for the `--config <path>` / `FRONTMCP_CONFIG` branch so a
64
+ * legacy exec-only config passed via explicit path resolves the same way
65
+ * an auto-discovered one does: `config: undefined`, no throw, callers fall
66
+ * back to `loadExecConfig`. Real parse failures still propagate.
67
+ */
68
+ export declare function tryLoadFrontMcpConfigFromFile(configPath: string): Promise<FrontMcpConfigParsed | undefined>;
41
69
  /**
42
70
  * Validate raw config against the Zod schema.
43
71
  */