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.
@@ -1 +1 @@
1
- {"version":3,"file":"test.js","sourceRoot":"","sources":["../../../src/commands/test.ts"],"names":[],"mappings":";;AAsFA,0BAoHC;;AA1MD,mDAA6B;AAC7B,+CAAyB;AACzB,iDAAoD;AAEpD,sCAA8B;AAC9B,oCAA8C;AAE9C;;;GAGG;AACH,SAAS,kBAAkB,CAAC,GAAW,EAAE,IAAgB;IACvD,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC;IAE1C,OAAO;QACL,wCAAwC;QACxC,eAAe,EAAE,MAAM;QAEvB,2BAA2B;QAC3B,OAAO,EAAE,GAAG;QAEZ,mCAAmC;QACnC,SAAS,EAAE,CAAC,2BAA2B,EAAE,gCAAgC,EAAE,uBAAuB,CAAC;QAEnG,uDAAuD;QACvD,SAAS,EAAE;YACT,cAAc,EAAE;gBACd,WAAW;gBACX;oBACE,GAAG,EAAE;wBACH,MAAM,EAAE,QAAQ;wBAChB,MAAM,EAAE;4BACN,MAAM,EAAE,YAAY;4BACpB,UAAU,EAAE,IAAI;4BAChB,aAAa,EAAE,IAAI;yBACpB;wBACD,SAAS,EAAE;4BACT,iBAAiB,EAAE,IAAI;4BACvB,eAAe,EAAE,IAAI;yBACtB;wBACD,cAAc,EAAE,IAAI;wBACpB,eAAe,EAAE,IAAI;wBACrB,KAAK,EAAE,IAAI;qBACZ;oBACD,MAAM,EAAE;wBACN,IAAI,EAAE,KAAK;qBACZ;oBACD,UAAU,EAAE,IAAI;oBAChB,KAAK,EAAE,KAAK;iBACb;aACF;SACF;QAED,8BAA8B;QAC9B,oBAAoB,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC;QAEhE,eAAe;QACf,WAAW;QAEX,iDAAiD;QACjD,kBAAkB,EAAE,CAAC,yBAAyB,CAAC;QAE/C,kCAAkC;QAClC,uBAAuB,EAAE,CAAC,0BAA0B,CAAC;QAErD,kBAAkB;QAClB,sBAAsB,EAAE,CAAC,gBAAgB,EAAE,QAAQ,CAAC;QAEpD,kDAAkD;QAClD,eAAe,EAAE,KAAK;QAEtB,iBAAiB;QACjB,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,IAAI;KAC9B,CAAC;AACJ,CAAC;AAED;;;;;;;;;GASG;AACI,KAAK,UAAU,OAAO,CAAC,IAAgB;IAC5C,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAE1B,0BAA0B;IAC1B,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACrC,MAAM,SAAS,GAAG,MAAM,IAAA,eAAU,EAAC,MAAM,CAAC,CAAC;IAE3C,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,IAAA,UAAC,EAAC,KAAK,EAAE,yBAAyB,CAAC,CAAC,CAAC;QACnD,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAClB,OAAO,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;QACrC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC1B,OAAO,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAC1C,OAAO,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC;QAClD,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAClB,OAAO,CAAC,KAAK,CAAC,oDAAoD,CAAC,CAAC;QACpE,OAAO,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;QACjC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,8CAA8C;IAC9C,MAAM,MAAM,GAAG,kBAAkB,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAC7C,MAAM,OAAO,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC;IAC5B,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,wBAAwB,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IACjF,MAAM,QAAG,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAEjE,uBAAuB;IACvB,MAAM,QAAQ,GAAa,CAAC,MAAM,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;IAE5D,uEAAuE;IACvE,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACnB,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IAC/B,CAAC;IAED,iBAAiB;IACjB,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC3B,CAAC;IAED,mBAAmB;IACnB,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC7B,CAAC;IAED,gEAAgE;IAChE,MAAM,YAAY,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,6BAA6B;IACnE,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,QAAQ,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,CAAC;IACjC,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,GAAG,IAAA,UAAC,EAAC,MAAM,EAAE,QAAQ,CAAC,yBAAyB,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;IACvG,OAAO,CAAC,GAAG,CAAC,GAAG,IAAA,UAAC,EAAC,MAAM,EAAE,QAAQ,CAAC,yCAAyC,CAAC,CAAC;IAE7E,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACnB,OAAO,CAAC,GAAG,CAAC,GAAG,IAAA,UAAC,EAAC,MAAM,EAAE,QAAQ,CAAC,2CAA2C,CAAC,CAAC;IACjF,CAAC;IAED,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,GAAG,IAAA,UAAC,EAAC,MAAM,EAAE,QAAQ,CAAC,qBAAqB,CAAC,CAAC;IAC3D,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,GAAG,IAAA,UAAC,EAAC,MAAM,EAAE,OAAO,CAAC,yBAAyB,CAAC,CAAC;IAE5D,+DAA+D;IAC/D,qEAAqE;IACrE,MAAM,IAAI,GAAG,IAAA,qBAAK,EAAC,KAAK,EAAE,QAAQ,EAAE;QAClC,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,KAAK;QACZ,GAAG;KACJ,CAAC,CAAC;IAEH,iBAAiB;IACjB,MAAM,OAAO,GAAG,KAAK,EAAE,IAAmB,EAAE,EAAE;QAC5C,IAAI,CAAC;YACH,IAAI,IAAI,EAAE,CAAC;gBACT,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACtB,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,4BAA4B;QAC5B,IAAI,CAAC;YACH,MAAM,QAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC/B,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;QACxB,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE;YACzB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,4BAA4B;IAC5B,IAAI,CAAC;QACH,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC1C,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;gBACxB,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;oBACf,OAAO,EAAE,CAAC;gBACZ,CAAC;qBAAM,CAAC;oBACN,MAAM,CAAC,IAAI,KAAK,CAAC,yBAAyB,IAAI,EAAE,CAAC,CAAC,CAAC;gBACrD,CAAC;YACH,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBACvB,MAAM,CAAC,GAAG,CAAC,CAAC;YACd,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;YAAS,CAAC;QACT,4BAA4B;QAC5B,IAAI,CAAC;YACH,MAAM,QAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC/B,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;IACH,CAAC;AACH,CAAC","sourcesContent":["import * as path from 'path';\nimport * as os from 'os';\nimport { spawn, ChildProcess } from 'child_process';\nimport { ParsedArgs } from '../args';\nimport { c } from '../colors';\nimport { fileExists, fsp } from '../utils/fs';\n\n/**\n * Generate Jest configuration programmatically for E2E tests.\n * This eliminates the need for projects to have their own jest.e2e.config.ts.\n */\nfunction generateJestConfig(cwd: string, opts: ParsedArgs): object {\n const testTimeout = opts.timeout ?? 60000;\n\n return {\n // Use Node.js environment for E2E tests\n testEnvironment: 'node',\n\n // Root directory for tests\n rootDir: cwd,\n\n // Test file patterns for E2E tests\n testMatch: ['<rootDir>/e2e/**/*.e2e.ts', '<rootDir>/e2e/**/*.e2e.test.ts', '<rootDir>/**/*.e2e.ts'],\n\n // Transform TypeScript files using @swc/jest for speed\n transform: {\n '^.+\\\\.[tj]s$': [\n '@swc/jest',\n {\n jsc: {\n target: 'es2022',\n parser: {\n syntax: 'typescript',\n decorators: true,\n dynamicImport: true,\n },\n transform: {\n decoratorMetadata: true,\n legacyDecorator: true,\n },\n keepClassNames: true,\n externalHelpers: true,\n loose: true,\n },\n module: {\n type: 'es6',\n },\n sourceMaps: true,\n swcrc: false,\n },\n ],\n },\n\n // File extensions to consider\n moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],\n\n // Test timeout\n testTimeout,\n\n // Setup files that run after Jest is initialized\n setupFilesAfterEnv: ['@frontmcp/testing/setup'],\n\n // Transform packages that use ESM\n transformIgnorePatterns: ['node_modules/(?!(jose)/)'],\n\n // Ignore patterns\n testPathIgnorePatterns: ['/node_modules/', '/dist/'],\n\n // Coverage settings (disabled by default for E2E)\n collectCoverage: false,\n\n // Verbose output\n verbose: opts.verbose ?? true,\n };\n}\n\n/**\n * Run E2E tests using Jest with auto-injected configuration.\n *\n * Usage:\n * frontmcp test # Run E2E tests in current directory\n * frontmcp test --runInBand # Run tests sequentially (recommended for E2E)\n * frontmcp test --watch # Run tests in watch mode\n * frontmcp test --verbose # Show verbose output\n * frontmcp test --timeout 60000 # Set test timeout (default: 60000ms)\n */\nexport async function runTest(opts: ParsedArgs): Promise<void> {\n const cwd = process.cwd();\n\n // Check for e2e directory\n const e2eDir = path.join(cwd, 'e2e');\n const hasE2EDir = await fileExists(e2eDir);\n\n if (!hasE2EDir) {\n console.error(c('red', 'No e2e directory found.'));\n console.error('');\n console.error('Expected structure:');\n console.error(' ./e2e/');\n console.error(' ├── your-test.e2e.ts');\n console.error(' └── another-test.e2e.test.ts');\n console.error('');\n console.error('Create an e2e directory with test files, then run:');\n console.error(' frontmcp test');\n process.exit(1);\n }\n\n // Generate Jest config and write to temp file\n const config = generateJestConfig(cwd, opts);\n const tempDir = os.tmpdir();\n const configPath = path.join(tempDir, `frontmcp-jest-config-${Date.now()}.json`);\n await fsp.writeFile(configPath, JSON.stringify(config, null, 2));\n\n // Build Jest arguments\n const jestArgs: string[] = ['jest', '--config', configPath];\n\n // Add --runInBand for sequential execution (recommended for E2E tests)\n if (opts.runInBand) {\n jestArgs.push('--runInBand');\n }\n\n // Add watch mode\n if (opts.watch) {\n jestArgs.push('--watch');\n }\n\n // Add verbose flag\n if (opts.verbose) {\n jestArgs.push('--verbose');\n }\n\n // Add any additional positional args (e.g., test file patterns)\n const testPatterns = opts._.slice(1); // Skip 'test' command itself\n if (testPatterns.length > 0) {\n jestArgs.push(...testPatterns);\n }\n\n console.log(`${c('cyan', '[test]')} running E2E tests in ${path.relative(process.cwd(), cwd) || '.'}`);\n console.log(`${c('gray', '[test]')} using auto-injected Jest configuration`);\n\n if (opts.runInBand) {\n console.log(`${c('gray', '[test]')} running tests sequentially (--runInBand)`);\n }\n\n if (opts.watch) {\n console.log(`${c('gray', '[test]')} watch mode enabled`);\n }\n\n console.log(`${c('gray', 'hint:')} press Ctrl+C to stop\\n`);\n\n // Run Jest directly via node_modules/.bin or npx without shell\n // Using shell: false with explicit args array avoids escaping issues\n const jest = spawn('npx', jestArgs, {\n stdio: 'inherit',\n shell: false,\n cwd,\n });\n\n // Handle cleanup\n const cleanup = async (proc?: ChildProcess) => {\n try {\n if (proc) {\n proc.kill('SIGINT');\n }\n } catch {\n // ignore\n }\n // Clean up temp config file\n try {\n await fsp.unlink(configPath);\n } catch {\n // ignore\n }\n };\n\n process.on('SIGINT', () => {\n cleanup(jest).finally(() => {\n process.exit(0);\n });\n });\n\n // Wait for Jest to complete\n try {\n await new Promise<void>((resolve, reject) => {\n jest.on('close', (code) => {\n if (code === 0) {\n resolve();\n } else {\n reject(new Error(`Jest exited with code ${code}`));\n }\n });\n jest.on('error', (err) => {\n reject(err);\n });\n });\n } finally {\n // Clean up temp config file\n try {\n await fsp.unlink(configPath);\n } catch {\n // ignore\n }\n }\n}\n"]}
1
+ {"version":3,"file":"test.js","sourceRoot":"","sources":["../../../src/commands/test.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from 'path';\nimport * as os from 'os';\nimport { spawn, ChildProcess } from 'child_process';\nimport { ParsedArgs } from '../args';\nimport { c } from '../colors';\nimport { fileExists } from '@frontmcp/utils';\nimport { fsp } from '../utils/fs';\n\n/**\n * Generate Jest configuration programmatically for E2E tests.\n * This eliminates the need for projects to have their own jest.e2e.config.ts.\n */\nfunction generateJestConfig(cwd: string, opts: ParsedArgs): object {\n const testTimeout = opts.timeout ?? 60000;\n\n return {\n // Use Node.js environment for E2E tests\n testEnvironment: 'node',\n\n // Root directory for tests\n rootDir: cwd,\n\n // Test file patterns for E2E tests\n testMatch: ['<rootDir>/e2e/**/*.e2e.ts', '<rootDir>/e2e/**/*.e2e.test.ts', '<rootDir>/**/*.e2e.ts'],\n\n // Transform TypeScript files using @swc/jest for speed\n transform: {\n '^.+\\\\.[tj]s$': [\n '@swc/jest',\n {\n jsc: {\n target: 'es2022',\n parser: {\n syntax: 'typescript',\n decorators: true,\n dynamicImport: true,\n },\n transform: {\n decoratorMetadata: true,\n legacyDecorator: true,\n },\n keepClassNames: true,\n externalHelpers: true,\n loose: true,\n },\n module: {\n type: 'es6',\n },\n sourceMaps: true,\n swcrc: false,\n },\n ],\n },\n\n // File extensions to consider\n moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],\n\n // Test timeout\n testTimeout,\n\n // Setup files that run after Jest is initialized\n setupFilesAfterEnv: ['@frontmcp/testing/setup'],\n\n // Transform packages that use ESM\n transformIgnorePatterns: ['node_modules/(?!(jose)/)'],\n\n // Ignore patterns\n testPathIgnorePatterns: ['/node_modules/', '/dist/'],\n\n // Coverage settings\n collectCoverage: opts.coverage ?? false,\n\n // Coverage configuration when enabled\n ...(opts.coverage\n ? {\n coverageDirectory: '<rootDir>/coverage',\n coverageReporters: ['text', 'lcov', 'json'],\n collectCoverageFrom: ['<rootDir>/src/**/*.ts', '!<rootDir>/src/**/*.test.ts', '!<rootDir>/src/**/*.spec.ts'],\n }\n : {}),\n\n // Verbose output\n verbose: opts.verbose ?? true,\n };\n}\n\n/**\n * Run E2E tests using Jest with auto-injected configuration.\n *\n * Usage:\n * frontmcp test # Run E2E tests in current directory\n * frontmcp test --runInBand # Run tests sequentially (recommended for E2E)\n * frontmcp test --watch # Run tests in watch mode\n * frontmcp test --verbose # Show verbose output\n * frontmcp test --timeout 60000 # Set test timeout (default: 60000ms)\n */\nexport async function runTest(opts: ParsedArgs): Promise<void> {\n const cwd = process.cwd();\n\n // Check for e2e directory\n const e2eDir = path.join(cwd, 'e2e');\n const hasE2EDir = await fileExists(e2eDir);\n\n if (!hasE2EDir) {\n console.error(c('red', 'No e2e directory found.'));\n console.error('');\n console.error('Expected structure:');\n console.error(' ./e2e/');\n console.error(' ├── your-test.e2e.ts');\n console.error(' └── another-test.e2e.test.ts');\n console.error('');\n console.error('Create an e2e directory with test files, then run:');\n console.error(' frontmcp test');\n process.exit(1);\n }\n\n // Generate Jest config and write to temp file\n const config = generateJestConfig(cwd, opts);\n const tempDir = os.tmpdir();\n const configPath = path.join(tempDir, `frontmcp-jest-config-${Date.now()}.json`);\n await fsp.writeFile(configPath, JSON.stringify(config, null, 2));\n\n // Build Jest arguments\n const jestArgs: string[] = ['jest', '--config', configPath];\n\n // Add --runInBand for sequential execution (recommended for E2E tests)\n if (opts.runInBand) {\n jestArgs.push('--runInBand');\n }\n\n // Add watch mode\n if (opts.watch) {\n jestArgs.push('--watch');\n }\n\n // Add verbose flag\n if (opts.verbose) {\n jestArgs.push('--verbose');\n }\n\n // Add coverage flag\n if (opts.coverage) {\n jestArgs.push('--coverage');\n }\n\n // Add any additional positional args (e.g., test file patterns)\n const testPatterns = opts._.slice(1); // Skip 'test' command itself\n if (testPatterns.length > 0) {\n jestArgs.push(...testPatterns);\n }\n\n console.log(`${c('cyan', '[test]')} running E2E tests in ${path.relative(process.cwd(), cwd) || '.'}`);\n console.log(`${c('gray', '[test]')} using auto-injected Jest configuration`);\n\n if (opts.runInBand) {\n console.log(`${c('gray', '[test]')} running tests sequentially (--runInBand)`);\n }\n\n if (opts.watch) {\n console.log(`${c('gray', '[test]')} watch mode enabled`);\n }\n\n if (opts.coverage) {\n console.log(`${c('gray', '[test]')} coverage collection enabled`);\n }\n\n console.log(`${c('gray', 'hint:')} press Ctrl+C to stop\\n`);\n\n // Run Jest directly via node_modules/.bin or npx without shell\n // Using shell: false with explicit args array avoids escaping issues\n const jest = spawn('npx', jestArgs, {\n stdio: 'inherit',\n shell: false,\n cwd,\n });\n\n // Handle cleanup\n const cleanup = async (proc?: ChildProcess) => {\n try {\n if (proc) {\n proc.kill('SIGINT');\n }\n } catch {\n // ignore\n }\n // Clean up temp config file\n try {\n await fsp.unlink(configPath);\n } catch {\n // ignore\n }\n };\n\n process.on('SIGINT', () => {\n cleanup(jest).finally(() => {\n process.exit(0);\n });\n });\n\n // Wait for Jest to complete\n try {\n await new Promise<void>((resolve, reject) => {\n jest.on('close', (code) => {\n if (code === 0) {\n resolve();\n } else {\n reject(new Error(`Jest exited with code ${code}`));\n }\n });\n jest.on('error', (err) => {\n reject(err);\n });\n });\n } finally {\n // Clean up temp config file\n try {\n await fsp.unlink(configPath);\n } catch {\n // ignore\n }\n }\n}\n"]}
package/src/tsconfig.js CHANGED
@@ -8,7 +8,7 @@ exports.runInit = runInit;
8
8
  const tslib_1 = require("tslib");
9
9
  const path = tslib_1.__importStar(require("path"));
10
10
  const colors_1 = require("./colors");
11
- const fs_1 = require("./utils/fs");
11
+ const utils_1 = require("@frontmcp/utils");
12
12
  exports.REQUIRED_DECORATOR_FIELDS = {
13
13
  target: 'es2021',
14
14
  module: 'esnext',
@@ -88,16 +88,16 @@ function checkRequiredTsOptions(compilerOptions) {
88
88
  async function runInit(baseDir) {
89
89
  const cwd = baseDir ?? process.cwd();
90
90
  const tsconfigPath = path.join(cwd, 'tsconfig.json');
91
- const existing = await (0, fs_1.readJSON)(tsconfigPath);
91
+ const existing = await (0, utils_1.readJSON)(tsconfigPath);
92
92
  if (!existing) {
93
93
  console.log((0, colors_1.c)('yellow', `tsconfig.json not found — creating one in ${path.relative(process.cwd(), cwd) || '.'}.`));
94
- await (0, fs_1.writeJSON)(tsconfigPath, exports.RECOMMENDED_TSCONFIG);
94
+ await (0, utils_1.writeJSON)(tsconfigPath, exports.RECOMMENDED_TSCONFIG);
95
95
  console.log((0, colors_1.c)('green', '✅ Created tsconfig.json with required decorator settings.'));
96
96
  return;
97
97
  }
98
98
  let merged = deepMerge(exports.RECOMMENDED_TSCONFIG, existing);
99
99
  merged = ensureRequiredTsOptions(merged);
100
- await (0, fs_1.writeJSON)(tsconfigPath, merged);
100
+ await (0, utils_1.writeJSON)(tsconfigPath, merged);
101
101
  console.log((0, colors_1.c)('green', '✅ tsconfig.json verified and updated (required decorator settings enforced).'));
102
102
  }
103
103
  //# sourceMappingURL=tsconfig.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tsconfig.js","sourceRoot":"","sources":["../../src/tsconfig.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from 'path';\nimport { c } from './colors';\nimport { fileExists, readJSON, writeJSON } from './utils/fs';\n\nexport const REQUIRED_DECORATOR_FIELDS = {\n target: 'es2021',\n module: 'esnext',\n emitDecoratorMetadata: true,\n experimentalDecorators: true,\n strictFunctionTypes: true,\n moduleResolution: 'node',\n} as const;\n\nexport const RECOMMENDED_TSCONFIG = {\n compilerOptions: {\n target: REQUIRED_DECORATOR_FIELDS.target,\n module: REQUIRED_DECORATOR_FIELDS.module,\n emitDecoratorMetadata: REQUIRED_DECORATOR_FIELDS.emitDecoratorMetadata,\n experimentalDecorators: REQUIRED_DECORATOR_FIELDS.experimentalDecorators,\n strictFunctionTypes: REQUIRED_DECORATOR_FIELDS.strictFunctionTypes,\n moduleResolution: REQUIRED_DECORATOR_FIELDS.moduleResolution,\n strict: true,\n esModuleInterop: true,\n resolveJsonModule: true,\n skipLibCheck: true,\n sourceMap: true,\n outDir: 'dist',\n rootDir: 'src',\n types: ['node', '@types/jest', '@frontmcp/testing'],\n },\n include: ['src/**/*'],\n} as const;\n\nexport function deepMerge<T extends Record<string, any>, U extends Record<string, any>>(base: T, patch: U): T & U {\n const out: Record<string, any> = { ...base };\n for (const [k, v] of Object.entries(patch)) {\n if (v && typeof v === 'object' && !Array.isArray(v)) {\n out[k] = deepMerge(base[k] ?? {}, v as Record<string, any>);\n } else {\n out[k] = v;\n }\n }\n return out as T & U;\n}\n\nexport function ensureRequiredTsOptions(obj: Record<string, any>): Record<string, any> {\n const next = { ...obj };\n next.compilerOptions = { ...(next.compilerOptions || {}) };\n next.compilerOptions.target = REQUIRED_DECORATOR_FIELDS.target;\n next.compilerOptions.module = REQUIRED_DECORATOR_FIELDS.module;\n next.compilerOptions.emitDecoratorMetadata = REQUIRED_DECORATOR_FIELDS.emitDecoratorMetadata;\n next.compilerOptions.experimentalDecorators = REQUIRED_DECORATOR_FIELDS.experimentalDecorators;\n return next;\n}\n\nfunction normalizeStr(x: unknown): string | undefined {\n return typeof x === 'string' ? x.toLowerCase() : undefined;\n}\n\nexport function checkRequiredTsOptions(compilerOptions: Record<string, any> | undefined) {\n const issues: string[] = [];\n const ok: string[] = [];\n\n const target = normalizeStr(compilerOptions?.target);\n const moduleVal = normalizeStr(compilerOptions?.module);\n const edm = compilerOptions?.emitDecoratorMetadata;\n const ed = compilerOptions?.experimentalDecorators;\n\n if (target === REQUIRED_DECORATOR_FIELDS.target)\n ok.push(`compilerOptions.target = \"${REQUIRED_DECORATOR_FIELDS.target}\"`);\n else issues.push(`compilerOptions.target should be \"${REQUIRED_DECORATOR_FIELDS.target}\"`);\n\n if (moduleVal === REQUIRED_DECORATOR_FIELDS.module)\n ok.push(`compilerOptions.module = \"${REQUIRED_DECORATOR_FIELDS.module}\"`);\n else issues.push(`compilerOptions.module should be \"${REQUIRED_DECORATOR_FIELDS.module}\"`);\n\n if (edm === REQUIRED_DECORATOR_FIELDS.emitDecoratorMetadata) ok.push(`compilerOptions.emitDecoratorMetadata = true`);\n else issues.push(`compilerOptions.emitDecoratorMetadata should be true`);\n\n if (ed === REQUIRED_DECORATOR_FIELDS.experimentalDecorators) ok.push(`compilerOptions.experimentalDecorators = true`);\n else issues.push(`compilerOptions.experimentalDecorators should be true`);\n\n return { ok, issues };\n}\n\nexport async function runInit(baseDir?: string): Promise<void> {\n const cwd = baseDir ?? process.cwd();\n const tsconfigPath = path.join(cwd, 'tsconfig.json');\n const existing = await readJSON<Record<string, any>>(tsconfigPath);\n\n if (!existing) {\n console.log(c('yellow', `tsconfig.json not found — creating one in ${path.relative(process.cwd(), cwd) || '.'}.`));\n await writeJSON(tsconfigPath, RECOMMENDED_TSCONFIG);\n console.log(c('green', '✅ Created tsconfig.json with required decorator settings.'));\n return;\n }\n\n let merged = deepMerge(RECOMMENDED_TSCONFIG as any, existing);\n merged = ensureRequiredTsOptions(merged);\n\n await writeJSON(tsconfigPath, merged);\n console.log(c('green', '✅ tsconfig.json verified and updated (required decorator settings enforced).'));\n}\n"]}
1
+ {"version":3,"file":"tsconfig.js","sourceRoot":"","sources":["../../src/tsconfig.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from 'path';\nimport { c } from './colors';\nimport { fileExists, readJSON, writeJSON } from '@frontmcp/utils';\n\nexport const REQUIRED_DECORATOR_FIELDS = {\n target: 'es2021',\n module: 'esnext',\n emitDecoratorMetadata: true,\n experimentalDecorators: true,\n strictFunctionTypes: true,\n moduleResolution: 'node',\n} as const;\n\nexport const RECOMMENDED_TSCONFIG = {\n compilerOptions: {\n target: REQUIRED_DECORATOR_FIELDS.target,\n module: REQUIRED_DECORATOR_FIELDS.module,\n emitDecoratorMetadata: REQUIRED_DECORATOR_FIELDS.emitDecoratorMetadata,\n experimentalDecorators: REQUIRED_DECORATOR_FIELDS.experimentalDecorators,\n strictFunctionTypes: REQUIRED_DECORATOR_FIELDS.strictFunctionTypes,\n moduleResolution: REQUIRED_DECORATOR_FIELDS.moduleResolution,\n strict: true,\n esModuleInterop: true,\n resolveJsonModule: true,\n skipLibCheck: true,\n sourceMap: true,\n outDir: 'dist',\n rootDir: 'src',\n types: ['node', '@types/jest', '@frontmcp/testing'],\n },\n include: ['src/**/*'],\n} as const;\n\nexport function deepMerge<T extends Record<string, any>, U extends Record<string, any>>(base: T, patch: U): T & U {\n const out: Record<string, any> = { ...base };\n for (const [k, v] of Object.entries(patch)) {\n if (v && typeof v === 'object' && !Array.isArray(v)) {\n out[k] = deepMerge(base[k] ?? {}, v as Record<string, any>);\n } else {\n out[k] = v;\n }\n }\n return out as T & U;\n}\n\nexport function ensureRequiredTsOptions(obj: Record<string, any>): Record<string, any> {\n const next = { ...obj };\n next.compilerOptions = { ...(next.compilerOptions || {}) };\n next.compilerOptions.target = REQUIRED_DECORATOR_FIELDS.target;\n next.compilerOptions.module = REQUIRED_DECORATOR_FIELDS.module;\n next.compilerOptions.emitDecoratorMetadata = REQUIRED_DECORATOR_FIELDS.emitDecoratorMetadata;\n next.compilerOptions.experimentalDecorators = REQUIRED_DECORATOR_FIELDS.experimentalDecorators;\n return next;\n}\n\nfunction normalizeStr(x: unknown): string | undefined {\n return typeof x === 'string' ? x.toLowerCase() : undefined;\n}\n\nexport function checkRequiredTsOptions(compilerOptions: Record<string, any> | undefined) {\n const issues: string[] = [];\n const ok: string[] = [];\n\n const target = normalizeStr(compilerOptions?.target);\n const moduleVal = normalizeStr(compilerOptions?.module);\n const edm = compilerOptions?.emitDecoratorMetadata;\n const ed = compilerOptions?.experimentalDecorators;\n\n if (target === REQUIRED_DECORATOR_FIELDS.target)\n ok.push(`compilerOptions.target = \"${REQUIRED_DECORATOR_FIELDS.target}\"`);\n else issues.push(`compilerOptions.target should be \"${REQUIRED_DECORATOR_FIELDS.target}\"`);\n\n if (moduleVal === REQUIRED_DECORATOR_FIELDS.module)\n ok.push(`compilerOptions.module = \"${REQUIRED_DECORATOR_FIELDS.module}\"`);\n else issues.push(`compilerOptions.module should be \"${REQUIRED_DECORATOR_FIELDS.module}\"`);\n\n if (edm === REQUIRED_DECORATOR_FIELDS.emitDecoratorMetadata) ok.push(`compilerOptions.emitDecoratorMetadata = true`);\n else issues.push(`compilerOptions.emitDecoratorMetadata should be true`);\n\n if (ed === REQUIRED_DECORATOR_FIELDS.experimentalDecorators) ok.push(`compilerOptions.experimentalDecorators = true`);\n else issues.push(`compilerOptions.experimentalDecorators should be true`);\n\n return { ok, issues };\n}\n\nexport async function runInit(baseDir?: string): Promise<void> {\n const cwd = baseDir ?? process.cwd();\n const tsconfigPath = path.join(cwd, 'tsconfig.json');\n const existing = await readJSON<Record<string, any>>(tsconfigPath);\n\n if (!existing) {\n console.log(c('yellow', `tsconfig.json not found — creating one in ${path.relative(process.cwd(), cwd) || '.'}.`));\n await writeJSON(tsconfigPath, RECOMMENDED_TSCONFIG);\n console.log(c('green', '✅ Created tsconfig.json with required decorator settings.'));\n return;\n }\n\n let merged = deepMerge(RECOMMENDED_TSCONFIG as any, existing);\n merged = ensureRequiredTsOptions(merged);\n\n await writeJSON(tsconfigPath, merged);\n console.log(c('green', '✅ tsconfig.json verified and updated (required decorator settings enforced).'));\n}\n"]}
package/src/utils/fs.d.ts CHANGED
@@ -1,11 +1,7 @@
1
1
  import { promises as fsp } from 'fs';
2
- export declare function fileExists(p: string): Promise<boolean>;
3
- export declare function readJSON<T = any>(jsonPath: string): Promise<T | null>;
4
- export declare function writeJSON(p: string, obj: any): Promise<void>;
2
+ /**
3
+ * Resolve entry file for CLI commands.
4
+ * CLI-specific: includes colored error messages and CLI usage hints.
5
+ */
5
6
  export declare function resolveEntry(cwd: string, explicit?: string): Promise<string>;
6
- export declare function runCmd(cmd: string, args: string[], opts?: {
7
- cwd?: string;
8
- }): Promise<void>;
9
- export declare function ensureDir(p: string): Promise<void>;
10
- export declare function isDirEmpty(dir: string): Promise<boolean>;
11
7
  export { fsp };
package/src/utils/fs.js CHANGED
@@ -1,71 +1,49 @@
1
1
  "use strict";
2
+ // file: libs/cli/src/utils/fs.ts
3
+ // CLI-specific file system utilities
2
4
  Object.defineProperty(exports, "__esModule", { value: true });
3
5
  exports.fsp = void 0;
4
- exports.fileExists = fileExists;
5
- exports.readJSON = readJSON;
6
- exports.writeJSON = writeJSON;
7
6
  exports.resolveEntry = resolveEntry;
8
- exports.runCmd = runCmd;
9
- exports.ensureDir = ensureDir;
10
- exports.isDirEmpty = isDirEmpty;
11
7
  const tslib_1 = require("tslib");
12
- const fs = tslib_1.__importStar(require("fs"));
8
+ const path = tslib_1.__importStar(require("path"));
13
9
  const fs_1 = require("fs");
14
10
  Object.defineProperty(exports, "fsp", { enumerable: true, get: function () { return fs_1.promises; } });
15
- const path = tslib_1.__importStar(require("path"));
16
- const child_process_1 = require("child_process");
17
11
  const colors_1 = require("../colors");
18
- async function fileExists(p) {
19
- try {
20
- await fs_1.promises.access(p, fs.constants.F_OK);
21
- return true;
22
- }
23
- catch {
24
- return false;
25
- }
26
- }
27
- async function readJSON(jsonPath) {
28
- try {
29
- const buf = await fs_1.promises.readFile(jsonPath, 'utf8');
30
- return JSON.parse(buf);
31
- }
32
- catch {
33
- return null;
34
- }
35
- }
36
- async function writeJSON(p, obj) {
37
- await fs_1.promises.writeFile(p, JSON.stringify(obj, null, 2) + '\n', 'utf8');
38
- }
12
+ const utils_1 = require("@frontmcp/utils");
39
13
  function tryCandidates(base) {
40
14
  const exts = ['', '.ts', '.tsx', '.js', '.mjs', '.cjs'];
41
15
  return exts.map((ext) => base + ext);
42
16
  }
17
+ /**
18
+ * Resolve entry file for CLI commands.
19
+ * CLI-specific: includes colored error messages and CLI usage hints.
20
+ */
43
21
  async function resolveEntry(cwd, explicit) {
44
22
  if (explicit) {
45
23
  const full = path.resolve(cwd, explicit);
46
- if (await fileExists(full))
24
+ if (await (0, utils_1.fileExists)(full))
47
25
  return full;
48
26
  throw new Error(`Entry override not found: ${explicit}`);
49
27
  }
50
28
  const pkgPath = path.join(cwd, 'package.json');
51
- if (await fileExists(pkgPath)) {
52
- const pkg = await readJSON(pkgPath);
29
+ if (await (0, utils_1.fileExists)(pkgPath)) {
30
+ const pkg = await (0, utils_1.readJSON)(pkgPath);
53
31
  if (pkg && typeof pkg.main === 'string' && pkg.main.trim()) {
54
32
  const mainCandidates = tryCandidates(path.resolve(cwd, pkg.main));
55
33
  for (const p of mainCandidates) {
56
- if (await fileExists(p))
34
+ if (await (0, utils_1.fileExists)(p))
57
35
  return p;
58
36
  }
59
37
  const asDir = path.resolve(cwd, pkg.main);
60
38
  const idxCandidates = tryCandidates(path.join(asDir, 'index'));
61
39
  for (const p of idxCandidates) {
62
- if (await fileExists(p))
40
+ if (await (0, utils_1.fileExists)(p))
63
41
  return p;
64
42
  }
65
43
  }
66
44
  }
67
45
  const fallback = path.join(cwd, 'src', 'main.ts');
68
- if (await fileExists(fallback))
46
+ if (await (0, utils_1.fileExists)(fallback))
69
47
  return fallback;
70
48
  const msg = [
71
49
  (0, colors_1.c)('red', 'No entry file found.'),
@@ -80,25 +58,4 @@ async function resolveEntry(cwd, explicit) {
80
58
  ].join('\n');
81
59
  throw new Error(msg);
82
60
  }
83
- function runCmd(cmd, args, opts = {}) {
84
- return new Promise((resolve, reject) => {
85
- const child = (0, child_process_1.spawn)(cmd, args, { stdio: 'inherit', shell: false, ...opts });
86
- child.on('close', (code) => (code === 0 ? resolve() : reject(new Error(`${cmd} exited with code ${code}`))));
87
- child.on('error', reject);
88
- });
89
- }
90
- async function ensureDir(p) {
91
- await fs_1.promises.mkdir(p, { recursive: true });
92
- }
93
- async function isDirEmpty(dir) {
94
- try {
95
- const items = await fs_1.promises.readdir(dir);
96
- return items.length === 0;
97
- }
98
- catch (e) {
99
- if (e?.code === 'ENOENT')
100
- return true;
101
- throw e;
102
- }
103
- }
104
61
  //# sourceMappingURL=fs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"fs.js","sourceRoot":"","sources":["../../../src/utils/fs.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'fs';\nimport { promises as fsp } from 'fs';\nimport * as path from 'path';\nimport { spawn } from 'child_process';\nimport { c } from '../colors';\n\nexport async function fileExists(p: string): Promise<boolean> {\n try {\n await fsp.access(p, fs.constants.F_OK);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function readJSON<T = any>(jsonPath: string): Promise<T | null> {\n try {\n const buf = await fsp.readFile(jsonPath, 'utf8');\n return JSON.parse(buf) as T;\n } catch {\n return null;\n }\n}\n\nexport async function writeJSON(p: string, obj: any) {\n await fsp.writeFile(p, JSON.stringify(obj, null, 2) + '\\n', 'utf8');\n}\n\nfunction tryCandidates(base: string): string[] {\n const exts = ['', '.ts', '.tsx', '.js', '.mjs', '.cjs'];\n return exts.map((ext) => base + ext);\n}\n\nexport async function resolveEntry(cwd: string, explicit?: string): Promise<string> {\n if (explicit) {\n const full = path.resolve(cwd, explicit);\n if (await fileExists(full)) return full;\n throw new Error(`Entry override not found: ${explicit}`);\n }\n\n const pkgPath = path.join(cwd, 'package.json');\n if (await fileExists(pkgPath)) {\n const pkg = await readJSON<any>(pkgPath);\n if (pkg && typeof pkg.main === 'string' && pkg.main.trim()) {\n const mainCandidates = tryCandidates(path.resolve(cwd, pkg.main));\n for (const p of mainCandidates) {\n if (await fileExists(p)) return p;\n }\n const asDir = path.resolve(cwd, pkg.main);\n const idxCandidates = tryCandidates(path.join(asDir, 'index'));\n for (const p of idxCandidates) {\n if (await fileExists(p)) return p;\n }\n }\n }\n\n const fallback = path.join(cwd, 'src', 'main.ts');\n if (await fileExists(fallback)) return fallback;\n\n const msg = [\n c('red', 'No entry file found.'),\n '',\n 'I looked for:',\n ` • ${pkgPath} with a valid \"main\" field`,\n ` • ${path.relative(cwd, fallback)}`,\n '',\n 'Please create an entry file (e.g. src/main.ts) or set \"main\" in package.json,',\n 'or run with an explicit path:',\n ` frontmcp dev --entry src/main.ts`,\n ].join('\\n');\n throw new Error(msg);\n}\n\nexport function runCmd(cmd: string, args: string[], opts: { cwd?: string } = {}): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(cmd, args, { stdio: 'inherit', shell: false, ...opts });\n child.on('close', (code) => (code === 0 ? resolve() : reject(new Error(`${cmd} exited with code ${code}`))));\n child.on('error', reject);\n });\n}\n\nexport async function ensureDir(p: string): Promise<void> {\n await fsp.mkdir(p, { recursive: true });\n}\n\nexport async function isDirEmpty(dir: string): Promise<boolean> {\n try {\n const items = await fsp.readdir(dir);\n return items.length === 0;\n } catch (e: unknown) {\n if ((e as NodeJS.ErrnoException)?.code === 'ENOENT') return true;\n throw e;\n }\n}\n\nexport { fsp }; // re-export if needed in other modules\n"]}
1
+ {"version":3,"file":"fs.js","sourceRoot":"","sources":["../../../src/utils/fs.ts"],"names":[],"mappings":";AAAA,iCAAiC;AACjC,qCAAqC;;;AAgBrC,oCAsCC;;AApDD,mDAA6B;AAC7B,2BAAqC;AAqD5B,oFArDY,aAAG,OAqDZ;AApDZ,sCAA8B;AAC9B,2CAAuD;AAEvD,SAAS,aAAa,CAAC,IAAY;IACjC,MAAM,IAAI,GAAG,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACxD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC;AACvC,CAAC;AAED;;;GAGG;AACI,KAAK,UAAU,YAAY,CAAC,GAAW,EAAE,QAAiB;IAC/D,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QACzC,IAAI,MAAM,IAAA,kBAAU,EAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,6BAA6B,QAAQ,EAAE,CAAC,CAAC;IAC3D,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;IAC/C,IAAI,MAAM,IAAA,kBAAU,EAAC,OAAO,CAAC,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,MAAM,IAAA,gBAAQ,EAAoB,OAAO,CAAC,CAAC;QACvD,IAAI,GAAG,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;YAC3D,MAAM,cAAc,GAAG,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;YAClE,KAAK,MAAM,CAAC,IAAI,cAAc,EAAE,CAAC;gBAC/B,IAAI,MAAM,IAAA,kBAAU,EAAC,CAAC,CAAC;oBAAE,OAAO,CAAC,CAAC;YACpC,CAAC;YACD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;YAC1C,MAAM,aAAa,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;YAC/D,KAAK,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC;gBAC9B,IAAI,MAAM,IAAA,kBAAU,EAAC,CAAC,CAAC;oBAAE,OAAO,CAAC,CAAC;YACpC,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;IAClD,IAAI,MAAM,IAAA,kBAAU,EAAC,QAAQ,CAAC;QAAE,OAAO,QAAQ,CAAC;IAEhD,MAAM,GAAG,GAAG;QACV,IAAA,UAAC,EAAC,KAAK,EAAE,sBAAsB,CAAC;QAChC,EAAE;QACF,eAAe;QACf,OAAO,OAAO,4BAA4B;QAC1C,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,EAAE;QACrC,EAAE;QACF,+EAA+E;QAC/E,+BAA+B;QAC/B,oCAAoC;KACrC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACb,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC;AACvB,CAAC","sourcesContent":["// file: libs/cli/src/utils/fs.ts\n// CLI-specific file system utilities\n\nimport * as path from 'path';\nimport { promises as fsp } from 'fs';\nimport { c } from '../colors';\nimport { fileExists, readJSON } from '@frontmcp/utils';\n\nfunction tryCandidates(base: string): string[] {\n const exts = ['', '.ts', '.tsx', '.js', '.mjs', '.cjs'];\n return exts.map((ext) => base + ext);\n}\n\n/**\n * Resolve entry file for CLI commands.\n * CLI-specific: includes colored error messages and CLI usage hints.\n */\nexport async function resolveEntry(cwd: string, explicit?: string): Promise<string> {\n if (explicit) {\n const full = path.resolve(cwd, explicit);\n if (await fileExists(full)) return full;\n throw new Error(`Entry override not found: ${explicit}`);\n }\n\n const pkgPath = path.join(cwd, 'package.json');\n if (await fileExists(pkgPath)) {\n const pkg = await readJSON<{ main?: string }>(pkgPath);\n if (pkg && typeof pkg.main === 'string' && pkg.main.trim()) {\n const mainCandidates = tryCandidates(path.resolve(cwd, pkg.main));\n for (const p of mainCandidates) {\n if (await fileExists(p)) return p;\n }\n const asDir = path.resolve(cwd, pkg.main);\n const idxCandidates = tryCandidates(path.join(asDir, 'index'));\n for (const p of idxCandidates) {\n if (await fileExists(p)) return p;\n }\n }\n }\n\n const fallback = path.join(cwd, 'src', 'main.ts');\n if (await fileExists(fallback)) return fallback;\n\n const msg = [\n c('red', 'No entry file found.'),\n '',\n 'I looked for:',\n ` • ${pkgPath} with a valid \"main\" field`,\n ` • ${path.relative(cwd, fallback)}`,\n '',\n 'Please create an entry file (e.g. src/main.ts) or set \"main\" in package.json,',\n 'or run with an explicit path:',\n ` frontmcp dev --entry src/main.ts`,\n ].join('\\n');\n throw new Error(msg);\n}\n\nexport { fsp }; // re-export if needed in other modules\n"]}