frontmcp 0.6.3 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -1
- package/src/args.d.ts +1 -0
- package/src/args.js +2 -0
- package/src/args.js.map +1 -1
- package/src/cli.js +1 -0
- package/src/cli.js.map +1 -1
- package/src/commands/build/adapters/vercel.js +11 -11
- package/src/commands/build/adapters/vercel.js.map +1 -1
- package/src/commands/build/index.js +6 -5
- package/src/commands/build/index.js.map +1 -1
- package/src/commands/create.js +25 -14
- package/src/commands/create.js.map +1 -1
- package/src/commands/doctor.js +5 -5
- package/src/commands/doctor.js.map +1 -1
- package/src/commands/inspector.js +2 -2
- package/src/commands/inspector.js.map +1 -1
- package/src/commands/template.js +6 -6
- package/src/commands/template.js.map +1 -1
- package/src/commands/test.js +19 -3
- package/src/commands/test.js.map +1 -1
- package/src/tsconfig.js +4 -4
- package/src/tsconfig.js.map +1 -1
- package/src/utils/fs.d.ts +4 -8
- package/src/utils/fs.js +14 -57
- package/src/utils/fs.js.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "frontmcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"description": "FrontMCP command line interface",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"homepage": "https://docs.agentfront.dev",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"frontmcp": "./src/cli.js"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
+
"@frontmcp/utils": "0.7.2",
|
|
29
30
|
"tslib": "^2.3.0",
|
|
30
31
|
"@rspack/core": "^1.3.12"
|
|
31
32
|
},
|
package/src/args.d.ts
CHANGED
package/src/args.js
CHANGED
|
@@ -23,6 +23,8 @@ function parseArgs(argv) {
|
|
|
23
23
|
const parsed = parseInt(argv[++i], 10);
|
|
24
24
|
out.timeout = Number.isNaN(parsed) ? undefined : parsed;
|
|
25
25
|
}
|
|
26
|
+
else if (a === '--coverage' || a === '-c')
|
|
27
|
+
out.coverage = true;
|
|
26
28
|
// Create command flags
|
|
27
29
|
else if (a === '--yes' || a === '-y')
|
|
28
30
|
out.yes = true;
|
package/src/args.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"args.js","sourceRoot":"","sources":["../../src/args.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"args.js","sourceRoot":"","sources":["../../src/args.ts"],"names":[],"mappings":";;AAiCA,8BAwBC;AAxBD,SAAgB,SAAS,CAAC,IAAc;IACtC,MAAM,GAAG,GAAe,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC;IAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,CAAC,KAAK,WAAW,IAAI,CAAC,KAAK,IAAI;YAAE,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;aACvD,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,IAAI;YAAE,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;aACzD,IAAI,CAAC,KAAK,WAAW,IAAI,CAAC,KAAK,IAAI;YAAE,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC,CAAsB,CAAC;aAClF,IAAI,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI;YAAE,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;aAClD,IAAI,CAAC,KAAK,aAAa,IAAI,CAAC,KAAK,IAAI;YAAE,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC;aAC5D,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,IAAI;YAAE,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC;aACpD,IAAI,CAAC,KAAK,WAAW,IAAI,CAAC,KAAK,IAAI;YAAE,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC;aACxD,IAAI,CAAC,KAAK,WAAW,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;YACzC,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACvC,GAAG,CAAC,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;QAC1D,CAAC;aAAM,IAAI,CAAC,KAAK,YAAY,IAAI,CAAC,KAAK,IAAI;YAAE,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC;QACjE,uBAAuB;aAClB,IAAI,CAAC,KAAK,OAAO,IAAI,CAAC,KAAK,IAAI;YAAE,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC;aAChD,IAAI,CAAC,KAAK,UAAU;YAAE,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,CAAsB,CAAC;aAClE,IAAI,CAAC,KAAK,SAAS;YAAE,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,CAAqB,CAAC;aAC/D,IAAI,CAAC,KAAK,QAAQ;YAAE,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;aACpC,IAAI,CAAC,KAAK,WAAW;YAAE,GAAG,CAAC,IAAI,GAAG,KAAK,CAAC;;YACxC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACrB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC","sourcesContent":["export type Command =\n | 'dev'\n | 'build'\n | 'init'\n | 'doctor'\n | 'inspector'\n | 'create'\n | 'help'\n | 'template'\n | 'version'\n | 'test';\n\nexport type DeploymentAdapter = 'node' | 'vercel' | 'lambda' | 'cloudflare';\nexport type RedisSetupOption = 'docker' | 'existing' | 'none';\n\nexport interface ParsedArgs {\n _: string[];\n outDir?: string;\n entry?: string;\n help?: boolean;\n runInBand?: boolean;\n watch?: boolean;\n verbose?: boolean;\n timeout?: number;\n coverage?: boolean;\n adapter?: DeploymentAdapter;\n // Create command flags\n yes?: boolean;\n target?: DeploymentAdapter;\n redis?: RedisSetupOption;\n cicd?: boolean;\n}\n\nexport function parseArgs(argv: string[]): ParsedArgs {\n const out: ParsedArgs = { _: [] };\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i];\n if (a === '--out-dir' || a === '-o') out.outDir = argv[++i];\n else if (a === '--entry' || a === '-e') out.entry = argv[++i];\n else if (a === '--adapter' || a === '-a') out.adapter = argv[++i] as DeploymentAdapter;\n else if (a === '--help' || a === '-h') out.help = true;\n else if (a === '--runInBand' || a === '-i') out.runInBand = true;\n else if (a === '--watch' || a === '-w') out.watch = true;\n else if (a === '--verbose' || a === '-v') out.verbose = true;\n else if (a === '--timeout' || a === '-t') {\n const parsed = parseInt(argv[++i], 10);\n out.timeout = Number.isNaN(parsed) ? undefined : parsed;\n } else if (a === '--coverage' || a === '-c') out.coverage = true;\n // Create command flags\n else if (a === '--yes' || a === '-y') out.yes = true;\n else if (a === '--target') out.target = argv[++i] as DeploymentAdapter;\n else if (a === '--redis') out.redis = argv[++i] as RedisSetupOption;\n else if (a === '--cicd') out.cicd = true;\n else if (a === '--no-cicd') out.cicd = false;\n else out._.push(a);\n }\n return out;\n}\n"]}
|
package/src/cli.js
CHANGED
|
@@ -48,6 +48,7 @@ ${(0, colors_1.c)('bold', 'Test Options')}
|
|
|
48
48
|
-w, --watch Run tests in watch mode
|
|
49
49
|
-v, --verbose Show verbose test output
|
|
50
50
|
-t, --timeout <ms> Set test timeout (default: 60000ms)
|
|
51
|
+
-c, --coverage Collect test coverage
|
|
51
52
|
|
|
52
53
|
${(0, colors_1.c)('bold', 'Examples')}
|
|
53
54
|
frontmcp dev
|
package/src/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":";;AACA;;GAEG;;AAEH,qCAA6B;AAC7B,iCAAwD;AACxD,wCAAwC;AACxC,4CAA4C;AAC5C,yCAAqC;AACrC,8CAA8C;AAC9C,oDAAoD;AACpD,8CAA8C;AAC9C,kDAAkD;AAClD,0CAA0C;AAE1C,SAAS,QAAQ;IACf,OAAO,CAAC,GAAG,CAAC;EACZ,IAAA,UAAC,EAAC,MAAM,EAAE,UAAU,CAAC;;EAErB,IAAA,UAAC,EAAC,MAAM,EAAE,OAAO,CAAC;;;EAGlB,IAAA,UAAC,EAAC,MAAM,EAAE,UAAU,CAAC;;;;;;;;;;;EAWrB,IAAA,UAAC,EAAC,MAAM,EAAE,SAAS,CAAC;;;;EAIpB,IAAA,UAAC,EAAC,MAAM,EAAE,gBAAgB,CAAC;;;;;;;EAO3B,IAAA,UAAC,EAAC,MAAM,EAAE,cAAc,CAAC
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n/**\n * frontmcp - FrontMCP command line interface\n */\n\nimport { c } from './colors';\nimport { Command, ParsedArgs, parseArgs } from './args';\nimport { runDev } from './commands/dev';\nimport { runBuild } from './commands/build';\nimport { runInit } from './tsconfig';\nimport { runDoctor } from './commands/doctor';\nimport { runInspector } from './commands/inspector';\nimport { runCreate } from './commands/create';\nimport { runTemplate } from './commands/template';\nimport { runTest } from './commands/test';\n\nfunction showHelp(): void {\n console.log(`\n${c('bold', 'frontmcp')} — FrontMCP command line interface\n\n${c('bold', 'Usage')}\n frontmcp <command> [options]\n\n${c('bold', 'Commands')}\n dev Start in development mode (tsx --watch <entry> + async type-check)\n build Compile entry with TypeScript (tsc)\n test Run E2E tests with auto-injected Jest configuration\n init Create or fix a tsconfig.json suitable for FrontMCP\n doctor Check Node/npm versions and tsconfig requirements\n inspector Launch MCP Inspector (npx @modelcontextprotocol/inspector)\n create [name] Scaffold a new FrontMCP project (interactive if name omitted)\n template <type> Scaffold a template by type (e.g., \"3rd-party-integration\")\n help Show this help message\n\n${c('bold', 'Options')}\n -o, --out-dir <dir> Output directory (default: ./dist)\n -e, --entry <path> Manually specify entry file path\n\n${c('bold', 'Create Options')}\n -y, --yes Use defaults (non-interactive mode)\n --target <target> Deployment target: node, vercel, lambda, cloudflare\n --redis <setup> Redis setup: docker, existing, none (node target only)\n --cicd Enable GitHub Actions CI/CD\n --no-cicd Disable GitHub Actions CI/CD\n\n${c('bold', 'Test Options')}\n -i, --runInBand Run tests sequentially (recommended for E2E)\n -w, --watch Run tests in watch mode\n -v, --verbose Show verbose test output\n -t, --timeout <ms> Set test timeout (default: 60000ms)\n -c, --coverage Collect test coverage\n\n${c('bold', 'Examples')}\n frontmcp dev\n frontmcp build --out-dir build\n frontmcp test --runInBand\n frontmcp init\n frontmcp doctor\n frontmcp inspector\n npx frontmcp create # Interactive mode\n npx frontmcp create my-mcp --yes # Use defaults\n npx frontmcp create my-mcp --target vercel # Vercel deployment\n npx frontmcp template marketplace-3rd-tools\n`);\n}\n\nasync function main(): Promise<void> {\n const argv = process.argv.slice(2);\n const parsed: ParsedArgs = parseArgs(argv);\n const cmd = parsed._[0] as Command | undefined;\n\n if (parsed.help || !cmd) {\n showHelp();\n process.exit(0);\n }\n\n try {\n switch (cmd) {\n case 'dev':\n await runDev(parsed);\n break;\n case 'build':\n parsed.outDir = parsed.outDir || 'dist';\n await runBuild(parsed);\n break;\n case 'init':\n await runInit();\n break;\n case 'doctor':\n await runDoctor();\n break;\n case 'inspector':\n await runInspector();\n break;\n case 'create': {\n const projectName = parsed._[1];\n await runCreate(projectName, {\n yes: parsed.yes,\n target: parsed.target,\n redis: parsed.redis,\n cicd: parsed.cicd,\n });\n break;\n }\n case 'template': {\n const type = parsed._[1]; // e.g. \"3rd-party-integration\"\n await runTemplate(type);\n break;\n }\n case 'test':\n await runTest(parsed);\n break;\n case 'help':\n showHelp();\n break;\n default:\n console.error(c('red', `Unknown command: ${cmd}`));\n showHelp();\n process.exitCode = 1;\n }\n } catch (err: unknown) {\n console.error('\\n' + c('red', err instanceof Error ? err.stack || err.message : String(err)));\n process.exit(1);\n }\n}\n\nmain();\n"]}
|
|
@@ -3,9 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.vercelAdapter = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const path = tslib_1.__importStar(require("path"));
|
|
6
|
-
const fs = tslib_1.__importStar(require("fs/promises"));
|
|
7
6
|
const fs_1 = require("fs");
|
|
8
7
|
const child_process_1 = require("child_process");
|
|
8
|
+
const utils_1 = require("@frontmcp/utils");
|
|
9
9
|
const PACKAGE_MANAGERS = {
|
|
10
10
|
bun: { install: 'bun install', run: 'bun run build' },
|
|
11
11
|
pnpm: { install: 'pnpm install', run: 'pnpm run build' },
|
|
@@ -100,21 +100,21 @@ export default async function handler(req, res) {
|
|
|
100
100
|
const outputDir = path.join(cwd, '.vercel', 'output');
|
|
101
101
|
const funcDir = path.join(outputDir, 'functions', 'index.func');
|
|
102
102
|
// Create directories
|
|
103
|
-
await
|
|
103
|
+
await (0, utils_1.mkdir)(funcDir, { recursive: true });
|
|
104
104
|
// Copy all files from dist to the function directory
|
|
105
105
|
// This includes handler.cjs and any chunk files (*.handler.cjs)
|
|
106
|
-
const distFiles = await
|
|
106
|
+
const distFiles = await (0, utils_1.readdir)(outDir);
|
|
107
107
|
for (const file of distFiles) {
|
|
108
108
|
const srcPath = path.join(outDir, file);
|
|
109
109
|
const destPath = path.join(funcDir, file);
|
|
110
|
-
const
|
|
111
|
-
if (
|
|
110
|
+
const fileStat = await (0, utils_1.stat)(srcPath);
|
|
111
|
+
if (fileStat.isDirectory()) {
|
|
112
112
|
// Recursively copy directories
|
|
113
|
-
await
|
|
113
|
+
await (0, utils_1.cp)(srcPath, destPath, { recursive: true });
|
|
114
114
|
}
|
|
115
115
|
else {
|
|
116
116
|
// Copy files
|
|
117
|
-
await
|
|
117
|
+
await (0, utils_1.copyFile)(srcPath, destPath);
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
120
|
// Install runtime dependencies that can't be statically bundled (dynamic requires)
|
|
@@ -123,7 +123,7 @@ export default async function handler(req, res) {
|
|
|
123
123
|
const runtimeDeps = ['@vercel/kv', 'esbuild', '@swc/core'];
|
|
124
124
|
// Read package.json to get the exact versions
|
|
125
125
|
const pkgJsonPath = path.join(cwd, 'package.json');
|
|
126
|
-
const pkgJson = JSON.parse(await
|
|
126
|
+
const pkgJson = JSON.parse(await (0, utils_1.readFile)(pkgJsonPath, 'utf-8'));
|
|
127
127
|
const allDeps = { ...pkgJson.dependencies, ...pkgJson.devDependencies };
|
|
128
128
|
// Build list of deps with versions
|
|
129
129
|
const depsToInstall = [];
|
|
@@ -136,7 +136,7 @@ export default async function handler(req, res) {
|
|
|
136
136
|
if (depsToInstall.length > 0) {
|
|
137
137
|
// Create package.json in function directory
|
|
138
138
|
const funcPkgJson = { name: 'index.func', private: true, dependencies: {} };
|
|
139
|
-
await
|
|
139
|
+
await (0, utils_1.writeFile)(path.join(funcDir, 'package.json'), JSON.stringify(funcPkgJson, null, 2));
|
|
140
140
|
// Install dependencies using npm (works on all platforms)
|
|
141
141
|
try {
|
|
142
142
|
(0, child_process_1.execSync)(`npm install ${depsToInstall.join(' ')} --omit=dev`, {
|
|
@@ -154,13 +154,13 @@ export default async function handler(req, res) {
|
|
|
154
154
|
handler: bundleOutput,
|
|
155
155
|
launcherType: 'Nodejs',
|
|
156
156
|
};
|
|
157
|
-
await
|
|
157
|
+
await (0, utils_1.writeFile)(path.join(funcDir, '.vc-config.json'), JSON.stringify(vcConfig, null, 2));
|
|
158
158
|
// Create output config (config.json) with routing
|
|
159
159
|
const outputConfig = {
|
|
160
160
|
version: 3,
|
|
161
161
|
routes: [{ src: '/(.*)', dest: '/index' }],
|
|
162
162
|
};
|
|
163
|
-
await
|
|
163
|
+
await (0, utils_1.writeFile)(path.join(outputDir, 'config.json'), JSON.stringify(outputConfig, null, 2));
|
|
164
164
|
},
|
|
165
165
|
};
|
|
166
166
|
//# sourceMappingURL=vercel.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vercel.js","sourceRoot":"","sources":["../../../../../src/commands/build/adapters/vercel.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from 'path';\nimport * as fs from 'fs/promises';\nimport { existsSync } from 'fs';\nimport { execSync } from 'child_process';\nimport { AdapterTemplate } from '../types';\n\ntype PackageManager = 'npm' | 'yarn' | 'pnpm' | 'bun';\n\ninterface PackageManagerConfig {\n install: string;\n run: string;\n}\n\nconst PACKAGE_MANAGERS: Record<PackageManager, PackageManagerConfig> = {\n bun: { install: 'bun install', run: 'bun run build' },\n pnpm: { install: 'pnpm install', run: 'pnpm run build' },\n yarn: { install: 'yarn install', run: 'yarn build' },\n npm: { install: 'npm install', run: 'npm run build' },\n};\n\nconst LOCKFILE_TO_PM: Record<string, PackageManager> = {\n 'bun.lockb': 'bun',\n 'pnpm-lock.yaml': 'pnpm',\n 'yarn.lock': 'yarn',\n 'package-lock.json': 'npm',\n};\n\n/**\n * Detect package manager based on lockfile presence.\n * Priority: bun > pnpm > yarn > npm (fastest to slowest install times)\n */\nfunction detectPackageManager(cwd: string): PackageManager {\n for (const [lockfile, pm] of Object.entries(LOCKFILE_TO_PM)) {\n if (existsSync(path.join(cwd, lockfile))) {\n return pm;\n }\n }\n return 'npm'; // Default fallback\n}\n\n/**\n * Vercel adapter - serverless deployment on Vercel.\n * Compiles to ESM, bundles with rspack to CJS for maximum compatibility.\n *\n * Uses Vercel Build Output API for deployment:\n * - Creates .vercel/output/config.json with routing\n * - Creates .vercel/output/functions/index.func/ with handler\n *\n * The build process:\n * 1. TypeScript compiles to ESM in dist/\n * 2. serverless-setup.js is generated (sets FRONTMCP_SERVERLESS=1)\n * 3. index.js imports setup first, then main module\n * 4. rspack bundles everything into handler.cjs\n * 5. Build Output API structure is created in .vercel/output/\n *\n * @see https://vercel.com/docs/build-output-api/v3\n */\nexport const vercelAdapter: AdapterTemplate = {\n moduleFormat: 'esnext',\n shouldBundle: true,\n bundleOutput: 'handler.cjs',\n\n getSetupTemplate: () => `// Serverless environment setup - MUST be imported first\n// This sets FRONTMCP_SERVERLESS before any decorators run\n// Required because ESM hoists imports before other statements\nprocess.env.FRONTMCP_SERVERLESS = '1';\n`,\n\n getEntryTemplate: (mainModulePath: string) => `// Auto-generated Vercel entry point\n// Generated by: frontmcp build --adapter vercel\nimport './serverless-setup.js';\nimport '${mainModulePath}';\nimport { getServerlessHandlerAsync } from '@frontmcp/sdk';\n\nlet handlerPromise = null;\n\nexport default async function handler(req, res) {\n if (!handlerPromise) {\n handlerPromise = getServerlessHandlerAsync();\n }\n const app = await handlerPromise;\n return app(req, res);\n}\n`,\n\n // Detect package manager and generate appropriate vercel.json\n getConfig: (cwd: string) => {\n const pm = detectPackageManager(cwd);\n const config = PACKAGE_MANAGERS[pm];\n return {\n version: 2,\n buildCommand: config.run,\n installCommand: config.install,\n };\n },\n\n configFileName: 'vercel.json',\n\n /**\n * Create Vercel Build Output API structure after bundling.\n * This allows Vercel to deploy the function without needing an /api folder.\n *\n * Structure created:\n * .vercel/output/\n * ├── config.json (routes all requests to index function)\n * └── functions/\n * └── index.func/\n * ├── .vc-config.json (Node.js 22 runtime config)\n * ├── handler.cjs (bundled handler + chunks)\n * └── node_modules/ (runtime dependencies that can't be bundled)\n */\n postBundle: async (outDir: string, cwd: string, bundleOutput: string) => {\n const outputDir = path.join(cwd, '.vercel', 'output');\n const funcDir = path.join(outputDir, 'functions', 'index.func');\n\n // Create directories\n await fs.mkdir(funcDir, { recursive: true });\n\n // Copy all files from dist to the function directory\n // This includes handler.cjs and any chunk files (*.handler.cjs)\n const distFiles = await fs.readdir(outDir);\n for (const file of distFiles) {\n const srcPath = path.join(outDir, file);\n const destPath = path.join(funcDir, file);\n const stat = await fs.stat(srcPath);\n\n if (stat.isDirectory()) {\n // Recursively copy directories\n await fs.cp(srcPath, destPath, { recursive: true });\n } else {\n // Copy files\n await fs.copyFile(srcPath, destPath);\n }\n }\n\n // Install runtime dependencies that can't be statically bundled (dynamic requires)\n // These are packages loaded via require() inside functions that rspack can't analyze\n // We install them fresh to ensure correct platform binaries (linux-x64 for Vercel)\n const runtimeDeps = ['@vercel/kv', 'esbuild', '@swc/core'];\n\n // Read package.json to get the exact versions\n const pkgJsonPath = path.join(cwd, 'package.json');\n const pkgJson = JSON.parse(await fs.readFile(pkgJsonPath, 'utf-8'));\n const allDeps = { ...pkgJson.dependencies, ...pkgJson.devDependencies };\n\n // Build list of deps with versions\n const depsToInstall: string[] = [];\n for (const dep of runtimeDeps) {\n const version = allDeps[dep];\n if (version) {\n depsToInstall.push(`${dep}@${version}`);\n }\n }\n\n if (depsToInstall.length > 0) {\n // Create package.json in function directory\n const funcPkgJson = { name: 'index.func', private: true, dependencies: {} };\n await fs.writeFile(path.join(funcDir, 'package.json'), JSON.stringify(funcPkgJson, null, 2));\n\n // Install dependencies using npm (works on all platforms)\n try {\n execSync(`npm install ${depsToInstall.join(' ')} --omit=dev`, {\n cwd: funcDir,\n stdio: 'pipe',\n });\n } catch {\n // Silently continue if install fails - the dep might not be needed\n }\n }\n\n // Create function config (.vc-config.json)\n const vcConfig = {\n runtime: 'nodejs22.x',\n handler: bundleOutput,\n launcherType: 'Nodejs',\n };\n await fs.writeFile(\n path.join(funcDir, '.vc-config.json'),\n JSON.stringify(vcConfig, null, 2),\n );\n\n // Create output config (config.json) with routing\n const outputConfig = {\n version: 3,\n routes: [{ src: '/(.*)', dest: '/index' }],\n };\n await fs.writeFile(\n path.join(outputDir, 'config.json'),\n JSON.stringify(outputConfig, null, 2),\n );\n },\n};\n"]}
|
|
1
|
+
{"version":3,"file":"vercel.js","sourceRoot":"","sources":["../../../../../src/commands/build/adapters/vercel.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from 'path';\nimport { existsSync } from 'fs';\nimport { execSync } from 'child_process';\nimport { mkdir, readdir, stat, cp, copyFile, readFile, writeFile } from '@frontmcp/utils';\nimport { AdapterTemplate } from '../types';\n\ntype PackageManager = 'npm' | 'yarn' | 'pnpm' | 'bun';\n\ninterface PackageManagerConfig {\n install: string;\n run: string;\n}\n\nconst PACKAGE_MANAGERS: Record<PackageManager, PackageManagerConfig> = {\n bun: { install: 'bun install', run: 'bun run build' },\n pnpm: { install: 'pnpm install', run: 'pnpm run build' },\n yarn: { install: 'yarn install', run: 'yarn build' },\n npm: { install: 'npm install', run: 'npm run build' },\n};\n\nconst LOCKFILE_TO_PM: Record<string, PackageManager> = {\n 'bun.lockb': 'bun',\n 'pnpm-lock.yaml': 'pnpm',\n 'yarn.lock': 'yarn',\n 'package-lock.json': 'npm',\n};\n\n/**\n * Detect package manager based on lockfile presence.\n * Priority: bun > pnpm > yarn > npm (fastest to slowest install times)\n */\nfunction detectPackageManager(cwd: string): PackageManager {\n for (const [lockfile, pm] of Object.entries(LOCKFILE_TO_PM)) {\n if (existsSync(path.join(cwd, lockfile))) {\n return pm;\n }\n }\n return 'npm'; // Default fallback\n}\n\n/**\n * Vercel adapter - serverless deployment on Vercel.\n * Compiles to ESM, bundles with rspack to CJS for maximum compatibility.\n *\n * Uses Vercel Build Output API for deployment:\n * - Creates .vercel/output/config.json with routing\n * - Creates .vercel/output/functions/index.func/ with handler\n *\n * The build process:\n * 1. TypeScript compiles to ESM in dist/\n * 2. serverless-setup.js is generated (sets FRONTMCP_SERVERLESS=1)\n * 3. index.js imports setup first, then main module\n * 4. rspack bundles everything into handler.cjs\n * 5. Build Output API structure is created in .vercel/output/\n *\n * @see https://vercel.com/docs/build-output-api/v3\n */\nexport const vercelAdapter: AdapterTemplate = {\n moduleFormat: 'esnext',\n shouldBundle: true,\n bundleOutput: 'handler.cjs',\n\n getSetupTemplate: () => `// Serverless environment setup - MUST be imported first\n// This sets FRONTMCP_SERVERLESS before any decorators run\n// Required because ESM hoists imports before other statements\nprocess.env.FRONTMCP_SERVERLESS = '1';\n`,\n\n getEntryTemplate: (mainModulePath: string) => `// Auto-generated Vercel entry point\n// Generated by: frontmcp build --adapter vercel\nimport './serverless-setup.js';\nimport '${mainModulePath}';\nimport { getServerlessHandlerAsync } from '@frontmcp/sdk';\n\nlet handlerPromise = null;\n\nexport default async function handler(req, res) {\n if (!handlerPromise) {\n handlerPromise = getServerlessHandlerAsync();\n }\n const app = await handlerPromise;\n return app(req, res);\n}\n`,\n\n // Detect package manager and generate appropriate vercel.json\n getConfig: (cwd: string) => {\n const pm = detectPackageManager(cwd);\n const config = PACKAGE_MANAGERS[pm];\n return {\n version: 2,\n buildCommand: config.run,\n installCommand: config.install,\n };\n },\n\n configFileName: 'vercel.json',\n\n /**\n * Create Vercel Build Output API structure after bundling.\n * This allows Vercel to deploy the function without needing an /api folder.\n *\n * Structure created:\n * .vercel/output/\n * ├── config.json (routes all requests to index function)\n * └── functions/\n * └── index.func/\n * ├── .vc-config.json (Node.js 22 runtime config)\n * ├── handler.cjs (bundled handler + chunks)\n * └── node_modules/ (runtime dependencies that can't be bundled)\n */\n postBundle: async (outDir: string, cwd: string, bundleOutput: string) => {\n const outputDir = path.join(cwd, '.vercel', 'output');\n const funcDir = path.join(outputDir, 'functions', 'index.func');\n\n // Create directories\n await mkdir(funcDir, { recursive: true });\n\n // Copy all files from dist to the function directory\n // This includes handler.cjs and any chunk files (*.handler.cjs)\n const distFiles = await readdir(outDir);\n for (const file of distFiles) {\n const srcPath = path.join(outDir, file);\n const destPath = path.join(funcDir, file);\n const fileStat = await stat(srcPath);\n\n if (fileStat.isDirectory()) {\n // Recursively copy directories\n await cp(srcPath, destPath, { recursive: true });\n } else {\n // Copy files\n await copyFile(srcPath, destPath);\n }\n }\n\n // Install runtime dependencies that can't be statically bundled (dynamic requires)\n // These are packages loaded via require() inside functions that rspack can't analyze\n // We install them fresh to ensure correct platform binaries (linux-x64 for Vercel)\n const runtimeDeps = ['@vercel/kv', 'esbuild', '@swc/core'];\n\n // Read package.json to get the exact versions\n const pkgJsonPath = path.join(cwd, 'package.json');\n const pkgJson = JSON.parse(await readFile(pkgJsonPath, 'utf-8'));\n const allDeps = { ...pkgJson.dependencies, ...pkgJson.devDependencies };\n\n // Build list of deps with versions\n const depsToInstall: string[] = [];\n for (const dep of runtimeDeps) {\n const version = allDeps[dep];\n if (version) {\n depsToInstall.push(`${dep}@${version}`);\n }\n }\n\n if (depsToInstall.length > 0) {\n // Create package.json in function directory\n const funcPkgJson = { name: 'index.func', private: true, dependencies: {} };\n await writeFile(path.join(funcDir, 'package.json'), JSON.stringify(funcPkgJson, null, 2));\n\n // Install dependencies using npm (works on all platforms)\n try {\n execSync(`npm install ${depsToInstall.join(' ')} --omit=dev`, {\n cwd: funcDir,\n stdio: 'pipe',\n });\n } catch {\n // Silently continue if install fails - the dep might not be needed\n }\n }\n\n // Create function config (.vc-config.json)\n const vcConfig = {\n runtime: 'nodejs22.x',\n handler: bundleOutput,\n launcherType: 'Nodejs',\n };\n await writeFile(\n path.join(funcDir, '.vc-config.json'),\n JSON.stringify(vcConfig, null, 2),\n );\n\n // Create output config (config.json) with routing\n const outputConfig = {\n version: 3,\n routes: [{ src: '/(.*)', dest: '/index' }],\n };\n await writeFile(\n path.join(outputDir, 'config.json'),\n JSON.stringify(outputConfig, null, 2),\n );\n },\n};\n"]}
|
|
@@ -4,6 +4,7 @@ exports.runBuild = runBuild;
|
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const path = tslib_1.__importStar(require("path"));
|
|
6
6
|
const colors_1 = require("../../colors");
|
|
7
|
+
const utils_1 = require("@frontmcp/utils");
|
|
7
8
|
const fs_1 = require("../../utils/fs");
|
|
8
9
|
const tsconfig_1 = require("../../tsconfig");
|
|
9
10
|
const adapters_1 = require("./adapters");
|
|
@@ -49,7 +50,7 @@ async function generateAdapterFiles(adapter, outDir, entryBasename, cwd) {
|
|
|
49
50
|
// Generate config file if adapter has one (skip if already exists)
|
|
50
51
|
if (template.getConfig && template.configFileName) {
|
|
51
52
|
const configPath = path.join(cwd, template.configFileName);
|
|
52
|
-
if (await (0,
|
|
53
|
+
if (await (0, utils_1.fileExists)(configPath)) {
|
|
53
54
|
console.log((0, colors_1.c)('yellow', ` ${template.configFileName} already exists (skipping)`));
|
|
54
55
|
}
|
|
55
56
|
else {
|
|
@@ -60,7 +61,7 @@ async function generateAdapterFiles(adapter, outDir, entryBasename, cwd) {
|
|
|
60
61
|
}
|
|
61
62
|
else {
|
|
62
63
|
// Write as JSON
|
|
63
|
-
await (0,
|
|
64
|
+
await (0, utils_1.writeJSON)(configPath, configContent);
|
|
64
65
|
}
|
|
65
66
|
console.log((0, colors_1.c)('green', ` Generated ${template.configFileName}`));
|
|
66
67
|
}
|
|
@@ -91,7 +92,7 @@ async function runBuild(opts) {
|
|
|
91
92
|
const entry = await (0, fs_1.resolveEntry)(cwd, opts.entry);
|
|
92
93
|
const outDir = path.resolve(cwd, opts.outDir || 'dist');
|
|
93
94
|
const adapter = (opts.adapter || 'node');
|
|
94
|
-
await (0,
|
|
95
|
+
await (0, utils_1.ensureDir)(outDir);
|
|
95
96
|
// Validate adapter
|
|
96
97
|
const template = adapters_1.ADAPTERS[adapter];
|
|
97
98
|
if (!template) {
|
|
@@ -108,7 +109,7 @@ async function runBuild(opts) {
|
|
|
108
109
|
console.log(`${(0, colors_1.c)('cyan', '[build]')} adapter: ${adapter} (${moduleFormat})`);
|
|
109
110
|
// Build TypeScript compiler arguments
|
|
110
111
|
const tsconfigPath = path.join(cwd, 'tsconfig.json');
|
|
111
|
-
const hasTsconfig = await (0,
|
|
112
|
+
const hasTsconfig = await (0, utils_1.fileExists)(tsconfigPath);
|
|
112
113
|
const args = ['-y', 'tsc'];
|
|
113
114
|
if (hasTsconfig) {
|
|
114
115
|
console.log((0, colors_1.c)('gray', `[build] tsconfig.json detected — compiling with project settings`));
|
|
@@ -129,7 +130,7 @@ async function runBuild(opts) {
|
|
|
129
130
|
args.push('--outDir', outDir);
|
|
130
131
|
args.push('--skipLibCheck');
|
|
131
132
|
// Run TypeScript compiler
|
|
132
|
-
await (0,
|
|
133
|
+
await (0, utils_1.runCmd)('npx', args);
|
|
133
134
|
// Generate adapter-specific files
|
|
134
135
|
if (adapter !== 'node') {
|
|
135
136
|
console.log((0, colors_1.c)('cyan', `[build] Generating ${adapter} deployment files...`));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/commands/build/index.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from 'path';\nimport { ParsedArgs } from '../../args';\nimport { c } from '../../colors';\nimport { ensureDir, fileExists, fsp, runCmd, resolveEntry, writeJSON } from '../../utils/fs';\nimport { REQUIRED_DECORATOR_FIELDS } from '../../tsconfig';\nimport { ADAPTERS } from './adapters';\nimport { AdapterName } from './types';\nimport { bundleForServerless } from './bundler';\n\nfunction isTsLike(p: string): boolean {\n return /\\.tsx?$/i.test(p);\n}\n\n/**\n * Generate adapter-specific entry point and config files.\n */\nasync function generateAdapterFiles(\n adapter: AdapterName,\n outDir: string,\n entryBasename: string,\n cwd: string,\n): Promise<void> {\n const template = ADAPTERS[adapter];\n\n // Generate serverless setup file first (if adapter has one)\n // This file sets FRONTMCP_SERVERLESS=1 before any imports run\n if (template.getSetupTemplate) {\n const setupContent = template.getSetupTemplate();\n const setupPath = path.join(outDir, 'serverless-setup.js');\n await fsp.writeFile(setupPath, setupContent, 'utf8');\n console.log(c('green', ` Generated serverless setup at ${path.relative(cwd, setupPath)}`));\n }\n\n // Generate index.js entry point\n const mainModuleName = entryBasename.replace(/\\.tsx?$/, '.js');\n const entryContent = template.getEntryTemplate(`./${mainModuleName}`);\n\n // Skip if no entry template (e.g., node adapter)\n if (entryContent) {\n const entryPath = path.join(outDir, 'index.js');\n await fsp.writeFile(entryPath, entryContent, 'utf8');\n console.log(c('green', ` Generated ${adapter} entry at ${path.relative(cwd, entryPath)}`));\n }\n\n // Bundle if adapter requires it (creates single CJS file for serverless)\n if (template.shouldBundle && template.bundleOutput) {\n console.log(c('cyan', `[build] Bundling for ${adapter}...`));\n const entryPath = path.join(outDir, 'index.js');\n await bundleForServerless(entryPath, outDir, template.bundleOutput);\n console.log(c('green', ` Created bundle: ${template.bundleOutput}`));\n\n // Run post-bundle hook if defined (e.g., create Build Output API structure)\n if (template.postBundle) {\n console.log(c('cyan', `[build] Creating ${adapter} deployment structure...`));\n await template.postBundle(outDir, cwd, template.bundleOutput);\n console.log(c('green', ` Created deployment output structure`));\n }\n }\n\n // Generate config file if adapter has one (skip if already exists)\n if (template.getConfig && template.configFileName) {\n const configPath = path.join(cwd, template.configFileName);\n\n if (await fileExists(configPath)) {\n console.log(c('yellow', ` ${template.configFileName} already exists (skipping)`));\n } else {\n const configContent = template.getConfig(cwd);\n\n if (typeof configContent === 'string') {\n // Write as plain text (e.g., TOML for wrangler.toml)\n await fsp.writeFile(configPath, configContent, 'utf8');\n } else {\n // Write as JSON\n await writeJSON(configPath, configContent);\n }\n console.log(c('green', ` Generated ${template.configFileName}`));\n }\n }\n}\n\n/**\n * Build the FrontMCP server for a specific deployment target.\n *\n * @param opts - Build options from CLI arguments\n *\n * @example\n * ```bash\n * # Build for Node.js (default)\n * frontmcp build\n *\n * # Build for Vercel\n * frontmcp build --adapter vercel\n *\n * # Build for AWS Lambda\n * frontmcp build --adapter lambda\n *\n * # Build for Cloudflare Workers\n * frontmcp build --adapter cloudflare\n * ```\n */\nexport async function runBuild(opts: ParsedArgs): Promise<void> {\n const cwd = process.cwd();\n const entry = await resolveEntry(cwd, opts.entry);\n const outDir = path.resolve(cwd, opts.outDir || 'dist');\n const adapter = (opts.adapter || 'node') as AdapterName;\n await ensureDir(outDir);\n\n // Validate adapter\n const template = ADAPTERS[adapter];\n if (!template) {\n const available = Object.keys(ADAPTERS).join(', ');\n throw new Error(`Unknown adapter: ${adapter}. Available: ${available}`);\n }\n\n // Warn about experimental adapters\n if (adapter === 'cloudflare') {\n console.log(\n c('yellow', '⚠️ Cloudflare Workers adapter is experimental. See docs for limitations.'),\n );\n }\n\n const moduleFormat = template.moduleFormat;\n\n console.log(`${c('cyan', '[build]')} entry: ${path.relative(cwd, entry)}`);\n console.log(`${c('cyan', '[build]')} outDir: ${path.relative(cwd, outDir)}`);\n console.log(`${c('cyan', '[build]')} adapter: ${adapter} (${moduleFormat})`);\n\n // Build TypeScript compiler arguments\n const tsconfigPath = path.join(cwd, 'tsconfig.json');\n const hasTsconfig = await fileExists(tsconfigPath);\n const args: string[] = ['-y', 'tsc'];\n\n if (hasTsconfig) {\n console.log(c('gray', `[build] tsconfig.json detected — compiling with project settings`));\n args.push('--project', tsconfigPath);\n } else {\n args.push(entry);\n args.push('--rootDir', path.dirname(entry));\n if (!isTsLike(entry)) {\n args.push('--allowJs');\n console.log(c('yellow', '[build] Entry is not TypeScript; enabling --allowJs'));\n }\n args.push('--experimentalDecorators', '--emitDecoratorMetadata');\n args.push('--target', REQUIRED_DECORATOR_FIELDS.target);\n }\n\n // Always pass module format to override tsconfig\n args.push('--module', moduleFormat);\n args.push('--outDir', outDir);\n args.push('--skipLibCheck');\n\n // Run TypeScript compiler\n await runCmd('npx', args);\n\n // Generate adapter-specific files\n if (adapter !== 'node') {\n console.log(c('cyan', `[build] Generating ${adapter} deployment files...`));\n const entryBasename = path.basename(entry);\n await generateAdapterFiles(adapter, outDir, entryBasename, cwd);\n }\n\n console.log(c('green', '✅ Build completed.'));\n console.log(c('gray', `Output placed in ${path.relative(cwd, outDir)}`));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/commands/build/index.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from 'path';\nimport { ParsedArgs } from '../../args';\nimport { c } from '../../colors';\nimport { ensureDir, fileExists, runCmd, writeJSON } from '@frontmcp/utils';\nimport { fsp, resolveEntry } from '../../utils/fs';\nimport { REQUIRED_DECORATOR_FIELDS } from '../../tsconfig';\nimport { ADAPTERS } from './adapters';\nimport { AdapterName } from './types';\nimport { bundleForServerless } from './bundler';\n\nfunction isTsLike(p: string): boolean {\n return /\\.tsx?$/i.test(p);\n}\n\n/**\n * Generate adapter-specific entry point and config files.\n */\nasync function generateAdapterFiles(\n adapter: AdapterName,\n outDir: string,\n entryBasename: string,\n cwd: string,\n): Promise<void> {\n const template = ADAPTERS[adapter];\n\n // Generate serverless setup file first (if adapter has one)\n // This file sets FRONTMCP_SERVERLESS=1 before any imports run\n if (template.getSetupTemplate) {\n const setupContent = template.getSetupTemplate();\n const setupPath = path.join(outDir, 'serverless-setup.js');\n await fsp.writeFile(setupPath, setupContent, 'utf8');\n console.log(c('green', ` Generated serverless setup at ${path.relative(cwd, setupPath)}`));\n }\n\n // Generate index.js entry point\n const mainModuleName = entryBasename.replace(/\\.tsx?$/, '.js');\n const entryContent = template.getEntryTemplate(`./${mainModuleName}`);\n\n // Skip if no entry template (e.g., node adapter)\n if (entryContent) {\n const entryPath = path.join(outDir, 'index.js');\n await fsp.writeFile(entryPath, entryContent, 'utf8');\n console.log(c('green', ` Generated ${adapter} entry at ${path.relative(cwd, entryPath)}`));\n }\n\n // Bundle if adapter requires it (creates single CJS file for serverless)\n if (template.shouldBundle && template.bundleOutput) {\n console.log(c('cyan', `[build] Bundling for ${adapter}...`));\n const entryPath = path.join(outDir, 'index.js');\n await bundleForServerless(entryPath, outDir, template.bundleOutput);\n console.log(c('green', ` Created bundle: ${template.bundleOutput}`));\n\n // Run post-bundle hook if defined (e.g., create Build Output API structure)\n if (template.postBundle) {\n console.log(c('cyan', `[build] Creating ${adapter} deployment structure...`));\n await template.postBundle(outDir, cwd, template.bundleOutput);\n console.log(c('green', ` Created deployment output structure`));\n }\n }\n\n // Generate config file if adapter has one (skip if already exists)\n if (template.getConfig && template.configFileName) {\n const configPath = path.join(cwd, template.configFileName);\n\n if (await fileExists(configPath)) {\n console.log(c('yellow', ` ${template.configFileName} already exists (skipping)`));\n } else {\n const configContent = template.getConfig(cwd);\n\n if (typeof configContent === 'string') {\n // Write as plain text (e.g., TOML for wrangler.toml)\n await fsp.writeFile(configPath, configContent, 'utf8');\n } else {\n // Write as JSON\n await writeJSON(configPath, configContent);\n }\n console.log(c('green', ` Generated ${template.configFileName}`));\n }\n }\n}\n\n/**\n * Build the FrontMCP server for a specific deployment target.\n *\n * @param opts - Build options from CLI arguments\n *\n * @example\n * ```bash\n * # Build for Node.js (default)\n * frontmcp build\n *\n * # Build for Vercel\n * frontmcp build --adapter vercel\n *\n * # Build for AWS Lambda\n * frontmcp build --adapter lambda\n *\n * # Build for Cloudflare Workers\n * frontmcp build --adapter cloudflare\n * ```\n */\nexport async function runBuild(opts: ParsedArgs): Promise<void> {\n const cwd = process.cwd();\n const entry = await resolveEntry(cwd, opts.entry);\n const outDir = path.resolve(cwd, opts.outDir || 'dist');\n const adapter = (opts.adapter || 'node') as AdapterName;\n await ensureDir(outDir);\n\n // Validate adapter\n const template = ADAPTERS[adapter];\n if (!template) {\n const available = Object.keys(ADAPTERS).join(', ');\n throw new Error(`Unknown adapter: ${adapter}. Available: ${available}`);\n }\n\n // Warn about experimental adapters\n if (adapter === 'cloudflare') {\n console.log(\n c('yellow', '⚠️ Cloudflare Workers adapter is experimental. See docs for limitations.'),\n );\n }\n\n const moduleFormat = template.moduleFormat;\n\n console.log(`${c('cyan', '[build]')} entry: ${path.relative(cwd, entry)}`);\n console.log(`${c('cyan', '[build]')} outDir: ${path.relative(cwd, outDir)}`);\n console.log(`${c('cyan', '[build]')} adapter: ${adapter} (${moduleFormat})`);\n\n // Build TypeScript compiler arguments\n const tsconfigPath = path.join(cwd, 'tsconfig.json');\n const hasTsconfig = await fileExists(tsconfigPath);\n const args: string[] = ['-y', 'tsc'];\n\n if (hasTsconfig) {\n console.log(c('gray', `[build] tsconfig.json detected — compiling with project settings`));\n args.push('--project', tsconfigPath);\n } else {\n args.push(entry);\n args.push('--rootDir', path.dirname(entry));\n if (!isTsLike(entry)) {\n args.push('--allowJs');\n console.log(c('yellow', '[build] Entry is not TypeScript; enabling --allowJs'));\n }\n args.push('--experimentalDecorators', '--emitDecoratorMetadata');\n args.push('--target', REQUIRED_DECORATOR_FIELDS.target);\n }\n\n // Always pass module format to override tsconfig\n args.push('--module', moduleFormat);\n args.push('--outDir', outDir);\n args.push('--skipLibCheck');\n\n // Run TypeScript compiler\n await runCmd('npx', args);\n\n // Generate adapter-specific files\n if (adapter !== 'node') {\n console.log(c('cyan', `[build] Generating ${adapter} deployment files...`));\n const entryBasename = path.basename(entry);\n await generateAdapterFiles(adapter, outDir, entryBasename, cwd);\n }\n\n console.log(c('green', '✅ Build completed.'));\n console.log(c('gray', `Output placed in ${path.relative(cwd, outDir)}`));\n}\n"]}
|
package/src/commands/create.js
CHANGED
|
@@ -6,10 +6,9 @@ const path = tslib_1.__importStar(require("path"));
|
|
|
6
6
|
const readline = tslib_1.__importStar(require("readline"));
|
|
7
7
|
const fs_1 = require("fs");
|
|
8
8
|
const colors_1 = require("../colors");
|
|
9
|
-
const
|
|
9
|
+
const utils_1 = require("@frontmcp/utils");
|
|
10
10
|
const tsconfig_1 = require("../tsconfig");
|
|
11
11
|
const version_1 = require("../version");
|
|
12
|
-
const fs_3 = require("../utils/fs");
|
|
13
12
|
function createPrompt() {
|
|
14
13
|
const rl = readline.createInterface({
|
|
15
14
|
input: process.stdin,
|
|
@@ -66,11 +65,11 @@ function pkgNameFromCwd(cwd) {
|
|
|
66
65
|
.toLowerCase() || 'frontmcp-app');
|
|
67
66
|
}
|
|
68
67
|
async function scaffoldFileIfMissing(baseDir, p, content) {
|
|
69
|
-
if (await (0,
|
|
68
|
+
if (await (0, utils_1.fileExists)(p)) {
|
|
70
69
|
console.log((0, colors_1.c)('gray', `skip: ${path.relative(baseDir, p)} already exists`));
|
|
71
70
|
return;
|
|
72
71
|
}
|
|
73
|
-
await (0,
|
|
72
|
+
await (0, utils_1.ensureDir)(path.dirname(p));
|
|
74
73
|
await fs_1.promises.writeFile(p, content.replace(/^\n/, ''), 'utf8');
|
|
75
74
|
console.log((0, colors_1.c)('green', `✓ created ${path.relative(baseDir, p)}`));
|
|
76
75
|
}
|
|
@@ -216,6 +215,15 @@ export default {
|
|
|
216
215
|
transformIgnorePatterns: ['node_modules/(?!(jose)/)'],
|
|
217
216
|
};
|
|
218
217
|
`;
|
|
218
|
+
const TEMPLATE_TSCONFIG_E2E = `
|
|
219
|
+
{
|
|
220
|
+
"extends": "./tsconfig.json",
|
|
221
|
+
"compilerOptions": {
|
|
222
|
+
"types": ["node", "jest"]
|
|
223
|
+
},
|
|
224
|
+
"include": ["e2e/**/*.ts", "jest.e2e.config.ts"]
|
|
225
|
+
}
|
|
226
|
+
`;
|
|
219
227
|
const TEMPLATE_DOCKER_COMPOSE = `
|
|
220
228
|
version: '3.8'
|
|
221
229
|
|
|
@@ -404,7 +412,8 @@ See the [Redis Setup Guide](https://docs.agentfront.dev/docs/deployment/redis-se
|
|
|
404
412
|
│ ├── calc.app.ts # Example app
|
|
405
413
|
│ └── tools/
|
|
406
414
|
│ └── add.tool.ts # Example tool
|
|
407
|
-
|
|
415
|
+
├── tsconfig.json # TypeScript config
|
|
416
|
+
└── tsconfig.e2e.json # TypeScript config for E2E tests
|
|
408
417
|
\`\`\`
|
|
409
418
|
|
|
410
419
|
## Learn More
|
|
@@ -1041,7 +1050,8 @@ No additional secrets required - uses \`GITHUB_TOKEN\` for GHCR.
|
|
|
1041
1050
|
│ ├── calc.app.ts # Example app
|
|
1042
1051
|
│ └── tools/
|
|
1043
1052
|
│ └── add.tool.ts # Example tool
|
|
1044
|
-
|
|
1053
|
+
├── tsconfig.json # TypeScript config
|
|
1054
|
+
└── tsconfig.e2e.json # TypeScript config for E2E tests
|
|
1045
1055
|
\`\`\`
|
|
1046
1056
|
|
|
1047
1057
|
## Learn More
|
|
@@ -1107,7 +1117,7 @@ async function scaffoldDeploymentFiles(targetDir, options) {
|
|
|
1107
1117
|
switch (deploymentTarget) {
|
|
1108
1118
|
case 'node': {
|
|
1109
1119
|
const ciDir = path.join(targetDir, 'ci');
|
|
1110
|
-
await (0,
|
|
1120
|
+
await (0, utils_1.ensureDir)(ciDir);
|
|
1111
1121
|
await scaffoldFileIfMissing(targetDir, path.join(ciDir, 'Dockerfile'), TEMPLATE_DOCKERFILE_CI);
|
|
1112
1122
|
const dockerCompose = redisSetup === 'docker' ? TEMPLATE_DOCKER_COMPOSE_WITH_REDIS : TEMPLATE_DOCKER_COMPOSE_NO_REDIS;
|
|
1113
1123
|
await scaffoldFileIfMissing(targetDir, path.join(ciDir, 'docker-compose.yml'), dockerCompose);
|
|
@@ -1119,7 +1129,7 @@ async function scaffoldDeploymentFiles(targetDir, options) {
|
|
|
1119
1129
|
break;
|
|
1120
1130
|
case 'lambda': {
|
|
1121
1131
|
const ciDir = path.join(targetDir, 'ci');
|
|
1122
|
-
await (0,
|
|
1132
|
+
await (0, utils_1.ensureDir)(ciDir);
|
|
1123
1133
|
await scaffoldFileIfMissing(targetDir, path.join(ciDir, 'template.yaml'), TEMPLATE_SAM_YAML(projectName));
|
|
1124
1134
|
break;
|
|
1125
1135
|
}
|
|
@@ -1139,7 +1149,7 @@ NODE_ENV=development
|
|
|
1139
1149
|
`;
|
|
1140
1150
|
async function scaffoldGitHubActions(targetDir, deploymentTarget) {
|
|
1141
1151
|
const workflowDir = path.join(targetDir, '.github', 'workflows');
|
|
1142
|
-
await (0,
|
|
1152
|
+
await (0, utils_1.ensureDir)(workflowDir);
|
|
1143
1153
|
// Always create CI and E2E workflows
|
|
1144
1154
|
await scaffoldFileIfMissing(targetDir, path.join(workflowDir, 'ci.yml'), TEMPLATE_GH_CI);
|
|
1145
1155
|
await scaffoldFileIfMissing(targetDir, path.join(workflowDir, 'e2e.yml'), TEMPLATE_GH_E2E);
|
|
@@ -1172,7 +1182,7 @@ async function scaffoldProject(options) {
|
|
|
1172
1182
|
console.log((0, colors_1.c)('gray', 'Pick a different project name or remove/rename the existing file.'));
|
|
1173
1183
|
process.exit(1);
|
|
1174
1184
|
}
|
|
1175
|
-
if (!(await (0,
|
|
1185
|
+
if (!(await (0, utils_1.isDirEmpty)(targetDir))) {
|
|
1176
1186
|
console.error((0, colors_1.c)('red', `Refusing to scaffold into non-empty directory: ${path.relative(process.cwd(), targetDir)}`));
|
|
1177
1187
|
console.log((0, colors_1.c)('gray', 'Pick a different name or start with an empty folder.'));
|
|
1178
1188
|
process.exit(1);
|
|
@@ -1180,7 +1190,7 @@ async function scaffoldProject(options) {
|
|
|
1180
1190
|
}
|
|
1181
1191
|
catch (e) {
|
|
1182
1192
|
if (e && typeof e === 'object' && 'code' in e && e.code === 'ENOENT') {
|
|
1183
|
-
await (0,
|
|
1193
|
+
await (0, utils_1.ensureDir)(targetDir);
|
|
1184
1194
|
}
|
|
1185
1195
|
else {
|
|
1186
1196
|
throw e;
|
|
@@ -1206,6 +1216,7 @@ async function scaffoldProject(options) {
|
|
|
1206
1216
|
// E2E scaffolding
|
|
1207
1217
|
await scaffoldFileIfMissing(targetDir, path.join(targetDir, 'e2e', 'server.e2e.test.ts'), TEMPLATE_E2E_TEST_TS);
|
|
1208
1218
|
await scaffoldFileIfMissing(targetDir, path.join(targetDir, 'jest.e2e.config.ts'), TEMPLATE_JEST_E2E_CONFIG);
|
|
1219
|
+
await scaffoldFileIfMissing(targetDir, path.join(targetDir, 'tsconfig.e2e.json'), TEMPLATE_TSCONFIG_E2E);
|
|
1209
1220
|
// Git configuration
|
|
1210
1221
|
await scaffoldFileIfMissing(targetDir, path.join(targetDir, '.gitignore'), TEMPLATE_GITIGNORE);
|
|
1211
1222
|
// Deployment-specific files
|
|
@@ -1259,7 +1270,7 @@ function printNextSteps(folder, deploymentTarget, redisSetup, enableGitHubAction
|
|
|
1259
1270
|
// =============================================================================
|
|
1260
1271
|
async function upsertPackageJsonWithTarget(cwd, nameOverride, selfVersion, deploymentTarget) {
|
|
1261
1272
|
const pkgPath = path.join(cwd, 'package.json');
|
|
1262
|
-
const existing = await (0,
|
|
1273
|
+
const existing = await (0, utils_1.readJSON)(pkgPath);
|
|
1263
1274
|
const frontmcpLibRange = `~${selfVersion}`;
|
|
1264
1275
|
const baseScripts = {
|
|
1265
1276
|
dev: 'frontmcp dev',
|
|
@@ -1312,7 +1323,7 @@ async function upsertPackageJsonWithTarget(cwd, nameOverride, selfVersion, deplo
|
|
|
1312
1323
|
},
|
|
1313
1324
|
};
|
|
1314
1325
|
if (!existing) {
|
|
1315
|
-
await (0,
|
|
1326
|
+
await (0, utils_1.writeJSON)(pkgPath, base);
|
|
1316
1327
|
console.log((0, colors_1.c)('green', '✅ Created package.json (synced @frontmcp libs to CLI version + exact frontmcp)'));
|
|
1317
1328
|
return;
|
|
1318
1329
|
}
|
|
@@ -1338,7 +1349,7 @@ async function upsertPackageJsonWithTarget(cwd, nameOverride, selfVersion, deplo
|
|
|
1338
1349
|
...(existing.devDependencies || {}),
|
|
1339
1350
|
...base.devDependencies,
|
|
1340
1351
|
};
|
|
1341
|
-
await (0,
|
|
1352
|
+
await (0, utils_1.writeJSON)(pkgPath, merged);
|
|
1342
1353
|
console.log((0, colors_1.c)('green', '✅ Updated package.json (synced @frontmcp libs + frontmcp to current CLI version)'));
|
|
1343
1354
|
}
|
|
1344
1355
|
// =============================================================================
|