@frontmcp/nx 0.12.2 → 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/ui-component/files/__className__/__className__.spec.tsx__tmpl__ +17 -0
- package/generators/ui-component/files/__className__/__className__.tsx__tmpl__ +14 -0
- package/generators/ui-component/files/__className__/index.ts__tmpl__ +3 -0
- package/generators/ui-component/schema.d.ts +5 -0
- package/generators/ui-component/schema.js +3 -0
- package/generators/ui-component/schema.js.map +1 -0
- package/generators/ui-component/schema.json +27 -0
- package/generators/ui-component/ui-component.d.ts +4 -0
- package/generators/ui-component/ui-component.js +33 -0
- package/generators/ui-component/ui-component.js.map +1 -0
- package/generators/ui-page/files/__className__/__className__.spec.tsx__tmpl__ +17 -0
- package/generators/ui-page/files/__className__/__className__.tsx__tmpl__ +16 -0
- package/generators/ui-page/files/__className__/index.ts__tmpl__ +3 -0
- package/generators/ui-page/schema.d.ts +5 -0
- package/generators/ui-page/schema.js +3 -0
- package/generators/ui-page/schema.js.map +1 -0
- package/generators/ui-page/schema.json +27 -0
- package/generators/ui-page/ui-page.d.ts +4 -0
- package/generators/ui-page/ui-page.js +33 -0
- package/generators/ui-page/ui-page.js.map +1 -0
- package/generators/ui-shared/add-ui-entry.d.ts +16 -0
- package/generators/ui-shared/add-ui-entry.js +60 -0
- package/generators/ui-shared/add-ui-entry.js.map +1 -0
- package/generators/ui-shell/files/__fileName__/__fileName__.shell.spec.ts__tmpl__ +16 -0
- package/generators/ui-shell/files/__fileName__/__fileName__.shell.ts__tmpl__ +20 -0
- package/generators/ui-shell/files/__fileName__/index.ts__tmpl__ +2 -0
- package/generators/ui-shell/schema.d.ts +5 -0
- package/generators/ui-shell/schema.js +3 -0
- package/generators/ui-shell/schema.js.map +1 -0
- package/generators/ui-shell/schema.json +27 -0
- package/generators/ui-shell/ui-shell.d.ts +4 -0
- package/generators/ui-shell/ui-shell.js +30 -0
- package/generators/ui-shell/ui-shell.js.map +1 -0
- package/generators/workspace/files/AGENTS.md__tmpl__ +52 -0
- package/generators/workspace/files/CLAUDE.md__tmpl__ +216 -0
- package/generators/workspace/files/README.md__tmpl__ +70 -0
- package/generators/workspace/files/__dot__cursorrules__tmpl__ +3 -0
- package/generators/workspace/files/__dot__gitignore__tmpl__ +3 -0
- package/generators/workspace/files/__dot__mcp.json__tmpl__ +8 -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 +20 -0
- package/index.d.ts +3 -0
- package/index.js +7 -1
- package/index.js.map +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.addUiEntry = addUiEntry;
|
|
4
|
+
const devkit_1 = require("@nx/devkit");
|
|
5
|
+
function escapeRegExp(str) {
|
|
6
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Adds an entry point to an existing UI package:
|
|
10
|
+
* 1. Updates project.json `additionalEntryPoints` in both build-cjs and build-esm
|
|
11
|
+
* 2. Updates tsconfig.base.json path aliases (wildcard already covers it, but explicit is fine)
|
|
12
|
+
* 3. Adds re-export to the barrel index.ts
|
|
13
|
+
*/
|
|
14
|
+
function addUiEntry(tree, options) {
|
|
15
|
+
const { packageRoot, entryName, importPath } = options;
|
|
16
|
+
const entryPath = `${packageRoot}/src/${entryName}/index.ts`;
|
|
17
|
+
// 1. Update project.json — add to additionalEntryPoints in build-cjs and build-esm
|
|
18
|
+
const projectJsonPath = `${packageRoot}/project.json`;
|
|
19
|
+
if (tree.exists(projectJsonPath)) {
|
|
20
|
+
(0, devkit_1.updateJson)(tree, projectJsonPath, (json) => {
|
|
21
|
+
for (const target of ['build-cjs', 'build-esm']) {
|
|
22
|
+
const opts = json.targets?.[target]?.options;
|
|
23
|
+
if (opts) {
|
|
24
|
+
opts.additionalEntryPoints = opts.additionalEntryPoints ?? [];
|
|
25
|
+
if (!opts.additionalEntryPoints.includes(entryPath)) {
|
|
26
|
+
opts.additionalEntryPoints.push(entryPath);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return json;
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
// 2. Update tsconfig.base.json — add explicit path alias
|
|
34
|
+
// The wildcard alias already covers resolution, but adding an explicit
|
|
35
|
+
// entry improves IDE completion and Nx dep graph accuracy.
|
|
36
|
+
if (tree.exists('tsconfig.base.json')) {
|
|
37
|
+
(0, devkit_1.updateJson)(tree, 'tsconfig.base.json', (json) => {
|
|
38
|
+
const paths = json.compilerOptions?.paths ?? {};
|
|
39
|
+
const aliasKey = `${importPath}/${entryName}`;
|
|
40
|
+
if (!paths[aliasKey]) {
|
|
41
|
+
paths[aliasKey] = [`${packageRoot}/src/${entryName}/index.ts`];
|
|
42
|
+
}
|
|
43
|
+
json.compilerOptions = json.compilerOptions ?? {};
|
|
44
|
+
json.compilerOptions.paths = paths;
|
|
45
|
+
return json;
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
// 3. Add re-export to barrel index.ts
|
|
49
|
+
const barrelPath = `${packageRoot}/src/index.ts`;
|
|
50
|
+
if (tree.exists(barrelPath)) {
|
|
51
|
+
const existing = tree.read(barrelPath, 'utf-8') ?? '';
|
|
52
|
+
const exportLine = `export * from './${entryName}';\n`;
|
|
53
|
+
const duplicatePattern = new RegExp(`^export \\* from '\\./${escapeRegExp(entryName)}';?$`, 'm');
|
|
54
|
+
if (!duplicatePattern.test(existing)) {
|
|
55
|
+
const normalized = existing.endsWith('\n') || existing === '' ? existing : existing + '\n';
|
|
56
|
+
tree.write(barrelPath, normalized + exportLine);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=add-ui-entry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add-ui-entry.js","sourceRoot":"","sources":["../../../../src/generators/ui-shared/add-ui-entry.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Tree, updateJson } from '@nx/devkit';\n\nfunction escapeRegExp(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nexport interface AddUiEntryOptions {\n /** The UI package root, e.g. 'ui/components' */\n packageRoot: string;\n /** The entry name, e.g. 'LoginForm' or 'admin-dashboard' */\n entryName: string;\n /** The npm scope name, e.g. '@frontmcp/ui-components' */\n importPath: string;\n}\n\n/**\n * Adds an entry point to an existing UI package:\n * 1. Updates project.json `additionalEntryPoints` in both build-cjs and build-esm\n * 2. Updates tsconfig.base.json path aliases (wildcard already covers it, but explicit is fine)\n * 3. Adds re-export to the barrel index.ts\n */\nexport function addUiEntry(tree: Tree, options: AddUiEntryOptions): void {\n const { packageRoot, entryName, importPath } = options;\n const entryPath = `${packageRoot}/src/${entryName}/index.ts`;\n\n // 1. Update project.json — add to additionalEntryPoints in build-cjs and build-esm\n const projectJsonPath = `${packageRoot}/project.json`;\n if (tree.exists(projectJsonPath)) {\n updateJson(tree, projectJsonPath, (json) => {\n for (const target of ['build-cjs', 'build-esm']) {\n const opts = json.targets?.[target]?.options;\n if (opts) {\n opts.additionalEntryPoints = opts.additionalEntryPoints ?? [];\n if (!opts.additionalEntryPoints.includes(entryPath)) {\n opts.additionalEntryPoints.push(entryPath);\n }\n }\n }\n return json;\n });\n }\n\n // 2. Update tsconfig.base.json — add explicit path alias\n // The wildcard alias already covers resolution, but adding an explicit\n // entry improves IDE completion and Nx dep graph accuracy.\n if (tree.exists('tsconfig.base.json')) {\n updateJson(tree, 'tsconfig.base.json', (json) => {\n const paths = json.compilerOptions?.paths ?? {};\n const aliasKey = `${importPath}/${entryName}`;\n if (!paths[aliasKey]) {\n paths[aliasKey] = [`${packageRoot}/src/${entryName}/index.ts`];\n }\n json.compilerOptions = json.compilerOptions ?? {};\n json.compilerOptions.paths = paths;\n return json;\n });\n }\n\n // 3. Add re-export to barrel index.ts\n const barrelPath = `${packageRoot}/src/index.ts`;\n if (tree.exists(barrelPath)) {\n const existing = tree.read(barrelPath, 'utf-8') ?? '';\n const exportLine = `export * from './${entryName}';\\n`;\n const duplicatePattern = new RegExp(`^export \\\\* from '\\\\./${escapeRegExp(entryName)}';?$`, 'm');\n if (!duplicatePattern.test(existing)) {\n const normalized = existing.endsWith('\\n') || existing === '' ? existing : existing + '\\n';\n tree.write(barrelPath, normalized + exportLine);\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { build<%= className %>Shell } from './<%= fileName %>.shell';
|
|
2
|
+
|
|
3
|
+
describe('build<%= className %>Shell', () => {
|
|
4
|
+
it('should be defined', () => {
|
|
5
|
+
expect(build<%= className %>Shell).toBeDefined();
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it('should be a function', () => {
|
|
9
|
+
expect(typeof build<%= className %>Shell).toBe('function');
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('should return an HTML string', () => {
|
|
13
|
+
const result = build<%= className %>Shell({ toolName: 'test' });
|
|
14
|
+
expect(typeof result).toBe('string');
|
|
15
|
+
});
|
|
16
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { buildShell } from '@frontmcp/uipack';
|
|
2
|
+
|
|
3
|
+
function escapeHtml(str: string): string {
|
|
4
|
+
return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface <%= className %>ShellOptions {
|
|
8
|
+
toolName: string;
|
|
9
|
+
input?: unknown;
|
|
10
|
+
output?: unknown;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function build<%= className %>Shell(options: <%= className %>ShellOptions) {
|
|
14
|
+
const content = `<div id="app">TODO: implement ${escapeHtml(options.toolName)} shell</div>`;
|
|
15
|
+
return buildShell(content, {
|
|
16
|
+
toolName: options.toolName,
|
|
17
|
+
input: options.input,
|
|
18
|
+
output: options.output,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../../src/generators/ui-shell/schema.ts"],"names":[],"mappings":"","sourcesContent":["export interface UiShellGeneratorSchema {\n name: string;\n description?: string;\n skipFormat?: boolean;\n}\n"]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/schema",
|
|
3
|
+
"$id": "FrontMcpUiShell",
|
|
4
|
+
"title": "FrontMCP UI Shell Generator",
|
|
5
|
+
"description": "Add a shell template entry to ui/shells",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"name": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"description": "Shell name (kebab-case, e.g. admin-dashboard)",
|
|
11
|
+
"$default": { "$source": "argv", "index": 0 },
|
|
12
|
+
"x-prompt": "What name would you like for the shell (kebab-case)?",
|
|
13
|
+
"x-priority": "important"
|
|
14
|
+
},
|
|
15
|
+
"description": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"description": "Brief description of the shell template",
|
|
18
|
+
"default": ""
|
|
19
|
+
},
|
|
20
|
+
"skipFormat": {
|
|
21
|
+
"type": "boolean",
|
|
22
|
+
"default": false,
|
|
23
|
+
"x-priority": "internal"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"required": ["name"]
|
|
27
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type Tree, type GeneratorCallback } from '@nx/devkit';
|
|
2
|
+
import type { UiShellGeneratorSchema } from './schema.js';
|
|
3
|
+
export declare function uiShellGenerator(tree: Tree, schema: UiShellGeneratorSchema): Promise<GeneratorCallback | void>;
|
|
4
|
+
export default uiShellGenerator;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.uiShellGenerator = uiShellGenerator;
|
|
4
|
+
const devkit_1 = require("@nx/devkit");
|
|
5
|
+
const path_1 = require("path");
|
|
6
|
+
const add_ui_entry_js_1 = require("../ui-shared/add-ui-entry.js");
|
|
7
|
+
const PACKAGE_ROOT = 'ui/shells';
|
|
8
|
+
const IMPORT_PATH = '@frontmcp/ui-shells';
|
|
9
|
+
async function uiShellGenerator(tree, schema) {
|
|
10
|
+
const { className, fileName } = (0, devkit_1.names)(schema.name);
|
|
11
|
+
// Generate shell files from templates (kebab-case naming)
|
|
12
|
+
(0, devkit_1.generateFiles)(tree, (0, path_1.join)(__dirname, 'files'), `${PACKAGE_ROOT}/src`, {
|
|
13
|
+
className,
|
|
14
|
+
fileName,
|
|
15
|
+
name: schema.name,
|
|
16
|
+
description: schema.description ?? '',
|
|
17
|
+
tmpl: '',
|
|
18
|
+
});
|
|
19
|
+
// Add entry point to project.json, tsconfig.base.json, and barrel index.ts
|
|
20
|
+
(0, add_ui_entry_js_1.addUiEntry)(tree, {
|
|
21
|
+
packageRoot: PACKAGE_ROOT,
|
|
22
|
+
entryName: fileName,
|
|
23
|
+
importPath: IMPORT_PATH,
|
|
24
|
+
});
|
|
25
|
+
if (!schema.skipFormat) {
|
|
26
|
+
await (0, devkit_1.formatFiles)(tree);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
exports.default = uiShellGenerator;
|
|
30
|
+
//# sourceMappingURL=ui-shell.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-shell.js","sourceRoot":"","sources":["../../../../src/generators/ui-shell/ui-shell.ts"],"names":[],"mappings":";;AAQA,4CAsBC;AA9BD,uCAAkG;AAClG,+BAA4B;AAE5B,kEAA0D;AAE1D,MAAM,YAAY,GAAG,WAAW,CAAC;AACjC,MAAM,WAAW,GAAG,qBAAqB,CAAC;AAEnC,KAAK,UAAU,gBAAgB,CAAC,IAAU,EAAE,MAA8B;IAC/E,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,IAAA,cAAK,EAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAEnD,0DAA0D;IAC1D,IAAA,sBAAa,EAAC,IAAI,EAAE,IAAA,WAAI,EAAC,SAAS,EAAE,OAAO,CAAC,EAAE,GAAG,YAAY,MAAM,EAAE;QACnE,SAAS;QACT,QAAQ;QACR,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,EAAE;QACrC,IAAI,EAAE,EAAE;KACT,CAAC,CAAC;IAEH,2EAA2E;IAC3E,IAAA,4BAAU,EAAC,IAAI,EAAE;QACf,WAAW,EAAE,YAAY;QACzB,SAAS,EAAE,QAAQ;QACnB,UAAU,EAAE,WAAW;KACxB,CAAC,CAAC;IAEH,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;QACvB,MAAM,IAAA,oBAAW,EAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC;AAED,kBAAe,gBAAgB,CAAC","sourcesContent":["import { type Tree, formatFiles, generateFiles, names, type GeneratorCallback } from '@nx/devkit';\nimport { join } from 'path';\nimport type { UiShellGeneratorSchema } from './schema.js';\nimport { addUiEntry } from '../ui-shared/add-ui-entry.js';\n\nconst PACKAGE_ROOT = 'ui/shells';\nconst IMPORT_PATH = '@frontmcp/ui-shells';\n\nexport async function uiShellGenerator(tree: Tree, schema: UiShellGeneratorSchema): Promise<GeneratorCallback | void> {\n const { className, fileName } = names(schema.name);\n\n // Generate shell files from templates (kebab-case naming)\n generateFiles(tree, join(__dirname, 'files'), `${PACKAGE_ROOT}/src`, {\n className,\n fileName,\n name: schema.name,\n description: schema.description ?? '',\n tmpl: '',\n });\n\n // Add entry point to project.json, tsconfig.base.json, and barrel index.ts\n addUiEntry(tree, {\n packageRoot: PACKAGE_ROOT,\n entryName: fileName,\n importPath: IMPORT_PATH,\n });\n\n if (!schema.skipFormat) {\n await formatFiles(tree);\n }\n}\n\nexport default uiShellGenerator;\n"]}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# <%= name %> — Agent Guidelines
|
|
2
|
+
|
|
3
|
+
## Project Type
|
|
4
|
+
|
|
5
|
+
FrontMCP monorepo — TypeScript-first framework for building MCP (Model Context Protocol) servers.
|
|
6
|
+
|
|
7
|
+
## Architecture
|
|
8
|
+
|
|
9
|
+
- **Monorepo**: Nx-based with `apps/`, `libs/`, `servers/` workspaces
|
|
10
|
+
- **Language**: TypeScript with strict mode enabled
|
|
11
|
+
- **Build system**: Nx (`npx nx build/test/serve <project>`)
|
|
12
|
+
- **Testing**: Jest with 95%+ coverage requirement
|
|
13
|
+
- **Package manager**: <%= packageManager %>
|
|
14
|
+
|
|
15
|
+
## Code Generation
|
|
16
|
+
|
|
17
|
+
**Always use Nx generators** — never create files manually:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npx nx g @frontmcp/nx:tool <Name> --project <lib>
|
|
21
|
+
npx nx g @frontmcp/nx:resource <Name> --project <lib>
|
|
22
|
+
npx nx g @frontmcp/nx:prompt <Name> --project <lib>
|
|
23
|
+
npx nx g @frontmcp/nx:provider <Name> --project <lib>
|
|
24
|
+
npx nx g @frontmcp/nx:app <name>
|
|
25
|
+
npx nx g @frontmcp/nx:lib <name>
|
|
26
|
+
npx nx g @frontmcp/nx:server <name>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
See `CLAUDE.md` for the full list of 19 generators.
|
|
30
|
+
|
|
31
|
+
## Key Decorators & Context Classes
|
|
32
|
+
|
|
33
|
+
| Decorator | Context Class | Purpose |
|
|
34
|
+
|-----------|---------------|---------|
|
|
35
|
+
| `@Tool` | `ToolContext` | MCP tool with Zod input/output |
|
|
36
|
+
| `@Resource` / `@ResourceTemplate` | `ResourceContext` | MCP resource |
|
|
37
|
+
| `@Prompt` | `PromptContext` | MCP prompt returning `GetPromptResult` |
|
|
38
|
+
| `@Provider` | — | DI provider with Symbol token |
|
|
39
|
+
| `@App` | — | Application grouping tools/resources/prompts |
|
|
40
|
+
| `@FrontMcp` | — | Server entry point |
|
|
41
|
+
|
|
42
|
+
## Constraints
|
|
43
|
+
|
|
44
|
+
- No `any` types — use `unknown` for generic defaults
|
|
45
|
+
- No raw `node:crypto` or `fs` — use `@frontmcp/utils`
|
|
46
|
+
- No non-null assertions (`!`) — throw proper errors
|
|
47
|
+
- Zod v4 for all schema validation
|
|
48
|
+
- `@frontmcp/testing` for test harnesses
|
|
49
|
+
|
|
50
|
+
## Documentation Access
|
|
51
|
+
|
|
52
|
+
The `.mcp.json` file configures a `frontmcp-docs` MCP server. Use the `SearchAgentFront` tool to search FrontMCP documentation.
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# <%= name %> — FrontMCP Workspace
|
|
2
|
+
|
|
3
|
+
This is a **FrontMCP** monorepo — a TypeScript-first framework for building production-grade MCP (Model Context Protocol) servers with decorators, dependency injection, and strict type safety.
|
|
4
|
+
|
|
5
|
+
## Monorepo Structure
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
<%= name %>/
|
|
9
|
+
apps/ # MCP application definitions (@App decorator)
|
|
10
|
+
libs/ # Shared libraries (tools, resources, providers)
|
|
11
|
+
servers/ # Deployment shells (Express/Fastify adapters)
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Key Commands
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# Build / test / serve a specific project
|
|
18
|
+
npx nx build <project>
|
|
19
|
+
npx nx test <project>
|
|
20
|
+
npx nx serve <project>
|
|
21
|
+
|
|
22
|
+
# Run across all projects
|
|
23
|
+
npx nx run-many -t build
|
|
24
|
+
npx nx run-many -t test
|
|
25
|
+
|
|
26
|
+
# Start dev server with watch mode
|
|
27
|
+
npx nx dev <server-project>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Nx Generators
|
|
31
|
+
|
|
32
|
+
Always use generators to scaffold new code — never create files manually.
|
|
33
|
+
|
|
34
|
+
### Structural generators
|
|
35
|
+
|
|
36
|
+
| Generator | Command | Description |
|
|
37
|
+
|-----------|---------|-------------|
|
|
38
|
+
| workspace | `npx nx g @frontmcp/nx:workspace <name>` | New FrontMCP monorepo |
|
|
39
|
+
| app | `npx nx g @frontmcp/nx:app <name>` | MCP application |
|
|
40
|
+
| lib | `npx nx g @frontmcp/nx:lib <name>` | Shared library |
|
|
41
|
+
| server | `npx nx g @frontmcp/nx:server <name>` | Deployment shell |
|
|
42
|
+
|
|
43
|
+
### Component generators (use `--project` to target a library)
|
|
44
|
+
|
|
45
|
+
| Generator | Command | Description |
|
|
46
|
+
|-----------|---------|-------------|
|
|
47
|
+
| tool | `npx nx g @frontmcp/nx:tool <Name> --project <lib>` | MCP tool with Zod schemas |
|
|
48
|
+
| resource | `npx nx g @frontmcp/nx:resource <Name> --project <lib>` | MCP resource |
|
|
49
|
+
| prompt | `npx nx g @frontmcp/nx:prompt <Name> --project <lib>` | MCP prompt |
|
|
50
|
+
| skill | `npx nx g @frontmcp/nx:skill <Name> --project <lib>` | Composite skill |
|
|
51
|
+
| agent | `npx nx g @frontmcp/nx:agent <Name> --project <lib>` | Agent definition |
|
|
52
|
+
| provider | `npx nx g @frontmcp/nx:provider <Name> --project <lib>` | DI provider |
|
|
53
|
+
| plugin | `npx nx g @frontmcp/nx:plugin <Name> --project <lib>` | Plugin |
|
|
54
|
+
| adapter | `npx nx g @frontmcp/nx:adapter <Name> --project <lib>` | Framework adapter |
|
|
55
|
+
| auth-provider | `npx nx g @frontmcp/nx:auth-provider <Name> --project <lib>` | Auth provider |
|
|
56
|
+
| flow | `npx nx g @frontmcp/nx:flow <Name> --project <lib>` | Flow definition |
|
|
57
|
+
| job | `npx nx g @frontmcp/nx:job <Name> --project <lib>` | Background job |
|
|
58
|
+
| workflow | `npx nx g @frontmcp/nx:workflow <Name> --project <lib>` | Multi-step workflow |
|
|
59
|
+
|
|
60
|
+
### UI generators
|
|
61
|
+
|
|
62
|
+
| Generator | Command | Description |
|
|
63
|
+
|-----------|---------|-------------|
|
|
64
|
+
| ui-component | `npx nx g @frontmcp/nx:ui-component <Name>` | React component (PascalCase) |
|
|
65
|
+
| ui-page | `npx nx g @frontmcp/nx:ui-page <Name>` | Full-page React component |
|
|
66
|
+
| ui-shell | `npx nx g @frontmcp/nx:ui-shell <name>` | Server-side HTML shell (kebab-case) |
|
|
67
|
+
|
|
68
|
+
## Architecture Patterns
|
|
69
|
+
|
|
70
|
+
### Server entry point (`main.ts`)
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
import { FrontMcp, StdioTransport } from '@frontmcp/sdk';
|
|
74
|
+
import { MyApp } from './my-app.app';
|
|
75
|
+
|
|
76
|
+
@FrontMcp({
|
|
77
|
+
name: 'my-server',
|
|
78
|
+
version: '1.0.0',
|
|
79
|
+
apps: [MyApp],
|
|
80
|
+
})
|
|
81
|
+
class MyServer {}
|
|
82
|
+
|
|
83
|
+
new StdioTransport(MyServer).start();
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### App definition
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
import { App } from '@frontmcp/sdk';
|
|
90
|
+
import { MyTool } from './tools/my-tool.tool';
|
|
91
|
+
import { MyResource } from './resources/my-resource.resource';
|
|
92
|
+
|
|
93
|
+
@App({
|
|
94
|
+
tools: [MyTool],
|
|
95
|
+
resources: [MyResource],
|
|
96
|
+
prompts: [],
|
|
97
|
+
providers: [],
|
|
98
|
+
})
|
|
99
|
+
export class MyApp {}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Tool (most common pattern)
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
import { Tool, ToolContext } from '@frontmcp/sdk';
|
|
106
|
+
import { z } from 'zod';
|
|
107
|
+
|
|
108
|
+
const inputSchema = z.object({
|
|
109
|
+
query: z.string().describe('Search query'),
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const outputSchema = z.object({
|
|
113
|
+
results: z.array(z.string()),
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
@Tool({
|
|
117
|
+
name: 'search',
|
|
118
|
+
description: 'Search for items',
|
|
119
|
+
inputSchema,
|
|
120
|
+
outputSchema,
|
|
121
|
+
})
|
|
122
|
+
export class SearchTool extends ToolContext<typeof inputSchema, typeof outputSchema> {
|
|
123
|
+
async execute(input: z.infer<typeof inputSchema>) {
|
|
124
|
+
const results = ['result1', 'result2'];
|
|
125
|
+
return { results };
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Resource
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
import { Resource, ResourceContext } from '@frontmcp/sdk';
|
|
134
|
+
|
|
135
|
+
@Resource({
|
|
136
|
+
uri: 'myapp://config',
|
|
137
|
+
name: 'App Configuration',
|
|
138
|
+
mimeType: 'application/json',
|
|
139
|
+
})
|
|
140
|
+
export class ConfigResource extends ResourceContext {
|
|
141
|
+
async read() {
|
|
142
|
+
return { uri: 'myapp://config', text: JSON.stringify({ key: 'value' }) };
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Resource Template (dynamic URIs)
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
import { ResourceTemplate, ResourceContext } from '@frontmcp/sdk';
|
|
151
|
+
|
|
152
|
+
@ResourceTemplate({
|
|
153
|
+
uriTemplate: 'myapp://users/{userId}',
|
|
154
|
+
name: 'User Profile',
|
|
155
|
+
mimeType: 'application/json',
|
|
156
|
+
})
|
|
157
|
+
export class UserResource extends ResourceContext<{ userId: string }> {
|
|
158
|
+
async read(params: { userId: string }) {
|
|
159
|
+
return { uri: `myapp://users/${params.userId}`, text: JSON.stringify({ id: params.userId }) };
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Prompt
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
import { Prompt, PromptContext } from '@frontmcp/sdk';
|
|
168
|
+
import type { GetPromptResult } from '@modelcontextprotocol/sdk/types.js';
|
|
169
|
+
|
|
170
|
+
@Prompt({
|
|
171
|
+
name: 'summarize',
|
|
172
|
+
description: 'Summarize content',
|
|
173
|
+
})
|
|
174
|
+
export class SummarizePrompt extends PromptContext {
|
|
175
|
+
async execute(args: Record<string, string>): Promise<GetPromptResult> {
|
|
176
|
+
return {
|
|
177
|
+
messages: [
|
|
178
|
+
{ role: 'user', content: { type: 'text', text: `Summarize: ${args['content']}` } },
|
|
179
|
+
],
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Provider (dependency injection)
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
import { Provider } from '@frontmcp/sdk';
|
|
189
|
+
|
|
190
|
+
export const DB_TOKEN = Symbol('DB');
|
|
191
|
+
|
|
192
|
+
@Provider({ token: DB_TOKEN })
|
|
193
|
+
export class DatabaseProvider {
|
|
194
|
+
provide() {
|
|
195
|
+
return new DatabaseClient({ url: process.env['DATABASE_URL'] });
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// In a tool, access via this.get(DB_TOKEN):
|
|
200
|
+
async execute(input) {
|
|
201
|
+
const db = this.get(DB_TOKEN);
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Code Conventions
|
|
206
|
+
|
|
207
|
+
- **TypeScript strict mode** — no `any` types without justification; prefer `unknown`
|
|
208
|
+
- **Zod v4** for all input/output schema validation
|
|
209
|
+
- **`@frontmcp/utils`** for crypto and file-system operations (never use `node:crypto` or `fs` directly)
|
|
210
|
+
- **95%+ test coverage** required (statements, branches, functions, lines)
|
|
211
|
+
- **`@frontmcp/testing`** for test harnesses (`createTestHarness`, `createToolTestHarness`)
|
|
212
|
+
- **No non-null assertions** (`!`) — throw proper errors instead
|
|
213
|
+
|
|
214
|
+
## Documentation
|
|
215
|
+
|
|
216
|
+
This workspace includes a `.mcp.json` that configures the **frontmcp-docs** MCP server. AI coding agents can use the `SearchAgentFront` tool to search the full FrontMCP documentation at any time.
|
|
@@ -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,3 @@
|
|
|
1
|
+
Read CLAUDE.md for full project instructions, architecture patterns, and code conventions.
|
|
2
|
+
Always use Nx generators (`npx nx g @frontmcp/nx:<generator>`) — never create files manually.
|
|
3
|
+
Use the frontmcp-docs MCP server (configured in .mcp.json) to search FrontMCP documentation.
|
|
@@ -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"]}
|