frontmcp 1.1.1 → 1.1.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 +5 -5
- package/src/commands/build/adapters/cloudflare.js +40 -16
- package/src/commands/build/adapters/cloudflare.js.map +1 -1
- package/src/commands/build/adapters/lambda.js +45 -8
- package/src/commands/build/adapters/lambda.js.map +1 -1
- package/src/commands/build/adapters/vercel.js +24 -10
- package/src/commands/build/adapters/vercel.js.map +1 -1
- package/src/commands/build/bundler.js +33 -1
- package/src/commands/build/bundler.js.map +1 -1
- package/src/commands/build/exec/cli-runtime/generate-cli-entry.js +48 -18
- package/src/commands/build/exec/cli-runtime/generate-cli-entry.js.map +1 -1
- package/src/commands/build/exec/config.d.ts +1 -1
- package/src/commands/build/exec/config.js +30 -1
- package/src/commands/build/exec/config.js.map +1 -1
- package/src/commands/build/exec/index.d.ts +1 -0
- package/src/commands/build/exec/index.js +6 -0
- package/src/commands/build/exec/index.js.map +1 -1
- package/src/commands/build/index.js +13 -10
- package/src/commands/build/index.js.map +1 -1
- package/src/commands/build/load-entry-config.d.ts +28 -0
- package/src/commands/build/load-entry-config.js +116 -6
- package/src/commands/build/load-entry-config.js.map +1 -1
- package/src/commands/build/types.d.ts +19 -3
- package/src/commands/build/types.js.map +1 -1
- package/src/config/frontmcp-config.loader.js +66 -25
- package/src/config/frontmcp-config.loader.js.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate-cli-entry.js","sourceRoot":"","sources":["../../../../../../src/commands/build/exec/cli-runtime/generate-cli-entry.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Generates the CLI entry point TypeScript/JavaScript source code.\n * This creates a commander.js-based CLI where each MCP tool is a subcommand.\n */\n\nimport { type CliConfig, type OAuthConfig } from '../config';\nimport { EXTRACT_PUBLIC_MESSAGE_SNIPPET } from './extract-public-message.snippet';\nimport { type ExtractedSchema, type ExtractedTool, type ExtractedPrompt, type ExtractedResourceTemplate, type ExtractedCapabilities, type ExtractedJob, SYSTEM_TOOL_NAMES } from './schema-extractor';\nimport { schemaToCommander, generateOptionCode, camelToKebab } from './schema-to-commander';\n\nexport const RESERVED_COMMANDS = new Set([\n 'resource', 'template', 'prompt', 'subscribe',\n 'login', 'logout', 'connect', 'serve', 'daemon',\n 'doctor', 'install', 'uninstall', 'sessions', 'help', 'version',\n 'skills', 'job', 'workflow',\n // Reserved by the symmetric `prompt get <name>` / `resource read <uri>`\n // sub-API; included so a user-defined entry can never shadow them.\n 'get', 'list', 'read',\n]);\n\nexport interface CliEntryOptions {\n appName: string;\n appVersion: string;\n description: string;\n serverBundleFilename: string;\n outputDefault: 'text' | 'json';\n authRequired: boolean;\n excludeTools: string[];\n nativeDeps: NonNullable<CliConfig['nativeDeps']>;\n schema: ExtractedSchema;\n oauthConfig?: OAuthConfig;\n /** When true, generate static requires that esbuild can resolve (for SEA builds). */\n selfContained?: boolean;\n}\n\n/**\n * Resolve tool command name, appending '-tool' suffix if it conflicts with a built-in command.\n * Returns { cmdName, wasRenamed } so the caller can log a warning at build time.\n */\nexport function resolveToolCommandName(toolName: string): { cmdName: string; wasRenamed: boolean } {\n const cmdName = camelToKebab(toolName).replace(/_/g, '-');\n if (RESERVED_COMMANDS.has(cmdName)) {\n return { cmdName: `${cmdName}-tool`, wasRenamed: true };\n }\n return { cmdName, wasRenamed: false };\n}\n\n/**\n * Generate the CLI entry source code (CJS module).\n */\nexport function generateCliEntry(options: CliEntryOptions): string {\n const {\n appName,\n appVersion,\n description,\n serverBundleFilename,\n outputDefault,\n schema,\n excludeTools,\n oauthConfig,\n authRequired,\n } = options;\n\n const capabilities = schema.capabilities;\n\n const filteredTools = schema.tools.filter(\n (t) => !excludeTools.includes(t.name) && !SYSTEM_TOOL_NAMES.has(t.name),\n );\n\n const selfContained = !!options.selfContained;\n\n const sections: string[] = [\n generateHeader(appName, appVersion, description, serverBundleFilename, outputDefault, authRequired, capabilities, oauthConfig, selfContained),\n generateToolCommands(filteredTools, appName),\n generateResourceCommands(schema),\n generateTemplateCommands(schema.resourceTemplates),\n generatePromptCommands(schema.prompts),\n capabilities.skills ? generateSkillsCommands() : '',\n capabilities.jobs ? generateJobCommands(schema.jobs) : '',\n capabilities.workflows ? generateWorkflowCommands() : '',\n generateSubscribeCommands(),\n ...(authRequired ? [\n generateLoginCommand(appName, oauthConfig),\n generateLogoutCommand(appName),\n generateSessionCommands(),\n ] : []),\n generateServeCommand(serverBundleFilename, selfContained),\n generateDoctorCommand(appName, options.nativeDeps),\n generateInstallCommand(appName, options.nativeDeps, selfContained),\n generateDaemonCommands(appName, serverBundleFilename, selfContained),\n generateFooter(),\n ];\n\n return sections.filter(Boolean).join('\\n\\n');\n}\n\nfunction generateHeader(\n appName: string,\n appVersion: string,\n description: string,\n serverBundleFilename: string,\n outputDefault: string,\n authRequired: boolean,\n capabilities: ExtractedCapabilities,\n oauthConfig?: OAuthConfig,\n selfContained?: boolean,\n): string {\n const hasOAuth = !!oauthConfig;\n\n // Build the group routing map dynamically\n const skillsRouting = capabilities.skills ? `\\n else if (name === 'skills') groups['Skills'].push(sub);` : '';\n const jobsRouting = capabilities.jobs ? `\\n else if (name === 'job') groups['Jobs'].push(sub);` : '';\n const workflowsRouting = capabilities.workflows ? `\\n else if (name === 'workflow') groups['Workflows'].push(sub);` : '';\n const authRouting = authRequired ? `\\n else if (['login', 'logout', 'sessions', 'connect'].indexOf(name) !== -1) groups['Auth'].push(sub);` : '';\n\n // Build the groups object dynamically\n const groupEntries: string[] = [\n ` 'Tools': []`,\n ` 'Resources & Prompts': []`,\n ];\n if (capabilities.skills) groupEntries.push(` 'Skills': []`);\n if (capabilities.jobs) groupEntries.push(` 'Jobs': []`);\n if (capabilities.workflows) groupEntries.push(` 'Workflows': []`);\n if (authRequired) groupEntries.push(` 'Auth': []`);\n groupEntries.push(` 'Subscriptions': []`);\n groupEntries.push(` 'System': []`);\n\n return `'use strict';\n${selfContained ? `\n// SEA daemon mode: when spawned by 'daemon start', run the server directly\n// using the inlined (bundled) server code — no external requires needed.\nif (process.env.__FRONTMCP_DAEMON_MODE === '1') {\n require('reflect-metadata');\n // Suppress @FrontMcp decorator auto-bootstrap — daemon handles bootstrap explicitly below.\n process.env.FRONTMCP_SCHEMA_EXTRACT = '1';\n var _dMod = require(${JSON.stringify('../' + serverBundleFilename)});\n delete process.env.FRONTMCP_SCHEMA_EXTRACT;\n var _dSdk = require('@frontmcp/sdk');\n var _FMI = _dSdk.FrontMcpInstance || _dSdk.default.FrontMcpInstance;\n var _raw = _dMod.default || _dMod;\n var _cfg = (typeof _raw === 'function' && typeof Reflect !== 'undefined' && Reflect.getMetadata)\n ? (Reflect.getMetadata('__frontmcp:config', _raw) || _raw) : _raw;\n var _dp = process.env.FRONTMCP_DAEMON_PORT;\n if (_dp) {\n var _port = parseInt(_dp, 10);\n _cfg = Object.assign({}, _cfg, { http: Object.assign({}, _cfg.http || {}, { port: _port }) });\n process.env.PORT = _dp;\n _FMI.bootstrap(_cfg)\n .then(function() { console.log('Daemon listening on port ' + _port); })\n .catch(function(e) { console.error('Daemon failed:', e); process.exit(1); });\n } else {\n var _sp = process.env.FRONTMCP_DAEMON_SOCKET;\n _FMI.runUnixSocket(Object.assign({}, _cfg, { socketPath: _sp }))\n .then(function() { console.log('Daemon listening on ' + _sp); })\n .catch(function(e) { console.error('Daemon failed:', e); process.exit(1); });\n }\n return;\n}\n` : ''}\n// Stdio mode: when --stdio is passed, run as an MCP stdio server (stdin/stdout JSON-RPC).\n// Detected early before commander to avoid overhead and ensure stdout stays clean for MCP protocol.\n// Logs go to ~/.frontmcp/logs/{appName}-*.log — stdout is reserved for MCP JSON-RPC only.\nif (process.argv.includes('--stdio')) {\n // Set app name for file logging before any initialization\n process.env.FRONTMCP_APP_NAME = process.env.FRONTMCP_APP_NAME || ${JSON.stringify(appName)};\n require('reflect-metadata');\n process.env.FRONTMCP_SCHEMA_EXTRACT = '1';\n var _sMod = require(${selfContained ? `${JSON.stringify('../' + serverBundleFilename)}` : `require('path').join(__dirname, ${JSON.stringify(serverBundleFilename)})`});\n delete process.env.FRONTMCP_SCHEMA_EXTRACT;\n var _sSdk = require('@frontmcp/sdk');\n var _sFMI = _sSdk.FrontMcpInstance || _sSdk.default.FrontMcpInstance;\n var _sRaw = _sMod.default || _sMod;\n var _sCfg = (typeof _sRaw === 'function' && typeof Reflect !== 'undefined' && Reflect.getMetadata)\n ? (Reflect.getMetadata('__frontmcp:config', _sRaw) || _sRaw) : _sRaw;\n _sFMI.runStdio(_sCfg)\n .catch(function(e) { console.error('Stdio server failed:', e); process.exit(1); });\n return;\n}\n\nvar { Command, Option } = require('commander');\nvar path = require('path');\nvar fs = require('fs');\nvar os = require('os');\nvar fmt = require('./output-formatter');\n${authRequired ? \"var sessions = require('./session-manager');\\nvar creds = require('./credential-store');\" : ''}\n${hasOAuth ? \"var oauthHelper = require('./oauth-helper');\" : ''}\n\nvar APP_NAME = ${JSON.stringify(appName)};\nvar SCRIPT_DIR = __dirname;\nvar FRONTMCP_HOME = process.env.FRONTMCP_HOME || path.join(os.homedir(), '.frontmcp');\n// Set app name for file logger (writes to ~/.frontmcp/logs/{appName}-{timestamp}.log)\nprocess.env.FRONTMCP_APP_NAME = process.env.FRONTMCP_APP_NAME || APP_NAME;\n${selfContained\n ? `// Self-contained: server bundle and SDK are inlined by esbuild\nvar SERVER_BUNDLE = '../${serverBundleFilename}';`\n : `var SERVER_BUNDLE = path.join(SCRIPT_DIR, ${JSON.stringify(serverBundleFilename)});`}\n\nvar _client = null;\nasync function getClient() {\n if (_client) return _client;\n\n // Try daemon first — Unix socket HTTP (~5-15ms vs ~420ms in-process)\n var socketPath = path.join(FRONTMCP_HOME, 'sockets', APP_NAME + '.sock');\n if (fs.existsSync(socketPath)) {\n try {\n var daemonClient = require('./daemon-client');\n var dc = daemonClient.createDaemonClient(socketPath);\n await dc.ping();\n _client = dc;\n return _client;\n } catch (_) { /* daemon not available, fall through */ }\n }\n\n // Fallback: in-process connect (with CLI mode for faster init)\n // Suppress @FrontMcp decorator bootstrap — we only need config metadata, not a running server.\n process.env.FRONTMCP_SCHEMA_EXTRACT = '1';\n var mod = require(${selfContained ? `'../${serverBundleFilename}'` : 'SERVER_BUNDLE'});\n delete process.env.FRONTMCP_SCHEMA_EXTRACT;\n var configOrClass = mod.default || mod;\n var sdk = require('@frontmcp/sdk');\n var connect = sdk.connect || sdk.direct.connect;${authRequired ? `\n var sessionName = sessions.getActiveSessionName();\n var store = creds.createCredentialStore();\n var credBlob = await store.get(sessionName);\n var connectOpts = credBlob ? { authToken: credBlob.token, mode: 'cli' } : { mode: 'cli' };\n _client = await connect(configOrClass, connectOpts);` : `\n _client = await connect(configOrClass, { mode: 'cli' });`}\n return _client;\n}\n\nasync function closeClient() {\n if (_client && typeof _client.close === 'function') {\n try { await _client.close(); } catch (_) {}\n }\n _client = null;\n}\n\n// Flag set by long-running commands (serve, daemon) to prevent the footer from calling process.exit().\nvar _isLongRunning = false;\n\n${EXTRACT_PUBLIC_MESSAGE_SNIPPET}\n\nvar program = new Command();\n// Make Commander's own usage errors (unknown subcommand, missing required option,\n// invalid value) exit with code 2 instead of the default 0 — matches POSIX\n// convention and lets shell scripts/CI distinguish runtime failures from usage.\n//\n// Sets process.exitCode and re-throws so the parseAsync() footer can run\n// closeClient() / native-addon teardown before the actual exit. Calling\n// process.exit() directly here would skip that and could leave better-sqlite3\n// / ONNX / file handles in a corrupt state for short-lived runs.\nprogram.exitOverride(function(err) {\n if (err.code === 'commander.helpDisplayed' || err.code === 'commander.help' || err.code === 'commander.version') {\n process.exitCode = 0;\n } else if (err.code === 'commander.unknownCommand' || err.code === 'commander.unknownOption' ||\n err.code === 'commander.missingArgument' || err.code === 'commander.missingMandatoryOptionValue' ||\n err.code === 'commander.invalidArgument' || err.code === 'commander.optionMissingArgument' ||\n err.code === 'commander.invalidOptionArgument' || err.code === 'commander.excessArguments') {\n process.exitCode = 2;\n } else {\n process.exitCode = 1;\n }\n // Re-throw so parseAsync().catch in the footer runs cleanup before exit.\n throw err;\n});\nprogram\n .name(${JSON.stringify(appName)})\n .version(${JSON.stringify(appVersion)})\n .description(${JSON.stringify(description || `${appName} CLI`)})\n .option('--output <mode>', 'Output format: text or json', ${JSON.stringify(outputDefault)})\n .option('--verbose', 'Enable verbose console logging (logs always go to ~/.frontmcp/logs/)')\n .option('--log-dir <path>', 'Directory for log files (default: ~/.frontmcp/logs/)');\n\n// Wire --verbose and --log-dir to env vars early (before any command action runs).\n// Parse argv directly since commander hooks may not be available in all versions.\n(function() {\n var argv = process.argv;\n if (argv.indexOf('--verbose') !== -1) {\n process.env.FRONTMCP_CLI_VERBOSE = '1';\n }\n var logDirIdx = argv.indexOf('--log-dir');\n if (logDirIdx !== -1 && argv[logDirIdx + 1]) {\n process.env.FRONTMCP_LOG_DIR = argv[logDirIdx + 1];\n }\n})();\n\nprogram.configureHelp({\n sortSubcommands: false,\n formatHelp: function(cmd, helper) {\n var groups = {\n${groupEntries.join(',\\n')}\n };\n var toolCmdNames = cmd._toolCommandNames || [];\n cmd.commands.forEach(function(sub) {\n var name = sub.name();\n if (toolCmdNames.indexOf(name) !== -1) groups['Tools'].push(sub);\n else if (['resource', 'template', 'prompt'].indexOf(name) !== -1) groups['Resources & Prompts'].push(sub);${skillsRouting}${jobsRouting}${workflowsRouting}${authRouting}\n else if (name === 'subscribe') groups['Subscriptions'].push(sub);\n else groups['System'].push(sub);\n });\n var termWidth = helper.padWidth(cmd, helper);\n var lines = [];\n lines.push('Usage: ' + helper.commandUsage(cmd));\n lines.push('');\n var desc = helper.commandDescription(cmd);\n if (desc) { lines.push(desc); lines.push(''); }\n var globalOpts = helper.formatHelp ? helper.visibleOptions(cmd) : [];\n if (globalOpts.length > 0) {\n lines.push('Options:');\n globalOpts.forEach(function(opt) {\n lines.push(' ' + helper.optionTerm(opt).padEnd(termWidth) + ' ' + helper.optionDescription(opt));\n });\n lines.push('');\n }\n Object.keys(groups).forEach(function(groupName) {\n var cmds = groups[groupName];\n if (cmds.length === 0) return;\n lines.push(groupName + ':');\n cmds.forEach(function(sub) {\n lines.push(' ' + helper.subcommandTerm(sub).padEnd(termWidth) + ' ' + helper.subcommandDescription(sub));\n });\n lines.push('');\n });\n return lines.join('\\\\n');\n }\n});\n\nprogram.action(function() { program.outputHelp(); });`;\n}\n\nfunction generateToolCommands(tools: ExtractedTool[], appName: string): string {\n if (tools.length === 0) return '// No tools extracted\\nprogram._toolCommandNames = [];';\n\n const cmdNames: string[] = [];\n const commands = tools.map((tool) => {\n const { cmdName } = resolveToolCommandName(tool.name);\n cmdNames.push(cmdName);\n const { options } = schemaToCommander(tool.inputSchema);\n const optionLines = options.map((o) => ` ${generateOptionCode(o)}`).join('\\n');\n\n return `program\n .command(${JSON.stringify(cmdName)})\n .description(${JSON.stringify(tool.description)})\n${optionLines}\n .action(async function(opts) {\n try {\n var client = await getClient();\n var args = {};\n var rawOpts = this.opts();\n ${generateArgMapping(tool)}\n var result = await client.callTool(${JSON.stringify(tool.name)}, args);\n var mode = program.opts().output || ${JSON.stringify('text')};\n console.log(fmt.formatToolResult(result, mode));\n // The SDK converts thrown errors into a CallToolResult with isError:true\n // (so HTTP/JSON-RPC clients still get a structured response). Detect\n // that here and map to a non-zero exit code so shell scripts can gate\n // on success — Zod input validation errors → exit 2 (usage), all\n // other tool errors → exit 1 (runtime).\n if (result && result.isError === true) {\n var rmeta = (result && result._meta) || {};\n process.exitCode = (rmeta.code === 'INVALID_INPUT') ? 2 : 1;\n }\n } catch (err) {\n var meta = err && err._meta ? err._meta : (err && err.data && err.data._meta ? err.data._meta : null);\n if (meta && meta.authorization_required) {\n console.error('Authorization required' + (meta.app ? ' for ' + meta.app : ''));\n if (meta.auth_url) console.error('Authorize at: ' + meta.auth_url);\n console.error('Or run: ' + ${JSON.stringify(appName)} + ' login');\n process.exitCode = 1;\n } else {\n // Thrown error path (transport / DI / pre-flow failure) — same\n // mapping as the isError result path above.\n var isUsage = err && err.code === 'INVALID_INPUT';\n _exitWithError(err, isUsage ? 2 : 1);\n }\n }\n });`;\n });\n\n return `program._toolCommandNames = ${JSON.stringify(cmdNames)};\\n\\n${commands.join('\\n\\n')}`;\n}\n\nfunction generateArgMapping(tool: ExtractedTool): string {\n const props = (tool.inputSchema as Record<string, unknown>).properties as Record<string, Record<string, unknown>> | undefined;\n if (!props) return '';\n\n const mappings = Object.keys(props).map((propName) => {\n const propSchema = props[propName];\n const kebab = camelToKebab(propName);\n // Commander converts kebab-case flags to camelCase in opts()\n const camel = kebabToCamel(kebab);\n\n // Resolve type for object detection\n let propType = propSchema?.type as string | string[] | undefined;\n if (Array.isArray(propType)) {\n propType = propType.find((t: string) => t !== 'null') || propType[0];\n }\n\n if (propType === 'object') {\n return `if (rawOpts[${JSON.stringify(camel)}] !== undefined) {\n try { args[${JSON.stringify(propName)}] = JSON.parse(rawOpts[${JSON.stringify(camel)}]); }\n catch (_jsonErr) { console.error('Invalid JSON for --${kebab}'); process.exitCode = 1; return; }\n }`;\n }\n\n return `if (rawOpts[${JSON.stringify(camel)}] !== undefined) args[${JSON.stringify(propName)}] = rawOpts[${JSON.stringify(camel)}];`;\n });\n\n return mappings.join('\\n ');\n}\n\nfunction generateJobArgMapping(inputSchema: Record<string, unknown>): string {\n const props = (inputSchema as Record<string, unknown>).properties as Record<string, Record<string, unknown>> | undefined;\n if (!props) return '';\n\n const mappings = Object.keys(props).map((propName) => {\n const propSchema = props[propName];\n const kebab = camelToKebab(propName);\n const camel = kebabToCamel(kebab);\n\n let propType = propSchema?.type as string | string[] | undefined;\n if (Array.isArray(propType)) {\n propType = propType.find((t: string) => t !== 'null') || propType[0];\n }\n\n if (propType === 'object') {\n return `if (rawOpts[${JSON.stringify(camel)}] !== undefined) {\n try { input[${JSON.stringify(propName)}] = JSON.parse(rawOpts[${JSON.stringify(camel)}]); }\n catch (_jsonErr) { console.error('Invalid JSON for --${kebab}'); process.exitCode = 1; return; }\n }`;\n }\n\n return `if (rawOpts[${JSON.stringify(camel)}] !== undefined) input[${JSON.stringify(propName)}] = rawOpts[${JSON.stringify(camel)}];`;\n });\n\n return mappings.join('\\n ');\n}\n\nfunction generateResourceCommands(_schema: ExtractedSchema): string {\n return `var resourceCmd = program.command('resource').description('Resource operations');\n\nresourceCmd\n .command('list')\n .description('List available resources')\n .action(async function() {\n try {\n var client = await getClient();\n var result = await client.listResources();\n var mode = program.opts().output || 'text';\n if (mode === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n var resources = result.resources || [];\n if (resources.length === 0) { console.log('No resources available.'); return; }\n resources.forEach(function(r) {\n console.log(' ' + r.uri + (r.description ? ' - ' + r.description : ''));\n });\n }\n } catch (err) {\n _exitWithError(err, 1);\n }\n });\n\nresourceCmd\n .command('read <uri>')\n .description('Read a resource by URI')\n .action(async function(uri) {\n try {\n var client = await getClient();\n var result = await client.readResource(uri);\n var mode = program.opts().output || 'text';\n console.log(fmt.formatResourceResult(result, mode));\n } catch (err) {\n _exitWithError(err, 1);\n }\n });`;\n}\n\nfunction generateTemplateCommands(templates: ExtractedResourceTemplate[]): string {\n if (!templates || templates.length === 0) return '// No resource templates extracted';\n\n const subcommands = templates.map((tmpl) => {\n const cmdName = camelToKebab(tmpl.name).replace(/_/g, '-');\n // Extract {param} placeholders from URI template\n const paramNames = extractTemplateParams(tmpl.uriTemplate);\n const optionLines = paramNames\n .map((p) => ` .requiredOption('--${camelToKebab(p)} <value>', 'Template parameter: ${p}')`)\n .join('\\n');\n\n const paramMapping = paramNames\n .map((p) => {\n const camel = kebabToCamel(camelToKebab(p));\n return `uri = uri.replace('{${p}}', encodeURIComponent(rawOpts[${JSON.stringify(camel)}]));`;\n })\n .join('\\n ');\n\n return `templateCmd\n .command(${JSON.stringify(cmdName)})\n .description(${JSON.stringify(tmpl.description || `Read resource from template: ${tmpl.uriTemplate}`)})\n${optionLines}\n .action(async function(opts) {\n try {\n var client = await getClient();\n var rawOpts = this.opts();\n var uri = ${JSON.stringify(tmpl.uriTemplate)};\n ${paramMapping}\n var result = await client.readResource(uri);\n var mode = program.opts().output || 'text';\n console.log(fmt.formatResourceResult(result, mode));\n } catch (err) {\n _exitWithError(err, 1);\n }\n });`;\n });\n\n return `var templateCmd = program.command('template').description('Resource template operations');\n\ntemplateCmd\n .command('list')\n .description('List available resource templates')\n .action(async function() {\n try {\n var client = await getClient();\n var result = await client.listResourceTemplates();\n var mode = program.opts().output || 'text';\n if (mode === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n var templates = result.resourceTemplates || [];\n if (templates.length === 0) { console.log('No resource templates available.'); return; }\n templates.forEach(function(t) {\n console.log(' ' + t.uriTemplate + (t.description ? ' - ' + t.description : ''));\n });\n }\n } catch (err) {\n _exitWithError(err, 1);\n }\n });\n\n${subcommands.join('\\n\\n')}`;\n}\n\nfunction generatePromptCommands(prompts: ExtractedPrompt[]): string {\n // Map known prompts → option specs so `prompt get <name>` knows which flags\n // to accept per prompt. Unknown prompt names still call getPrompt() and\n // surface the server's error to the user.\n const promptArgsMap = prompts.map((p) => {\n const args = (p.arguments || []).map((a) => ({\n name: a.name,\n kebab: camelToKebab(a.name),\n camel: kebabToCamel(camelToKebab(a.name)),\n required: !!a.required,\n }));\n return `${JSON.stringify(p.name)}: ${JSON.stringify(args)}`;\n }).join(',\\n ');\n\n const subcommands = prompts.map((prompt) => {\n const cmdName = camelToKebab(prompt.name).replace(/_/g, '-');\n const argOptions = (prompt.arguments || [])\n .map((a) => {\n const flag = `--${camelToKebab(a.name)} <value>`;\n const desc = a.description || '';\n return a.required\n ? ` .requiredOption('${flag}', '${escapeStr(desc)}')`\n : ` .option('${flag}', '${escapeStr(desc)}')`;\n })\n .join('\\n');\n\n return `promptCmd\n .command(${JSON.stringify(cmdName)})\n .description(${JSON.stringify((prompt.description || '') + ' (deprecated alias — use `prompt get ' + cmdName + '`)')})\n${argOptions}\n .action(async function(opts) {\n try {\n var client = await getClient();\n var args = {};\n var rawOpts = this.opts();\n ${(prompt.arguments || []).map((a) => {\n const camel = kebabToCamel(camelToKebab(a.name));\n return `if (rawOpts[${JSON.stringify(camel)}] !== undefined) args[${JSON.stringify(a.name)}] = rawOpts[${JSON.stringify(camel)}];`;\n }).join('\\n ')}\n var result = await client.getPrompt(${JSON.stringify(prompt.name)}, args);\n var mode = program.opts().output || 'text';\n console.log(fmt.formatPromptResult(result, mode));\n } catch (err) {\n _exitWithError(err, 1);\n }\n });`;\n });\n\n return `var promptCmd = program.command('prompt').description('Prompt operations');\n\npromptCmd\n .command('list')\n .description('List available prompts')\n .action(async function() {\n try {\n var client = await getClient();\n var result = await client.listPrompts();\n var mode = program.opts().output || 'text';\n if (mode === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n var prompts = result.prompts || [];\n if (prompts.length === 0) { console.log('No prompts available.'); return; }\n prompts.forEach(function(p) {\n console.log(' ' + p.name + (p.description ? ' - ' + p.description : ''));\n });\n }\n } catch (err) {\n _exitWithError(err, 1);\n }\n });\n\n// Symmetric \\`prompt get <name>\\` to mirror \\`resource read <uri>\\`. Looks up\n// per-prompt argument metadata from \\`promptArgs\\` and forwards as MCP\n// \\`prompts/get\\` request arguments. Unknown / missing required flags exit 2.\n//\n// Robust flag parser supports:\n// --key value (canonical form)\n// --key=value (single-token form)\n// --bool (boolean — value defaults to \"true\")\n// -- (end-of-options marker; everything after is ignored)\n// Unknown flags fail-fast with exit 2 instead of being silently dropped.\nvar promptArgs = {\n ${promptArgsMap}\n };\nvar _getCmd = promptCmd\n .command('get <name>')\n .description('Render a prompt by name')\n .allowUnknownOption(true)\n .action(async function(name) {\n try {\n var spec = promptArgs[name];\n if (!spec) {\n console.error('Error: Unknown prompt: ' + name);\n process.exitCode = 1;\n return;\n }\n var rawTokens = this.args.slice(1);\n var args = {};\n var unknown = [];\n var byKebab = {};\n for (var s = 0; s < spec.length; s++) byKebab[spec[s].kebab] = spec[s];\n for (var i = 0; i < rawTokens.length; i++) {\n var tok = rawTokens[i];\n if (tok === '--') break;\n if (typeof tok !== 'string' || tok.indexOf('--') !== 0) continue;\n var keyAndVal = tok.slice(2);\n var key, val;\n var eq = keyAndVal.indexOf('=');\n if (eq >= 0) {\n key = keyAndVal.slice(0, eq);\n val = keyAndVal.slice(eq + 1);\n } else {\n key = keyAndVal;\n var next = (i + 1 < rawTokens.length) ? rawTokens[i + 1] : undefined;\n if (typeof next === 'string' && next.indexOf('--') !== 0) {\n val = next;\n i++;\n } else {\n val = 'true';\n }\n }\n var match = byKebab[key];\n if (!match) { unknown.push('--' + key); continue; }\n args[match.name] = val;\n }\n if (unknown.length > 0) {\n console.error('Error: unknown option(s) for prompt \"' + name + '\": ' + unknown.join(', '));\n process.exitCode = 2;\n return;\n }\n // Validate required args\n for (var r = 0; r < spec.length; r++) {\n if (spec[r].required && args[spec[r].name] === undefined) {\n console.error('Error: missing required option --' + spec[r].kebab);\n process.exitCode = 2;\n return;\n }\n }\n var client = await getClient();\n var result = await client.getPrompt(name, args);\n var mode = program.opts().output || 'text';\n console.log(fmt.formatPromptResult(result, mode));\n } catch (err) {\n _exitWithError(err, 1);\n }\n });\n\n${subcommands.join('\\n\\n')}`;\n}\n\nfunction generateSkillsCommands(): string {\n return `var skillsCmd = program.command('skills').description('Skill operations');\n\nskillsCmd\n .command('search [query]')\n .description('Search for skills')\n .action(async function(query) {\n try {\n var client = await getClient();\n var result = await client.searchSkills(query || '');\n var mode = program.opts().output || 'text';\n if (mode === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n var skills = result.skills || [];\n if (skills.length === 0) { console.log('No skills found.'); return; }\n console.log('\\\\n Skills matching \"' + (query || '') + '\":\\\\n');\n skills.forEach(function(s) {\n var tags = (s.tags || []).slice(0, 3).join(', ');\n var score = s.score != null ? ' [score: ' + Number(s.score).toFixed(2) + ']' : '';\n console.log(' ' + (s.name || s.id) + score);\n if (s.description) console.log(' ' + s.description.split('. Use when')[0]);\n if (tags) console.log(' tags: ' + tags);\n console.log('');\n });\n console.log(' ' + skills.length + ' result(s).');\n console.log(\" Use '\" + program.name() + \" skills read <name>' for full details.\");\n console.log(\" Use '\" + program.name() + \" skills load <name>' to load a skill.\\\\n\");\n }\n } catch (err) {\n _exitWithError(err, 1);\n }\n });\n\nskillsCmd\n .command('load <ids...>')\n .description('Load skills by ID')\n .action(async function(ids) {\n try {\n var client = await getClient();\n var result = await client.loadSkills(ids);\n var mode = program.opts().output || 'text';\n if (mode === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n console.log('Loaded ' + ids.length + ' skill(s).');\n if (result && typeof result === 'object') {\n console.log(JSON.stringify(result, null, 2));\n }\n }\n } catch (err) {\n _exitWithError(err, 1);\n }\n });\n\nskillsCmd\n .command('read <name>')\n .description('Read full details for a skill')\n .action(async function(name) {\n try {\n var client = await getClient();\n var result = await client.loadSkills([name]);\n var mode = program.opts().output || 'text';\n if (mode === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n var skills = result.skills || [];\n if (skills.length === 0) { console.log('Skill \"' + name + '\" not found.'); return; }\n var sk = skills[0];\n console.log('\\\\n ' + sk.name);\n if (sk.description) console.log(' ' + sk.description);\n console.log('');\n if (sk.instructions) {\n console.log(sk.instructions);\n console.log('');\n }\n if (sk.tools && sk.tools.length > 0) {\n console.log(' Tools (' + sk.tools.length + '):');\n sk.tools.forEach(function(t) {\n console.log(' ' + t.name + (t.available ? '' : ' (unavailable)'));\n });\n console.log('');\n }\n if (result.nextSteps) console.log(' ' + result.nextSteps);\n console.log(\" Load: \" + program.name() + \" skills load \" + name + '\\\\n');\n }\n } catch (err) {\n _exitWithError(err, 1);\n }\n });\n\nskillsCmd\n .command('list')\n .description('List available skills')\n .action(async function() {\n try {\n var client = await getClient();\n var result = await client.listSkills();\n var mode = program.opts().output || 'text';\n if (mode === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n var skills = result.skills || [];\n if (skills.length === 0) { console.log('No skills available.'); return; }\n console.log('\\\\n Available Skills (' + skills.length + '):\\\\n');\n skills.forEach(function(s) {\n var desc = s.description ? s.description.split('. Use when')[0] : '';\n console.log(' ' + (s.name || s.id));\n if (desc) console.log(' ' + desc);\n console.log('');\n });\n console.log(\" Use '\" + program.name() + \" skills search <query>' for semantic search.\");\n console.log(\" Use '\" + program.name() + \" skills read <name>' for full details.\\\\n\");\n }\n } catch (err) {\n _exitWithError(err, 1);\n }\n });`;\n}\n\nfunction generateJobCommands(jobs: ExtractedJob[]): string {\n // Generate typed 'run' subcommands for each known job\n const runSubcommands = jobs.map((job) => {\n const jobCmdName = camelToKebab(job.name).replace(/_/g, '-');\n\n if (job.inputSchema) {\n const { options } = schemaToCommander(job.inputSchema);\n const optionLines = options.map((o) => ` ${generateOptionCode(o)}`).join('\\n');\n const argMapping = generateJobArgMapping(job.inputSchema);\n\n return `jobRunCmd\n .command(${JSON.stringify(jobCmdName)})\n .description(${JSON.stringify(job.description || `Run the ${job.name} job`)})\n${optionLines}\n .option('--background', 'Run in background mode')\n .action(async function(opts) {\n try {\n var client = await getClient();\n var input = {};\n var rawOpts = this.opts();\n ${argMapping}\n var result = await client.executeJob(${JSON.stringify(job.name)}, input, { background: !!rawOpts.background });\n var mode = program.opts().output || 'text';\n if (mode === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n if (rawOpts.background && result && result.runId) {\n console.log('Job started. Run ID: ' + result.runId);\n } else {\n console.log(JSON.stringify(result, null, 2));\n }\n }\n } catch (err) {\n _exitWithError(err, 1);\n }\n });`;\n }\n\n // No inputSchema — fall back to generic --input <json>\n return `jobRunCmd\n .command(${JSON.stringify(jobCmdName)})\n .description(${JSON.stringify(job.description || `Run the ${job.name} job`)})\n .option('--input <json>', 'Job input as JSON string')\n .option('--background', 'Run in background mode')\n .action(async function(opts) {\n try {\n var client = await getClient();\n var input = {};\n if (opts.input) {\n try { input = JSON.parse(opts.input); }\n catch (_) { console.error('Invalid JSON for --input'); process.exitCode = 1; return; }\n }\n var result = await client.executeJob(${JSON.stringify(job.name)}, input, { background: !!opts.background });\n var mode = program.opts().output || 'text';\n if (mode === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n if (opts.background && result && result.runId) {\n console.log('Job started. Run ID: ' + result.runId);\n } else {\n console.log(JSON.stringify(result, null, 2));\n }\n }\n } catch (err) {\n _exitWithError(err, 1);\n }\n });`;\n });\n\n // Generic fallback 'run' for jobs not known at build time\n const genericRun = `jobRunCmd\n .command('_run <name>')\n .description('Run a job by name (generic)')\n .option('--input <json>', 'Job input as JSON string')\n .option('--background', 'Run in background mode')\n .action(async function(name, opts) {\n try {\n var client = await getClient();\n var input = {};\n if (opts.input) {\n try { input = JSON.parse(opts.input); }\n catch (_) { console.error('Invalid JSON for --input'); process.exitCode = 1; return; }\n }\n var result = await client.executeJob(name, input, { background: !!opts.background });\n var mode = program.opts().output || 'text';\n if (mode === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n if (opts.background && result && result.runId) {\n console.log('Job started. Run ID: ' + result.runId);\n } else {\n console.log(JSON.stringify(result, null, 2));\n }\n }\n } catch (err) {\n _exitWithError(err, 1);\n }\n });`;\n\n return `var jobCmd = program.command('job').description('Job operations');\n\njobCmd\n .command('list')\n .description('List available jobs')\n .action(async function() {\n try {\n var client = await getClient();\n var result = await client.listJobs();\n var mode = program.opts().output || 'text';\n if (mode === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n var jobs = result.jobs || result || [];\n if (Array.isArray(jobs) && jobs.length === 0) { console.log('No jobs available.'); return; }\n if (Array.isArray(jobs)) {\n jobs.forEach(function(j) {\n console.log(' ' + (j.name || j.id || JSON.stringify(j)));\n });\n } else {\n console.log(JSON.stringify(result, null, 2));\n }\n }\n } catch (err) {\n _exitWithError(err, 1);\n }\n });\n\nvar jobRunCmd = jobCmd.command('run').description('Run a job');\n\n${runSubcommands.join('\\n\\n')}\n\n${jobs.length > 0 ? genericRun : `jobRunCmd\n .argument('<name>', 'Job name')\n .option('--input <json>', 'Job input as JSON string')\n .option('--background', 'Run in background mode')\n .action(async function(name, opts) {\n try {\n var client = await getClient();\n var input = {};\n if (opts.input) {\n try { input = JSON.parse(opts.input); }\n catch (_) { console.error('Invalid JSON for --input'); process.exitCode = 1; return; }\n }\n var result = await client.executeJob(name, input, { background: !!opts.background });\n var mode = program.opts().output || 'text';\n if (mode === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n if (opts.background && result && result.runId) {\n console.log('Job started. Run ID: ' + result.runId);\n } else {\n console.log(JSON.stringify(result, null, 2));\n }\n }\n } catch (err) {\n _exitWithError(err, 1);\n }\n });`}\n\njobCmd\n .command('status <runId>')\n .description('Get the status of a job run')\n .action(async function(runId) {\n try {\n var client = await getClient();\n var result = await client.getJobStatus(runId);\n var mode = program.opts().output || 'text';\n if (mode === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n console.log('Status: ' + (result.status || JSON.stringify(result)));\n }\n } catch (err) {\n _exitWithError(err, 1);\n }\n });`;\n}\n\nfunction generateWorkflowCommands(): string {\n return `var workflowCmd = program.command('workflow').description('Workflow operations');\n\nworkflowCmd\n .command('list')\n .description('List available workflows')\n .action(async function() {\n try {\n var client = await getClient();\n var result = await client.listWorkflows();\n var mode = program.opts().output || 'text';\n if (mode === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n var workflows = result.workflows || result || [];\n if (Array.isArray(workflows) && workflows.length === 0) { console.log('No workflows available.'); return; }\n if (Array.isArray(workflows)) {\n workflows.forEach(function(w) {\n console.log(' ' + (w.name || w.id || JSON.stringify(w)));\n });\n } else {\n console.log(JSON.stringify(result, null, 2));\n }\n }\n } catch (err) {\n _exitWithError(err, 1);\n }\n });\n\nworkflowCmd\n .command('run <name>')\n .description('Run a workflow by name')\n .option('--input <json>', 'Workflow input as JSON string')\n .option('--background', 'Run in background mode')\n .action(async function(name, opts) {\n try {\n var client = await getClient();\n var input = {};\n if (opts.input) {\n try { input = JSON.parse(opts.input); }\n catch (_) { console.error('Invalid JSON for --input'); process.exitCode = 1; return; }\n }\n var result = await client.executeWorkflow(name, input, { background: !!opts.background });\n var mode = program.opts().output || 'text';\n if (mode === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n if (opts.background && result && result.runId) {\n console.log('Workflow started. Run ID: ' + result.runId);\n } else {\n console.log(JSON.stringify(result, null, 2));\n }\n }\n } catch (err) {\n _exitWithError(err, 1);\n }\n });\n\nworkflowCmd\n .command('status <runId>')\n .description('Get the status of a workflow run')\n .action(async function(runId) {\n try {\n var client = await getClient();\n var result = await client.getWorkflowStatus(runId);\n var mode = program.opts().output || 'text';\n if (mode === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n console.log('Status: ' + (result.status || JSON.stringify(result)));\n }\n } catch (err) {\n _exitWithError(err, 1);\n }\n });`;\n}\n\nfunction generateSubscribeCommands(): string {\n return `\n// Subscribe commands need push support (onNotification/onResourceUpdated).\n// Daemon HTTP cannot push, so we force in-process when daemon was used.\nasync function getSubscribeClient() {\n var client = await getClient();\n // If connected via daemon, the onNotification/onResourceUpdated are no-ops.\n // Reconnect via in-process for push support.\n if (client._isDaemon) {\n // Close the daemon client before replacing with in-process client\n if (typeof client.close === 'function') { try { await client.close(); } catch (_) {} }\n _client = null;\n var mod = require(SERVER_BUNDLE);\n var configOrClass = mod.default || mod;\n var sdk = require('@frontmcp/sdk');\n var connect = sdk.connect || sdk.direct.connect;\n _client = await connect(configOrClass, { mode: 'cli' });\n return _client;\n }\n return client;\n}\n\nvar subscribeCmd = program.command('subscribe').description('Subscribe to updates');\n\nsubscribeCmd\n .command('resource <uri>')\n .description('Stream resource updates (Ctrl+C to stop)')\n .action(async function(uri) {\n try {\n var client = await getSubscribeClient();\n await client.subscribeResource(uri);\n var mode = program.opts().output || 'text';\n console.log('Subscribed to resource: ' + uri);\n console.log('Waiting for updates... (Ctrl+C to stop)\\\\n');\n client.onResourceUpdated(function(uri) {\n console.log(fmt.formatSubscriptionEvent({ type: 'resource_updated', uri: uri, timestamp: new Date().toISOString() }, mode));\n });\n process.on('SIGINT', async function() {\n console.log('\\\\nUnsubscribing...');\n try { await client.unsubscribeResource(uri); } catch (_) { /* ok */ }\n await closeClient();\n process.exit(0);\n });\n // Keep process alive — setInterval creates an active event loop handle\n // so Node.js won't exit even with InMemoryTransport (no persistent I/O)\n setInterval(function() {}, 2147483647);\n await new Promise(function() {});\n } catch (err) {\n _exitWithError(err, 1);\n }\n });\n\nsubscribeCmd\n .command('notification <name>')\n .description('Stream notifications (Ctrl+C to stop)')\n .action(async function(name) {\n try {\n var client = await getSubscribeClient();\n var mode = program.opts().output || 'text';\n console.log('Listening for notification: ' + name);\n console.log('Waiting for events... (Ctrl+C to stop)\\\\n');\n client.onNotification(function(notification) {\n if (notification.method === name || name === '*') {\n console.log(fmt.formatSubscriptionEvent({ type: 'notification', method: notification.method, params: notification.params, timestamp: new Date().toISOString() }, mode));\n }\n });\n process.on('SIGINT', async function() {\n console.log('\\\\nStopping...');\n await closeClient();\n process.exit(0);\n });\n // Keep process alive — setInterval creates an active event loop handle\n // so Node.js won't exit even with InMemoryTransport (no persistent I/O)\n setInterval(function() {}, 2147483647);\n await new Promise(function() {});\n } catch (err) {\n _exitWithError(err, 1);\n }\n });`;\n}\n\nfunction generateLoginCommand(appName: string, oauthConfig?: OAuthConfig): string {\n const serverUrl = oauthConfig?.serverUrl || '';\n const clientId = oauthConfig?.clientId || appName;\n const defaultScope = oauthConfig?.defaultScope || '';\n const portStart = oauthConfig?.portRange?.[0] ?? 17830;\n const portEnd = oauthConfig?.portRange?.[1] ?? 17850;\n const timeout = oauthConfig?.timeout ?? 120000;\n\n return `program\n .command('login')\n .description('Authenticate via OAuth')\n .option('--server <url>', 'Server URL for OAuth'${serverUrl ? `, ${JSON.stringify(serverUrl)}` : ''})\n .option('--session <name>', 'Session name', 'default')\n .option('--scope <scopes>', 'OAuth scopes'${defaultScope ? `, ${JSON.stringify(defaultScope)}` : ''})\n .option('--no-browser', 'Print URL instead of opening browser')\n .action(async function(opts) {\n var serverUrl = opts.server || process.env.FRONTMCP_SERVER_URL || ${JSON.stringify(serverUrl)};\n if (!serverUrl) {\n console.error('Server URL required. Use --server <url> or set FRONTMCP_SERVER_URL.');\n process.exitCode = 1;\n return;\n }\n try {\n var oauthHelper = require('./oauth-helper');\n var result = await oauthHelper.startOAuthLogin({\n serverUrl: serverUrl,\n clientId: ${JSON.stringify(clientId)},\n scope: opts.scope || ${JSON.stringify(defaultScope)},\n portStart: ${portStart},\n portEnd: ${portEnd},\n timeout: ${timeout},\n noBrowser: !opts.browser\n });\n var sessionName = opts.session || 'default';\n var store = creds.createCredentialStore();\n await store.set(sessionName, result);\n sessions.getOrCreateSession(sessionName);\n console.log('Logged in successfully. Session: ' + sessionName);\n } catch (err) {\n console.error('Login failed:', err.message || err);\n process.exitCode = 1;\n }\n });`;\n}\n\nfunction generateLogoutCommand(_appName: string): string {\n return `program\n .command('logout')\n .description('Clear stored credentials')\n .option('--session <name>', 'Session to log out')\n .option('--all', 'Log out of all sessions')\n .action(async function(opts) {\n var store = creds.createCredentialStore();\n if (opts.all) {\n var allSessions = await store.list();\n for (var i = 0; i < allSessions.length; i++) {\n await store.delete(allSessions[i]);\n }\n console.log('Logged out of ' + allSessions.length + ' session(s).');\n } else {\n var sessionName = opts.session || sessions.getActiveSessionName();\n await store.delete(sessionName);\n console.log('Logged out of session: ' + sessionName);\n }\n });`;\n}\n\nfunction generateSessionCommands(): string {\n return `var sessionsCmd = program.command('sessions').description('Session management');\n\nsessionsCmd\n .command('list')\n .description('List all sessions')\n .action(function() {\n var list = sessions.listSessions();\n if (list.length === 0) { console.log('No sessions.'); return; }\n list.forEach(function(s) {\n var marker = s.isActive ? ' (active)' : '';\n console.log(' ' + s.name + marker + ' - last used: ' + s.lastUsedAt);\n });\n });\n\nsessionsCmd\n .command('switch <name>')\n .description('Switch to a named session')\n .action(function(name) {\n sessions.switchSession(name);\n console.log('Switched to session: ' + name);\n });\n\nsessionsCmd\n .command('delete <name>')\n .description('Delete a session')\n .action(async function(name) {\n var store = creds.createCredentialStore();\n await store.delete(name);\n sessions.deleteSession(name);\n console.log('Deleted session: ' + name);\n });\n\nprogram\n .command('connect')\n .description('Authenticate and store credentials')\n .option('--session <name>', 'Session name', 'default')\n .option('--token <token>', 'Auth token (or pass via stdin)')\n .action(async function(opts) {\n var sessionName = opts.session || 'default';\n var token = opts.token;\n if (!token) {\n console.log('Usage: ' + program.name() + ' connect --token <your-token>');\n console.log(' Or pipe token: echo \"tok_xxx\" | ' + program.name() + ' connect');\n process.exitCode = 1;\n return;\n }\n var store = creds.createCredentialStore();\n await store.set(sessionName, { token: token });\n sessions.getOrCreateSession(sessionName);\n console.log('Credentials stored for session: ' + sessionName);\n });`;\n}\n\nfunction generateServeCommand(serverBundleFilename: string, selfContained?: boolean): string {\n // In self-contained/SEA mode, use a static relative require that esbuild can resolve at bundle time.\n // In normal mode, use dynamic path.join for runtime resolution from disk.\n const requireExpr = selfContained\n ? `require(${JSON.stringify('../' + serverBundleFilename)})`\n : `require(path.join(SCRIPT_DIR, ${JSON.stringify(serverBundleFilename)}))`;\n\n return `program\n .command('serve')\n .description('Start the MCP server')\n .option('-p, --port <port>', 'Port number', function(v) { return parseInt(v, 10); })\n .option('--stdio', 'Run as stdio transport (stdin/stdout JSON-RPC) for use in .mcp.json')\n .action(async function(opts) {\n if (opts.stdio) {\n // --stdio on serve is handled by the early argv check at the top of the entry;\n // this branch is a fallback in case commander parsed it first.\n _isLongRunning = true;\n process.env.FRONTMCP_SCHEMA_EXTRACT = '1';\n var sMod = ${requireExpr};\n delete process.env.FRONTMCP_SCHEMA_EXTRACT;\n var sRaw = sMod.default || sMod;\n var sSdk = require('@frontmcp/sdk');\n var sFMI = sSdk.FrontMcpInstance || sSdk.default.FrontMcpInstance;\n var sCfg = (typeof sRaw === 'function' && typeof Reflect !== 'undefined' && Reflect.getMetadata)\n ? (Reflect.getMetadata('__frontmcp:config', sRaw) || sRaw) : sRaw;\n await sFMI.runStdio(sCfg);\n return;\n }\n _isLongRunning = true;\n // Suppress @FrontMcp decorator auto-bootstrap during require() — the CLI\n // serve command handles bootstrap explicitly below with port/config overrides.\n process.env.FRONTMCP_SCHEMA_EXTRACT = '1';\n var mod = ${requireExpr};\n delete process.env.FRONTMCP_SCHEMA_EXTRACT;\n if (opts.port) process.env.PORT = String(opts.port);\n // If the bundle exports a start() function (@FrontMcp-decorated class auto-bootstraps), use it\n if (typeof mod.start === 'function') { await mod.start(); return; }\n if (typeof mod.default?.start === 'function') { await mod.default.start(); return; }\n // Otherwise, bootstrap the plain config object via FrontMcpInstance\n var raw = mod.default || mod;\n var sdk = require('@frontmcp/sdk');\n var FrontMcpInstance = sdk.FrontMcpInstance || sdk.default.FrontMcpInstance;\n var config = (typeof raw === 'function' && typeof Reflect !== 'undefined' && Reflect.getMetadata)\n ? (Reflect.getMetadata('__frontmcp:config', raw) || raw) : raw;\n if (opts.port) config = Object.assign({}, config, { http: Object.assign({}, config.http || {}, { port: opts.port }) });\n await FrontMcpInstance.bootstrap(config);\n });`;\n}\n\nfunction generateDoctorCommand(\n appName: string,\n nativeDeps: NonNullable<CliConfig['nativeDeps']>,\n): string {\n const checks: string[] = [];\n\n if (nativeDeps.brew?.length) {\n for (const pkg of nativeDeps.brew) {\n checks.push(` { name: ${JSON.stringify(pkg)}, type: 'brew', check: 'brew list ${pkg}' }`);\n }\n }\n if (nativeDeps.apt?.length) {\n for (const pkg of nativeDeps.apt) {\n checks.push(` { name: ${JSON.stringify(pkg)}, type: 'apt', check: 'dpkg -l ${pkg}' }`);\n }\n }\n if (nativeDeps.npm?.length) {\n for (const pkg of nativeDeps.npm) {\n checks.push(` { name: ${JSON.stringify(pkg)}, type: 'npm', check: 'npm ls ${pkg}' }`);\n }\n }\n\n return `program\n .command('doctor')\n .description('Check system dependencies and configuration')\n .option('--fix', 'Attempt to install missing dependencies')\n .action(async function(opts) {\n var exec = require('child_process').execSync;\n var ok = true;\n\n // Check Node.js version\n var nodeMajor = parseInt(process.versions.node.split('.')[0], 10);\n if (nodeMajor >= 22) {\n console.log(' [ok] Node.js v' + process.versions.node);\n } else {\n console.log(' [!!] Node.js v' + process.versions.node + ' (>=22 required)');\n ok = false;\n }\n\n var deps = [\n${checks.join(',\\n')}\n ];\n\n for (var i = 0; i < deps.length; i++) {\n var dep = deps[i];\n try {\n exec(dep.check, { stdio: 'ignore' });\n console.log(' [ok] ' + dep.name + ' (' + dep.type + ')');\n } catch (_) {\n console.log(' [!!] ' + dep.name + ' (' + dep.type + ') - not found');\n ok = false;\n if (opts.fix) {\n try {\n var installCmd = dep.type === 'brew' ? 'brew install ' + dep.name\n : dep.type === 'apt' ? 'sudo apt-get install -y ' + dep.name\n : 'npm install ' + dep.name;\n console.log(' Installing: ' + installCmd);\n exec(installCmd, { stdio: 'inherit' });\n console.log(' [ok] Installed ' + dep.name);\n } catch (e) {\n console.log(' [!!] Failed to install ' + dep.name);\n }\n }\n }\n }\n\n // Check FRONTMCP_HOME directory\n var fs = require('fs');\n var appDir = require('path').join(FRONTMCP_HOME, 'apps', ${JSON.stringify(appName)});\n if (fs.existsSync(appDir)) {\n console.log(' [ok] App directory: ' + appDir);\n } else {\n console.log(' [!!] App directory not found: ' + appDir);\n ok = false;\n if (opts.fix) {\n fs.mkdirSync(appDir, { recursive: true });\n console.log(' [fixed] Created ' + appDir);\n }\n }\n\n if (ok) console.log('\\\\nAll checks passed.');\n else {\n console.log('\\\\nSome checks failed.' + (opts.fix ? '' : ' Run with --fix to attempt repairs.'));\n process.exitCode = 1;\n }\n });`;\n}\n\nfunction generateInstallCommand(\n appName: string,\n nativeDeps: NonNullable<CliConfig['nativeDeps']>,\n selfContained?: boolean,\n): string {\n const depEntries: string[] = [];\n if (nativeDeps.brew?.length) {\n for (const pkg of nativeDeps.brew) {\n depEntries.push(` { name: ${JSON.stringify(pkg)}, type: 'brew', install: 'brew install ${pkg}', check: 'brew list ${pkg}' }`);\n }\n }\n if (nativeDeps.npm?.length) {\n for (const pkg of nativeDeps.npm) {\n depEntries.push(` { name: ${JSON.stringify(pkg)}, type: 'npm', install: 'npm install ${pkg}', check: 'npm ls ${pkg}' }`);\n }\n }\n\n return `program\n .command('install')\n .description('Install to ~/.frontmcp/ and set up dependencies')\n .option('--prefix <path>', 'Installation prefix directory')\n .option('--bin-dir <path>', 'Directory for symlink (default: ~/.local/bin or /usr/local/bin)')\n .action(async function(opts) {\n var fs = require('fs');\n var pathMod = require('path');\n var os = require('os');\n var exec = require('child_process').execSync;\n var installBase = opts.prefix || FRONTMCP_HOME;\n var appDir = pathMod.join(installBase, 'apps', ${JSON.stringify(appName)});\n var dirs = ['', '/data', '/sessions', '/credentials'].map(function(s) { return appDir + s; });\n\n console.log('Installing ${appName}...');\n dirs.forEach(function(d) { fs.mkdirSync(d, { recursive: true }); });\n\n // Copy bundle files and skill content\n var files = fs.readdirSync(SCRIPT_DIR).filter(function(f) {\n return f.endsWith('.js') || f.endsWith('.json') || f.endsWith('.md')${selfContained ? \" || f.endsWith('-bin')\" : ''};\n });\n files.forEach(function(f) {\n fs.copyFileSync(pathMod.join(SCRIPT_DIR, f), pathMod.join(appDir, f));\n });\n // Copy skill content directories (only those that exist in the build output)\n var entries = fs.readdirSync(SCRIPT_DIR, { withFileTypes: true });\n entries.forEach(function(ent) {\n if (ent.isDirectory()) {\n fs.cpSync(pathMod.join(SCRIPT_DIR, ent.name), pathMod.join(appDir, ent.name), { recursive: true });\n }\n });\n console.log(' Copied ' + files.length + ' files to ' + appDir);\n\n // Install native deps\n var deps = [\n${depEntries.join(',\\n')}\n ];\n for (var i = 0; i < deps.length; i++) {\n var dep = deps[i];\n try { exec(dep.check, { stdio: 'ignore' }); }\n catch (_) {\n console.log(' [' + (i + 1) + '/' + deps.length + '] Installing ' + dep.name + ' via ' + dep.type + '...');\n try { exec(dep.install, { stdio: 'inherit' }); }\n catch (e) { console.log(' Warning: Failed to install ' + dep.name); }\n }\n }\n\n // Set execute permission on the entry point\n var entryFile = pathMod.join(appDir, ${JSON.stringify(selfContained ? `${appName}-cli-bin` : `${appName}-cli.bundle.js`)});\n try { fs.chmodSync(entryFile, 0o755); } catch (_) { /* ok */ }\n\n // Create symlink\n var binDirs = opts.binDir ? [opts.binDir] : ['/usr/local/bin', pathMod.join(os.homedir(), '.local', 'bin')];\n var linked = false;\n for (var j = 0; j < binDirs.length && !linked; j++) {\n try {\n fs.mkdirSync(binDirs[j], { recursive: true });\n var linkPath = pathMod.join(binDirs[j], ${JSON.stringify(appName)});\n try { fs.unlinkSync(linkPath); } catch (_) { /* ok */ }\n fs.symlinkSync(entryFile, linkPath);\n console.log(' Symlinked: ' + linkPath);\n linked = true;\n } catch (_) { /* try next */ }\n }\n\n console.log('\\\\nInstalled. Run: ${appName} --help');\n });\n\nprogram\n .command('uninstall')\n .description('Remove from ~/.frontmcp/ and clean up')\n .option('--prefix <path>', 'Installation prefix directory')\n .option('--bin-dir <path>', 'Directory where symlink was created')\n .action(async function(opts) {\n var fs = require('fs');\n var pathMod = require('path');\n var os = require('os');\n var uninstallBase = opts.prefix || FRONTMCP_HOME;\n var appDir = pathMod.join(uninstallBase, 'apps', ${JSON.stringify(appName)});\n\n // Remove credentials (if auth is enabled)\n if (typeof creds !== 'undefined') {\n var store = creds.createCredentialStore();\n var credSessions = await store.list();\n for (var i = 0; i < credSessions.length; i++) {\n await store.delete(credSessions[i]);\n }\n }\n\n // Remove symlink\n var binDirs = opts.binDir ? [opts.binDir] : ['/usr/local/bin', pathMod.join(os.homedir(), '.local', 'bin')];\n binDirs.forEach(function(d) {\n try { fs.unlinkSync(pathMod.join(d, ${JSON.stringify(appName)})); } catch (_) { /* ok */ }\n });\n\n // Remove app directory\n fs.rmSync(appDir, { recursive: true, force: true });\n console.log('Uninstalled ${appName}.');\n });`;\n}\n\nfunction generateDaemonCommands(appName: string, serverBundleFilename: string, selfContained?: boolean): string {\n return `var daemonCmd = program.command('daemon').description('Daemon management');\n\ndaemonCmd\n .command('start')\n .description('Start as a background daemon')\n .option('-p, --port <port>', 'Listen on a TCP port instead of a Unix socket', function(v) { return parseInt(v, 10); })\n .option('--idle-timeout <ms>', 'Auto-stop after idle period (ms, 0 to disable)', function(v) { return parseInt(v, 10); }, 300000)\n .action(async function(opts) {\n var { spawn } = require('child_process');\n var pathMod = require('path');\n var pidDir = pathMod.join(FRONTMCP_HOME, 'pids');\n var logDir = pathMod.join(FRONTMCP_HOME, 'logs');\n var socketDir = pathMod.join(FRONTMCP_HOME, 'sockets');\n fs.mkdirSync(pidDir, { recursive: true });\n fs.mkdirSync(logDir, { recursive: true });\n fs.mkdirSync(socketDir, { recursive: true });\n\n var usePort = !!opts.port;\n var socketPath = pathMod.join(socketDir, ${JSON.stringify(appName)} + '.sock');\n\n // Clean up stale socket file (only relevant in socket mode)\n if (!usePort) { try { fs.unlinkSync(socketPath); } catch (_) { /* ok */ } }\n\n // Check if already running\n var pidPath = pathMod.join(pidDir, ${JSON.stringify(appName)} + '.pid');\n try {\n var existing = JSON.parse(fs.readFileSync(pidPath, 'utf8'));\n process.kill(existing.pid, 0);\n console.log('Daemon already running (PID: ' + existing.pid + ').');\n return;\n } catch (_) { /* not running, proceed */ }\n\n var env = Object.assign({}, process.env, {\n FRONTMCP_DAEMON_IDLE_TIMEOUT: String(opts.idleTimeout)\n });\n if (usePort) {\n env.FRONTMCP_DAEMON_PORT = String(opts.port);\n } else {\n env.FRONTMCP_DAEMON_SOCKET = socketPath;\n }\n\n var logPath = pathMod.join(logDir, ${JSON.stringify(appName)} + '.log');\n var out = fs.openSync(logPath, 'a');\n var err = fs.openSync(logPath, 'a');\n\n${selfContained ? ` // SEA mode: spawn the binary itself in daemon mode — all code is inlined\n env.__FRONTMCP_DAEMON_MODE = '1';\n var child = spawn(process.execPath, [], {\n detached: true,\n stdio: ['ignore', out, err],\n env: env\n });` : ` // Start the daemon via a small wrapper script\n // Always use absolute path for the server bundle (SCRIPT_DIR resolves to __dirname at runtime)\n var serverBundlePath = pathMod.join(SCRIPT_DIR, ${JSON.stringify(serverBundleFilename)});\n var daemonScript = 'require(\"reflect-metadata\");' +\n 'process.env.FRONTMCP_SCHEMA_EXTRACT=\"1\";' +\n 'var mod = require(' + JSON.stringify(serverBundlePath) + ');' +\n 'delete process.env.FRONTMCP_SCHEMA_EXTRACT;' +\n 'var sdk = require(\"@frontmcp/sdk\");' +\n 'var FrontMcpInstance = sdk.FrontMcpInstance || sdk.default.FrontMcpInstance;' +\n 'var raw = mod.default || mod;' +\n ${'// If the export is a @FrontMcp-decorated class, extract config via Reflect metadata'}\n 'var config = (typeof raw === \"function\" && typeof Reflect !== \"undefined\" && Reflect.getMetadata) ' +\n ' ? (Reflect.getMetadata(\"__frontmcp:config\", raw) || raw) : raw;';\n\n if (usePort) {\n daemonScript +=\n 'config = Object.assign({}, config, { http: Object.assign({}, config.http || {}, { port: ' + opts.port + ' }) });' +\n 'process.env.PORT = ' + JSON.stringify(String(opts.port)) + ';' +\n 'FrontMcpInstance.bootstrap(config)' +\n '.then(function() { console.log(\"Daemon listening on port ' + opts.port + '\"); })' +\n '.catch(function(e) { console.error(\"Daemon failed:\", e); process.exit(1); });';\n } else {\n daemonScript +=\n 'FrontMcpInstance.runUnixSocket(Object.assign({}, config, { socketPath: ' + JSON.stringify(socketPath) + ' }))' +\n '.then(function() { console.log(\"Daemon listening on \" + ' + JSON.stringify(socketPath) + '); })' +\n '.catch(function(e) { console.error(\"Daemon failed:\", e); process.exit(1); });';\n }\n\n var child = spawn('node', ['-e', daemonScript], {\n detached: true,\n stdio: ['ignore', out, err],\n env: env\n });`}\n\n // Close inherited file descriptors in the parent — the child already has its own copy.\n fs.closeSync(out);\n fs.closeSync(err);\n\n var pidData = { pid: child.pid, startedAt: new Date().toISOString() };\n if (usePort) {\n pidData.port = opts.port;\n } else {\n pidData.socketPath = socketPath;\n }\n fs.writeFileSync(pidPath, JSON.stringify(pidData));\n child.unref();\n\n if (usePort) {\n // For port mode, wait briefly then check if process is still alive\n await new Promise(function(r) { setTimeout(r, 1000); });\n try {\n process.kill(child.pid, 0);\n console.log('Daemon started (PID: ' + child.pid + '). Port: ' + opts.port);\n console.log('Logs: ' + logPath);\n } catch (_) {\n console.log('Daemon failed to start. Check logs: ' + logPath);\n }\n } else {\n // Wait for socket file to appear (max 5s)\n var waited = 0;\n while (!fs.existsSync(socketPath) && waited < 5000) {\n await new Promise(function(r) { setTimeout(r, 100); });\n waited += 100;\n }\n\n if (fs.existsSync(socketPath)) {\n console.log('Daemon started (PID: ' + child.pid + '). Socket: ' + socketPath);\n console.log('Logs: ' + logPath);\n } else {\n console.log('Daemon started (PID: ' + child.pid + ') but socket not yet available.');\n console.log('Check logs: ' + logPath);\n }\n }\n });\n\ndaemonCmd\n .command('stop')\n .description('Stop the daemon')\n .action(function() {\n var pathMod = require('path');\n var pidPath = pathMod.join(FRONTMCP_HOME, 'pids', ${JSON.stringify(appName)} + '.pid');\n try {\n var data = JSON.parse(fs.readFileSync(pidPath, 'utf8'));\n process.kill(data.pid, 'SIGTERM');\n fs.unlinkSync(pidPath);\n // Clean up socket file\n if (data.socketPath) {\n try { fs.unlinkSync(data.socketPath); } catch (_) { /* ok */ }\n }\n console.log('Daemon stopped (PID: ' + data.pid + ').');\n } catch (e) {\n console.log('No running daemon found.');\n }\n });\n\ndaemonCmd\n .command('status')\n .description('Check daemon status')\n .action(function() {\n var pathMod = require('path');\n var pidPath = pathMod.join(FRONTMCP_HOME, 'pids', ${JSON.stringify(appName)} + '.pid');\n try {\n var data = JSON.parse(fs.readFileSync(pidPath, 'utf8'));\n try {\n process.kill(data.pid, 0);\n var listenInfo = data.port ? ', port: ' + data.port : (data.socketPath && fs.existsSync(data.socketPath) ? ', socket: active' : '');\n console.log('Running (PID: ' + data.pid + ', started: ' + data.startedAt + listenInfo + ')');\n } catch (_) {\n console.log('Not running (stale PID file).');\n fs.unlinkSync(pidPath);\n }\n } catch (_) { console.log('Not running.'); }\n });\n\ndaemonCmd\n .command('logs')\n .description('Tail daemon logs')\n .option('-n, --lines <n>', 'Number of lines', function(v) { return parseInt(v, 10); }, 50)\n .action(function(opts) {\n var pathMod = require('path');\n var logPath = pathMod.join(FRONTMCP_HOME, 'logs', ${JSON.stringify(appName)} + '.log');\n try {\n var content = fs.readFileSync(logPath, 'utf8');\n var lines = content.split('\\\\n');\n var start = Math.max(0, lines.length - opts.lines);\n console.log(lines.slice(start).join('\\\\n'));\n } catch (_) { console.log('No logs found.'); }\n });`;\n}\n\nfunction generateFooter(): string {\n return `program.on('command:*', function(args) {\n console.error('Unknown command: ' + args[0]);\n process.exitCode = 1;\n});\nprogram.parseAsync(process.argv).then(async function() {\n // Long-running commands (serve) set _isLongRunning to keep the event loop alive.\n // Short-lived commands close the client and exit explicitly to avoid hanging\n // on unclosed handles (file loggers, in-memory transport, etc.).\n if (_isLongRunning) return;\n await closeClient();\n // Defer process.exit() by one event-loop tick so native addon destructors\n // (ONNX runtime, etc.) can release mutexes before V8 tears down.\n setImmediate(function() { process.exit(process.exitCode || 0); });\n}).catch(async function(err) {\n // Commander errors come through exitOverride with the code already set on\n // process.exitCode. They are user-facing usage errors, not fatals — don't\n // re-print \"Fatal:\" / \"Unknown error\" for them.\n var isCommanderErr = err && typeof err.code === 'string' && err.code.indexOf('commander.') === 0;\n if (!isCommanderErr) {\n console.error('Fatal:', err.message || err);\n }\n await closeClient();\n // Use the exit code set by exitOverride (which can legitimately be 0 for\n // --help / --version). Only fall back to 1 when no code was set.\n setImmediate(function() {\n var code = (typeof process.exitCode === 'number') ? process.exitCode : 1;\n process.exit(code);\n });\n});`;\n}\n\n/**\n * Extract {param} placeholders from a URI template string.\n */\nexport function extractTemplateParams(uriTemplate: string): string[] {\n const matches = uriTemplate.match(/\\{([^}]+)\\}/g);\n if (!matches) return [];\n return matches.map((m) => m.slice(1, -1));\n}\n\nfunction kebabToCamel(str: string): string {\n return str.replace(/-([a-z])/g, (_, c) => c.toUpperCase());\n}\n\nfunction escapeStr(s: string): string {\n return s.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n}\n"]}
|
|
1
|
+
{"version":3,"file":"generate-cli-entry.js","sourceRoot":"","sources":["../../../../../../src/commands/build/exec/cli-runtime/generate-cli-entry.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAoCH,wDAMC;AAKD,4CA4CC;AA+oDD,sDAIC;AA3uDD,qFAAkF;AAClF,yDAAsM;AACtM,+DAA4F;AAE/E,QAAA,iBAAiB,GAAG,IAAI,GAAG,CAAC;IACvC,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,WAAW;IAC7C,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ;IAC/C,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS;IAC/D,QAAQ,EAAE,KAAK,EAAE,UAAU;IAC3B,wEAAwE;IACxE,mEAAmE;IACnE,KAAK,EAAE,MAAM,EAAE,MAAM;CACtB,CAAC,CAAC;AAiBH;;;GAGG;AACH,SAAgB,sBAAsB,CAAC,QAAgB;IACrD,MAAM,OAAO,GAAG,IAAA,kCAAY,EAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC1D,IAAI,yBAAiB,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QACnC,OAAO,EAAE,OAAO,EAAE,GAAG,OAAO,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;IAC1D,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;AACxC,CAAC;AAED;;GAEG;AACH,SAAgB,gBAAgB,CAAC,OAAwB;IACvD,MAAM,EACJ,OAAO,EACP,UAAU,EACV,WAAW,EACX,oBAAoB,EACpB,aAAa,EACb,MAAM,EACN,YAAY,EACZ,WAAW,EACX,YAAY,GACb,GAAG,OAAO,CAAC;IAEZ,MAAM,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC;IAEzC,MAAM,aAAa,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CACvC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,oCAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CACxE,CAAC;IAEF,MAAM,aAAa,GAAG,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;IAE9C,MAAM,QAAQ,GAAa;QACzB,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,oBAAoB,EAAE,aAAa,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,aAAa,CAAC;QAC7I,oBAAoB,CAAC,aAAa,EAAE,OAAO,CAAC;QAC5C,wBAAwB,CAAC,MAAM,CAAC;QAChC,wBAAwB,CAAC,MAAM,CAAC,iBAAiB,CAAC;QAClD,sBAAsB,CAAC,MAAM,CAAC,OAAO,CAAC;QACtC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,sBAAsB,EAAE,CAAC,CAAC,CAAC,EAAE;QACnD,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;QACzD,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC,wBAAwB,EAAE,CAAC,CAAC,CAAC,EAAE;QACxD,yBAAyB,EAAE;QAC3B,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC;YACjB,oBAAoB,CAAC,OAAO,EAAE,WAAW,CAAC;YAC1C,qBAAqB,CAAC,OAAO,CAAC;YAC9B,uBAAuB,EAAE;SAC1B,CAAC,CAAC,CAAC,EAAE,CAAC;QACP,oBAAoB,CAAC,oBAAoB,EAAE,aAAa,CAAC;QACzD,qBAAqB,CAAC,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC;QAClD,sBAAsB,CAAC,OAAO,EAAE,OAAO,CAAC,UAAU,EAAE,aAAa,CAAC;QAClE,sBAAsB,CAAC,OAAO,EAAE,oBAAoB,EAAE,aAAa,CAAC;QACpE,cAAc,EAAE;KACjB,CAAC;IAEF,OAAO,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC/C,CAAC;AAED,SAAS,cAAc,CACrB,OAAe,EACf,UAAkB,EAClB,WAAmB,EACnB,oBAA4B,EAC5B,aAAqB,EACrB,YAAqB,EACrB,YAAmC,EACnC,WAAyB,EACzB,aAAuB;IAEvB,MAAM,QAAQ,GAAG,CAAC,CAAC,WAAW,CAAC;IAE/B,0CAA0C;IAC1C,MAAM,aAAa,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,iEAAiE,CAAC,CAAC,CAAC,EAAE,CAAC;IACnH,MAAM,WAAW,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,4DAA4D,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1G,MAAM,gBAAgB,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC,sEAAsE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9H,MAAM,WAAW,GAAG,YAAY,CAAC,CAAC,CAAC,6GAA6G,CAAC,CAAC,CAAC,EAAE,CAAC;IAEtJ,sCAAsC;IACtC,MAAM,YAAY,GAAa;QAC7B,mBAAmB;QACnB,iCAAiC;KAClC,CAAC;IACF,IAAI,YAAY,CAAC,MAAM;QAAE,YAAY,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IACjE,IAAI,YAAY,CAAC,IAAI;QAAE,YAAY,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAC7D,IAAI,YAAY,CAAC,SAAS;QAAE,YAAY,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;IACvE,IAAI,YAAY;QAAE,YAAY,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IACxD,YAAY,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;IAC/C,YAAY,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IAExC,OAAO;EACP,aAAa,CAAC,CAAC,CAAC;;;;;;;wBAOM,IAAI,CAAC,SAAS,CAAC,KAAK,GAAG,oBAAoB,CAAC;;;;;;;;;;;;;;;;;;;;;;;CAuBnE,CAAC,CAAC,CAAC,EAAE;;;;;;qEAM+D,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;;;wBAGpE,aAAa,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,GAAG,oBAAoB,CAAC,EAAE,CAAC,CAAC,CAAC,mCAAmC,IAAI,CAAC,SAAS,CAAC,oBAAoB,CAAC,GAAG;;;;;;;;;;;;;;;;;EAiBpK,YAAY,CAAC,CAAC,CAAC,0FAA0F,CAAC,CAAC,CAAC,EAAE;EAC9G,QAAQ,CAAC,CAAC,CAAC,8CAA8C,CAAC,CAAC,CAAC,EAAE;;iBAE/C,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;;;;;EAKtC,aAAa;QACX,CAAC,CAAC;0BACoB,oBAAoB,IAAI;QAC9C,CAAC,CAAC,6CAA6C,IAAI,CAAC,SAAS,CAAC,oBAAoB,CAAC,IAAI;;;;;;;;;;;;;;;;;;;;;sBAqBrE,aAAa,CAAC,CAAC,CAAC,OAAO,oBAAoB,GAAG,CAAC,CAAC,CAAC,eAAe;;;;oDAIlC,YAAY,CAAC,CAAC,CAAC;;;;;uDAKZ,CAAC,CAAC,CAAC;2DACC;;;;;;;;;;;;;;EAczD,+DAA8B;;;;;;;;;;;;;;;;;;;;;;;;;;UA0BtB,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;aACpB,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC;iBACtB,IAAI,CAAC,SAAS,CAAC,WAAW,IAAI,GAAG,OAAO,MAAM,CAAC;8DACF,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC;;;;;;;;;;;;;;;;;;;;;EAqBzF,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC;;;;;;kHAMwF,aAAa,GAAG,WAAW,GAAG,gBAAgB,GAAG,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sDA+BxH,CAAC;AACvD,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAsB,EAAE,OAAe;IACnE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,wDAAwD,CAAC;IAExF,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QAClC,MAAM,EAAE,OAAO,EAAE,GAAG,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtD,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACvB,MAAM,EAAE,OAAO,EAAE,GAAG,IAAA,uCAAiB,EAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACxD,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,IAAA,wCAAkB,EAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEhF,OAAO;aACE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;iBACnB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC;EAC/C,WAAW;;;;;;QAML,kBAAkB,CAAC,IAAI,CAAC;2CACW,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;4CACxB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;;;;;;;;;;;;;;;;qCAgB7B,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;;;;;;;;;MAStD,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,+BAA+B,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAQ,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;AAChG,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAmB;IAC7C,MAAM,KAAK,GAAI,IAAI,CAAC,WAAuC,CAAC,UAAiE,CAAC;IAC9H,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IAEtB,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE;QACnD,MAAM,UAAU,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC;QACnC,MAAM,KAAK,GAAG,IAAA,kCAAY,EAAC,QAAQ,CAAC,CAAC;QACrC,6DAA6D;QAC7D,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;QAElC,oCAAoC;QACpC,IAAI,QAAQ,GAAG,UAAU,EAAE,IAAqC,CAAC;QACjE,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC5B,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC;QACvE,CAAC;QAED,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC1B,OAAO,eAAe,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;qBAC5B,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,0BAA0B,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;+DAC7B,KAAK;QAC5D,CAAC;QACL,CAAC;QAED,OAAO,eAAe,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,yBAAyB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,eAAe,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC;IACvI,CAAC,CAAC,CAAC;IAEH,OAAO,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;AACnC,CAAC;AAED,SAAS,qBAAqB,CAAC,WAAoC;IACjE,MAAM,KAAK,GAAI,WAAuC,CAAC,UAAiE,CAAC;IACzH,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IAEtB,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE;QACnD,MAAM,UAAU,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC;QACnC,MAAM,KAAK,GAAG,IAAA,kCAAY,EAAC,QAAQ,CAAC,CAAC;QACrC,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;QAElC,IAAI,QAAQ,GAAG,UAAU,EAAE,IAAqC,CAAC;QACjE,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC5B,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC;QACvE,CAAC;QAED,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC1B,OAAO,eAAe,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;sBAC3B,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,0BAA0B,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;+DAC9B,KAAK;QAC5D,CAAC;QACL,CAAC;QAED,OAAO,eAAe,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,0BAA0B,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,eAAe,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC;IACxI,CAAC,CAAC,CAAC;IAEH,OAAO,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;AACnC,CAAC;AAED,SAAS,wBAAwB,CAAC,OAAwB;IACxD,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAoCH,CAAC;AACP,CAAC;AAED,SAAS,wBAAwB,CAAC,SAAsC;IACtE,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,oCAAoC,CAAC;IAEtF,MAAM,WAAW,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACzC,MAAM,OAAO,GAAG,IAAA,kCAAY,EAAC,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAC3D,iDAAiD;QACjD,MAAM,UAAU,GAAG,qBAAqB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC3D,MAAM,WAAW,GAAG,UAAU;aAC3B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,wBAAwB,IAAA,kCAAY,EAAC,CAAC,CAAC,mCAAmC,CAAC,IAAI,CAAC;aAC3F,IAAI,CAAC,IAAI,CAAC,CAAC;QAEd,MAAM,YAAY,GAAG,UAAU;aAC5B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACT,MAAM,KAAK,GAAG,YAAY,CAAC,IAAA,kCAAY,EAAC,CAAC,CAAC,CAAC,CAAC;YAC5C,OAAO,uBAAuB,CAAC,kCAAkC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC;QAC/F,CAAC,CAAC;aACD,IAAI,CAAC,UAAU,CAAC,CAAC;QAEpB,OAAO;aACE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;iBACnB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,IAAI,gCAAgC,IAAI,CAAC,WAAW,EAAE,CAAC;EACrG,WAAW;;;;;kBAKK,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC;QAC1C,YAAY;;;;;;;MAOd,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO;;;;;;;;;;;;;;;;;;;;;;;;EAwBP,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;AAC7B,CAAC;AAED,SAAS,sBAAsB,CAAC,OAA0B;IACxD,4EAA4E;IAC5E,wEAAwE;IACxE,0CAA0C;IAC1C,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACtC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC3C,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,KAAK,EAAE,IAAA,kCAAY,EAAC,CAAC,CAAC,IAAI,CAAC;YAC3B,KAAK,EAAE,YAAY,CAAC,IAAA,kCAAY,EAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACzC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ;SACvB,CAAC,CAAC,CAAC;QACJ,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;IAC9D,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAErB,6EAA6E;IAC7E,4EAA4E;IAC5E,2EAA2E;IAC3E,yDAAyD;IACzD,mEAAmE;IACnE,0EAA0E;IAC1E,0EAA0E;IAC1E,sEAAsE;IACtE,sEAAsE;IACtE,MAAM,aAAa,GAAG,IAAI,GAAG,EAAU,CAAC;IACxC,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,IAAI,EAAE,EAAE,CAAC;YAClC,aAAa,CAAC,GAAG,CAAC,IAAA,kCAAY,EAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC;IACD,MAAM,oBAAoB,GAAG,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC;SACnD,IAAI,EAAE;SACN,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,aAAa,IAAI,CAAC,SAAS,CAAC,KAAK,KAAK,UAAU,CAAC,OAAO,CAAC;SACxE,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;QACzC,MAAM,OAAO,GAAG,IAAA,kCAAY,EAAC,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAC7D,MAAM,UAAU,GAAG,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC;aACxC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACT,MAAM,IAAI,GAAG,KAAK,IAAA,kCAAY,EAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC;YACjD,MAAM,IAAI,GAAG,CAAC,CAAC,WAAW,IAAI,EAAE,CAAC;YACjC,OAAO,CAAC,CAAC,QAAQ;gBACf,CAAC,CAAC,sBAAsB,IAAI,OAAO,SAAS,CAAC,IAAI,CAAC,IAAI;gBACtD,CAAC,CAAC,cAAc,IAAI,OAAO,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;QACnD,CAAC,CAAC;aACD,IAAI,CAAC,IAAI,CAAC,CAAC;QAEd,OAAO;aACE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;iBACnB,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,WAAW,IAAI,EAAE,CAAC,GAAG,uCAAuC,GAAG,OAAO,GAAG,IAAI,CAAC;EACpH,UAAU;;;;;;QAMJ,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACnC,MAAM,KAAK,GAAG,YAAY,CAAC,IAAA,kCAAY,EAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;YACjD,OAAO,eAAe,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,yBAAyB,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC;QACrI,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC;4CACmB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC;;;;;;MAMjE,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAmCD,aAAa;;;;;EAKnB,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuEpB,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;AAC7B,CAAC;AAED,SAAS,sBAAsB;IAC7B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAoHH,CAAC;AACP,CAAC;AAED,SAAS,mBAAmB,CAAC,IAAoB;IAC/C,sDAAsD;IACtD,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QACtC,MAAM,UAAU,GAAG,IAAA,kCAAY,EAAC,GAAG,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAE7D,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;YACpB,MAAM,EAAE,OAAO,EAAE,GAAG,IAAA,uCAAiB,EAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YACvD,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,IAAA,wCAAkB,EAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAChF,MAAM,UAAU,GAAG,qBAAqB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YAE1D,OAAO;aACA,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC;iBACtB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,IAAI,WAAW,GAAG,CAAC,IAAI,MAAM,CAAC;EAC3E,WAAW;;;;;;;QAOL,UAAU;6CAC2B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;;;;;;;;;;;;;;MAc/D,CAAC;QACH,CAAC;QAED,uDAAuD;QACvD,OAAO;aACE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC;iBACtB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,IAAI,WAAW,GAAG,CAAC,IAAI,MAAM,CAAC;;;;;;;;;;;6CAWhC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;;;;;;;;;;;;;;MAc/D,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,0DAA0D;IAC1D,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;MA2Bf,CAAC;IAEL,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8BP,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC;;EAE3B,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;MA0B3B;;;;;;;;;;;;;;;;;;MAkBA,CAAC;AACP,CAAC;AAED,SAAS,wBAAwB;IAC/B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAyEH,CAAC;AACP,CAAC;AAED,SAAS,yBAAyB;IAChC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MA6EH,CAAC;AACP,CAAC;AAED,SAAS,oBAAoB,CAAC,OAAe,EAAE,WAAyB;IACtE,MAAM,SAAS,GAAG,WAAW,EAAE,SAAS,IAAI,EAAE,CAAC;IAC/C,MAAM,QAAQ,GAAG,WAAW,EAAE,QAAQ,IAAI,OAAO,CAAC;IAClD,MAAM,YAAY,GAAG,WAAW,EAAE,YAAY,IAAI,EAAE,CAAC;IACrD,MAAM,SAAS,GAAG,WAAW,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC;IACvD,MAAM,OAAO,GAAG,WAAW,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC;IACrD,MAAM,OAAO,GAAG,WAAW,EAAE,OAAO,IAAI,MAAM,CAAC;IAE/C,OAAO;;;oDAG2C,SAAS,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;;8CAEvD,YAAY,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;;;wEAG7B,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC;;;;;;;;;;oBAU7E,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;+BACb,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC;qBACtC,SAAS;mBACX,OAAO;mBACP,OAAO;;;;;;;;;;;;MAYpB,CAAC;AACP,CAAC;AAED,SAAS,qBAAqB,CAAC,QAAgB;IAC7C,OAAO;;;;;;;;;;;;;;;;;;MAkBH,CAAC;AACP,CAAC;AAED,SAAS,uBAAuB;IAC9B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAkDH,CAAC;AACP,CAAC;AAED,SAAS,oBAAoB,CAAC,oBAA4B,EAAE,aAAuB;IACjF,qGAAqG;IACrG,0EAA0E;IAC1E,MAAM,WAAW,GAAG,aAAa;QAC/B,CAAC,CAAC,WAAW,IAAI,CAAC,SAAS,CAAC,KAAK,GAAG,oBAAoB,CAAC,GAAG;QAC5D,CAAC,CAAC,iCAAiC,IAAI,CAAC,SAAS,CAAC,oBAAoB,CAAC,IAAI,CAAC;IAE9E,OAAO;;;;;;;;;;;mBAWU,WAAW;;;;;;;;;;;;;;gBAcd,WAAW;;;;;;;;;;;;;;MAcrB,CAAC;AACP,CAAC;AAED,SAAS,qBAAqB,CAC5B,OAAe,EACf,UAAgD;IAEhD,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,IAAI,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;QAC5B,KAAK,MAAM,GAAG,IAAI,UAAU,CAAC,IAAI,EAAE,CAAC;YAClC,MAAM,CAAC,IAAI,CAAC,aAAa,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,qCAAqC,GAAG,KAAK,CAAC,CAAC;QAC7F,CAAC;IACH,CAAC;IACD,IAAI,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC;QAC3B,KAAK,MAAM,GAAG,IAAI,UAAU,CAAC,GAAG,EAAE,CAAC;YACjC,MAAM,CAAC,IAAI,CAAC,aAAa,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,kCAAkC,GAAG,KAAK,CAAC,CAAC;QAC1F,CAAC;IACH,CAAC;IACD,IAAI,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC;QAC3B,KAAK,MAAM,GAAG,IAAI,UAAU,CAAC,GAAG,EAAE,CAAC;YACjC,MAAM,CAAC,IAAI,CAAC,aAAa,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,iCAAiC,GAAG,KAAK,CAAC,CAAC;QACzF,CAAC;IACH,CAAC;IAED,OAAO;;;;;;;;;;;;;;;;;;EAkBP,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;+DA4B2C,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;;;MAiBhF,CAAC;AACP,CAAC;AAED,SAAS,sBAAsB,CAC7B,OAAe,EACf,UAAgD,EAChD,aAAuB;IAEvB,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,IAAI,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;QAC5B,KAAK,MAAM,GAAG,IAAI,UAAU,CAAC,IAAI,EAAE,CAAC;YAClC,UAAU,CAAC,IAAI,CAAC,aAAa,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,0CAA0C,GAAG,wBAAwB,GAAG,KAAK,CAAC,CAAC;QACjI,CAAC;IACH,CAAC;IACD,IAAI,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC;QAC3B,KAAK,MAAM,GAAG,IAAI,UAAU,CAAC,GAAG,EAAE,CAAC;YACjC,UAAU,CAAC,IAAI,CAAC,aAAa,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,wCAAwC,GAAG,qBAAqB,GAAG,KAAK,CAAC,CAAC;QAC5H,CAAC;IACH,CAAC;IAED,OAAO;;;;;;;;;;;qDAW4C,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;;;8BAG9C,OAAO;;;;;4EAKuC,aAAa,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;;;;;;EAgBvH,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC;;;;;;;;;;;;;2CAamB,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,OAAO,UAAU,CAAC,CAAC,CAAC,GAAG,OAAO,gBAAgB,CAAC;;;;;;;;;kDAS1E,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;;;;;;;;sCAQnC,OAAO;;;;;;;;;;;;;uDAaU,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;;;;;;;;;;;;;;4CAclC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;;;;;+BAKpC,OAAO;MAChC,CAAC;AACP,CAAC;AAED,SAAS,sBAAsB,CAAC,OAAe,EAAE,oBAA4B,EAAE,aAAuB;IACpG,OAAO;;;;;;;;;;;;;;;;;;+CAkBsC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;;;;;;yCAM7B,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;;;yCAiBvB,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;;;;EAI9D,aAAa,CAAC,CAAC,CAAC;;;;;;QAMV,CAAC,CAAC,CAAC;;sDAE2C,IAAI,CAAC,SAAS,CAAC,oBAAoB,CAAC;;;;;;;;QAQlF,sFAAsF;;;;;;;;;;;;;;;;;;;;;;QAsBtF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wDAgDgD,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;wDAoBvB,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;wDAoBvB,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;;;;;;;MAOzE,CAAC;AACP,CAAC;AAED,SAAS,cAAc;IACrB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA4BL,CAAC;AACL,CAAC;AAED;;GAEG;AACH,SAAgB,qBAAqB,CAAC,WAAmB;IACvD,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IAClD,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC;IACxB,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C,CAAC;AAED,SAAS,YAAY,CAAC,GAAW;IAC/B,OAAO,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;AAC7D,CAAC;AAED,SAAS,SAAS,CAAC,CAAS;IAC1B,OAAO,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AACvD,CAAC","sourcesContent":["/**\n * Generates the CLI entry point TypeScript/JavaScript source code.\n * This creates a commander.js-based CLI where each MCP tool is a subcommand.\n */\n\nimport { type CliConfig, type OAuthConfig } from '../config';\nimport { EXTRACT_PUBLIC_MESSAGE_SNIPPET } from './extract-public-message.snippet';\nimport { type ExtractedSchema, type ExtractedTool, type ExtractedPrompt, type ExtractedResourceTemplate, type ExtractedCapabilities, type ExtractedJob, SYSTEM_TOOL_NAMES } from './schema-extractor';\nimport { schemaToCommander, generateOptionCode, camelToKebab } from './schema-to-commander';\n\nexport const RESERVED_COMMANDS = new Set([\n 'resource', 'template', 'prompt', 'subscribe',\n 'login', 'logout', 'connect', 'serve', 'daemon',\n 'doctor', 'install', 'uninstall', 'sessions', 'help', 'version',\n 'skills', 'job', 'workflow',\n // Reserved by the symmetric `prompt get <name>` / `resource read <uri>`\n // sub-API; included so a user-defined entry can never shadow them.\n 'get', 'list', 'read',\n]);\n\nexport interface CliEntryOptions {\n appName: string;\n appVersion: string;\n description: string;\n serverBundleFilename: string;\n outputDefault: 'text' | 'json';\n authRequired: boolean;\n excludeTools: string[];\n nativeDeps: NonNullable<CliConfig['nativeDeps']>;\n schema: ExtractedSchema;\n oauthConfig?: OAuthConfig;\n /** When true, generate static requires that esbuild can resolve (for SEA builds). */\n selfContained?: boolean;\n}\n\n/**\n * Resolve tool command name, appending '-tool' suffix if it conflicts with a built-in command.\n * Returns { cmdName, wasRenamed } so the caller can log a warning at build time.\n */\nexport function resolveToolCommandName(toolName: string): { cmdName: string; wasRenamed: boolean } {\n const cmdName = camelToKebab(toolName).replace(/_/g, '-');\n if (RESERVED_COMMANDS.has(cmdName)) {\n return { cmdName: `${cmdName}-tool`, wasRenamed: true };\n }\n return { cmdName, wasRenamed: false };\n}\n\n/**\n * Generate the CLI entry source code (CJS module).\n */\nexport function generateCliEntry(options: CliEntryOptions): string {\n const {\n appName,\n appVersion,\n description,\n serverBundleFilename,\n outputDefault,\n schema,\n excludeTools,\n oauthConfig,\n authRequired,\n } = options;\n\n const capabilities = schema.capabilities;\n\n const filteredTools = schema.tools.filter(\n (t) => !excludeTools.includes(t.name) && !SYSTEM_TOOL_NAMES.has(t.name),\n );\n\n const selfContained = !!options.selfContained;\n\n const sections: string[] = [\n generateHeader(appName, appVersion, description, serverBundleFilename, outputDefault, authRequired, capabilities, oauthConfig, selfContained),\n generateToolCommands(filteredTools, appName),\n generateResourceCommands(schema),\n generateTemplateCommands(schema.resourceTemplates),\n generatePromptCommands(schema.prompts),\n capabilities.skills ? generateSkillsCommands() : '',\n capabilities.jobs ? generateJobCommands(schema.jobs) : '',\n capabilities.workflows ? generateWorkflowCommands() : '',\n generateSubscribeCommands(),\n ...(authRequired ? [\n generateLoginCommand(appName, oauthConfig),\n generateLogoutCommand(appName),\n generateSessionCommands(),\n ] : []),\n generateServeCommand(serverBundleFilename, selfContained),\n generateDoctorCommand(appName, options.nativeDeps),\n generateInstallCommand(appName, options.nativeDeps, selfContained),\n generateDaemonCommands(appName, serverBundleFilename, selfContained),\n generateFooter(),\n ];\n\n return sections.filter(Boolean).join('\\n\\n');\n}\n\nfunction generateHeader(\n appName: string,\n appVersion: string,\n description: string,\n serverBundleFilename: string,\n outputDefault: string,\n authRequired: boolean,\n capabilities: ExtractedCapabilities,\n oauthConfig?: OAuthConfig,\n selfContained?: boolean,\n): string {\n const hasOAuth = !!oauthConfig;\n\n // Build the group routing map dynamically\n const skillsRouting = capabilities.skills ? `\\n else if (name === 'skills') groups['Skills'].push(sub);` : '';\n const jobsRouting = capabilities.jobs ? `\\n else if (name === 'job') groups['Jobs'].push(sub);` : '';\n const workflowsRouting = capabilities.workflows ? `\\n else if (name === 'workflow') groups['Workflows'].push(sub);` : '';\n const authRouting = authRequired ? `\\n else if (['login', 'logout', 'sessions', 'connect'].indexOf(name) !== -1) groups['Auth'].push(sub);` : '';\n\n // Build the groups object dynamically\n const groupEntries: string[] = [\n ` 'Tools': []`,\n ` 'Resources & Prompts': []`,\n ];\n if (capabilities.skills) groupEntries.push(` 'Skills': []`);\n if (capabilities.jobs) groupEntries.push(` 'Jobs': []`);\n if (capabilities.workflows) groupEntries.push(` 'Workflows': []`);\n if (authRequired) groupEntries.push(` 'Auth': []`);\n groupEntries.push(` 'Subscriptions': []`);\n groupEntries.push(` 'System': []`);\n\n return `'use strict';\n${selfContained ? `\n// SEA daemon mode: when spawned by 'daemon start', run the server directly\n// using the inlined (bundled) server code — no external requires needed.\nif (process.env.__FRONTMCP_DAEMON_MODE === '1') {\n require('reflect-metadata');\n // Suppress @FrontMcp decorator auto-bootstrap — daemon handles bootstrap explicitly below.\n process.env.FRONTMCP_SCHEMA_EXTRACT = '1';\n var _dMod = require(${JSON.stringify('../' + serverBundleFilename)});\n delete process.env.FRONTMCP_SCHEMA_EXTRACT;\n var _dSdk = require('@frontmcp/sdk');\n var _FMI = _dSdk.FrontMcpInstance || _dSdk.default.FrontMcpInstance;\n var _raw = _dMod.default || _dMod;\n var _cfg = (typeof _raw === 'function' && typeof Reflect !== 'undefined' && Reflect.getMetadata)\n ? (Reflect.getMetadata('__frontmcp:config', _raw) || _raw) : _raw;\n var _dp = process.env.FRONTMCP_DAEMON_PORT;\n if (_dp) {\n var _port = parseInt(_dp, 10);\n _cfg = Object.assign({}, _cfg, { http: Object.assign({}, _cfg.http || {}, { port: _port }) });\n process.env.PORT = _dp;\n _FMI.bootstrap(_cfg)\n .then(function() { console.log('Daemon listening on port ' + _port); })\n .catch(function(e) { console.error('Daemon failed:', e); process.exit(1); });\n } else {\n var _sp = process.env.FRONTMCP_DAEMON_SOCKET;\n _FMI.runUnixSocket(Object.assign({}, _cfg, { socketPath: _sp }))\n .then(function() { console.log('Daemon listening on ' + _sp); })\n .catch(function(e) { console.error('Daemon failed:', e); process.exit(1); });\n }\n return;\n}\n` : ''}\n// Stdio mode: when --stdio is passed, run as an MCP stdio server (stdin/stdout JSON-RPC).\n// Detected early before commander to avoid overhead and ensure stdout stays clean for MCP protocol.\n// Logs go to ~/.frontmcp/logs/{appName}-*.log — stdout is reserved for MCP JSON-RPC only.\nif (process.argv.includes('--stdio')) {\n // Set app name for file logging before any initialization\n process.env.FRONTMCP_APP_NAME = process.env.FRONTMCP_APP_NAME || ${JSON.stringify(appName)};\n require('reflect-metadata');\n process.env.FRONTMCP_SCHEMA_EXTRACT = '1';\n var _sMod = require(${selfContained ? `${JSON.stringify('../' + serverBundleFilename)}` : `require('path').join(__dirname, ${JSON.stringify(serverBundleFilename)})`});\n delete process.env.FRONTMCP_SCHEMA_EXTRACT;\n var _sSdk = require('@frontmcp/sdk');\n var _sFMI = _sSdk.FrontMcpInstance || _sSdk.default.FrontMcpInstance;\n var _sRaw = _sMod.default || _sMod;\n var _sCfg = (typeof _sRaw === 'function' && typeof Reflect !== 'undefined' && Reflect.getMetadata)\n ? (Reflect.getMetadata('__frontmcp:config', _sRaw) || _sRaw) : _sRaw;\n _sFMI.runStdio(_sCfg)\n .catch(function(e) { console.error('Stdio server failed:', e); process.exit(1); });\n return;\n}\n\nvar { Command, Option } = require('commander');\nvar path = require('path');\nvar fs = require('fs');\nvar os = require('os');\nvar fmt = require('./output-formatter');\n${authRequired ? \"var sessions = require('./session-manager');\\nvar creds = require('./credential-store');\" : ''}\n${hasOAuth ? \"var oauthHelper = require('./oauth-helper');\" : ''}\n\nvar APP_NAME = ${JSON.stringify(appName)};\nvar SCRIPT_DIR = __dirname;\nvar FRONTMCP_HOME = process.env.FRONTMCP_HOME || path.join(os.homedir(), '.frontmcp');\n// Set app name for file logger (writes to ~/.frontmcp/logs/{appName}-{timestamp}.log)\nprocess.env.FRONTMCP_APP_NAME = process.env.FRONTMCP_APP_NAME || APP_NAME;\n${selfContained\n ? `// Self-contained: server bundle and SDK are inlined by esbuild\nvar SERVER_BUNDLE = '../${serverBundleFilename}';`\n : `var SERVER_BUNDLE = path.join(SCRIPT_DIR, ${JSON.stringify(serverBundleFilename)});`}\n\nvar _client = null;\nasync function getClient() {\n if (_client) return _client;\n\n // Try daemon first — Unix socket HTTP (~5-15ms vs ~420ms in-process)\n var socketPath = path.join(FRONTMCP_HOME, 'sockets', APP_NAME + '.sock');\n if (fs.existsSync(socketPath)) {\n try {\n var daemonClient = require('./daemon-client');\n var dc = daemonClient.createDaemonClient(socketPath);\n await dc.ping();\n _client = dc;\n return _client;\n } catch (_) { /* daemon not available, fall through */ }\n }\n\n // Fallback: in-process connect (with CLI mode for faster init)\n // Suppress @FrontMcp decorator bootstrap — we only need config metadata, not a running server.\n process.env.FRONTMCP_SCHEMA_EXTRACT = '1';\n var mod = require(${selfContained ? `'../${serverBundleFilename}'` : 'SERVER_BUNDLE'});\n delete process.env.FRONTMCP_SCHEMA_EXTRACT;\n var configOrClass = mod.default || mod;\n var sdk = require('@frontmcp/sdk');\n var connect = sdk.connect || sdk.direct.connect;${authRequired ? `\n var sessionName = sessions.getActiveSessionName();\n var store = creds.createCredentialStore();\n var credBlob = await store.get(sessionName);\n var connectOpts = credBlob ? { authToken: credBlob.token, mode: 'cli' } : { mode: 'cli' };\n _client = await connect(configOrClass, connectOpts);` : `\n _client = await connect(configOrClass, { mode: 'cli' });`}\n return _client;\n}\n\nasync function closeClient() {\n if (_client && typeof _client.close === 'function') {\n try { await _client.close(); } catch (_) {}\n }\n _client = null;\n}\n\n// Flag set by long-running commands (serve, daemon) to prevent the footer from calling process.exit().\nvar _isLongRunning = false;\n\n${EXTRACT_PUBLIC_MESSAGE_SNIPPET}\n\nvar program = new Command();\n// Make Commander's own usage errors (unknown subcommand, missing required option,\n// invalid value) exit with code 2 instead of the default 0 — matches POSIX\n// convention and lets shell scripts/CI distinguish runtime failures from usage.\n//\n// Sets process.exitCode and re-throws so the parseAsync() footer can run\n// closeClient() / native-addon teardown before the actual exit. Calling\n// process.exit() directly here would skip that and could leave better-sqlite3\n// / ONNX / file handles in a corrupt state for short-lived runs.\nprogram.exitOverride(function(err) {\n if (err.code === 'commander.helpDisplayed' || err.code === 'commander.help' || err.code === 'commander.version') {\n process.exitCode = 0;\n } else if (err.code === 'commander.unknownCommand' || err.code === 'commander.unknownOption' ||\n err.code === 'commander.missingArgument' || err.code === 'commander.missingMandatoryOptionValue' ||\n err.code === 'commander.invalidArgument' || err.code === 'commander.optionMissingArgument' ||\n err.code === 'commander.invalidOptionArgument' || err.code === 'commander.excessArguments') {\n process.exitCode = 2;\n } else {\n process.exitCode = 1;\n }\n // Re-throw so parseAsync().catch in the footer runs cleanup before exit.\n throw err;\n});\nprogram\n .name(${JSON.stringify(appName)})\n .version(${JSON.stringify(appVersion)})\n .description(${JSON.stringify(description || `${appName} CLI`)})\n .option('--output <mode>', 'Output format: text or json', ${JSON.stringify(outputDefault)})\n .option('--verbose', 'Enable verbose console logging (logs always go to ~/.frontmcp/logs/)')\n .option('--log-dir <path>', 'Directory for log files (default: ~/.frontmcp/logs/)');\n\n// Wire --verbose and --log-dir to env vars early (before any command action runs).\n// Parse argv directly since commander hooks may not be available in all versions.\n(function() {\n var argv = process.argv;\n if (argv.indexOf('--verbose') !== -1) {\n process.env.FRONTMCP_CLI_VERBOSE = '1';\n }\n var logDirIdx = argv.indexOf('--log-dir');\n if (logDirIdx !== -1 && argv[logDirIdx + 1]) {\n process.env.FRONTMCP_LOG_DIR = argv[logDirIdx + 1];\n }\n})();\n\nprogram.configureHelp({\n sortSubcommands: false,\n formatHelp: function(cmd, helper) {\n var groups = {\n${groupEntries.join(',\\n')}\n };\n var toolCmdNames = cmd._toolCommandNames || [];\n cmd.commands.forEach(function(sub) {\n var name = sub.name();\n if (toolCmdNames.indexOf(name) !== -1) groups['Tools'].push(sub);\n else if (['resource', 'template', 'prompt'].indexOf(name) !== -1) groups['Resources & Prompts'].push(sub);${skillsRouting}${jobsRouting}${workflowsRouting}${authRouting}\n else if (name === 'subscribe') groups['Subscriptions'].push(sub);\n else groups['System'].push(sub);\n });\n var termWidth = helper.padWidth(cmd, helper);\n var lines = [];\n lines.push('Usage: ' + helper.commandUsage(cmd));\n lines.push('');\n var desc = helper.commandDescription(cmd);\n if (desc) { lines.push(desc); lines.push(''); }\n var globalOpts = helper.formatHelp ? helper.visibleOptions(cmd) : [];\n if (globalOpts.length > 0) {\n lines.push('Options:');\n globalOpts.forEach(function(opt) {\n lines.push(' ' + helper.optionTerm(opt).padEnd(termWidth) + ' ' + helper.optionDescription(opt));\n });\n lines.push('');\n }\n Object.keys(groups).forEach(function(groupName) {\n var cmds = groups[groupName];\n if (cmds.length === 0) return;\n lines.push(groupName + ':');\n cmds.forEach(function(sub) {\n lines.push(' ' + helper.subcommandTerm(sub).padEnd(termWidth) + ' ' + helper.subcommandDescription(sub));\n });\n lines.push('');\n });\n return lines.join('\\\\n');\n }\n});\n\nprogram.action(function() { program.outputHelp(); });`;\n}\n\nfunction generateToolCommands(tools: ExtractedTool[], appName: string): string {\n if (tools.length === 0) return '// No tools extracted\\nprogram._toolCommandNames = [];';\n\n const cmdNames: string[] = [];\n const commands = tools.map((tool) => {\n const { cmdName } = resolveToolCommandName(tool.name);\n cmdNames.push(cmdName);\n const { options } = schemaToCommander(tool.inputSchema);\n const optionLines = options.map((o) => ` ${generateOptionCode(o)}`).join('\\n');\n\n return `program\n .command(${JSON.stringify(cmdName)})\n .description(${JSON.stringify(tool.description)})\n${optionLines}\n .action(async function(opts) {\n try {\n var client = await getClient();\n var args = {};\n var rawOpts = this.opts();\n ${generateArgMapping(tool)}\n var result = await client.callTool(${JSON.stringify(tool.name)}, args);\n var mode = program.opts().output || ${JSON.stringify('text')};\n console.log(fmt.formatToolResult(result, mode));\n // The SDK converts thrown errors into a CallToolResult with isError:true\n // (so HTTP/JSON-RPC clients still get a structured response). Detect\n // that here and map to a non-zero exit code so shell scripts can gate\n // on success — Zod input validation errors → exit 2 (usage), all\n // other tool errors → exit 1 (runtime).\n if (result && result.isError === true) {\n var rmeta = (result && result._meta) || {};\n process.exitCode = (rmeta.code === 'INVALID_INPUT') ? 2 : 1;\n }\n } catch (err) {\n var meta = err && err._meta ? err._meta : (err && err.data && err.data._meta ? err.data._meta : null);\n if (meta && meta.authorization_required) {\n console.error('Authorization required' + (meta.app ? ' for ' + meta.app : ''));\n if (meta.auth_url) console.error('Authorize at: ' + meta.auth_url);\n console.error('Or run: ' + ${JSON.stringify(appName)} + ' login');\n process.exitCode = 1;\n } else {\n // Thrown error path (transport / DI / pre-flow failure) — same\n // mapping as the isError result path above.\n var isUsage = err && err.code === 'INVALID_INPUT';\n _exitWithError(err, isUsage ? 2 : 1);\n }\n }\n });`;\n });\n\n return `program._toolCommandNames = ${JSON.stringify(cmdNames)};\\n\\n${commands.join('\\n\\n')}`;\n}\n\nfunction generateArgMapping(tool: ExtractedTool): string {\n const props = (tool.inputSchema as Record<string, unknown>).properties as Record<string, Record<string, unknown>> | undefined;\n if (!props) return '';\n\n const mappings = Object.keys(props).map((propName) => {\n const propSchema = props[propName];\n const kebab = camelToKebab(propName);\n // Commander converts kebab-case flags to camelCase in opts()\n const camel = kebabToCamel(kebab);\n\n // Resolve type for object detection\n let propType = propSchema?.type as string | string[] | undefined;\n if (Array.isArray(propType)) {\n propType = propType.find((t: string) => t !== 'null') || propType[0];\n }\n\n if (propType === 'object') {\n return `if (rawOpts[${JSON.stringify(camel)}] !== undefined) {\n try { args[${JSON.stringify(propName)}] = JSON.parse(rawOpts[${JSON.stringify(camel)}]); }\n catch (_jsonErr) { console.error('Invalid JSON for --${kebab}'); process.exitCode = 1; return; }\n }`;\n }\n\n return `if (rawOpts[${JSON.stringify(camel)}] !== undefined) args[${JSON.stringify(propName)}] = rawOpts[${JSON.stringify(camel)}];`;\n });\n\n return mappings.join('\\n ');\n}\n\nfunction generateJobArgMapping(inputSchema: Record<string, unknown>): string {\n const props = (inputSchema as Record<string, unknown>).properties as Record<string, Record<string, unknown>> | undefined;\n if (!props) return '';\n\n const mappings = Object.keys(props).map((propName) => {\n const propSchema = props[propName];\n const kebab = camelToKebab(propName);\n const camel = kebabToCamel(kebab);\n\n let propType = propSchema?.type as string | string[] | undefined;\n if (Array.isArray(propType)) {\n propType = propType.find((t: string) => t !== 'null') || propType[0];\n }\n\n if (propType === 'object') {\n return `if (rawOpts[${JSON.stringify(camel)}] !== undefined) {\n try { input[${JSON.stringify(propName)}] = JSON.parse(rawOpts[${JSON.stringify(camel)}]); }\n catch (_jsonErr) { console.error('Invalid JSON for --${kebab}'); process.exitCode = 1; return; }\n }`;\n }\n\n return `if (rawOpts[${JSON.stringify(camel)}] !== undefined) input[${JSON.stringify(propName)}] = rawOpts[${JSON.stringify(camel)}];`;\n });\n\n return mappings.join('\\n ');\n}\n\nfunction generateResourceCommands(_schema: ExtractedSchema): string {\n return `var resourceCmd = program.command('resource').description('Resource operations');\n\nresourceCmd\n .command('list')\n .description('List available resources')\n .action(async function() {\n try {\n var client = await getClient();\n var result = await client.listResources();\n var mode = program.opts().output || 'text';\n if (mode === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n var resources = result.resources || [];\n if (resources.length === 0) { console.log('No resources available.'); return; }\n resources.forEach(function(r) {\n console.log(' ' + r.uri + (r.description ? ' - ' + r.description : ''));\n });\n }\n } catch (err) {\n _exitWithError(err, 1);\n }\n });\n\nresourceCmd\n .command('read <uri>')\n .description('Read a resource by URI')\n .action(async function(uri) {\n try {\n var client = await getClient();\n var result = await client.readResource(uri);\n var mode = program.opts().output || 'text';\n console.log(fmt.formatResourceResult(result, mode));\n } catch (err) {\n _exitWithError(err, 1);\n }\n });`;\n}\n\nfunction generateTemplateCommands(templates: ExtractedResourceTemplate[]): string {\n if (!templates || templates.length === 0) return '// No resource templates extracted';\n\n const subcommands = templates.map((tmpl) => {\n const cmdName = camelToKebab(tmpl.name).replace(/_/g, '-');\n // Extract {param} placeholders from URI template\n const paramNames = extractTemplateParams(tmpl.uriTemplate);\n const optionLines = paramNames\n .map((p) => ` .requiredOption('--${camelToKebab(p)} <value>', 'Template parameter: ${p}')`)\n .join('\\n');\n\n const paramMapping = paramNames\n .map((p) => {\n const camel = kebabToCamel(camelToKebab(p));\n return `uri = uri.replace('{${p}}', encodeURIComponent(rawOpts[${JSON.stringify(camel)}]));`;\n })\n .join('\\n ');\n\n return `templateCmd\n .command(${JSON.stringify(cmdName)})\n .description(${JSON.stringify(tmpl.description || `Read resource from template: ${tmpl.uriTemplate}`)})\n${optionLines}\n .action(async function(opts) {\n try {\n var client = await getClient();\n var rawOpts = this.opts();\n var uri = ${JSON.stringify(tmpl.uriTemplate)};\n ${paramMapping}\n var result = await client.readResource(uri);\n var mode = program.opts().output || 'text';\n console.log(fmt.formatResourceResult(result, mode));\n } catch (err) {\n _exitWithError(err, 1);\n }\n });`;\n });\n\n return `var templateCmd = program.command('template').description('Resource template operations');\n\ntemplateCmd\n .command('list')\n .description('List available resource templates')\n .action(async function() {\n try {\n var client = await getClient();\n var result = await client.listResourceTemplates();\n var mode = program.opts().output || 'text';\n if (mode === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n var templates = result.resourceTemplates || [];\n if (templates.length === 0) { console.log('No resource templates available.'); return; }\n templates.forEach(function(t) {\n console.log(' ' + t.uriTemplate + (t.description ? ' - ' + t.description : ''));\n });\n }\n } catch (err) {\n _exitWithError(err, 1);\n }\n });\n\n${subcommands.join('\\n\\n')}`;\n}\n\nfunction generatePromptCommands(prompts: ExtractedPrompt[]): string {\n // Map known prompts → option specs so `prompt get <name>` knows which flags\n // to accept per prompt. Unknown prompt names still call getPrompt() and\n // surface the server's error to the user.\n const promptArgsMap = prompts.map((p) => {\n const args = (p.arguments || []).map((a) => ({\n name: a.name,\n kebab: camelToKebab(a.name),\n camel: kebabToCamel(camelToKebab(a.name)),\n required: !!a.required,\n }));\n return `${JSON.stringify(p.name)}: ${JSON.stringify(args)}`;\n }).join(',\\n ');\n\n // #382 round-2 — collect the union of all known prompt-arg kebab names so we\n // can register them as `.option(--<name> <value>)` on `prompt get`. Without\n // these registrations, Commander treats the value tokens (e.g. `add` after\n // `--op`) as extra positional args and rejects them with\n // `too many arguments for 'get'. Expected 1 argument but got 7.` —\n // breaking every prompt that takes arguments. Per-prompt validation still\n // happens inside the action handler against `promptArgs[name]`, so a user\n // that types `--op` for a prompt that doesn't declare it gets a clear\n // \"unknown option(s) for prompt\" error rather than silent acceptance.\n const allKebabNames = new Set<string>();\n for (const p of prompts) {\n for (const a of p.arguments || []) {\n allKebabNames.add(camelToKebab(a.name));\n }\n }\n const promptGetOptionLines = Array.from(allKebabNames)\n .sort()\n .map((kebab) => ` .option(${JSON.stringify(`--${kebab} <value>`)}, '')`)\n .join('\\n');\n\n const subcommands = prompts.map((prompt) => {\n const cmdName = camelToKebab(prompt.name).replace(/_/g, '-');\n const argOptions = (prompt.arguments || [])\n .map((a) => {\n const flag = `--${camelToKebab(a.name)} <value>`;\n const desc = a.description || '';\n return a.required\n ? ` .requiredOption('${flag}', '${escapeStr(desc)}')`\n : ` .option('${flag}', '${escapeStr(desc)}')`;\n })\n .join('\\n');\n\n return `promptCmd\n .command(${JSON.stringify(cmdName)})\n .description(${JSON.stringify((prompt.description || '') + ' (deprecated alias — use `prompt get ' + cmdName + '`)')})\n${argOptions}\n .action(async function(opts) {\n try {\n var client = await getClient();\n var args = {};\n var rawOpts = this.opts();\n ${(prompt.arguments || []).map((a) => {\n const camel = kebabToCamel(camelToKebab(a.name));\n return `if (rawOpts[${JSON.stringify(camel)}] !== undefined) args[${JSON.stringify(a.name)}] = rawOpts[${JSON.stringify(camel)}];`;\n }).join('\\n ')}\n var result = await client.getPrompt(${JSON.stringify(prompt.name)}, args);\n var mode = program.opts().output || 'text';\n console.log(fmt.formatPromptResult(result, mode));\n } catch (err) {\n _exitWithError(err, 1);\n }\n });`;\n });\n\n return `var promptCmd = program.command('prompt').description('Prompt operations');\n\npromptCmd\n .command('list')\n .description('List available prompts')\n .action(async function() {\n try {\n var client = await getClient();\n var result = await client.listPrompts();\n var mode = program.opts().output || 'text';\n if (mode === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n var prompts = result.prompts || [];\n if (prompts.length === 0) { console.log('No prompts available.'); return; }\n prompts.forEach(function(p) {\n console.log(' ' + p.name + (p.description ? ' - ' + p.description : ''));\n });\n }\n } catch (err) {\n _exitWithError(err, 1);\n }\n });\n\n// Symmetric \\`prompt get <name>\\` to mirror \\`resource read <uri>\\`. Looks up\n// per-prompt argument metadata from \\`promptArgs\\` and forwards as MCP\n// \\`prompts/get\\` request arguments. Unknown / missing required flags exit 2.\n//\n// Robust flag parser supports:\n// --key value (canonical form)\n// --key=value (single-token form)\n// --bool (boolean — value defaults to \"true\")\n// -- (end-of-options marker; everything after is ignored)\n// Unknown flags fail-fast with exit 2 instead of being silently dropped.\nvar promptArgs = {\n ${promptArgsMap}\n };\nvar _getCmd = promptCmd\n .command('get <name>')\n .description('Render a prompt by name')\n${promptGetOptionLines}\n .allowUnknownOption(true)\n .action(async function(name) {\n try {\n var spec = promptArgs[name];\n if (!spec) {\n console.error('Error: Unknown prompt: ' + name);\n process.exitCode = 1;\n return;\n }\n // Commander parsed registered options into rawOpts (camelCased). For\n // unregistered prompts (a flag a different prompt declares but this one\n // doesn't), fall back to scanning the raw token stream — that way an\n // out-of-spec --foo for \"this\" prompt still surfaces as an explicit\n // \"unknown option(s)\" error rather than being silently dropped.\n var rawOpts = this.opts();\n var rawTokens = this.args.slice(1);\n var args = {};\n var unknown = [];\n var byKebab = {};\n var byCamel = {};\n for (var s = 0; s < spec.length; s++) {\n byKebab[spec[s].kebab] = spec[s];\n byCamel[spec[s].camel] = spec[s];\n }\n // 1. Pull values from Commander-parsed options (registered names).\n for (var camelKey in rawOpts) {\n if (Object.prototype.hasOwnProperty.call(rawOpts, camelKey)) {\n var matchByCamel = byCamel[camelKey];\n if (matchByCamel) {\n args[matchByCamel.name] = rawOpts[camelKey];\n }\n }\n }\n // 2. Scan rawTokens for any --<flag> not in this prompt's spec — those\n // are real \"unknown for this prompt\" errors. (Commander already\n // consumed the registered ones; only out-of-spec flags survive here\n // via .allowUnknownOption(true).)\n for (var i = 0; i < rawTokens.length; i++) {\n var tok = rawTokens[i];\n if (tok === '--') break;\n if (typeof tok !== 'string' || tok.indexOf('--') !== 0) continue;\n var keyAndVal = tok.slice(2);\n var eq = keyAndVal.indexOf('=');\n var key = eq >= 0 ? keyAndVal.slice(0, eq) : keyAndVal;\n if (!byKebab[key]) {\n unknown.push('--' + key);\n }\n }\n if (unknown.length > 0) {\n console.error('Error: unknown option(s) for prompt \"' + name + '\": ' + unknown.join(', '));\n process.exitCode = 2;\n return;\n }\n // 3. Validate required args.\n for (var r = 0; r < spec.length; r++) {\n if (spec[r].required && args[spec[r].name] === undefined) {\n console.error('Error: missing required option --' + spec[r].kebab);\n process.exitCode = 2;\n return;\n }\n }\n var client = await getClient();\n var result = await client.getPrompt(name, args);\n var mode = program.opts().output || 'text';\n console.log(fmt.formatPromptResult(result, mode));\n } catch (err) {\n _exitWithError(err, 1);\n }\n });\n\n${subcommands.join('\\n\\n')}`;\n}\n\nfunction generateSkillsCommands(): string {\n return `var skillsCmd = program.command('skills').description('Skill operations');\n\nskillsCmd\n .command('search [query]')\n .description('Search for skills')\n .action(async function(query) {\n try {\n var client = await getClient();\n var result = await client.searchSkills(query || '');\n var mode = program.opts().output || 'text';\n if (mode === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n var skills = result.skills || [];\n if (skills.length === 0) { console.log('No skills found.'); return; }\n console.log('\\\\n Skills matching \"' + (query || '') + '\":\\\\n');\n skills.forEach(function(s) {\n var tags = (s.tags || []).slice(0, 3).join(', ');\n var score = s.score != null ? ' [score: ' + Number(s.score).toFixed(2) + ']' : '';\n console.log(' ' + (s.name || s.id) + score);\n if (s.description) console.log(' ' + s.description.split('. Use when')[0]);\n if (tags) console.log(' tags: ' + tags);\n console.log('');\n });\n console.log(' ' + skills.length + ' result(s).');\n console.log(\" Use '\" + program.name() + \" skills read <name>' for full details.\");\n console.log(\" Use '\" + program.name() + \" skills load <name>' to load a skill.\\\\n\");\n }\n } catch (err) {\n _exitWithError(err, 1);\n }\n });\n\nskillsCmd\n .command('load <ids...>')\n .description('Load skills by ID')\n .action(async function(ids) {\n try {\n var client = await getClient();\n var result = await client.loadSkills(ids);\n var mode = program.opts().output || 'text';\n if (mode === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n console.log('Loaded ' + ids.length + ' skill(s).');\n if (result && typeof result === 'object') {\n console.log(JSON.stringify(result, null, 2));\n }\n }\n } catch (err) {\n _exitWithError(err, 1);\n }\n });\n\nskillsCmd\n .command('read <name>')\n .description('Read full details for a skill')\n .action(async function(name) {\n try {\n var client = await getClient();\n var result = await client.loadSkills([name]);\n var mode = program.opts().output || 'text';\n if (mode === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n var skills = result.skills || [];\n if (skills.length === 0) { console.log('Skill \"' + name + '\" not found.'); return; }\n var sk = skills[0];\n console.log('\\\\n ' + sk.name);\n if (sk.description) console.log(' ' + sk.description);\n console.log('');\n if (sk.instructions) {\n console.log(sk.instructions);\n console.log('');\n }\n if (sk.tools && sk.tools.length > 0) {\n console.log(' Tools (' + sk.tools.length + '):');\n sk.tools.forEach(function(t) {\n console.log(' ' + t.name + (t.available ? '' : ' (unavailable)'));\n });\n console.log('');\n }\n if (result.nextSteps) console.log(' ' + result.nextSteps);\n console.log(\" Load: \" + program.name() + \" skills load \" + name + '\\\\n');\n }\n } catch (err) {\n _exitWithError(err, 1);\n }\n });\n\nskillsCmd\n .command('list')\n .description('List available skills')\n .action(async function() {\n try {\n var client = await getClient();\n var result = await client.listSkills();\n var mode = program.opts().output || 'text';\n if (mode === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n var skills = result.skills || [];\n if (skills.length === 0) { console.log('No skills available.'); return; }\n console.log('\\\\n Available Skills (' + skills.length + '):\\\\n');\n skills.forEach(function(s) {\n var desc = s.description ? s.description.split('. Use when')[0] : '';\n console.log(' ' + (s.name || s.id));\n if (desc) console.log(' ' + desc);\n console.log('');\n });\n console.log(\" Use '\" + program.name() + \" skills search <query>' for semantic search.\");\n console.log(\" Use '\" + program.name() + \" skills read <name>' for full details.\\\\n\");\n }\n } catch (err) {\n _exitWithError(err, 1);\n }\n });`;\n}\n\nfunction generateJobCommands(jobs: ExtractedJob[]): string {\n // Generate typed 'run' subcommands for each known job\n const runSubcommands = jobs.map((job) => {\n const jobCmdName = camelToKebab(job.name).replace(/_/g, '-');\n\n if (job.inputSchema) {\n const { options } = schemaToCommander(job.inputSchema);\n const optionLines = options.map((o) => ` ${generateOptionCode(o)}`).join('\\n');\n const argMapping = generateJobArgMapping(job.inputSchema);\n\n return `jobRunCmd\n .command(${JSON.stringify(jobCmdName)})\n .description(${JSON.stringify(job.description || `Run the ${job.name} job`)})\n${optionLines}\n .option('--background', 'Run in background mode')\n .action(async function(opts) {\n try {\n var client = await getClient();\n var input = {};\n var rawOpts = this.opts();\n ${argMapping}\n var result = await client.executeJob(${JSON.stringify(job.name)}, input, { background: !!rawOpts.background });\n var mode = program.opts().output || 'text';\n if (mode === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n if (rawOpts.background && result && result.runId) {\n console.log('Job started. Run ID: ' + result.runId);\n } else {\n console.log(JSON.stringify(result, null, 2));\n }\n }\n } catch (err) {\n _exitWithError(err, 1);\n }\n });`;\n }\n\n // No inputSchema — fall back to generic --input <json>\n return `jobRunCmd\n .command(${JSON.stringify(jobCmdName)})\n .description(${JSON.stringify(job.description || `Run the ${job.name} job`)})\n .option('--input <json>', 'Job input as JSON string')\n .option('--background', 'Run in background mode')\n .action(async function(opts) {\n try {\n var client = await getClient();\n var input = {};\n if (opts.input) {\n try { input = JSON.parse(opts.input); }\n catch (_) { console.error('Invalid JSON for --input'); process.exitCode = 1; return; }\n }\n var result = await client.executeJob(${JSON.stringify(job.name)}, input, { background: !!opts.background });\n var mode = program.opts().output || 'text';\n if (mode === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n if (opts.background && result && result.runId) {\n console.log('Job started. Run ID: ' + result.runId);\n } else {\n console.log(JSON.stringify(result, null, 2));\n }\n }\n } catch (err) {\n _exitWithError(err, 1);\n }\n });`;\n });\n\n // Generic fallback 'run' for jobs not known at build time\n const genericRun = `jobRunCmd\n .command('_run <name>')\n .description('Run a job by name (generic)')\n .option('--input <json>', 'Job input as JSON string')\n .option('--background', 'Run in background mode')\n .action(async function(name, opts) {\n try {\n var client = await getClient();\n var input = {};\n if (opts.input) {\n try { input = JSON.parse(opts.input); }\n catch (_) { console.error('Invalid JSON for --input'); process.exitCode = 1; return; }\n }\n var result = await client.executeJob(name, input, { background: !!opts.background });\n var mode = program.opts().output || 'text';\n if (mode === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n if (opts.background && result && result.runId) {\n console.log('Job started. Run ID: ' + result.runId);\n } else {\n console.log(JSON.stringify(result, null, 2));\n }\n }\n } catch (err) {\n _exitWithError(err, 1);\n }\n });`;\n\n return `var jobCmd = program.command('job').description('Job operations');\n\njobCmd\n .command('list')\n .description('List available jobs')\n .action(async function() {\n try {\n var client = await getClient();\n var result = await client.listJobs();\n var mode = program.opts().output || 'text';\n if (mode === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n var jobs = result.jobs || result || [];\n if (Array.isArray(jobs) && jobs.length === 0) { console.log('No jobs available.'); return; }\n if (Array.isArray(jobs)) {\n jobs.forEach(function(j) {\n console.log(' ' + (j.name || j.id || JSON.stringify(j)));\n });\n } else {\n console.log(JSON.stringify(result, null, 2));\n }\n }\n } catch (err) {\n _exitWithError(err, 1);\n }\n });\n\nvar jobRunCmd = jobCmd.command('run').description('Run a job');\n\n${runSubcommands.join('\\n\\n')}\n\n${jobs.length > 0 ? genericRun : `jobRunCmd\n .argument('<name>', 'Job name')\n .option('--input <json>', 'Job input as JSON string')\n .option('--background', 'Run in background mode')\n .action(async function(name, opts) {\n try {\n var client = await getClient();\n var input = {};\n if (opts.input) {\n try { input = JSON.parse(opts.input); }\n catch (_) { console.error('Invalid JSON for --input'); process.exitCode = 1; return; }\n }\n var result = await client.executeJob(name, input, { background: !!opts.background });\n var mode = program.opts().output || 'text';\n if (mode === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n if (opts.background && result && result.runId) {\n console.log('Job started. Run ID: ' + result.runId);\n } else {\n console.log(JSON.stringify(result, null, 2));\n }\n }\n } catch (err) {\n _exitWithError(err, 1);\n }\n });`}\n\njobCmd\n .command('status <runId>')\n .description('Get the status of a job run')\n .action(async function(runId) {\n try {\n var client = await getClient();\n var result = await client.getJobStatus(runId);\n var mode = program.opts().output || 'text';\n if (mode === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n console.log('Status: ' + (result.status || JSON.stringify(result)));\n }\n } catch (err) {\n _exitWithError(err, 1);\n }\n });`;\n}\n\nfunction generateWorkflowCommands(): string {\n return `var workflowCmd = program.command('workflow').description('Workflow operations');\n\nworkflowCmd\n .command('list')\n .description('List available workflows')\n .action(async function() {\n try {\n var client = await getClient();\n var result = await client.listWorkflows();\n var mode = program.opts().output || 'text';\n if (mode === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n var workflows = result.workflows || result || [];\n if (Array.isArray(workflows) && workflows.length === 0) { console.log('No workflows available.'); return; }\n if (Array.isArray(workflows)) {\n workflows.forEach(function(w) {\n console.log(' ' + (w.name || w.id || JSON.stringify(w)));\n });\n } else {\n console.log(JSON.stringify(result, null, 2));\n }\n }\n } catch (err) {\n _exitWithError(err, 1);\n }\n });\n\nworkflowCmd\n .command('run <name>')\n .description('Run a workflow by name')\n .option('--input <json>', 'Workflow input as JSON string')\n .option('--background', 'Run in background mode')\n .action(async function(name, opts) {\n try {\n var client = await getClient();\n var input = {};\n if (opts.input) {\n try { input = JSON.parse(opts.input); }\n catch (_) { console.error('Invalid JSON for --input'); process.exitCode = 1; return; }\n }\n var result = await client.executeWorkflow(name, input, { background: !!opts.background });\n var mode = program.opts().output || 'text';\n if (mode === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n if (opts.background && result && result.runId) {\n console.log('Workflow started. Run ID: ' + result.runId);\n } else {\n console.log(JSON.stringify(result, null, 2));\n }\n }\n } catch (err) {\n _exitWithError(err, 1);\n }\n });\n\nworkflowCmd\n .command('status <runId>')\n .description('Get the status of a workflow run')\n .action(async function(runId) {\n try {\n var client = await getClient();\n var result = await client.getWorkflowStatus(runId);\n var mode = program.opts().output || 'text';\n if (mode === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n console.log('Status: ' + (result.status || JSON.stringify(result)));\n }\n } catch (err) {\n _exitWithError(err, 1);\n }\n });`;\n}\n\nfunction generateSubscribeCommands(): string {\n return `\n// Subscribe commands need push support (onNotification/onResourceUpdated).\n// Daemon HTTP cannot push, so we force in-process when daemon was used.\nasync function getSubscribeClient() {\n var client = await getClient();\n // If connected via daemon, the onNotification/onResourceUpdated are no-ops.\n // Reconnect via in-process for push support.\n if (client._isDaemon) {\n // Close the daemon client before replacing with in-process client\n if (typeof client.close === 'function') { try { await client.close(); } catch (_) {} }\n _client = null;\n var mod = require(SERVER_BUNDLE);\n var configOrClass = mod.default || mod;\n var sdk = require('@frontmcp/sdk');\n var connect = sdk.connect || sdk.direct.connect;\n _client = await connect(configOrClass, { mode: 'cli' });\n return _client;\n }\n return client;\n}\n\nvar subscribeCmd = program.command('subscribe').description('Subscribe to updates');\n\nsubscribeCmd\n .command('resource <uri>')\n .description('Stream resource updates (Ctrl+C to stop)')\n .action(async function(uri) {\n try {\n var client = await getSubscribeClient();\n await client.subscribeResource(uri);\n var mode = program.opts().output || 'text';\n console.log('Subscribed to resource: ' + uri);\n console.log('Waiting for updates... (Ctrl+C to stop)\\\\n');\n client.onResourceUpdated(function(uri) {\n console.log(fmt.formatSubscriptionEvent({ type: 'resource_updated', uri: uri, timestamp: new Date().toISOString() }, mode));\n });\n process.on('SIGINT', async function() {\n console.log('\\\\nUnsubscribing...');\n try { await client.unsubscribeResource(uri); } catch (_) { /* ok */ }\n await closeClient();\n process.exit(0);\n });\n // Keep process alive — setInterval creates an active event loop handle\n // so Node.js won't exit even with InMemoryTransport (no persistent I/O)\n setInterval(function() {}, 2147483647);\n await new Promise(function() {});\n } catch (err) {\n _exitWithError(err, 1);\n }\n });\n\nsubscribeCmd\n .command('notification <name>')\n .description('Stream notifications (Ctrl+C to stop)')\n .action(async function(name) {\n try {\n var client = await getSubscribeClient();\n var mode = program.opts().output || 'text';\n console.log('Listening for notification: ' + name);\n console.log('Waiting for events... (Ctrl+C to stop)\\\\n');\n client.onNotification(function(notification) {\n if (notification.method === name || name === '*') {\n console.log(fmt.formatSubscriptionEvent({ type: 'notification', method: notification.method, params: notification.params, timestamp: new Date().toISOString() }, mode));\n }\n });\n process.on('SIGINT', async function() {\n console.log('\\\\nStopping...');\n await closeClient();\n process.exit(0);\n });\n // Keep process alive — setInterval creates an active event loop handle\n // so Node.js won't exit even with InMemoryTransport (no persistent I/O)\n setInterval(function() {}, 2147483647);\n await new Promise(function() {});\n } catch (err) {\n _exitWithError(err, 1);\n }\n });`;\n}\n\nfunction generateLoginCommand(appName: string, oauthConfig?: OAuthConfig): string {\n const serverUrl = oauthConfig?.serverUrl || '';\n const clientId = oauthConfig?.clientId || appName;\n const defaultScope = oauthConfig?.defaultScope || '';\n const portStart = oauthConfig?.portRange?.[0] ?? 17830;\n const portEnd = oauthConfig?.portRange?.[1] ?? 17850;\n const timeout = oauthConfig?.timeout ?? 120000;\n\n return `program\n .command('login')\n .description('Authenticate via OAuth')\n .option('--server <url>', 'Server URL for OAuth'${serverUrl ? `, ${JSON.stringify(serverUrl)}` : ''})\n .option('--session <name>', 'Session name', 'default')\n .option('--scope <scopes>', 'OAuth scopes'${defaultScope ? `, ${JSON.stringify(defaultScope)}` : ''})\n .option('--no-browser', 'Print URL instead of opening browser')\n .action(async function(opts) {\n var serverUrl = opts.server || process.env.FRONTMCP_SERVER_URL || ${JSON.stringify(serverUrl)};\n if (!serverUrl) {\n console.error('Server URL required. Use --server <url> or set FRONTMCP_SERVER_URL.');\n process.exitCode = 1;\n return;\n }\n try {\n var oauthHelper = require('./oauth-helper');\n var result = await oauthHelper.startOAuthLogin({\n serverUrl: serverUrl,\n clientId: ${JSON.stringify(clientId)},\n scope: opts.scope || ${JSON.stringify(defaultScope)},\n portStart: ${portStart},\n portEnd: ${portEnd},\n timeout: ${timeout},\n noBrowser: !opts.browser\n });\n var sessionName = opts.session || 'default';\n var store = creds.createCredentialStore();\n await store.set(sessionName, result);\n sessions.getOrCreateSession(sessionName);\n console.log('Logged in successfully. Session: ' + sessionName);\n } catch (err) {\n console.error('Login failed:', err.message || err);\n process.exitCode = 1;\n }\n });`;\n}\n\nfunction generateLogoutCommand(_appName: string): string {\n return `program\n .command('logout')\n .description('Clear stored credentials')\n .option('--session <name>', 'Session to log out')\n .option('--all', 'Log out of all sessions')\n .action(async function(opts) {\n var store = creds.createCredentialStore();\n if (opts.all) {\n var allSessions = await store.list();\n for (var i = 0; i < allSessions.length; i++) {\n await store.delete(allSessions[i]);\n }\n console.log('Logged out of ' + allSessions.length + ' session(s).');\n } else {\n var sessionName = opts.session || sessions.getActiveSessionName();\n await store.delete(sessionName);\n console.log('Logged out of session: ' + sessionName);\n }\n });`;\n}\n\nfunction generateSessionCommands(): string {\n return `var sessionsCmd = program.command('sessions').description('Session management');\n\nsessionsCmd\n .command('list')\n .description('List all sessions')\n .action(function() {\n var list = sessions.listSessions();\n if (list.length === 0) { console.log('No sessions.'); return; }\n list.forEach(function(s) {\n var marker = s.isActive ? ' (active)' : '';\n console.log(' ' + s.name + marker + ' - last used: ' + s.lastUsedAt);\n });\n });\n\nsessionsCmd\n .command('switch <name>')\n .description('Switch to a named session')\n .action(function(name) {\n sessions.switchSession(name);\n console.log('Switched to session: ' + name);\n });\n\nsessionsCmd\n .command('delete <name>')\n .description('Delete a session')\n .action(async function(name) {\n var store = creds.createCredentialStore();\n await store.delete(name);\n sessions.deleteSession(name);\n console.log('Deleted session: ' + name);\n });\n\nprogram\n .command('connect')\n .description('Authenticate and store credentials')\n .option('--session <name>', 'Session name', 'default')\n .option('--token <token>', 'Auth token (or pass via stdin)')\n .action(async function(opts) {\n var sessionName = opts.session || 'default';\n var token = opts.token;\n if (!token) {\n console.log('Usage: ' + program.name() + ' connect --token <your-token>');\n console.log(' Or pipe token: echo \"tok_xxx\" | ' + program.name() + ' connect');\n process.exitCode = 1;\n return;\n }\n var store = creds.createCredentialStore();\n await store.set(sessionName, { token: token });\n sessions.getOrCreateSession(sessionName);\n console.log('Credentials stored for session: ' + sessionName);\n });`;\n}\n\nfunction generateServeCommand(serverBundleFilename: string, selfContained?: boolean): string {\n // In self-contained/SEA mode, use a static relative require that esbuild can resolve at bundle time.\n // In normal mode, use dynamic path.join for runtime resolution from disk.\n const requireExpr = selfContained\n ? `require(${JSON.stringify('../' + serverBundleFilename)})`\n : `require(path.join(SCRIPT_DIR, ${JSON.stringify(serverBundleFilename)}))`;\n\n return `program\n .command('serve')\n .description('Start the MCP server')\n .option('-p, --port <port>', 'Port number', function(v) { return parseInt(v, 10); })\n .option('--stdio', 'Run as stdio transport (stdin/stdout JSON-RPC) for use in .mcp.json')\n .action(async function(opts) {\n if (opts.stdio) {\n // --stdio on serve is handled by the early argv check at the top of the entry;\n // this branch is a fallback in case commander parsed it first.\n _isLongRunning = true;\n process.env.FRONTMCP_SCHEMA_EXTRACT = '1';\n var sMod = ${requireExpr};\n delete process.env.FRONTMCP_SCHEMA_EXTRACT;\n var sRaw = sMod.default || sMod;\n var sSdk = require('@frontmcp/sdk');\n var sFMI = sSdk.FrontMcpInstance || sSdk.default.FrontMcpInstance;\n var sCfg = (typeof sRaw === 'function' && typeof Reflect !== 'undefined' && Reflect.getMetadata)\n ? (Reflect.getMetadata('__frontmcp:config', sRaw) || sRaw) : sRaw;\n await sFMI.runStdio(sCfg);\n return;\n }\n _isLongRunning = true;\n // Suppress @FrontMcp decorator auto-bootstrap during require() — the CLI\n // serve command handles bootstrap explicitly below with port/config overrides.\n process.env.FRONTMCP_SCHEMA_EXTRACT = '1';\n var mod = ${requireExpr};\n delete process.env.FRONTMCP_SCHEMA_EXTRACT;\n if (opts.port) process.env.PORT = String(opts.port);\n // If the bundle exports a start() function (@FrontMcp-decorated class auto-bootstraps), use it\n if (typeof mod.start === 'function') { await mod.start(); return; }\n if (typeof mod.default?.start === 'function') { await mod.default.start(); return; }\n // Otherwise, bootstrap the plain config object via FrontMcpInstance\n var raw = mod.default || mod;\n var sdk = require('@frontmcp/sdk');\n var FrontMcpInstance = sdk.FrontMcpInstance || sdk.default.FrontMcpInstance;\n var config = (typeof raw === 'function' && typeof Reflect !== 'undefined' && Reflect.getMetadata)\n ? (Reflect.getMetadata('__frontmcp:config', raw) || raw) : raw;\n if (opts.port) config = Object.assign({}, config, { http: Object.assign({}, config.http || {}, { port: opts.port }) });\n await FrontMcpInstance.bootstrap(config);\n });`;\n}\n\nfunction generateDoctorCommand(\n appName: string,\n nativeDeps: NonNullable<CliConfig['nativeDeps']>,\n): string {\n const checks: string[] = [];\n\n if (nativeDeps.brew?.length) {\n for (const pkg of nativeDeps.brew) {\n checks.push(` { name: ${JSON.stringify(pkg)}, type: 'brew', check: 'brew list ${pkg}' }`);\n }\n }\n if (nativeDeps.apt?.length) {\n for (const pkg of nativeDeps.apt) {\n checks.push(` { name: ${JSON.stringify(pkg)}, type: 'apt', check: 'dpkg -l ${pkg}' }`);\n }\n }\n if (nativeDeps.npm?.length) {\n for (const pkg of nativeDeps.npm) {\n checks.push(` { name: ${JSON.stringify(pkg)}, type: 'npm', check: 'npm ls ${pkg}' }`);\n }\n }\n\n return `program\n .command('doctor')\n .description('Check system dependencies and configuration')\n .option('--fix', 'Attempt to install missing dependencies')\n .action(async function(opts) {\n var exec = require('child_process').execSync;\n var ok = true;\n\n // Check Node.js version\n var nodeMajor = parseInt(process.versions.node.split('.')[0], 10);\n if (nodeMajor >= 22) {\n console.log(' [ok] Node.js v' + process.versions.node);\n } else {\n console.log(' [!!] Node.js v' + process.versions.node + ' (>=22 required)');\n ok = false;\n }\n\n var deps = [\n${checks.join(',\\n')}\n ];\n\n for (var i = 0; i < deps.length; i++) {\n var dep = deps[i];\n try {\n exec(dep.check, { stdio: 'ignore' });\n console.log(' [ok] ' + dep.name + ' (' + dep.type + ')');\n } catch (_) {\n console.log(' [!!] ' + dep.name + ' (' + dep.type + ') - not found');\n ok = false;\n if (opts.fix) {\n try {\n var installCmd = dep.type === 'brew' ? 'brew install ' + dep.name\n : dep.type === 'apt' ? 'sudo apt-get install -y ' + dep.name\n : 'npm install ' + dep.name;\n console.log(' Installing: ' + installCmd);\n exec(installCmd, { stdio: 'inherit' });\n console.log(' [ok] Installed ' + dep.name);\n } catch (e) {\n console.log(' [!!] Failed to install ' + dep.name);\n }\n }\n }\n }\n\n // Check FRONTMCP_HOME directory\n var fs = require('fs');\n var appDir = require('path').join(FRONTMCP_HOME, 'apps', ${JSON.stringify(appName)});\n if (fs.existsSync(appDir)) {\n console.log(' [ok] App directory: ' + appDir);\n } else {\n console.log(' [!!] App directory not found: ' + appDir);\n ok = false;\n if (opts.fix) {\n fs.mkdirSync(appDir, { recursive: true });\n console.log(' [fixed] Created ' + appDir);\n }\n }\n\n if (ok) console.log('\\\\nAll checks passed.');\n else {\n console.log('\\\\nSome checks failed.' + (opts.fix ? '' : ' Run with --fix to attempt repairs.'));\n process.exitCode = 1;\n }\n });`;\n}\n\nfunction generateInstallCommand(\n appName: string,\n nativeDeps: NonNullable<CliConfig['nativeDeps']>,\n selfContained?: boolean,\n): string {\n const depEntries: string[] = [];\n if (nativeDeps.brew?.length) {\n for (const pkg of nativeDeps.brew) {\n depEntries.push(` { name: ${JSON.stringify(pkg)}, type: 'brew', install: 'brew install ${pkg}', check: 'brew list ${pkg}' }`);\n }\n }\n if (nativeDeps.npm?.length) {\n for (const pkg of nativeDeps.npm) {\n depEntries.push(` { name: ${JSON.stringify(pkg)}, type: 'npm', install: 'npm install ${pkg}', check: 'npm ls ${pkg}' }`);\n }\n }\n\n return `program\n .command('install')\n .description('Install to ~/.frontmcp/ and set up dependencies')\n .option('--prefix <path>', 'Installation prefix directory')\n .option('--bin-dir <path>', 'Directory for symlink (default: ~/.local/bin or /usr/local/bin)')\n .action(async function(opts) {\n var fs = require('fs');\n var pathMod = require('path');\n var os = require('os');\n var exec = require('child_process').execSync;\n var installBase = opts.prefix || FRONTMCP_HOME;\n var appDir = pathMod.join(installBase, 'apps', ${JSON.stringify(appName)});\n var dirs = ['', '/data', '/sessions', '/credentials'].map(function(s) { return appDir + s; });\n\n console.log('Installing ${appName}...');\n dirs.forEach(function(d) { fs.mkdirSync(d, { recursive: true }); });\n\n // Copy bundle files and skill content\n var files = fs.readdirSync(SCRIPT_DIR).filter(function(f) {\n return f.endsWith('.js') || f.endsWith('.json') || f.endsWith('.md')${selfContained ? \" || f.endsWith('-bin')\" : ''};\n });\n files.forEach(function(f) {\n fs.copyFileSync(pathMod.join(SCRIPT_DIR, f), pathMod.join(appDir, f));\n });\n // Copy skill content directories (only those that exist in the build output)\n var entries = fs.readdirSync(SCRIPT_DIR, { withFileTypes: true });\n entries.forEach(function(ent) {\n if (ent.isDirectory()) {\n fs.cpSync(pathMod.join(SCRIPT_DIR, ent.name), pathMod.join(appDir, ent.name), { recursive: true });\n }\n });\n console.log(' Copied ' + files.length + ' files to ' + appDir);\n\n // Install native deps\n var deps = [\n${depEntries.join(',\\n')}\n ];\n for (var i = 0; i < deps.length; i++) {\n var dep = deps[i];\n try { exec(dep.check, { stdio: 'ignore' }); }\n catch (_) {\n console.log(' [' + (i + 1) + '/' + deps.length + '] Installing ' + dep.name + ' via ' + dep.type + '...');\n try { exec(dep.install, { stdio: 'inherit' }); }\n catch (e) { console.log(' Warning: Failed to install ' + dep.name); }\n }\n }\n\n // Set execute permission on the entry point\n var entryFile = pathMod.join(appDir, ${JSON.stringify(selfContained ? `${appName}-cli-bin` : `${appName}-cli.bundle.js`)});\n try { fs.chmodSync(entryFile, 0o755); } catch (_) { /* ok */ }\n\n // Create symlink\n var binDirs = opts.binDir ? [opts.binDir] : ['/usr/local/bin', pathMod.join(os.homedir(), '.local', 'bin')];\n var linked = false;\n for (var j = 0; j < binDirs.length && !linked; j++) {\n try {\n fs.mkdirSync(binDirs[j], { recursive: true });\n var linkPath = pathMod.join(binDirs[j], ${JSON.stringify(appName)});\n try { fs.unlinkSync(linkPath); } catch (_) { /* ok */ }\n fs.symlinkSync(entryFile, linkPath);\n console.log(' Symlinked: ' + linkPath);\n linked = true;\n } catch (_) { /* try next */ }\n }\n\n console.log('\\\\nInstalled. Run: ${appName} --help');\n });\n\nprogram\n .command('uninstall')\n .description('Remove from ~/.frontmcp/ and clean up')\n .option('--prefix <path>', 'Installation prefix directory')\n .option('--bin-dir <path>', 'Directory where symlink was created')\n .action(async function(opts) {\n var fs = require('fs');\n var pathMod = require('path');\n var os = require('os');\n var uninstallBase = opts.prefix || FRONTMCP_HOME;\n var appDir = pathMod.join(uninstallBase, 'apps', ${JSON.stringify(appName)});\n\n // Remove credentials (if auth is enabled)\n if (typeof creds !== 'undefined') {\n var store = creds.createCredentialStore();\n var credSessions = await store.list();\n for (var i = 0; i < credSessions.length; i++) {\n await store.delete(credSessions[i]);\n }\n }\n\n // Remove symlink\n var binDirs = opts.binDir ? [opts.binDir] : ['/usr/local/bin', pathMod.join(os.homedir(), '.local', 'bin')];\n binDirs.forEach(function(d) {\n try { fs.unlinkSync(pathMod.join(d, ${JSON.stringify(appName)})); } catch (_) { /* ok */ }\n });\n\n // Remove app directory\n fs.rmSync(appDir, { recursive: true, force: true });\n console.log('Uninstalled ${appName}.');\n });`;\n}\n\nfunction generateDaemonCommands(appName: string, serverBundleFilename: string, selfContained?: boolean): string {\n return `var daemonCmd = program.command('daemon').description('Daemon management');\n\ndaemonCmd\n .command('start')\n .description('Start as a background daemon')\n .option('-p, --port <port>', 'Listen on a TCP port instead of a Unix socket', function(v) { return parseInt(v, 10); })\n .option('--idle-timeout <ms>', 'Auto-stop after idle period (ms, 0 to disable)', function(v) { return parseInt(v, 10); }, 300000)\n .action(async function(opts) {\n var { spawn } = require('child_process');\n var pathMod = require('path');\n var pidDir = pathMod.join(FRONTMCP_HOME, 'pids');\n var logDir = pathMod.join(FRONTMCP_HOME, 'logs');\n var socketDir = pathMod.join(FRONTMCP_HOME, 'sockets');\n fs.mkdirSync(pidDir, { recursive: true });\n fs.mkdirSync(logDir, { recursive: true });\n fs.mkdirSync(socketDir, { recursive: true });\n\n var usePort = !!opts.port;\n var socketPath = pathMod.join(socketDir, ${JSON.stringify(appName)} + '.sock');\n\n // Clean up stale socket file (only relevant in socket mode)\n if (!usePort) { try { fs.unlinkSync(socketPath); } catch (_) { /* ok */ } }\n\n // Check if already running\n var pidPath = pathMod.join(pidDir, ${JSON.stringify(appName)} + '.pid');\n try {\n var existing = JSON.parse(fs.readFileSync(pidPath, 'utf8'));\n process.kill(existing.pid, 0);\n console.log('Daemon already running (PID: ' + existing.pid + ').');\n return;\n } catch (_) { /* not running, proceed */ }\n\n var env = Object.assign({}, process.env, {\n FRONTMCP_DAEMON_IDLE_TIMEOUT: String(opts.idleTimeout)\n });\n if (usePort) {\n env.FRONTMCP_DAEMON_PORT = String(opts.port);\n } else {\n env.FRONTMCP_DAEMON_SOCKET = socketPath;\n }\n\n var logPath = pathMod.join(logDir, ${JSON.stringify(appName)} + '.log');\n var out = fs.openSync(logPath, 'a');\n var err = fs.openSync(logPath, 'a');\n\n${selfContained ? ` // SEA mode: spawn the binary itself in daemon mode — all code is inlined\n env.__FRONTMCP_DAEMON_MODE = '1';\n var child = spawn(process.execPath, [], {\n detached: true,\n stdio: ['ignore', out, err],\n env: env\n });` : ` // Start the daemon via a small wrapper script\n // Always use absolute path for the server bundle (SCRIPT_DIR resolves to __dirname at runtime)\n var serverBundlePath = pathMod.join(SCRIPT_DIR, ${JSON.stringify(serverBundleFilename)});\n var daemonScript = 'require(\"reflect-metadata\");' +\n 'process.env.FRONTMCP_SCHEMA_EXTRACT=\"1\";' +\n 'var mod = require(' + JSON.stringify(serverBundlePath) + ');' +\n 'delete process.env.FRONTMCP_SCHEMA_EXTRACT;' +\n 'var sdk = require(\"@frontmcp/sdk\");' +\n 'var FrontMcpInstance = sdk.FrontMcpInstance || sdk.default.FrontMcpInstance;' +\n 'var raw = mod.default || mod;' +\n ${'// If the export is a @FrontMcp-decorated class, extract config via Reflect metadata'}\n 'var config = (typeof raw === \"function\" && typeof Reflect !== \"undefined\" && Reflect.getMetadata) ' +\n ' ? (Reflect.getMetadata(\"__frontmcp:config\", raw) || raw) : raw;';\n\n if (usePort) {\n daemonScript +=\n 'config = Object.assign({}, config, { http: Object.assign({}, config.http || {}, { port: ' + opts.port + ' }) });' +\n 'process.env.PORT = ' + JSON.stringify(String(opts.port)) + ';' +\n 'FrontMcpInstance.bootstrap(config)' +\n '.then(function() { console.log(\"Daemon listening on port ' + opts.port + '\"); })' +\n '.catch(function(e) { console.error(\"Daemon failed:\", e); process.exit(1); });';\n } else {\n daemonScript +=\n 'FrontMcpInstance.runUnixSocket(Object.assign({}, config, { socketPath: ' + JSON.stringify(socketPath) + ' }))' +\n '.then(function() { console.log(\"Daemon listening on \" + ' + JSON.stringify(socketPath) + '); })' +\n '.catch(function(e) { console.error(\"Daemon failed:\", e); process.exit(1); });';\n }\n\n var child = spawn('node', ['-e', daemonScript], {\n detached: true,\n stdio: ['ignore', out, err],\n env: env\n });`}\n\n // Close inherited file descriptors in the parent — the child already has its own copy.\n fs.closeSync(out);\n fs.closeSync(err);\n\n var pidData = { pid: child.pid, startedAt: new Date().toISOString() };\n if (usePort) {\n pidData.port = opts.port;\n } else {\n pidData.socketPath = socketPath;\n }\n fs.writeFileSync(pidPath, JSON.stringify(pidData));\n child.unref();\n\n if (usePort) {\n // For port mode, wait briefly then check if process is still alive\n await new Promise(function(r) { setTimeout(r, 1000); });\n try {\n process.kill(child.pid, 0);\n console.log('Daemon started (PID: ' + child.pid + '). Port: ' + opts.port);\n console.log('Logs: ' + logPath);\n } catch (_) {\n console.log('Daemon failed to start. Check logs: ' + logPath);\n }\n } else {\n // Wait for socket file to appear (max 5s)\n var waited = 0;\n while (!fs.existsSync(socketPath) && waited < 5000) {\n await new Promise(function(r) { setTimeout(r, 100); });\n waited += 100;\n }\n\n if (fs.existsSync(socketPath)) {\n console.log('Daemon started (PID: ' + child.pid + '). Socket: ' + socketPath);\n console.log('Logs: ' + logPath);\n } else {\n console.log('Daemon started (PID: ' + child.pid + ') but socket not yet available.');\n console.log('Check logs: ' + logPath);\n }\n }\n });\n\ndaemonCmd\n .command('stop')\n .description('Stop the daemon')\n .action(function() {\n var pathMod = require('path');\n var pidPath = pathMod.join(FRONTMCP_HOME, 'pids', ${JSON.stringify(appName)} + '.pid');\n try {\n var data = JSON.parse(fs.readFileSync(pidPath, 'utf8'));\n process.kill(data.pid, 'SIGTERM');\n fs.unlinkSync(pidPath);\n // Clean up socket file\n if (data.socketPath) {\n try { fs.unlinkSync(data.socketPath); } catch (_) { /* ok */ }\n }\n console.log('Daemon stopped (PID: ' + data.pid + ').');\n } catch (e) {\n console.log('No running daemon found.');\n }\n });\n\ndaemonCmd\n .command('status')\n .description('Check daemon status')\n .action(function() {\n var pathMod = require('path');\n var pidPath = pathMod.join(FRONTMCP_HOME, 'pids', ${JSON.stringify(appName)} + '.pid');\n try {\n var data = JSON.parse(fs.readFileSync(pidPath, 'utf8'));\n try {\n process.kill(data.pid, 0);\n var listenInfo = data.port ? ', port: ' + data.port : (data.socketPath && fs.existsSync(data.socketPath) ? ', socket: active' : '');\n console.log('Running (PID: ' + data.pid + ', started: ' + data.startedAt + listenInfo + ')');\n } catch (_) {\n console.log('Not running (stale PID file).');\n fs.unlinkSync(pidPath);\n }\n } catch (_) { console.log('Not running.'); }\n });\n\ndaemonCmd\n .command('logs')\n .description('Tail daemon logs')\n .option('-n, --lines <n>', 'Number of lines', function(v) { return parseInt(v, 10); }, 50)\n .action(function(opts) {\n var pathMod = require('path');\n var logPath = pathMod.join(FRONTMCP_HOME, 'logs', ${JSON.stringify(appName)} + '.log');\n try {\n var content = fs.readFileSync(logPath, 'utf8');\n var lines = content.split('\\\\n');\n var start = Math.max(0, lines.length - opts.lines);\n console.log(lines.slice(start).join('\\\\n'));\n } catch (_) { console.log('No logs found.'); }\n });`;\n}\n\nfunction generateFooter(): string {\n return `program.on('command:*', function(args) {\n console.error('Unknown command: ' + args[0]);\n process.exitCode = 1;\n});\nprogram.parseAsync(process.argv).then(async function() {\n // Long-running commands (serve) set _isLongRunning to keep the event loop alive.\n // Short-lived commands close the client and exit explicitly to avoid hanging\n // on unclosed handles (file loggers, in-memory transport, etc.).\n if (_isLongRunning) return;\n await closeClient();\n // Defer process.exit() by one event-loop tick so native addon destructors\n // (ONNX runtime, etc.) can release mutexes before V8 tears down.\n setImmediate(function() { process.exit(process.exitCode || 0); });\n}).catch(async function(err) {\n // Commander errors come through exitOverride with the code already set on\n // process.exitCode. They are user-facing usage errors, not fatals — don't\n // re-print \"Fatal:\" / \"Unknown error\" for them.\n var isCommanderErr = err && typeof err.code === 'string' && err.code.indexOf('commander.') === 0;\n if (!isCommanderErr) {\n console.error('Fatal:', err.message || err);\n }\n await closeClient();\n // Use the exit code set by exitOverride (which can legitimately be 0 for\n // --help / --version). Only fall back to 1 when no code was set.\n setImmediate(function() {\n var code = (typeof process.exitCode === 'number') ? process.exitCode : 1;\n process.exit(code);\n });\n});`;\n}\n\n/**\n * Extract {param} placeholders from a URI template string.\n */\nexport function extractTemplateParams(uriTemplate: string): string[] {\n const matches = uriTemplate.match(/\\{([^}]+)\\}/g);\n if (!matches) return [];\n return matches.map((m) => m.slice(1, -1));\n}\n\nfunction kebabToCamel(str: string): string {\n return str.replace(/-([a-z])/g, (_, c) => c.toUpperCase());\n}\n\nfunction escapeStr(s: string): string {\n return s.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n}\n"]}
|
|
@@ -56,7 +56,7 @@ export interface FrontmcpExecConfig {
|
|
|
56
56
|
};
|
|
57
57
|
}
|
|
58
58
|
/**
|
|
59
|
-
* Load frontmcp.config.js
|
|
59
|
+
* Load frontmcp.config.{ts,js,json,mjs,cjs} from the given directory.
|
|
60
60
|
* Falls back to deriving minimal config from package.json.
|
|
61
61
|
*/
|
|
62
62
|
export declare function loadExecConfig(cwd: string): Promise<FrontmcpExecConfig>;
|
|
@@ -9,13 +9,19 @@ const tslib_1 = require("tslib");
|
|
|
9
9
|
const path = tslib_1.__importStar(require("path"));
|
|
10
10
|
const fs = tslib_1.__importStar(require("fs"));
|
|
11
11
|
const CONFIG_FILENAMES = [
|
|
12
|
+
// #365 round-3 — `.ts` is checked first so the user's typed config takes
|
|
13
|
+
// priority over a stale `.js` left in the project. `.ts` loading routes
|
|
14
|
+
// through the same esbuild path as the new-shape loader so it works under
|
|
15
|
+
// `"type": "commonjs"` (Node's `require(.ts)` and `await import(.ts)` are
|
|
16
|
+
// both unreliable here and were the root cause of #365 1.1.0–1.1.2-beta.1).
|
|
17
|
+
'frontmcp.config.ts',
|
|
12
18
|
'frontmcp.config.js',
|
|
13
19
|
'frontmcp.config.json',
|
|
14
20
|
'frontmcp.config.mjs',
|
|
15
21
|
'frontmcp.config.cjs',
|
|
16
22
|
];
|
|
17
23
|
/**
|
|
18
|
-
* Load frontmcp.config.js
|
|
24
|
+
* Load frontmcp.config.{ts,js,json,mjs,cjs} from the given directory.
|
|
19
25
|
* Falls back to deriving minimal config from package.json.
|
|
20
26
|
*/
|
|
21
27
|
async function loadExecConfig(cwd) {
|
|
@@ -26,6 +32,29 @@ async function loadExecConfig(cwd) {
|
|
|
26
32
|
const content = fs.readFileSync(configPath, 'utf-8');
|
|
27
33
|
return JSON.parse(content);
|
|
28
34
|
}
|
|
35
|
+
if (filename.endsWith('.ts')) {
|
|
36
|
+
// Delegate to the new loader's esbuild transpile so `.ts` configs
|
|
37
|
+
// work under `"type": "commonjs"` projects. Hard-fails on parse error
|
|
38
|
+
// (no silent default) — matches frontmcp-config.loader semantics.
|
|
39
|
+
// tsc uses `--moduleResolution nodenext`, so the dynamic import
|
|
40
|
+
// needs an explicit `.js` suffix that resolves to the compiled
|
|
41
|
+
// output. The barrel (`../../../config/index.js`) re-exports
|
|
42
|
+
// `loadFrontMcpConfig` from the loader module.
|
|
43
|
+
const { loadFrontMcpConfig } = await import('../../../config/index.js');
|
|
44
|
+
try {
|
|
45
|
+
// The new-shape loader returns a parsed config — we only consume the
|
|
46
|
+
// legacy-shape fields here. Fields that exist in both shapes
|
|
47
|
+
// (name, version, entry, nodeVersion) carry through; new-shape-only
|
|
48
|
+
// fields like `deployments` are ignored by this consumer.
|
|
49
|
+
const newShape = await loadFrontMcpConfig(cwd);
|
|
50
|
+
return newShape;
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
throw new Error(`Failed to load ${filename}: ${err.message}\n` +
|
|
54
|
+
`If your config doesn't match the new schema (deployments[] etc.), ` +
|
|
55
|
+
`rename it to .js or use the legacy module.exports shape.`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
29
58
|
// JS/MJS/CJS config — require it
|
|
30
59
|
const mod = require(configPath);
|
|
31
60
|
return (mod.default || mod);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../../../src/commands/build/exec/config.ts"],"names":[],"mappings":";AAAA;;GAEG;;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../../../src/commands/build/exec/config.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * frontmcp.config.js/json schema and loader.\n */\n\nimport * as path from 'path';\nimport * as fs from 'fs';\nimport type { SetupDefinition } from './setup';\n\nexport interface OAuthConfig {\n serverUrl?: string;\n clientId?: string;\n defaultScope?: string;\n portRange?: [number, number];\n defaultPort?: number;\n timeout?: number;\n}\n\nexport interface CliConfig {\n enabled: boolean;\n outputDefault?: 'text' | 'json';\n authRequired?: boolean;\n description?: string;\n excludeTools?: string[];\n nativeDeps?: {\n brew?: string[];\n apt?: string[];\n npm?: string[];\n };\n oauth?: OAuthConfig;\n}\n\nexport type ConfigBuildTarget = 'cli' | 'node' | 'sdk' | 'browser' | 'cloudflare' | 'vercel' | 'lambda' | 'distributed';\n\nexport interface FrontmcpExecConfig {\n name: string;\n version?: string;\n entry?: string;\n /** Build target. When set, takes precedence over cli.enabled / sea.enabled. */\n target?: ConfigBuildTarget;\n storage?: {\n type: 'sqlite' | 'redis' | 'none';\n required?: boolean;\n };\n network?: {\n defaultPort?: number;\n supportsSocket?: boolean;\n };\n dependencies?: {\n system?: string[];\n nativeAddons?: string[];\n };\n nodeVersion?: string;\n esbuild?: {\n external?: string[];\n define?: Record<string, string>;\n target?: string;\n minify?: boolean;\n };\n setup?: SetupDefinition;\n cli?: CliConfig;\n sea?: {\n enabled?: boolean;\n };\n}\n\nconst CONFIG_FILENAMES = [\n // #365 round-3 — `.ts` is checked first so the user's typed config takes\n // priority over a stale `.js` left in the project. `.ts` loading routes\n // through the same esbuild path as the new-shape loader so it works under\n // `\"type\": \"commonjs\"` (Node's `require(.ts)` and `await import(.ts)` are\n // both unreliable here and were the root cause of #365 1.1.0–1.1.2-beta.1).\n 'frontmcp.config.ts',\n 'frontmcp.config.js',\n 'frontmcp.config.json',\n 'frontmcp.config.mjs',\n 'frontmcp.config.cjs',\n];\n\n/**\n * Load frontmcp.config.{ts,js,json,mjs,cjs} from the given directory.\n * Falls back to deriving minimal config from package.json.\n */\nexport async function loadExecConfig(cwd: string): Promise<FrontmcpExecConfig> {\n for (const filename of CONFIG_FILENAMES) {\n const configPath = path.join(cwd, filename);\n if (fs.existsSync(configPath)) {\n if (filename.endsWith('.json')) {\n const content = fs.readFileSync(configPath, 'utf-8');\n return JSON.parse(content) as FrontmcpExecConfig;\n }\n if (filename.endsWith('.ts')) {\n // Delegate to the new loader's esbuild transpile so `.ts` configs\n // work under `\"type\": \"commonjs\"` projects. Hard-fails on parse error\n // (no silent default) — matches frontmcp-config.loader semantics.\n // tsc uses `--moduleResolution nodenext`, so the dynamic import\n // needs an explicit `.js` suffix that resolves to the compiled\n // output. The barrel (`../../../config/index.js`) re-exports\n // `loadFrontMcpConfig` from the loader module.\n const { loadFrontMcpConfig } = await import('../../../config/index.js');\n try {\n // The new-shape loader returns a parsed config — we only consume the\n // legacy-shape fields here. Fields that exist in both shapes\n // (name, version, entry, nodeVersion) carry through; new-shape-only\n // fields like `deployments` are ignored by this consumer.\n const newShape = await loadFrontMcpConfig(cwd);\n return newShape as unknown as FrontmcpExecConfig;\n } catch (err) {\n throw new Error(\n `Failed to load ${filename}: ${(err as Error).message}\\n` +\n `If your config doesn't match the new schema (deployments[] etc.), ` +\n `rename it to .js or use the legacy module.exports shape.`,\n );\n }\n }\n // JS/MJS/CJS config — require it\n\n const mod = require(configPath);\n return (mod.default || mod) as FrontmcpExecConfig;\n }\n }\n\n // Fallback: derive from package.json\n const pkgPath = path.join(cwd, 'package.json');\n if (!fs.existsSync(pkgPath)) {\n throw new Error(\n 'No frontmcp.config.js/json found and no package.json. Create a frontmcp.config.js for build targets.',\n );\n }\n\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));\n return {\n name: pkg.name?.replace(/^@[^/]+\\//, '') || path.basename(cwd),\n version: pkg.version || '1.0.0',\n entry: pkg.main,\n };\n}\n\n/**\n * Validate config and return normalized version.\n */\nexport function normalizeConfig(config: FrontmcpExecConfig): Required<\n Pick<FrontmcpExecConfig, 'name' | 'version' | 'nodeVersion'>\n> &\n FrontmcpExecConfig {\n if (!config.name || !/^[a-zA-Z0-9._-]+$/.test(config.name)) {\n throw new Error(\n `Invalid app name: \"${config.name}\". Must be alphanumeric with .-_ only.`,\n );\n }\n\n return {\n ...config,\n name: config.name,\n version: config.version || '1.0.0',\n nodeVersion: config.nodeVersion || '>=22.0.0',\n };\n}\n"]}
|
|
@@ -49,6 +49,12 @@ async function buildExec(opts) {
|
|
|
49
49
|
...opts.execOverrides.cli,
|
|
50
50
|
};
|
|
51
51
|
}
|
|
52
|
+
// #365 round-3 — apply only when the legacy loader didn't already pick up
|
|
53
|
+
// a value (the legacy loader can read it from .js/.json/.cjs/.mjs configs;
|
|
54
|
+
// the new-shape forward fills the .ts gap).
|
|
55
|
+
if (opts.execOverrides.nodeVersion && !rawConfig.nodeVersion) {
|
|
56
|
+
rawConfig.nodeVersion = opts.execOverrides.nodeVersion;
|
|
57
|
+
}
|
|
52
58
|
}
|
|
53
59
|
const config = (0, config_1.normalizeConfig)(rawConfig);
|
|
54
60
|
const cliEnabled = opts.cli || config.cli?.enabled;
|