@frontmcp/nx 1.0.0-beta.1 → 1.0.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/executors/build-exec/build-exec.impl.js +1 -1
- package/executors/build-exec/build-exec.impl.js.map +1 -1
- package/executors.json +1 -1
- package/generators/server/files/lambda/template.yaml__tmpl__ +1 -1
- package/generators/server/files/node/docker-compose.yml__tmpl__ +14 -5
- package/generators/server/schema.d.ts +1 -0
- package/generators/server/schema.js.map +1 -1
- package/generators/server/schema.json +6 -0
- package/generators/server/server.js +47 -0
- package/generators/server/server.js.map +1 -1
- package/generators/skill-dir/files/__name__/SKILL.md__tmpl__ +14 -0
- package/generators/skill-dir/schema.d.ts +9 -0
- package/generators/skill-dir/schema.js +3 -0
- package/generators/skill-dir/schema.js.map +1 -0
- package/generators/skill-dir/schema.json +48 -0
- package/generators/skill-dir/skill-dir.d.ts +4 -0
- package/generators/skill-dir/skill-dir.js +35 -0
- package/generators/skill-dir/skill-dir.js.map +1 -0
- package/generators/workspace/files/README.md__tmpl__ +70 -0
- package/generators/workspace/files/__dot__nvmrc__tmpl__ +1 -0
- package/generators/workspace/files/package.json__tmpl__ +1 -1
- package/generators/workspace/workspace.js +19 -0
- package/generators/workspace/workspace.js.map +1 -1
- package/generators.json +5 -0
- package/package.json +3 -2
|
@@ -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', '--
|
|
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,
|
|
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 --
|
|
11
|
+
"description": "Build a distributable bundle using frontmcp build --target node"
|
|
12
12
|
},
|
|
13
13
|
"dev": {
|
|
14
14
|
"implementation": "./executors/dev/dev.impl",
|
|
@@ -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
|
|
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:
|
|
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
|
|
@@ -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":";;
|
|
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 @@
|
|
|
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`
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
24
|
|
@@ -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":";;
|
|
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.
|
|
3
|
+
"version": "1.0.0-beta.10",
|
|
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": ">=
|
|
33
|
+
"node": ">=24.0.0"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
+
"@frontmcp/skills": "1.0.0-beta.10",
|
|
36
37
|
"@nx/devkit": "22.3.3",
|
|
37
38
|
"tslib": "^2.3.0"
|
|
38
39
|
},
|