frontmcp 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +3 -3
  2. package/package.json +2 -4
  3. package/src/args.d.ts +7 -0
  4. package/src/args.js +13 -0
  5. package/src/args.js.map +1 -1
  6. package/src/cli.js +17 -3
  7. package/src/cli.js.map +1 -1
  8. package/src/commands/build/adapters/cloudflare.d.ts +8 -0
  9. package/src/commands/build/adapters/cloudflare.js +80 -0
  10. package/src/commands/build/adapters/cloudflare.js.map +1 -0
  11. package/src/commands/build/adapters/index.d.ts +12 -0
  12. package/src/commands/build/adapters/index.js +23 -0
  13. package/src/commands/build/adapters/index.js.map +1 -0
  14. package/src/commands/build/adapters/lambda.d.ts +11 -0
  15. package/src/commands/build/adapters/lambda.js +43 -0
  16. package/src/commands/build/adapters/lambda.js.map +1 -0
  17. package/src/commands/build/adapters/node.d.ts +7 -0
  18. package/src/commands/build/adapters/node.js +13 -0
  19. package/src/commands/build/adapters/node.js.map +1 -0
  20. package/src/commands/build/adapters/vercel.d.ts +8 -0
  21. package/src/commands/build/adapters/vercel.js +36 -0
  22. package/src/commands/build/adapters/vercel.js.map +1 -0
  23. package/src/commands/build/index.d.ts +22 -0
  24. package/src/commands/build/index.js +120 -0
  25. package/src/commands/build/index.js.map +1 -0
  26. package/src/commands/build/types.d.ts +23 -0
  27. package/src/commands/build/types.js +3 -0
  28. package/src/commands/build/types.js.map +1 -0
  29. package/src/commands/create.d.ts +15 -1
  30. package/src/commands/create.js +1199 -91
  31. package/src/commands/create.js.map +1 -1
  32. package/src/tsconfig.d.ts +1 -1
  33. package/src/tsconfig.js +1 -1
  34. package/src/tsconfig.js.map +1 -1
  35. package/src/commands/build.d.ts +0 -2
  36. package/src/commands/build.js +0 -43
  37. package/src/commands/build.js.map +0 -1
package/README.md CHANGED
@@ -1,9 +1,9 @@
1
1
  <div align="center">
2
2
 
3
3
  <picture>
4
- <source width="400" media="(prefers-color-scheme: dark)" srcset="docs/live/assets/logo/frontmcp.dark.svg">
5
- <source width="400" media="(prefers-color-scheme: light)" srcset="docs/live/assets/logo/frontmcp.light.svg">
6
- <img width="400" alt="FrontMCP Logo" src="docs/live/assets/logo/frontmcp.light.svg">
4
+ <source width="400" media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/agentfront/frontmcp/refs/heads/main/docs/live/assets/logo/frontmcp.dark.svg">
5
+ <source width="400" media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/agentfront/frontmcp/refs/heads/main/docs/live/assets/logo/frontmcp.light.svg">
6
+ <img width="400" alt="FrontMCP Logo" src="https://raw.githubusercontent.com/agentfront/frontmcp/refs/heads/main/docs/live/assets/logo/frontmcp.light.svg">
7
7
  </picture>
8
8
  <hr>
9
9
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "frontmcp",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "FrontMCP command line interface",
5
5
  "author": "AgentFront <info@agentfront.dev>",
6
6
  "homepage": "https://docs.agentfront.dev",
@@ -26,9 +26,7 @@
26
26
  "frontmcp": "./src/cli.js"
27
27
  },
28
28
  "dependencies": {
29
- "@frontmcp/sdk": "0.5.0",
30
- "@frontmcp/plugins": "0.5.0",
31
- "@frontmcp/adapters": "0.5.0"
29
+ "tslib": "^2.3.0"
32
30
  },
33
31
  "devDependencies": {
34
32
  "typescript": "^5.5.3",
package/src/args.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  export type Command = 'dev' | 'build' | 'init' | 'doctor' | 'inspector' | 'create' | 'help' | 'template' | 'version' | 'test';
2
+ export type DeploymentAdapter = 'node' | 'vercel' | 'lambda' | 'cloudflare';
3
+ export type RedisSetupOption = 'docker' | 'existing' | 'none';
2
4
  export interface ParsedArgs {
3
5
  _: string[];
4
6
  outDir?: string;
@@ -8,5 +10,10 @@ export interface ParsedArgs {
8
10
  watch?: boolean;
9
11
  verbose?: boolean;
10
12
  timeout?: number;
13
+ adapter?: DeploymentAdapter;
14
+ yes?: boolean;
15
+ target?: DeploymentAdapter;
16
+ redis?: RedisSetupOption;
17
+ cicd?: boolean;
11
18
  }
12
19
  export declare function parseArgs(argv: string[]): ParsedArgs;
package/src/args.js CHANGED
@@ -9,6 +9,8 @@ function parseArgs(argv) {
9
9
  out.outDir = argv[++i];
10
10
  else if (a === '--entry' || a === '-e')
11
11
  out.entry = argv[++i];
12
+ else if (a === '--adapter' || a === '-a')
13
+ out.adapter = argv[++i];
12
14
  else if (a === '--help' || a === '-h')
13
15
  out.help = true;
14
16
  else if (a === '--runInBand' || a === '-i')
@@ -21,6 +23,17 @@ function parseArgs(argv) {
21
23
  const parsed = parseInt(argv[++i], 10);
22
24
  out.timeout = Number.isNaN(parsed) ? undefined : parsed;
23
25
  }
26
+ // Create command flags
27
+ else if (a === '--yes' || a === '-y')
28
+ out.yes = true;
29
+ else if (a === '--target')
30
+ out.target = argv[++i];
31
+ else if (a === '--redis')
32
+ out.redis = argv[++i];
33
+ else if (a === '--cicd')
34
+ out.cicd = true;
35
+ else if (a === '--no-cicd')
36
+ out.cicd = false;
24
37
  else
25
38
  out._.push(a);
26
39
  }
package/src/args.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"args.js","sourceRoot":"","sources":["../../src/args.ts"],"names":[],"mappings":";;AAuBA,8BAgBC;AAhBD,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,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;;YAAM,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACvB,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 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}\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 === '--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 out._.push(a);\n }\n return out;\n}\n"]}
1
+ {"version":3,"file":"args.js","sourceRoot":"","sources":["../../src/args.ts"],"names":[],"mappings":";;AAgCA,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;QACD,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 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 }\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
@@ -28,7 +28,7 @@ ${(0, colors_1.c)('bold', 'Commands')}
28
28
  init Create or fix a tsconfig.json suitable for FrontMCP
29
29
  doctor Check Node/npm versions and tsconfig requirements
30
30
  inspector Launch MCP Inspector (npx @modelcontextprotocol/inspector)
31
- create <name> Scaffold a new FrontMCP project in ./<name>
31
+ create [name] Scaffold a new FrontMCP project (interactive if name omitted)
32
32
  template <type> Scaffold a template by type (e.g., "3rd-party-integration")
33
33
  help Show this help message
34
34
 
@@ -36,6 +36,13 @@ ${(0, colors_1.c)('bold', 'Options')}
36
36
  -o, --out-dir <dir> Output directory (default: ./dist)
37
37
  -e, --entry <path> Manually specify entry file path
38
38
 
39
+ ${(0, colors_1.c)('bold', 'Create Options')}
40
+ -y, --yes Use defaults (non-interactive mode)
41
+ --target <target> Deployment target: node, vercel, lambda, cloudflare
42
+ --redis <setup> Redis setup: docker, existing, none (node target only)
43
+ --cicd Enable GitHub Actions CI/CD
44
+ --no-cicd Disable GitHub Actions CI/CD
45
+
39
46
  ${(0, colors_1.c)('bold', 'Test Options')}
40
47
  -i, --runInBand Run tests sequentially (recommended for E2E)
41
48
  -w, --watch Run tests in watch mode
@@ -49,7 +56,9 @@ ${(0, colors_1.c)('bold', 'Examples')}
49
56
  frontmcp init
50
57
  frontmcp doctor
51
58
  frontmcp inspector
52
- npx frontmcp create my-mcp
59
+ npx frontmcp create # Interactive mode
60
+ npx frontmcp create my-mcp --yes # Use defaults
61
+ npx frontmcp create my-mcp --target vercel # Vercel deployment
53
62
  npx frontmcp template marketplace-3rd-tools
54
63
  `);
55
64
  }
@@ -81,7 +90,12 @@ async function main() {
81
90
  break;
82
91
  case 'create': {
83
92
  const projectName = parsed._[1];
84
- await (0, create_1.runCreate)(projectName);
93
+ await (0, create_1.runCreate)(projectName, {
94
+ yes: parsed.yes,
95
+ target: parsed.target,
96
+ redis: parsed.redis,
97
+ cicd: parsed.cicd,
98
+ });
85
99
  break;
86
100
  }
87
101
  case 'template': {
package/src/cli.js.map CHANGED
@@ -1 +1 @@
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 in ./<name>\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', '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\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 my-mcp\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 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"]}
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\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"]}
@@ -0,0 +1,8 @@
1
+ import { AdapterTemplate } from '../types';
2
+ /**
3
+ * Cloudflare Workers adapter - edge deployment on Cloudflare.
4
+ * Compiles to CommonJS and adapts the Express app to Cloudflare's fetch API.
5
+ *
6
+ * @see https://developers.cloudflare.com/workers/
7
+ */
8
+ export declare const cloudflareAdapter: AdapterTemplate;
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cloudflareAdapter = void 0;
4
+ /**
5
+ * Cloudflare Workers adapter - edge deployment on Cloudflare.
6
+ * Compiles to CommonJS and adapts the Express app to Cloudflare's fetch API.
7
+ *
8
+ * @see https://developers.cloudflare.com/workers/
9
+ */
10
+ exports.cloudflareAdapter = {
11
+ moduleFormat: 'commonjs',
12
+ getEntryTemplate: (mainModulePath) => `// Auto-generated Cloudflare Workers entry point
13
+ // Generated by: frontmcp build --adapter cloudflare
14
+ process.env.FRONTMCP_SERVERLESS = '1';
15
+
16
+ require('${mainModulePath}');
17
+ const { getServerlessHandlerAsync } = require('@frontmcp/sdk');
18
+
19
+ let app = null;
20
+
21
+ async function handleRequest(request) {
22
+ if (!app) {
23
+ app = await getServerlessHandlerAsync();
24
+ }
25
+
26
+ // Convert Cloudflare Request to Node.js format
27
+ const url = new URL(request.url);
28
+ const req = {
29
+ method: request.method,
30
+ url: url.pathname + url.search,
31
+ headers: Object.fromEntries(request.headers),
32
+ body: request.body,
33
+ };
34
+
35
+ return new Promise((resolve) => {
36
+ const res = {
37
+ statusCode: 200,
38
+ headers: {},
39
+ body: '',
40
+ status(code) { this.statusCode = code; return this; },
41
+ setHeader(key, value) { this.headers[key] = value; },
42
+ json(data) {
43
+ this.headers['Content-Type'] = 'application/json';
44
+ this.body = JSON.stringify(data);
45
+ resolve(new Response(this.body, {
46
+ status: this.statusCode,
47
+ headers: this.headers,
48
+ }));
49
+ },
50
+ send(data) {
51
+ this.body = data;
52
+ resolve(new Response(this.body, {
53
+ status: this.statusCode,
54
+ headers: this.headers,
55
+ }));
56
+ },
57
+ end() {
58
+ resolve(new Response(this.body, {
59
+ status: this.statusCode,
60
+ headers: this.headers,
61
+ }));
62
+ },
63
+ };
64
+ app(req, res);
65
+ });
66
+ }
67
+
68
+ module.exports = {
69
+ async fetch(request, env, ctx) {
70
+ return handleRequest(request);
71
+ }
72
+ };
73
+ `,
74
+ getConfig: () => `name = "frontmcp-worker"
75
+ main = "dist/index.js"
76
+ compatibility_date = "2024-01-01"
77
+ `,
78
+ configFileName: 'wrangler.toml',
79
+ };
80
+ //# sourceMappingURL=cloudflare.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare.js","sourceRoot":"","sources":["../../../../../src/commands/build/adapters/cloudflare.ts"],"names":[],"mappings":";;;AAEA;;;;;GAKG;AACU,QAAA,iBAAiB,GAAoB;IAChD,YAAY,EAAE,UAAU;IAExB,gBAAgB,EAAE,CAAC,cAAsB,EAAE,EAAE,CAAC;;;;WAIrC,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyDxB;IAEC,SAAS,EAAE,GAAG,EAAE,CAAC;;;CAGlB;IAEC,cAAc,EAAE,eAAe;CAChC,CAAC","sourcesContent":["import { AdapterTemplate } from '../types';\n\n/**\n * Cloudflare Workers adapter - edge deployment on Cloudflare.\n * Compiles to CommonJS and adapts the Express app to Cloudflare's fetch API.\n *\n * @see https://developers.cloudflare.com/workers/\n */\nexport const cloudflareAdapter: AdapterTemplate = {\n moduleFormat: 'commonjs',\n\n getEntryTemplate: (mainModulePath: string) => `// Auto-generated Cloudflare Workers entry point\n// Generated by: frontmcp build --adapter cloudflare\nprocess.env.FRONTMCP_SERVERLESS = '1';\n\nrequire('${mainModulePath}');\nconst { getServerlessHandlerAsync } = require('@frontmcp/sdk');\n\nlet app = null;\n\nasync function handleRequest(request) {\n if (!app) {\n app = await getServerlessHandlerAsync();\n }\n\n // Convert Cloudflare Request to Node.js format\n const url = new URL(request.url);\n const req = {\n method: request.method,\n url: url.pathname + url.search,\n headers: Object.fromEntries(request.headers),\n body: request.body,\n };\n\n return new Promise((resolve) => {\n const res = {\n statusCode: 200,\n headers: {},\n body: '',\n status(code) { this.statusCode = code; return this; },\n setHeader(key, value) { this.headers[key] = value; },\n json(data) {\n this.headers['Content-Type'] = 'application/json';\n this.body = JSON.stringify(data);\n resolve(new Response(this.body, {\n status: this.statusCode,\n headers: this.headers,\n }));\n },\n send(data) {\n this.body = data;\n resolve(new Response(this.body, {\n status: this.statusCode,\n headers: this.headers,\n }));\n },\n end() {\n resolve(new Response(this.body, {\n status: this.statusCode,\n headers: this.headers,\n }));\n },\n };\n app(req, res);\n });\n}\n\nmodule.exports = {\n async fetch(request, env, ctx) {\n return handleRequest(request);\n }\n};\n`,\n\n getConfig: () => `name = \"frontmcp-worker\"\nmain = \"dist/index.js\"\ncompatibility_date = \"2024-01-01\"\n`,\n\n configFileName: 'wrangler.toml',\n};\n"]}
@@ -0,0 +1,12 @@
1
+ import { AdapterTemplate, AdapterName } from '../types';
2
+ import { nodeAdapter } from './node';
3
+ import { vercelAdapter } from './vercel';
4
+ import { lambdaAdapter } from './lambda';
5
+ import { cloudflareAdapter } from './cloudflare';
6
+ /**
7
+ * Registry of all available deployment adapters.
8
+ * Each adapter configures how the FrontMCP server is compiled and packaged
9
+ * for a specific deployment target.
10
+ */
11
+ export declare const ADAPTERS: Record<AdapterName, AdapterTemplate>;
12
+ export { nodeAdapter, vercelAdapter, lambdaAdapter, cloudflareAdapter };
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cloudflareAdapter = exports.lambdaAdapter = exports.vercelAdapter = exports.nodeAdapter = exports.ADAPTERS = void 0;
4
+ const node_1 = require("./node");
5
+ Object.defineProperty(exports, "nodeAdapter", { enumerable: true, get: function () { return node_1.nodeAdapter; } });
6
+ const vercel_1 = require("./vercel");
7
+ Object.defineProperty(exports, "vercelAdapter", { enumerable: true, get: function () { return vercel_1.vercelAdapter; } });
8
+ const lambda_1 = require("./lambda");
9
+ Object.defineProperty(exports, "lambdaAdapter", { enumerable: true, get: function () { return lambda_1.lambdaAdapter; } });
10
+ const cloudflare_1 = require("./cloudflare");
11
+ Object.defineProperty(exports, "cloudflareAdapter", { enumerable: true, get: function () { return cloudflare_1.cloudflareAdapter; } });
12
+ /**
13
+ * Registry of all available deployment adapters.
14
+ * Each adapter configures how the FrontMCP server is compiled and packaged
15
+ * for a specific deployment target.
16
+ */
17
+ exports.ADAPTERS = {
18
+ node: node_1.nodeAdapter,
19
+ vercel: vercel_1.vercelAdapter,
20
+ lambda: lambda_1.lambdaAdapter,
21
+ cloudflare: cloudflare_1.cloudflareAdapter,
22
+ };
23
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/commands/build/adapters/index.ts"],"names":[],"mappings":";;;AACA,iCAAqC;AAiB5B,4FAjBA,kBAAW,OAiBA;AAhBpB,qCAAyC;AAgBnB,8FAhBb,sBAAa,OAgBa;AAfnC,qCAAyC;AAeJ,8FAf5B,sBAAa,OAe4B;AAdlD,6CAAiD;AAcG,kGAd3C,8BAAiB,OAc2C;AAZrE;;;;GAIG;AACU,QAAA,QAAQ,GAAyC;IAC5D,IAAI,EAAE,kBAAW;IACjB,MAAM,EAAE,sBAAa;IACrB,MAAM,EAAE,sBAAa;IACrB,UAAU,EAAE,8BAAiB;CAC9B,CAAC","sourcesContent":["import { AdapterTemplate, AdapterName } from '../types';\nimport { nodeAdapter } from './node';\nimport { vercelAdapter } from './vercel';\nimport { lambdaAdapter } from './lambda';\nimport { cloudflareAdapter } from './cloudflare';\n\n/**\n * Registry of all available deployment adapters.\n * Each adapter configures how the FrontMCP server is compiled and packaged\n * for a specific deployment target.\n */\nexport const ADAPTERS: Record<AdapterName, AdapterTemplate> = {\n node: nodeAdapter,\n vercel: vercelAdapter,\n lambda: lambdaAdapter,\n cloudflare: cloudflareAdapter,\n};\n\nexport { nodeAdapter, vercelAdapter, lambdaAdapter, cloudflareAdapter };\n"]}
@@ -0,0 +1,11 @@
1
+ import { AdapterTemplate } from '../types';
2
+ /**
3
+ * AWS Lambda adapter - serverless deployment on AWS Lambda.
4
+ * Compiles to ESM and uses @codegenie/serverless-express to wrap the Express app.
5
+ *
6
+ * Prerequisites:
7
+ * npm install @codegenie/serverless-express
8
+ *
9
+ * @see https://github.com/codegenie/serverless-express
10
+ */
11
+ export declare const lambdaAdapter: AdapterTemplate;
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.lambdaAdapter = void 0;
4
+ /**
5
+ * AWS Lambda adapter - serverless deployment on AWS Lambda.
6
+ * Compiles to ESM and uses @codegenie/serverless-express to wrap the Express app.
7
+ *
8
+ * Prerequisites:
9
+ * npm install @codegenie/serverless-express
10
+ *
11
+ * @see https://github.com/codegenie/serverless-express
12
+ */
13
+ exports.lambdaAdapter = {
14
+ moduleFormat: 'esnext',
15
+ getEntryTemplate: (mainModulePath) => `// Auto-generated AWS Lambda entry point
16
+ // Generated by: frontmcp build --adapter lambda
17
+ //
18
+ // IMPORTANT: This adapter requires @codegenie/serverless-express
19
+ // Install it with: npm install @codegenie/serverless-express
20
+ //
21
+ process.env.FRONTMCP_SERVERLESS = '1';
22
+
23
+ import '${mainModulePath}';
24
+ import { getServerlessHandlerAsync } from '@frontmcp/sdk';
25
+ import serverlessExpress from '@codegenie/serverless-express';
26
+
27
+ let serverlessExpressInstance = null;
28
+
29
+ async function setup() {
30
+ const app = await getServerlessHandlerAsync();
31
+ serverlessExpressInstance = serverlessExpress({ app });
32
+ }
33
+
34
+ export const handler = async (event, context) => {
35
+ if (!serverlessExpressInstance) {
36
+ await setup();
37
+ }
38
+ return serverlessExpressInstance(event, context);
39
+ };
40
+ `,
41
+ // No config file - user manages serverless.yml, SAM template, or CDK
42
+ };
43
+ //# sourceMappingURL=lambda.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lambda.js","sourceRoot":"","sources":["../../../../../src/commands/build/adapters/lambda.ts"],"names":[],"mappings":";;;AAEA;;;;;;;;GAQG;AACU,QAAA,aAAa,GAAoB;IAC5C,YAAY,EAAE,QAAQ;IAEtB,gBAAgB,EAAE,CAAC,cAAsB,EAAE,EAAE,CAAC;;;;;;;;UAQtC,cAAc;;;;;;;;;;;;;;;;;CAiBvB;IAEC,qEAAqE;CACtE,CAAC","sourcesContent":["import { AdapterTemplate } from '../types';\n\n/**\n * AWS Lambda adapter - serverless deployment on AWS Lambda.\n * Compiles to ESM and uses @codegenie/serverless-express to wrap the Express app.\n *\n * Prerequisites:\n * npm install @codegenie/serverless-express\n *\n * @see https://github.com/codegenie/serverless-express\n */\nexport const lambdaAdapter: AdapterTemplate = {\n moduleFormat: 'esnext',\n\n getEntryTemplate: (mainModulePath: string) => `// Auto-generated AWS Lambda entry point\n// Generated by: frontmcp build --adapter lambda\n//\n// IMPORTANT: This adapter requires @codegenie/serverless-express\n// Install it with: npm install @codegenie/serverless-express\n//\nprocess.env.FRONTMCP_SERVERLESS = '1';\n\nimport '${mainModulePath}';\nimport { getServerlessHandlerAsync } from '@frontmcp/sdk';\nimport serverlessExpress from '@codegenie/serverless-express';\n\nlet serverlessExpressInstance = null;\n\nasync function setup() {\n const app = await getServerlessHandlerAsync();\n serverlessExpressInstance = serverlessExpress({ app });\n}\n\nexport const handler = async (event, context) => {\n if (!serverlessExpressInstance) {\n await setup();\n }\n return serverlessExpressInstance(event, context);\n};\n`,\n\n // No config file - user manages serverless.yml, SAM template, or CDK\n};\n"]}
@@ -0,0 +1,7 @@
1
+ import { AdapterTemplate } from '../types';
2
+ /**
3
+ * Node.js adapter - default deployment target.
4
+ * Compiles to CommonJS for direct Node.js execution.
5
+ * No wrapper needed - the compiled main.js runs directly.
6
+ */
7
+ export declare const nodeAdapter: AdapterTemplate;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.nodeAdapter = void 0;
4
+ /**
5
+ * Node.js adapter - default deployment target.
6
+ * Compiles to CommonJS for direct Node.js execution.
7
+ * No wrapper needed - the compiled main.js runs directly.
8
+ */
9
+ exports.nodeAdapter = {
10
+ moduleFormat: 'commonjs',
11
+ getEntryTemplate: () => '', // No wrapper needed for node
12
+ };
13
+ //# sourceMappingURL=node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node.js","sourceRoot":"","sources":["../../../../../src/commands/build/adapters/node.ts"],"names":[],"mappings":";;;AAEA;;;;GAIG;AACU,QAAA,WAAW,GAAoB;IAC1C,YAAY,EAAE,UAAU;IACxB,gBAAgB,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,6BAA6B;CAC1D,CAAC","sourcesContent":["import { AdapterTemplate } from '../types';\n\n/**\n * Node.js adapter - default deployment target.\n * Compiles to CommonJS for direct Node.js execution.\n * No wrapper needed - the compiled main.js runs directly.\n */\nexport const nodeAdapter: AdapterTemplate = {\n moduleFormat: 'commonjs',\n getEntryTemplate: () => '', // No wrapper needed for node\n};\n"]}
@@ -0,0 +1,8 @@
1
+ import { AdapterTemplate } from '../types';
2
+ /**
3
+ * Vercel adapter - serverless deployment on Vercel.
4
+ * Compiles to ESM and generates a handler that exports the Express app.
5
+ *
6
+ * @see https://vercel.com/docs/frameworks/express
7
+ */
8
+ export declare const vercelAdapter: AdapterTemplate;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.vercelAdapter = void 0;
4
+ /**
5
+ * Vercel adapter - serverless deployment on Vercel.
6
+ * Compiles to ESM and generates a handler that exports the Express app.
7
+ *
8
+ * @see https://vercel.com/docs/frameworks/express
9
+ */
10
+ exports.vercelAdapter = {
11
+ moduleFormat: 'esnext',
12
+ getEntryTemplate: (mainModulePath) => `// Auto-generated Vercel entry point
13
+ // Generated by: frontmcp build --adapter vercel
14
+ process.env.FRONTMCP_SERVERLESS = '1';
15
+
16
+ import '${mainModulePath}';
17
+ import { getServerlessHandlerAsync } from '@frontmcp/sdk';
18
+
19
+ let handlerPromise = null;
20
+
21
+ export default async function handler(req, res) {
22
+ if (!handlerPromise) {
23
+ handlerPromise = getServerlessHandlerAsync();
24
+ }
25
+ const app = await handlerPromise;
26
+ return app(req, res);
27
+ }
28
+ `,
29
+ getConfig: () => ({
30
+ version: 2,
31
+ builds: [{ src: 'dist/index.js', use: '@vercel/node' }],
32
+ routes: [{ src: '/(.*)', dest: '/dist/index.js' }],
33
+ }),
34
+ configFileName: 'vercel.json',
35
+ };
36
+ //# sourceMappingURL=vercel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vercel.js","sourceRoot":"","sources":["../../../../../src/commands/build/adapters/vercel.ts"],"names":[],"mappings":";;;AAEA;;;;;GAKG;AACU,QAAA,aAAa,GAAoB;IAC5C,YAAY,EAAE,QAAQ;IAEtB,gBAAgB,EAAE,CAAC,cAAsB,EAAE,EAAE,CAAC;;;;UAItC,cAAc;;;;;;;;;;;;CAYvB;IAEC,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;QAChB,OAAO,EAAE,CAAC;QACV,MAAM,EAAE,CAAC,EAAE,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,EAAE,CAAC;QACvD,MAAM,EAAE,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC;KACnD,CAAC;IAEF,cAAc,EAAE,aAAa;CAC9B,CAAC","sourcesContent":["import { AdapterTemplate } from '../types';\n\n/**\n * Vercel adapter - serverless deployment on Vercel.\n * Compiles to ESM and generates a handler that exports the Express app.\n *\n * @see https://vercel.com/docs/frameworks/express\n */\nexport const vercelAdapter: AdapterTemplate = {\n moduleFormat: 'esnext',\n\n getEntryTemplate: (mainModulePath: string) => `// Auto-generated Vercel entry point\n// Generated by: frontmcp build --adapter vercel\nprocess.env.FRONTMCP_SERVERLESS = '1';\n\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 getConfig: () => ({\n version: 2,\n builds: [{ src: 'dist/index.js', use: '@vercel/node' }],\n routes: [{ src: '/(.*)', dest: '/dist/index.js' }],\n }),\n\n configFileName: 'vercel.json',\n};\n"]}
@@ -0,0 +1,22 @@
1
+ import { ParsedArgs } from '../../args';
2
+ /**
3
+ * Build the FrontMCP server for a specific deployment target.
4
+ *
5
+ * @param opts - Build options from CLI arguments
6
+ *
7
+ * @example
8
+ * ```bash
9
+ * # Build for Node.js (default)
10
+ * frontmcp build
11
+ *
12
+ * # Build for Vercel
13
+ * frontmcp build --adapter vercel
14
+ *
15
+ * # Build for AWS Lambda
16
+ * frontmcp build --adapter lambda
17
+ *
18
+ * # Build for Cloudflare Workers
19
+ * frontmcp build --adapter cloudflare
20
+ * ```
21
+ */
22
+ export declare function runBuild(opts: ParsedArgs): Promise<void>;
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runBuild = runBuild;
4
+ const tslib_1 = require("tslib");
5
+ const path = tslib_1.__importStar(require("path"));
6
+ const colors_1 = require("../../colors");
7
+ const fs_1 = require("../../utils/fs");
8
+ const tsconfig_1 = require("../../tsconfig");
9
+ const adapters_1 = require("./adapters");
10
+ function isTsLike(p) {
11
+ return /\.tsx?$/i.test(p);
12
+ }
13
+ /**
14
+ * Generate adapter-specific entry point and config files.
15
+ */
16
+ async function generateAdapterFiles(adapter, outDir, entryBasename, cwd) {
17
+ const template = adapters_1.ADAPTERS[adapter];
18
+ // Generate index.js entry point
19
+ const mainModuleName = entryBasename.replace(/\.tsx?$/, '.js');
20
+ const entryContent = template.getEntryTemplate(`./${mainModuleName}`);
21
+ // Skip if no entry template (e.g., node adapter)
22
+ if (entryContent) {
23
+ const entryPath = path.join(outDir, 'index.js');
24
+ await fs_1.fsp.writeFile(entryPath, entryContent, 'utf8');
25
+ console.log((0, colors_1.c)('green', ` Generated ${adapter} entry at ${path.relative(cwd, entryPath)}`));
26
+ }
27
+ // Generate config file if adapter has one (skip if already exists)
28
+ if (template.getConfig && template.configFileName) {
29
+ const configPath = path.join(cwd, template.configFileName);
30
+ if (await (0, fs_1.fileExists)(configPath)) {
31
+ console.log((0, colors_1.c)('yellow', ` ${template.configFileName} already exists (skipping)`));
32
+ }
33
+ else {
34
+ const configContent = template.getConfig();
35
+ if (typeof configContent === 'string') {
36
+ // Write as plain text (e.g., TOML for wrangler.toml)
37
+ await fs_1.fsp.writeFile(configPath, configContent, 'utf8');
38
+ }
39
+ else {
40
+ // Write as JSON
41
+ await (0, fs_1.writeJSON)(configPath, configContent);
42
+ }
43
+ console.log((0, colors_1.c)('green', ` Generated ${template.configFileName}`));
44
+ }
45
+ }
46
+ }
47
+ /**
48
+ * Build the FrontMCP server for a specific deployment target.
49
+ *
50
+ * @param opts - Build options from CLI arguments
51
+ *
52
+ * @example
53
+ * ```bash
54
+ * # Build for Node.js (default)
55
+ * frontmcp build
56
+ *
57
+ * # Build for Vercel
58
+ * frontmcp build --adapter vercel
59
+ *
60
+ * # Build for AWS Lambda
61
+ * frontmcp build --adapter lambda
62
+ *
63
+ * # Build for Cloudflare Workers
64
+ * frontmcp build --adapter cloudflare
65
+ * ```
66
+ */
67
+ async function runBuild(opts) {
68
+ const cwd = process.cwd();
69
+ const entry = await (0, fs_1.resolveEntry)(cwd, opts.entry);
70
+ const outDir = path.resolve(cwd, opts.outDir || 'dist');
71
+ const adapter = (opts.adapter || 'node');
72
+ await (0, fs_1.ensureDir)(outDir);
73
+ // Validate adapter
74
+ const template = adapters_1.ADAPTERS[adapter];
75
+ if (!template) {
76
+ const available = Object.keys(adapters_1.ADAPTERS).join(', ');
77
+ throw new Error(`Unknown adapter: ${adapter}. Available: ${available}`);
78
+ }
79
+ // Warn about experimental adapters
80
+ if (adapter === 'cloudflare') {
81
+ console.log((0, colors_1.c)('yellow', '⚠️ Cloudflare Workers adapter is experimental. See docs for limitations.'));
82
+ }
83
+ const moduleFormat = template.moduleFormat;
84
+ console.log(`${(0, colors_1.c)('cyan', '[build]')} entry: ${path.relative(cwd, entry)}`);
85
+ console.log(`${(0, colors_1.c)('cyan', '[build]')} outDir: ${path.relative(cwd, outDir)}`);
86
+ console.log(`${(0, colors_1.c)('cyan', '[build]')} adapter: ${adapter} (${moduleFormat})`);
87
+ // Build TypeScript compiler arguments
88
+ const tsconfigPath = path.join(cwd, 'tsconfig.json');
89
+ const hasTsconfig = await (0, fs_1.fileExists)(tsconfigPath);
90
+ const args = ['-y', 'tsc'];
91
+ if (hasTsconfig) {
92
+ console.log((0, colors_1.c)('gray', `[build] tsconfig.json detected — compiling with project settings`));
93
+ args.push('--project', tsconfigPath);
94
+ }
95
+ else {
96
+ args.push(entry);
97
+ args.push('--rootDir', path.dirname(entry));
98
+ if (!isTsLike(entry)) {
99
+ args.push('--allowJs');
100
+ console.log((0, colors_1.c)('yellow', '[build] Entry is not TypeScript; enabling --allowJs'));
101
+ }
102
+ args.push('--experimentalDecorators', '--emitDecoratorMetadata');
103
+ args.push('--target', tsconfig_1.REQUIRED_DECORATOR_FIELDS.target);
104
+ }
105
+ // Always pass module format to override tsconfig
106
+ args.push('--module', moduleFormat);
107
+ args.push('--outDir', outDir);
108
+ args.push('--skipLibCheck');
109
+ // Run TypeScript compiler
110
+ await (0, fs_1.runCmd)('npx', args);
111
+ // Generate adapter-specific files
112
+ if (adapter !== 'node') {
113
+ console.log((0, colors_1.c)('cyan', `[build] Generating ${adapter} deployment files...`));
114
+ const entryBasename = path.basename(entry);
115
+ await generateAdapterFiles(adapter, outDir, entryBasename, cwd);
116
+ }
117
+ console.log((0, colors_1.c)('green', '✅ Build completed.'));
118
+ console.log((0, colors_1.c)('gray', `Output placed in ${path.relative(cwd, outDir)}`));
119
+ }
120
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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';\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 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 // 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();\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"]}