@frontmcp/nx 1.0.0-beta.1 → 1.0.0-beta.11

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.
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.default = buildExecExecutor;
4
4
  const child_process_1 = require("child_process");
5
5
  async function buildExecExecutor(options, context) {
6
- const args = ['npx', 'frontmcp', 'build', '--exec'];
6
+ const args = ['npx', 'frontmcp', 'build', '--target', 'node'];
7
7
  if (options.entry)
8
8
  args.push('--entry', options.entry);
9
9
  if (options.outputPath)
@@ -1 +1 @@
1
- {"version":3,"file":"build-exec.impl.js","sourceRoot":"","sources":["../../../../src/executors/build-exec/build-exec.impl.ts"],"names":[],"mappings":";;AAIA,oCAqBC;AAxBD,iDAAyC;AAG1B,KAAK,UAAU,iBAAiB,CAC7C,OAAgC,EAChC,OAAwB;IAExB,MAAM,IAAI,GAAa,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC9D,IAAI,OAAO,CAAC,KAAK;QAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IACvD,IAAI,OAAO,CAAC,UAAU;QAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAEnE,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/B,OAAO,CAAC,GAAG,CAAC,YAAY,OAAO,EAAE,CAAC,CAAC;IAEnC,IAAI,CAAC;QACH,IAAA,wBAAQ,EAAC,OAAO,EAAE;YAChB,GAAG,EAAE,OAAO,CAAC,IAAI;YACjB,KAAK,EAAE,SAAS;YAChB,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE;SAC1C,CAAC,CAAC;QACH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC5B,CAAC;AACH,CAAC","sourcesContent":["import type { ExecutorContext } from '../executor-context.js';\nimport { execSync } from 'child_process';\nimport type { BuildExecExecutorSchema } from './schema.js';\n\nexport default async function buildExecExecutor(\n options: BuildExecExecutorSchema,\n context: ExecutorContext,\n): Promise<{ success: boolean }> {\n const args: string[] = ['npx', 'frontmcp', 'build', '--exec'];\n if (options.entry) args.push('--entry', options.entry);\n if (options.outputPath) args.push('--out-dir', options.outputPath);\n\n const command = args.join(' ');\n console.log(`Running: ${command}`);\n\n try {\n execSync(command, {\n cwd: context.root,\n stdio: 'inherit',\n env: { ...process.env, FORCE_COLOR: '1' },\n });\n return { success: true };\n } catch {\n return { success: false };\n }\n}\n"]}
1
+ {"version":3,"file":"build-exec.impl.js","sourceRoot":"","sources":["../../../../src/executors/build-exec/build-exec.impl.ts"],"names":[],"mappings":";;AAIA,oCAqBC;AAxBD,iDAAyC;AAG1B,KAAK,UAAU,iBAAiB,CAC7C,OAAgC,EAChC,OAAwB;IAExB,MAAM,IAAI,GAAa,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;IACxE,IAAI,OAAO,CAAC,KAAK;QAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IACvD,IAAI,OAAO,CAAC,UAAU;QAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAEnE,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/B,OAAO,CAAC,GAAG,CAAC,YAAY,OAAO,EAAE,CAAC,CAAC;IAEnC,IAAI,CAAC;QACH,IAAA,wBAAQ,EAAC,OAAO,EAAE;YAChB,GAAG,EAAE,OAAO,CAAC,IAAI;YACjB,KAAK,EAAE,SAAS;YAChB,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE;SAC1C,CAAC,CAAC;QACH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC5B,CAAC;AACH,CAAC","sourcesContent":["import type { ExecutorContext } from '../executor-context.js';\nimport { execSync } from 'child_process';\nimport type { BuildExecExecutorSchema } from './schema.js';\n\nexport default async function buildExecExecutor(\n options: BuildExecExecutorSchema,\n context: ExecutorContext,\n): Promise<{ success: boolean }> {\n const args: string[] = ['npx', 'frontmcp', 'build', '--target', 'node'];\n if (options.entry) args.push('--entry', options.entry);\n if (options.outputPath) args.push('--out-dir', options.outputPath);\n\n const command = args.join(' ');\n console.log(`Running: ${command}`);\n\n try {\n execSync(command, {\n cwd: context.root,\n stdio: 'inherit',\n env: { ...process.env, FORCE_COLOR: '1' },\n });\n return { success: true };\n } catch {\n return { success: false };\n }\n}\n"]}
package/executors.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "build-exec": {
9
9
  "implementation": "./executors/build-exec/build-exec.impl",
10
10
  "schema": "./executors/build-exec/schema.json",
11
- "description": "Build a distributable bundle using frontmcp build --exec"
11
+ "description": "Build a distributable bundle using frontmcp build --target node"
12
12
  },
13
13
  "dev": {
14
14
  "implementation": "./executors/dev/dev.impl",
@@ -5,7 +5,7 @@ Description: '<%= className %> FrontMCP Server'
5
5
  Globals:
6
6
  Function:
7
7
  Timeout: 30
8
- Runtime: nodejs22.x
8
+ Runtime: nodejs24.x
9
9
  MemorySize: 256
10
10
 
11
11
  Resources:
@@ -1,14 +1,13 @@
1
- version: '3.8'
2
-
3
1
  services:
4
2
  app:
5
3
  build:
6
4
  context: ../..
7
5
  dockerfile: <%= projectRoot %>/Dockerfile
8
6
  ports:
9
- - '3000:3000'
7
+ - '${PORT:-3000}:3000'
10
8
  environment:
11
- - NODE_ENV=production
9
+ - NODE_ENV=${NODE_ENV:-production}
10
+ - PORT=${PORT:-3000}
12
11
  <% if (redis === 'docker') { %>
13
12
  - REDIS_HOST=redis
14
13
  - REDIS_PORT=6379
@@ -20,9 +19,19 @@ services:
20
19
  image: redis:7-alpine
21
20
  ports:
22
21
  - '6379:6379'
22
+ volumes:
23
+ - redis-data:/data
24
+ command: redis-server --appendonly yes
23
25
  healthcheck:
24
26
  test: ['CMD', 'redis-cli', 'ping']
25
- interval: 10s
27
+ interval: 3s
26
28
  timeout: 5s
27
29
  retries: 3
30
+
31
+ volumes:
32
+ redis-data:
28
33
  <% } %>
34
+
35
+ # Selective rebuild:
36
+ # docker compose up --build app # rebuild only the app
37
+ # docker compose up --build # rebuild everything
@@ -4,6 +4,7 @@ export interface ServerGeneratorSchema {
4
4
  deploymentTarget?: 'node' | 'vercel' | 'lambda' | 'cloudflare';
5
5
  apps: string;
6
6
  redis?: 'docker' | 'existing' | 'none';
7
+ skills?: 'recommended' | 'minimal' | 'full' | 'none';
7
8
  tags?: string;
8
9
  skipFormat?: boolean;
9
10
  }
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../../src/generators/server/schema.ts"],"names":[],"mappings":"","sourcesContent":["export interface ServerGeneratorSchema {\n name: string;\n directory?: string;\n deploymentTarget?: 'node' | 'vercel' | 'lambda' | 'cloudflare';\n apps: string;\n redis?: 'docker' | 'existing' | 'none';\n tags?: string;\n skipFormat?: boolean;\n}\n"]}
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../../src/generators/server/schema.ts"],"names":[],"mappings":"","sourcesContent":["export interface ServerGeneratorSchema {\n name: string;\n directory?: string;\n deploymentTarget?: 'node' | 'vercel' | 'lambda' | 'cloudflare';\n apps: string;\n redis?: 'docker' | 'existing' | 'none';\n skills?: 'recommended' | 'minimal' | 'full' | 'none';\n tags?: string;\n skipFormat?: boolean;\n}\n"]}
@@ -51,6 +51,12 @@
51
51
  "description": "Comma-separated tags",
52
52
  "x-priority": "internal"
53
53
  },
54
+ "skills": {
55
+ "type": "string",
56
+ "description": "Skills bundle to include: recommended, minimal, full, none",
57
+ "enum": ["recommended", "minimal", "full", "none"],
58
+ "default": "recommended"
59
+ },
54
60
  "skipFormat": {
55
61
  "type": "boolean",
56
62
  "description": "Skip formatting files",
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.serverGenerator = serverGenerator;
4
+ const tslib_1 = require("tslib");
4
5
  const devkit_1 = require("@nx/devkit");
6
+ const fs = tslib_1.__importStar(require("fs"));
5
7
  const path_1 = require("path");
6
8
  const index_js_1 = require("./lib/index.js");
7
9
  async function serverGenerator(tree, schema) {
@@ -20,9 +22,54 @@ async function serverGeneratorInternal(tree, schema) {
20
22
  // Generate target-specific files
21
23
  const targetDir = (0, path_1.join)(__dirname, 'files', options.deploymentTarget);
22
24
  (0, devkit_1.generateFiles)(tree, targetDir, options.projectRoot, templateVars);
25
+ // Copy skills from catalog
26
+ const bundle = schema.skills ?? 'recommended';
27
+ if (bundle !== 'none') {
28
+ scaffoldCatalogSkills(tree, options.projectRoot, options.deploymentTarget, bundle);
29
+ }
23
30
  if (!options.skipFormat) {
24
31
  await (0, devkit_1.formatFiles)(tree);
25
32
  }
26
33
  }
34
+ function scaffoldCatalogSkills(tree, projectRoot, target, bundle) {
35
+ // Load skills catalog via @frontmcp/skills package at runtime
36
+ let skills;
37
+ try {
38
+ skills = require('@frontmcp/skills');
39
+ }
40
+ catch {
41
+ return;
42
+ }
43
+ let manifest;
44
+ try {
45
+ manifest = skills.loadManifest();
46
+ }
47
+ catch {
48
+ return;
49
+ }
50
+ const targetFiltered = skills.getSkillsByTarget(manifest.skills, target);
51
+ const matchingSkills = skills.getSkillsByBundle(targetFiltered, bundle);
52
+ for (const skill of matchingSkills) {
53
+ const sourceDir = skills.resolveSkillPath(skill);
54
+ const destDir = (0, path_1.join)(projectRoot, 'skills', skill.name);
55
+ copyDirToTree(tree, sourceDir, destDir);
56
+ }
57
+ }
58
+ function copyDirToTree(tree, sourceDir, destDir) {
59
+ if (!fs.existsSync(sourceDir))
60
+ return;
61
+ const entries = fs.readdirSync(sourceDir, { withFileTypes: true });
62
+ for (const entry of entries) {
63
+ const srcPath = (0, path_1.join)(sourceDir, entry.name);
64
+ const destPath = (0, path_1.join)(destDir, entry.name);
65
+ if (entry.isDirectory()) {
66
+ copyDirToTree(tree, srcPath, destPath);
67
+ }
68
+ else {
69
+ const content = fs.readFileSync(srcPath);
70
+ tree.write(destPath, content);
71
+ }
72
+ }
73
+ }
27
74
  exports.default = serverGenerator;
28
75
  //# sourceMappingURL=server.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../../src/generators/server/server.ts"],"names":[],"mappings":";;AAKA,0CAEC;AAPD,uCAA6G;AAC7G,+BAA4B;AAE5B,6CAAkD;AAE3C,KAAK,UAAU,eAAe,CAAC,IAAU,EAAE,MAA6B;IAC7E,OAAO,uBAAuB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAC/C,CAAC;AAED,KAAK,UAAU,uBAAuB,CAAC,IAAU,EAAE,MAA6B;IAC9E,MAAM,OAAO,GAAG,IAAA,2BAAgB,EAAC,MAAM,CAAC,CAAC;IAEzC,MAAM,YAAY,GAAG;QACnB,GAAG,OAAO;QACV,KAAK,EAAE,cAAO;QACd,IAAI,EAAE,EAAE;QACR,GAAG,EAAE,GAAG;KACT,CAAC;IAEF,0DAA0D;IAC1D,IAAA,sBAAa,EAAC,IAAI,EAAE,IAAA,WAAI,EAAC,SAAS,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,OAAO,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;IAE3F,iCAAiC;IACjC,MAAM,SAAS,GAAG,IAAA,WAAI,EAAC,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACrE,IAAA,sBAAa,EAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;IAElE,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;QACxB,MAAM,IAAA,oBAAW,EAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC;AAED,kBAAe,eAAe,CAAC","sourcesContent":["import { type Tree, formatFiles, generateFiles, names as nxNames, type GeneratorCallback } from '@nx/devkit';\nimport { join } from 'path';\nimport type { ServerGeneratorSchema } from './schema.js';\nimport { normalizeOptions } from './lib/index.js';\n\nexport async function serverGenerator(tree: Tree, schema: ServerGeneratorSchema): Promise<GeneratorCallback | void> {\n return serverGeneratorInternal(tree, schema);\n}\n\nasync function serverGeneratorInternal(tree: Tree, schema: ServerGeneratorSchema): Promise<GeneratorCallback | void> {\n const options = normalizeOptions(schema);\n\n const templateVars = {\n ...options,\n names: nxNames,\n tmpl: '',\n dot: '.',\n };\n\n // Generate common files (main.ts, project.json, tsconfig)\n generateFiles(tree, join(__dirname, 'files', 'common'), options.projectRoot, templateVars);\n\n // Generate target-specific files\n const targetDir = join(__dirname, 'files', options.deploymentTarget);\n generateFiles(tree, targetDir, options.projectRoot, templateVars);\n\n if (!options.skipFormat) {\n await formatFiles(tree);\n }\n}\n\nexport default serverGenerator;\n"]}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../../src/generators/server/server.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Tree, formatFiles, generateFiles, names as nxNames, type GeneratorCallback } from '@nx/devkit';\nimport * as fs from 'fs';\nimport { join } from 'path';\nimport type { ServerGeneratorSchema } from './schema.js';\nimport { normalizeOptions } from './lib/index.js';\n\nexport async function serverGenerator(tree: Tree, schema: ServerGeneratorSchema): Promise<GeneratorCallback | void> {\n return serverGeneratorInternal(tree, schema);\n}\n\nasync function serverGeneratorInternal(tree: Tree, schema: ServerGeneratorSchema): Promise<GeneratorCallback | void> {\n const options = normalizeOptions(schema);\n\n const templateVars = {\n ...options,\n names: nxNames,\n tmpl: '',\n dot: '.',\n };\n\n // Generate common files (main.ts, project.json, tsconfig)\n generateFiles(tree, join(__dirname, 'files', 'common'), options.projectRoot, templateVars);\n\n // Generate target-specific files\n const targetDir = join(__dirname, 'files', options.deploymentTarget);\n generateFiles(tree, targetDir, options.projectRoot, templateVars);\n\n // Copy skills from catalog\n const bundle = schema.skills ?? 'recommended';\n if (bundle !== 'none') {\n scaffoldCatalogSkills(tree, options.projectRoot, options.deploymentTarget, bundle);\n }\n\n if (!options.skipFormat) {\n await formatFiles(tree);\n }\n}\n\nfunction scaffoldCatalogSkills(tree: Tree, projectRoot: string, target: string, bundle: string): void {\n // Load skills catalog via @frontmcp/skills package at runtime\n let skills: {\n loadManifest: () => {\n skills: Array<{ name: string; path: string; targets: string[]; hasResources: boolean; bundle?: string[] }>;\n };\n resolveSkillPath: (entry: { path: string }) => string;\n getSkillsByTarget: (\n s: Array<{ targets: string[] }>,\n t: string,\n ) => Array<{ name: string; path: string; targets: string[]; hasResources: boolean; bundle?: string[] }>;\n getSkillsByBundle: (\n s: Array<{ bundle?: string[] }>,\n b: string,\n ) => Array<{ name: string; path: string; targets: string[]; hasResources: boolean; bundle?: string[] }>;\n };\n try {\n skills = require('@frontmcp/skills');\n } catch {\n return;\n }\n\n let manifest;\n try {\n manifest = skills.loadManifest();\n } catch {\n return;\n }\n\n const targetFiltered = skills.getSkillsByTarget(manifest.skills, target);\n const matchingSkills = skills.getSkillsByBundle(targetFiltered, bundle);\n\n for (const skill of matchingSkills) {\n const sourceDir = skills.resolveSkillPath(skill);\n const destDir = join(projectRoot, 'skills', skill.name);\n copyDirToTree(tree, sourceDir, destDir);\n }\n}\n\nfunction copyDirToTree(tree: Tree, sourceDir: string, destDir: string): void {\n if (!fs.existsSync(sourceDir)) return;\n const entries = fs.readdirSync(sourceDir, { withFileTypes: true });\n for (const entry of entries) {\n const srcPath = join(sourceDir, entry.name);\n const destPath = join(destDir, entry.name);\n if (entry.isDirectory()) {\n copyDirToTree(tree, srcPath, destPath);\n } else {\n const content = fs.readFileSync(srcPath);\n tree.write(destPath, content);\n }\n }\n}\n\nexport default serverGenerator;\n"]}
@@ -0,0 +1,14 @@
1
+ ---
2
+ name: <%= name %>
3
+ description: <%= description %>
4
+ tags: [<%= tags %>]
5
+ ---
6
+ # <%= name %>
7
+
8
+ Add your skill instructions here.
9
+
10
+ ## Steps
11
+
12
+ 1. First step
13
+ 2. Second step
14
+ 3. Third step
@@ -0,0 +1,9 @@
1
+ export interface SkillDirGeneratorSchema {
2
+ name: string;
3
+ project: string;
4
+ description?: string;
5
+ directory?: string;
6
+ tags?: string;
7
+ withReferences?: boolean;
8
+ skipFormat?: boolean;
9
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../../src/generators/skill-dir/schema.ts"],"names":[],"mappings":"","sourcesContent":["export interface SkillDirGeneratorSchema {\n name: string;\n project: string;\n description?: string;\n directory?: string;\n tags?: string;\n withReferences?: boolean;\n skipFormat?: boolean;\n}\n"]}
@@ -0,0 +1,48 @@
1
+ {
2
+ "$schema": "https://json-schema.org/schema",
3
+ "$id": "FrontMcpSkillDir",
4
+ "title": "FrontMCP Skill Directory Generator",
5
+ "description": "Generate a SKILL.md-based skill directory",
6
+ "type": "object",
7
+ "properties": {
8
+ "name": {
9
+ "type": "string",
10
+ "description": "The skill name (kebab-case)",
11
+ "$default": { "$source": "argv", "index": 0 },
12
+ "x-prompt": "What name would you like for the skill?",
13
+ "x-priority": "important"
14
+ },
15
+ "project": {
16
+ "type": "string",
17
+ "description": "The project to add the skill to",
18
+ "x-prompt": "Which project should the skill be added to?",
19
+ "x-priority": "important"
20
+ },
21
+ "description": {
22
+ "type": "string",
23
+ "description": "Short description of what the skill does",
24
+ "x-prompt": "What does this skill do?",
25
+ "x-priority": "important"
26
+ },
27
+ "directory": {
28
+ "type": "string",
29
+ "description": "Custom directory relative to the project root (default: skills)"
30
+ },
31
+ "tags": {
32
+ "type": "string",
33
+ "description": "Comma-separated tags for categorization"
34
+ },
35
+ "withReferences": {
36
+ "type": "boolean",
37
+ "description": "Include a references/ directory",
38
+ "default": false
39
+ },
40
+ "skipFormat": {
41
+ "type": "boolean",
42
+ "description": "Skip formatting files",
43
+ "default": false,
44
+ "x-priority": "internal"
45
+ }
46
+ },
47
+ "required": ["name", "project"]
48
+ }
@@ -0,0 +1,4 @@
1
+ import { type Tree, type GeneratorCallback } from '@nx/devkit';
2
+ import type { SkillDirGeneratorSchema } from './schema.js';
3
+ export declare function skillDirGenerator(tree: Tree, schema: SkillDirGeneratorSchema): Promise<GeneratorCallback | void>;
4
+ export default skillDirGenerator;
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.skillDirGenerator = skillDirGenerator;
4
+ const devkit_1 = require("@nx/devkit");
5
+ const path_1 = require("path");
6
+ async function skillDirGenerator(tree, schema) {
7
+ const projectConfig = (0, devkit_1.readProjectConfiguration)(tree, schema.project);
8
+ const projectRoot = projectConfig.root;
9
+ const baseDir = schema.directory ?? 'skills';
10
+ const targetDir = (0, path_1.join)(projectRoot, baseDir);
11
+ const tags = schema.tags
12
+ ? schema.tags
13
+ .split(',')
14
+ .map((t) => t.trim())
15
+ .filter(Boolean)
16
+ .join(', ')
17
+ : schema.name;
18
+ const templateVars = {
19
+ name: schema.name,
20
+ description: schema.description ?? `Skill: ${schema.name}`,
21
+ tags,
22
+ tmpl: '',
23
+ };
24
+ (0, devkit_1.generateFiles)(tree, (0, path_1.join)(__dirname, 'files'), targetDir, templateVars);
25
+ // Create references/ directory if requested
26
+ if (schema.withReferences) {
27
+ const refDir = (0, path_1.join)(targetDir, schema.name, 'references');
28
+ tree.write((0, path_1.join)(refDir, '.gitkeep'), '');
29
+ }
30
+ if (!schema.skipFormat) {
31
+ await (0, devkit_1.formatFiles)(tree);
32
+ }
33
+ }
34
+ exports.default = skillDirGenerator;
35
+ //# sourceMappingURL=skill-dir.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-dir.js","sourceRoot":"","sources":["../../../../src/generators/skill-dir/skill-dir.ts"],"names":[],"mappings":";;AAIA,8CAmCC;AAvCD,uCAAqH;AACrH,+BAA4B;AAGrB,KAAK,UAAU,iBAAiB,CACrC,IAAU,EACV,MAA+B;IAE/B,MAAM,aAAa,GAAG,IAAA,iCAAwB,EAAC,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACrE,MAAM,WAAW,GAAG,aAAa,CAAC,IAAI,CAAC;IACvC,MAAM,OAAO,GAAG,MAAM,CAAC,SAAS,IAAI,QAAQ,CAAC;IAC7C,MAAM,SAAS,GAAG,IAAA,WAAI,EAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAE7C,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI;QACtB,CAAC,CAAC,MAAM,CAAC,IAAI;aACR,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aACpB,MAAM,CAAC,OAAO,CAAC;aACf,IAAI,CAAC,IAAI,CAAC;QACf,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC;IAEhB,MAAM,YAAY,GAAG;QACnB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,UAAU,MAAM,CAAC,IAAI,EAAE;QAC1D,IAAI;QACJ,IAAI,EAAE,EAAE;KACT,CAAC;IAEF,IAAA,sBAAa,EAAC,IAAI,EAAE,IAAA,WAAI,EAAC,SAAS,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;IAEvE,4CAA4C;IAC5C,IAAI,MAAM,CAAC,cAAc,EAAE,CAAC;QAC1B,MAAM,MAAM,GAAG,IAAA,WAAI,EAAC,SAAS,EAAE,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;QAC1D,IAAI,CAAC,KAAK,CAAC,IAAA,WAAI,EAAC,MAAM,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC;IAC3C,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;QACvB,MAAM,IAAA,oBAAW,EAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC;AAED,kBAAe,iBAAiB,CAAC","sourcesContent":["import { type Tree, formatFiles, generateFiles, readProjectConfiguration, type GeneratorCallback } from '@nx/devkit';\nimport { join } from 'path';\nimport type { SkillDirGeneratorSchema } from './schema.js';\n\nexport async function skillDirGenerator(\n tree: Tree,\n schema: SkillDirGeneratorSchema,\n): Promise<GeneratorCallback | void> {\n const projectConfig = readProjectConfiguration(tree, schema.project);\n const projectRoot = projectConfig.root;\n const baseDir = schema.directory ?? 'skills';\n const targetDir = join(projectRoot, baseDir);\n\n const tags = schema.tags\n ? schema.tags\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean)\n .join(', ')\n : schema.name;\n\n const templateVars = {\n name: schema.name,\n description: schema.description ?? `Skill: ${schema.name}`,\n tags,\n tmpl: '',\n };\n\n generateFiles(tree, join(__dirname, 'files'), targetDir, templateVars);\n\n // Create references/ directory if requested\n if (schema.withReferences) {\n const refDir = join(targetDir, schema.name, 'references');\n tree.write(join(refDir, '.gitkeep'), '');\n }\n\n if (!schema.skipFormat) {\n await formatFiles(tree);\n }\n}\n\nexport default skillDirGenerator;\n"]}
@@ -0,0 +1,70 @@
1
+ # <%= name %>
2
+
3
+ A FrontMCP Nx monorepo — TypeScript-first framework for building production-grade MCP servers.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ # Install dependencies
9
+ <%= packageManager %> install
10
+
11
+ # Start dev server (sample app)
12
+ npx nx dev demo
13
+
14
+ # Build all projects
15
+ npx nx run-many -t build
16
+
17
+ # Run all tests
18
+ npx nx run-many -t test
19
+ ```
20
+
21
+ ## Project Structure
22
+
23
+ ```
24
+ <%= name %>/
25
+ apps/ # MCP application definitions (@App decorator)
26
+ libs/ # Shared libraries (tools, resources, providers)
27
+ servers/ # Deployment shells (Express/Fastify adapters)
28
+ ```
29
+
30
+ ## Nx Generators
31
+
32
+ Use generators to scaffold new code:
33
+
34
+ | Generator | Command | Description |
35
+ |-----------|---------|-------------|
36
+ | app | `npx nx g @frontmcp/nx:app <name>` | MCP application |
37
+ | lib | `npx nx g @frontmcp/nx:lib <name>` | Shared library |
38
+ | server | `npx nx g @frontmcp/nx:server <name>` | Deployment shell |
39
+ | tool | `npx nx g @frontmcp/nx:tool <Name> --project <lib>` | MCP tool with Zod schemas |
40
+ | resource | `npx nx g @frontmcp/nx:resource <Name> --project <lib>` | MCP resource |
41
+ | prompt | `npx nx g @frontmcp/nx:prompt <Name> --project <lib>` | MCP prompt |
42
+ | provider | `npx nx g @frontmcp/nx:provider <Name> --project <lib>` | DI provider |
43
+
44
+ See `CLAUDE.md` for the full list of generators and architecture patterns.
45
+
46
+ ## Development Commands
47
+
48
+ ```bash
49
+ # Build a specific project
50
+ npx nx build <project>
51
+
52
+ # Test a specific project
53
+ npx nx test <project>
54
+
55
+ # Serve a project with watch
56
+ npx nx dev <project>
57
+
58
+ # Launch MCP Inspector
59
+ npx nx inspector <project>
60
+
61
+ # Run across all projects
62
+ npx nx run-many -t build
63
+ npx nx run-many -t test
64
+ ```
65
+
66
+ ## Learn More
67
+
68
+ - [FrontMCP Documentation](https://docs.agentfront.dev)
69
+ - [MCP Specification](https://modelcontextprotocol.io)
70
+ - AI coding agents can use the `frontmcp-docs` MCP server configured in `.mcp.json`
@@ -4,7 +4,7 @@
4
4
  "private": true,
5
5
  "license": "MIT",
6
6
  "engines": {
7
- "node": ">=22.0.0"
7
+ "node": ">=24.0.0"
8
8
  },
9
9
  "workspaces": [
10
10
  "apps/*",
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.workspaceGenerator = workspaceGenerator;
4
4
  const devkit_1 = require("@nx/devkit");
5
+ const child_process_1 = require("child_process");
5
6
  const path_1 = require("path");
6
7
  const index_js_1 = require("./lib/index.js");
7
8
  const versions_js_1 = require("../../utils/versions.js");
@@ -35,13 +36,31 @@ async function workspaceGeneratorInternal(tree, schema) {
35
36
  }
36
37
  await (0, devkit_1.formatFiles)(tree);
37
38
  if (options.skipInstall) {
39
+ if (!options.skipGit) {
40
+ return () => {
41
+ initGitRepository(options.workspaceRoot);
42
+ };
43
+ }
38
44
  return () => {
39
45
  /* noop */
40
46
  };
41
47
  }
42
48
  return () => {
43
49
  (0, devkit_1.installPackagesTask)(tree);
50
+ if (!options.skipGit) {
51
+ initGitRepository(options.workspaceRoot);
52
+ }
44
53
  };
45
54
  }
55
+ function initGitRepository(workspaceRoot) {
56
+ try {
57
+ (0, child_process_1.execSync)('git init', { cwd: workspaceRoot, stdio: 'ignore' });
58
+ (0, child_process_1.execSync)('git add -A', { cwd: workspaceRoot, stdio: 'ignore' });
59
+ (0, child_process_1.execSync)('git commit -m "Initial commit"', { cwd: workspaceRoot, stdio: 'ignore' });
60
+ }
61
+ catch {
62
+ // git may not be installed — silently skip
63
+ }
64
+ }
46
65
  exports.default = workspaceGenerator;
47
66
  //# sourceMappingURL=workspace.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../../../src/generators/workspace/workspace.ts"],"names":[],"mappings":";;AAMA,gDAEC;AARD,uCAAgH;AAChH,+BAA4B;AAE5B,6CAAkD;AAClD,yDAA6D;AAEtD,KAAK,UAAU,kBAAkB,CAAC,IAAU,EAAE,MAAgC;IACnF,OAAO,0BAA0B,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAClD,CAAC;AAED,KAAK,UAAU,0BAA0B,CAAC,IAAU,EAAE,MAAgC;IACpF,MAAM,OAAO,GAAG,IAAA,2BAAgB,EAAC,MAAM,CAAC,CAAC;IACzC,MAAM,eAAe,GAAG,IAAI,IAAA,gCAAkB,GAAE,EAAE,CAAC;IACnD,MAAM,SAAS,GAAG,QAAQ,CAAC;IAE3B,IAAA,sBAAa,EAAC,IAAI,EAAE,IAAA,WAAI,EAAC,SAAS,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,aAAa,EAAE;QACnE,GAAG,OAAO;QACV,eAAe;QACf,SAAS;QACT,IAAI,EAAE,EAAE;QACR,GAAG,EAAE,GAAG;KACT,CAAC,CAAC;IAEH,2BAA2B;IAC3B,IAAI,CAAC,KAAK,CAAC,IAAA,WAAI,EAAC,OAAO,CAAC,aAAa,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC;IAChE,IAAI,CAAC,KAAK,CAAC,IAAA,WAAI,EAAC,OAAO,CAAC,aAAa,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC;IAChE,IAAI,CAAC,KAAK,CAAC,IAAA,WAAI,EAAC,OAAO,CAAC,aAAa,EAAE,SAAS,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC;IAEnE,0DAA0D;IAC1D,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;QAC5B,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC;QACvD,MAAM,YAAY,CAAC,IAAI,EAAE;YACvB,IAAI,EAAE,MAAM;YACZ,SAAS,EAAE,IAAA,WAAI,EAAC,OAAO,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,CAAC;YACtD,IAAI,EAAE,YAAY;YAClB,UAAU,EAAE,IAAI;SACjB,CAAC,CAAC;IACL,CAAC;IAED,MAAM,IAAA,oBAAW,EAAC,IAAI,CAAC,CAAC;IAExB,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;QACxB,OAAO,GAAG,EAAE;YACV,UAAU;QACZ,CAAC,CAAC;IACJ,CAAC;IAED,OAAO,GAAG,EAAE;QACV,IAAA,4BAAmB,EAAC,IAAI,CAAC,CAAC;IAC5B,CAAC,CAAC;AACJ,CAAC;AAED,kBAAe,kBAAkB,CAAC","sourcesContent":["import { type Tree, formatFiles, generateFiles, installPackagesTask, type GeneratorCallback } from '@nx/devkit';\nimport { join } from 'path';\nimport type { WorkspaceGeneratorSchema } from './schema.js';\nimport { normalizeOptions } from './lib/index.js';\nimport { getFrontmcpVersion } from '../../utils/versions.js';\n\nexport async function workspaceGenerator(tree: Tree, schema: WorkspaceGeneratorSchema): Promise<GeneratorCallback> {\n return workspaceGeneratorInternal(tree, schema);\n}\n\nasync function workspaceGeneratorInternal(tree: Tree, schema: WorkspaceGeneratorSchema): Promise<GeneratorCallback> {\n const options = normalizeOptions(schema);\n const frontmcpVersion = `~${getFrontmcpVersion()}`;\n const nxVersion = '22.3.3';\n\n generateFiles(tree, join(__dirname, 'files'), options.workspaceRoot, {\n ...options,\n frontmcpVersion,\n nxVersion,\n tmpl: '',\n dot: '.',\n });\n\n // Create empty directories\n tree.write(join(options.workspaceRoot, 'apps', '.gitkeep'), '');\n tree.write(join(options.workspaceRoot, 'libs', '.gitkeep'), '');\n tree.write(join(options.workspaceRoot, 'servers', '.gitkeep'), '');\n\n // Compose with app generator when createSampleApp is true\n if (options.createSampleApp) {\n const { appGenerator } = await import('../app/app.js');\n await appGenerator(tree, {\n name: 'demo',\n directory: join(options.workspaceRoot, 'apps', 'demo'),\n tags: 'scope:apps',\n skipFormat: true,\n });\n }\n\n await formatFiles(tree);\n\n if (options.skipInstall) {\n return () => {\n /* noop */\n };\n }\n\n return () => {\n installPackagesTask(tree);\n };\n}\n\nexport default workspaceGenerator;\n"]}
1
+ {"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../../../src/generators/workspace/workspace.ts"],"names":[],"mappings":";;AAOA,gDAEC;AATD,uCAAgH;AAChH,iDAAyC;AACzC,+BAA4B;AAE5B,6CAAkD;AAClD,yDAA6D;AAEtD,KAAK,UAAU,kBAAkB,CAAC,IAAU,EAAE,MAAgC;IACnF,OAAO,0BAA0B,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAClD,CAAC;AAED,KAAK,UAAU,0BAA0B,CAAC,IAAU,EAAE,MAAgC;IACpF,MAAM,OAAO,GAAG,IAAA,2BAAgB,EAAC,MAAM,CAAC,CAAC;IACzC,MAAM,eAAe,GAAG,IAAI,IAAA,gCAAkB,GAAE,EAAE,CAAC;IACnD,MAAM,SAAS,GAAG,QAAQ,CAAC;IAE3B,IAAA,sBAAa,EAAC,IAAI,EAAE,IAAA,WAAI,EAAC,SAAS,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,aAAa,EAAE;QACnE,GAAG,OAAO;QACV,eAAe;QACf,SAAS;QACT,IAAI,EAAE,EAAE;QACR,GAAG,EAAE,GAAG;KACT,CAAC,CAAC;IAEH,2BAA2B;IAC3B,IAAI,CAAC,KAAK,CAAC,IAAA,WAAI,EAAC,OAAO,CAAC,aAAa,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC;IAChE,IAAI,CAAC,KAAK,CAAC,IAAA,WAAI,EAAC,OAAO,CAAC,aAAa,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC;IAChE,IAAI,CAAC,KAAK,CAAC,IAAA,WAAI,EAAC,OAAO,CAAC,aAAa,EAAE,SAAS,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC;IAEnE,0DAA0D;IAC1D,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;QAC5B,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC;QACvD,MAAM,YAAY,CAAC,IAAI,EAAE;YACvB,IAAI,EAAE,MAAM;YACZ,SAAS,EAAE,IAAA,WAAI,EAAC,OAAO,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,CAAC;YACtD,IAAI,EAAE,YAAY;YAClB,UAAU,EAAE,IAAI;SACjB,CAAC,CAAC;IACL,CAAC;IAED,MAAM,IAAA,oBAAW,EAAC,IAAI,CAAC,CAAC;IAExB,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;QACxB,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;YACrB,OAAO,GAAG,EAAE;gBACV,iBAAiB,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;YAC3C,CAAC,CAAC;QACJ,CAAC;QACD,OAAO,GAAG,EAAE;YACV,UAAU;QACZ,CAAC,CAAC;IACJ,CAAC;IAED,OAAO,GAAG,EAAE;QACV,IAAA,4BAAmB,EAAC,IAAI,CAAC,CAAC;QAC1B,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;YACrB,iBAAiB,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,aAAqB;IAC9C,IAAI,CAAC;QACH,IAAA,wBAAQ,EAAC,UAAU,EAAE,EAAE,GAAG,EAAE,aAAa,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC9D,IAAA,wBAAQ,EAAC,YAAY,EAAE,EAAE,GAAG,EAAE,aAAa,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QAChE,IAAA,wBAAQ,EAAC,gCAAgC,EAAE,EAAE,GAAG,EAAE,aAAa,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;IACtF,CAAC;IAAC,MAAM,CAAC;QACP,2CAA2C;IAC7C,CAAC;AACH,CAAC;AAED,kBAAe,kBAAkB,CAAC","sourcesContent":["import { type Tree, formatFiles, generateFiles, installPackagesTask, type GeneratorCallback } from '@nx/devkit';\nimport { execSync } from 'child_process';\nimport { join } from 'path';\nimport type { WorkspaceGeneratorSchema } from './schema.js';\nimport { normalizeOptions } from './lib/index.js';\nimport { getFrontmcpVersion } from '../../utils/versions.js';\n\nexport async function workspaceGenerator(tree: Tree, schema: WorkspaceGeneratorSchema): Promise<GeneratorCallback> {\n return workspaceGeneratorInternal(tree, schema);\n}\n\nasync function workspaceGeneratorInternal(tree: Tree, schema: WorkspaceGeneratorSchema): Promise<GeneratorCallback> {\n const options = normalizeOptions(schema);\n const frontmcpVersion = `~${getFrontmcpVersion()}`;\n const nxVersion = '22.3.3';\n\n generateFiles(tree, join(__dirname, 'files'), options.workspaceRoot, {\n ...options,\n frontmcpVersion,\n nxVersion,\n tmpl: '',\n dot: '.',\n });\n\n // Create empty directories\n tree.write(join(options.workspaceRoot, 'apps', '.gitkeep'), '');\n tree.write(join(options.workspaceRoot, 'libs', '.gitkeep'), '');\n tree.write(join(options.workspaceRoot, 'servers', '.gitkeep'), '');\n\n // Compose with app generator when createSampleApp is true\n if (options.createSampleApp) {\n const { appGenerator } = await import('../app/app.js');\n await appGenerator(tree, {\n name: 'demo',\n directory: join(options.workspaceRoot, 'apps', 'demo'),\n tags: 'scope:apps',\n skipFormat: true,\n });\n }\n\n await formatFiles(tree);\n\n if (options.skipInstall) {\n if (!options.skipGit) {\n return () => {\n initGitRepository(options.workspaceRoot);\n };\n }\n return () => {\n /* noop */\n };\n }\n\n return () => {\n installPackagesTask(tree);\n if (!options.skipGit) {\n initGitRepository(options.workspaceRoot);\n }\n };\n}\n\nfunction initGitRepository(workspaceRoot: string): void {\n try {\n execSync('git init', { cwd: workspaceRoot, stdio: 'ignore' });\n execSync('git add -A', { cwd: workspaceRoot, stdio: 'ignore' });\n execSync('git commit -m \"Initial commit\"', { cwd: workspaceRoot, stdio: 'ignore' });\n } catch {\n // git may not be installed — silently skip\n }\n}\n\nexport default workspaceGenerator;\n"]}
package/generators.json CHANGED
@@ -40,6 +40,11 @@
40
40
  "schema": "./generators/skill/schema.json",
41
41
  "description": "Generate a @Skill class"
42
42
  },
43
+ "skill-dir": {
44
+ "factory": "./generators/skill-dir/skill-dir",
45
+ "schema": "./generators/skill-dir/schema.json",
46
+ "description": "Generate a SKILL.md-based skill directory"
47
+ },
43
48
  "agent": {
44
49
  "factory": "./generators/agent/agent",
45
50
  "schema": "./generators/agent/schema.json",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frontmcp/nx",
3
- "version": "1.0.0-beta.1",
3
+ "version": "1.0.0-beta.11",
4
4
  "description": "Nx plugin for FrontMCP — generators and executors for building MCP servers",
5
5
  "author": "AgentFront <info@agentfront.dev>",
6
6
  "homepage": "https://docs.agentfront.dev",
@@ -30,9 +30,10 @@
30
30
  "generators": "./generators.json",
31
31
  "executors": "./executors.json",
32
32
  "engines": {
33
- "node": ">=22.0.0"
33
+ "node": ">=24.0.0"
34
34
  },
35
35
  "dependencies": {
36
+ "@frontmcp/skills": "1.0.0-beta.11",
36
37
  "@nx/devkit": "22.3.3",
37
38
  "tslib": "^2.3.0"
38
39
  },