frontmcp 1.0.1 → 1.0.3
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 +3 -3
- package/src/commands/build/exec/cli-runtime/generate-cli-entry.js +93 -27
- package/src/commands/build/exec/cli-runtime/generate-cli-entry.js.map +1 -1
- package/src/commands/skills/catalog.d.ts +13 -2
- package/src/commands/skills/catalog.js +8 -5
- package/src/commands/skills/catalog.js.map +1 -1
- package/src/core/cli.js +2 -4
- package/src/core/cli.js.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "frontmcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "FrontMCP command line interface",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"homepage": "https://docs.agentfront.dev",
|
|
@@ -30,10 +30,10 @@
|
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@clack/prompts": "^0.10.0",
|
|
33
|
-
"@frontmcp/utils": "1.0.
|
|
33
|
+
"@frontmcp/utils": "1.0.3",
|
|
34
34
|
"commander": "^13.0.0",
|
|
35
35
|
"tslib": "^2.3.0",
|
|
36
|
-
"vectoriadb": "^2.
|
|
36
|
+
"vectoriadb": "^2.2.0",
|
|
37
37
|
"@rspack/core": "^1.7.6",
|
|
38
38
|
"esbuild": "^0.27.3"
|
|
39
39
|
},
|
|
@@ -150,6 +150,16 @@ async function getClient() {
|
|
|
150
150
|
return _client;
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
+
async function closeClient() {
|
|
154
|
+
if (_client && typeof _client.close === 'function') {
|
|
155
|
+
try { await _client.close(); } catch (_) {}
|
|
156
|
+
}
|
|
157
|
+
_client = null;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Flag set by long-running commands (serve, daemon) to prevent the footer from calling process.exit().
|
|
161
|
+
var _isLongRunning = false;
|
|
162
|
+
|
|
153
163
|
var program = new Command();
|
|
154
164
|
program
|
|
155
165
|
.name(${JSON.stringify(appName)})
|
|
@@ -476,15 +486,20 @@ skillsCmd
|
|
|
476
486
|
if (mode === 'json') {
|
|
477
487
|
console.log(JSON.stringify(result, null, 2));
|
|
478
488
|
} else {
|
|
479
|
-
var skills = result.skills ||
|
|
480
|
-
if (
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
console.log(
|
|
487
|
-
|
|
489
|
+
var skills = result.skills || [];
|
|
490
|
+
if (skills.length === 0) { console.log('No skills found.'); return; }
|
|
491
|
+
console.log('\\n Skills matching "' + (query || '') + '":\\n');
|
|
492
|
+
skills.forEach(function(s) {
|
|
493
|
+
var tags = (s.tags || []).slice(0, 3).join(', ');
|
|
494
|
+
var score = s.score != null ? ' [score: ' + Number(s.score).toFixed(2) + ']' : '';
|
|
495
|
+
console.log(' ' + (s.name || s.id) + score);
|
|
496
|
+
if (s.description) console.log(' ' + s.description.split('. Use when')[0]);
|
|
497
|
+
if (tags) console.log(' tags: ' + tags);
|
|
498
|
+
console.log('');
|
|
499
|
+
});
|
|
500
|
+
console.log(' ' + skills.length + ' result(s).');
|
|
501
|
+
console.log(" Use '" + program.name() + " skills read <name>' for full details.");
|
|
502
|
+
console.log(" Use '" + program.name() + " skills load <name>' to load a skill.\\n");
|
|
488
503
|
}
|
|
489
504
|
} catch (err) {
|
|
490
505
|
console.error('Error:', err.message || err);
|
|
@@ -514,6 +529,43 @@ skillsCmd
|
|
|
514
529
|
}
|
|
515
530
|
});
|
|
516
531
|
|
|
532
|
+
skillsCmd
|
|
533
|
+
.command('read <name>')
|
|
534
|
+
.description('Read full details for a skill')
|
|
535
|
+
.action(async function(name) {
|
|
536
|
+
try {
|
|
537
|
+
var client = await getClient();
|
|
538
|
+
var result = await client.loadSkills([name]);
|
|
539
|
+
var mode = program.opts().output || 'text';
|
|
540
|
+
if (mode === 'json') {
|
|
541
|
+
console.log(JSON.stringify(result, null, 2));
|
|
542
|
+
} else {
|
|
543
|
+
var skills = result.skills || [];
|
|
544
|
+
if (skills.length === 0) { console.log('Skill "' + name + '" not found.'); return; }
|
|
545
|
+
var sk = skills[0];
|
|
546
|
+
console.log('\\n ' + sk.name);
|
|
547
|
+
if (sk.description) console.log(' ' + sk.description);
|
|
548
|
+
console.log('');
|
|
549
|
+
if (sk.instructions) {
|
|
550
|
+
console.log(sk.instructions);
|
|
551
|
+
console.log('');
|
|
552
|
+
}
|
|
553
|
+
if (sk.tools && sk.tools.length > 0) {
|
|
554
|
+
console.log(' Tools (' + sk.tools.length + '):');
|
|
555
|
+
sk.tools.forEach(function(t) {
|
|
556
|
+
console.log(' ' + t.name + (t.available ? '' : ' (unavailable)'));
|
|
557
|
+
});
|
|
558
|
+
console.log('');
|
|
559
|
+
}
|
|
560
|
+
if (result.nextSteps) console.log(' ' + result.nextSteps);
|
|
561
|
+
console.log(" Load: " + program.name() + " skills load " + name + '\\n');
|
|
562
|
+
}
|
|
563
|
+
} catch (err) {
|
|
564
|
+
console.error('Error:', err.message || err);
|
|
565
|
+
process.exitCode = 1;
|
|
566
|
+
}
|
|
567
|
+
});
|
|
568
|
+
|
|
517
569
|
skillsCmd
|
|
518
570
|
.command('list')
|
|
519
571
|
.description('List available skills')
|
|
@@ -525,15 +577,17 @@ skillsCmd
|
|
|
525
577
|
if (mode === 'json') {
|
|
526
578
|
console.log(JSON.stringify(result, null, 2));
|
|
527
579
|
} else {
|
|
528
|
-
var skills = result.skills ||
|
|
529
|
-
if (
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
console.log(
|
|
536
|
-
}
|
|
580
|
+
var skills = result.skills || [];
|
|
581
|
+
if (skills.length === 0) { console.log('No skills available.'); return; }
|
|
582
|
+
console.log('\\n Available Skills (' + skills.length + '):\\n');
|
|
583
|
+
skills.forEach(function(s) {
|
|
584
|
+
var desc = s.description ? s.description.split('. Use when')[0] : '';
|
|
585
|
+
console.log(' ' + (s.name || s.id));
|
|
586
|
+
if (desc) console.log(' ' + desc);
|
|
587
|
+
console.log('');
|
|
588
|
+
});
|
|
589
|
+
console.log(" Use '" + program.name() + " skills search <query>' for semantic search.");
|
|
590
|
+
console.log(" Use '" + program.name() + " skills read <name>' for full details.\\n");
|
|
537
591
|
}
|
|
538
592
|
} catch (err) {
|
|
539
593
|
console.error('Error:', err.message || err);
|
|
@@ -807,7 +861,9 @@ async function getSubscribeClient() {
|
|
|
807
861
|
// If connected via daemon, the onNotification/onResourceUpdated are no-ops.
|
|
808
862
|
// Reconnect via in-process for push support.
|
|
809
863
|
if (client._isDaemon) {
|
|
810
|
-
|
|
864
|
+
// Close the daemon client before replacing with in-process client
|
|
865
|
+
if (typeof client.close === 'function') { try { await client.close(); } catch (_) {} }
|
|
866
|
+
_client = null;
|
|
811
867
|
var mod = require(SERVER_BUNDLE);
|
|
812
868
|
var configOrClass = mod.default || mod;
|
|
813
869
|
var sdk = require('@frontmcp/sdk');
|
|
@@ -836,6 +892,7 @@ subscribeCmd
|
|
|
836
892
|
process.on('SIGINT', async function() {
|
|
837
893
|
console.log('\\nUnsubscribing...');
|
|
838
894
|
try { await client.unsubscribeResource(uri); } catch (_) { /* ok */ }
|
|
895
|
+
await closeClient();
|
|
839
896
|
process.exit(0);
|
|
840
897
|
});
|
|
841
898
|
// Keep process alive — setInterval creates an active event loop handle
|
|
@@ -862,8 +919,9 @@ subscribeCmd
|
|
|
862
919
|
console.log(fmt.formatSubscriptionEvent({ type: 'notification', method: notification.method, params: notification.params, timestamp: new Date().toISOString() }, mode));
|
|
863
920
|
}
|
|
864
921
|
});
|
|
865
|
-
process.on('SIGINT', function() {
|
|
922
|
+
process.on('SIGINT', async function() {
|
|
866
923
|
console.log('\\nStopping...');
|
|
924
|
+
await closeClient();
|
|
867
925
|
process.exit(0);
|
|
868
926
|
});
|
|
869
927
|
// Keep process alive — setInterval creates an active event loop handle
|
|
@@ -1004,6 +1062,7 @@ function generateServeCommand(serverBundleFilename, selfContained) {
|
|
|
1004
1062
|
.description('Start the HTTP/SSE server')
|
|
1005
1063
|
.option('-p, --port <port>', 'Port number', function(v) { return parseInt(v, 10); })
|
|
1006
1064
|
.action(async function(opts) {
|
|
1065
|
+
_isLongRunning = true;
|
|
1007
1066
|
var mod = ${requireExpr};
|
|
1008
1067
|
if (opts.port) process.env.PORT = String(opts.port);
|
|
1009
1068
|
// If the bundle exports a start() function (@FrontMcp-decorated class auto-bootstraps), use it
|
|
@@ -1280,6 +1339,10 @@ ${selfContained ? ` // SEA mode: spawn the binary itself in daemon mode — a
|
|
|
1280
1339
|
env: env
|
|
1281
1340
|
});`}
|
|
1282
1341
|
|
|
1342
|
+
// Close inherited file descriptors in the parent — the child already has its own copy.
|
|
1343
|
+
fs.closeSync(out);
|
|
1344
|
+
fs.closeSync(err);
|
|
1345
|
+
|
|
1283
1346
|
fs.writeFileSync(pidPath, JSON.stringify({
|
|
1284
1347
|
pid: child.pid,
|
|
1285
1348
|
socketPath: socketPath,
|
|
@@ -1362,14 +1425,17 @@ function generateFooter() {
|
|
|
1362
1425
|
console.error('Unknown command: ' + args[0]);
|
|
1363
1426
|
process.exitCode = 1;
|
|
1364
1427
|
});
|
|
1365
|
-
program.parseAsync(process.argv).then(function() {
|
|
1366
|
-
//
|
|
1367
|
-
//
|
|
1368
|
-
//
|
|
1369
|
-
|
|
1370
|
-
|
|
1428
|
+
program.parseAsync(process.argv).then(async function() {
|
|
1429
|
+
// Long-running commands (serve) set _isLongRunning to keep the event loop alive.
|
|
1430
|
+
// Short-lived commands close the client and exit explicitly to avoid hanging
|
|
1431
|
+
// on unclosed handles (file loggers, in-memory transport, etc.).
|
|
1432
|
+
if (_isLongRunning) return;
|
|
1433
|
+
await closeClient();
|
|
1434
|
+
process.exit(process.exitCode || 0);
|
|
1435
|
+
}).catch(async function(err) {
|
|
1371
1436
|
console.error('Fatal:', err.message || err);
|
|
1372
|
-
|
|
1437
|
+
await closeClient();
|
|
1438
|
+
process.exit(1);
|
|
1373
1439
|
});`;
|
|
1374
1440
|
}
|
|
1375
1441
|
/**
|
|
@@ -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 { CliConfig, OAuthConfig } from '../config';\nimport { ExtractedSchema, ExtractedTool, ExtractedPrompt, ExtractedResourceTemplate, ExtractedCapabilities, 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]);\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 var _dMod = require(${JSON.stringify('../' + serverBundleFilename)});\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 _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 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\nvar program = new Command();\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 } 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 } else {\n console.error('Error:', err.message || err);\n }\n process.exitCode = 1;\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 console.error('Error:', err.message || err);\n process.exitCode = 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 console.error('Error:', err.message || err);\n process.exitCode = 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 console.error('Error:', err.message || err);\n process.exitCode = 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 console.error('Error:', err.message || err);\n process.exitCode = 1;\n }\n });\n\n${subcommands.join('\\n\\n')}`;\n}\n\nfunction generatePromptCommands(prompts: ExtractedPrompt[]): string {\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 || '')})\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 console.error('Error:', err.message || err);\n process.exitCode = 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 console.error('Error:', err.message || err);\n process.exitCode = 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 || result || [];\n if (Array.isArray(skills) && skills.length === 0) { console.log('No skills found.'); return; }\n if (Array.isArray(skills)) {\n skills.forEach(function(s) {\n console.log(' ' + (s.name || s.id || JSON.stringify(s)));\n });\n } else {\n console.log(JSON.stringify(result, null, 2));\n }\n }\n } catch (err) {\n console.error('Error:', err.message || err);\n process.exitCode = 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 console.error('Error:', err.message || err);\n process.exitCode = 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 || result || [];\n if (Array.isArray(skills) && skills.length === 0) { console.log('No skills available.'); return; }\n if (Array.isArray(skills)) {\n skills.forEach(function(s) {\n console.log(' ' + (s.name || s.id || JSON.stringify(s)));\n });\n } else {\n console.log(JSON.stringify(result, null, 2));\n }\n }\n } catch (err) {\n console.error('Error:', err.message || err);\n process.exitCode = 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 console.error('Error:', err.message || err);\n process.exitCode = 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 console.error('Error:', err.message || err);\n process.exitCode = 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 console.error('Error:', err.message || err);\n process.exitCode = 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 console.error('Error:', err.message || err);\n process.exitCode = 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 console.error('Error:', err.message || err);\n process.exitCode = 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 console.error('Error:', err.message || err);\n process.exitCode = 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 console.error('Error:', err.message || err);\n process.exitCode = 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 console.error('Error:', err.message || err);\n process.exitCode = 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 console.error('Error:', err.message || err);\n process.exitCode = 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 _client = null; // clear cached daemon client\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 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 console.error('Error:', err.message || err);\n process.exitCode = 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', function() {\n console.log('\\\\nStopping...');\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 console.error('Error:', err.message || err);\n process.exitCode = 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 HTTP/SSE server')\n .option('-p, --port <port>', 'Port number', function(v) { return parseInt(v, 10); })\n .action(async function(opts) {\n var mod = ${requireExpr};\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 (Unix socket)')\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 socketPath = pathMod.join(socketDir, ${JSON.stringify(appName)} + '.sock');\n\n // Clean up stale socket file\n 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_SOCKET: socketPath,\n FRONTMCP_DAEMON_IDLE_TIMEOUT: String(opts.idleTimeout)\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 using runUnixSocket 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 'var mod = require(' + JSON.stringify(serverBundlePath) + ');' +\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 '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 var child = spawn('node', ['-e', daemonScript], {\n detached: true,\n stdio: ['ignore', out, err],\n env: env\n });`}\n\n fs.writeFileSync(pidPath, JSON.stringify({\n pid: child.pid,\n socketPath: socketPath,\n startedAt: new Date().toISOString()\n }));\n child.unref();\n\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\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 socketStatus = data.socketPath && fs.existsSync(data.socketPath) ? ', socket: active' : '';\n console.log('Running (PID: ' + data.pid + ', started: ' + data.startedAt + socketStatus + ')');\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(function() {\n // Use exitCode instead of process.exit() so long-running commands\n // (e.g., serve) keep the event loop alive while short-lived commands\n // exit naturally when the event loop drains.\n process.exitCode = process.exitCode || 0;\n}).catch(function(err) {\n console.error('Fatal:', err.message || err);\n process.exitCode = 1;\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":"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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 { CliConfig, OAuthConfig } from '../config';\nimport { ExtractedSchema, ExtractedTool, ExtractedPrompt, ExtractedResourceTemplate, ExtractedCapabilities, 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]);\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 var _dMod = require(${JSON.stringify('../' + serverBundleFilename)});\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 _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 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\nvar program = new Command();\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 } 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 } else {\n console.error('Error:', err.message || err);\n }\n process.exitCode = 1;\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 console.error('Error:', err.message || err);\n process.exitCode = 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 console.error('Error:', err.message || err);\n process.exitCode = 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 console.error('Error:', err.message || err);\n process.exitCode = 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 console.error('Error:', err.message || err);\n process.exitCode = 1;\n }\n });\n\n${subcommands.join('\\n\\n')}`;\n}\n\nfunction generatePromptCommands(prompts: ExtractedPrompt[]): string {\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 || '')})\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 console.error('Error:', err.message || err);\n process.exitCode = 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 console.error('Error:', err.message || err);\n process.exitCode = 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 console.error('Error:', err.message || err);\n process.exitCode = 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 console.error('Error:', err.message || err);\n process.exitCode = 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 console.error('Error:', err.message || err);\n process.exitCode = 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 console.error('Error:', err.message || err);\n process.exitCode = 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 console.error('Error:', err.message || err);\n process.exitCode = 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 console.error('Error:', err.message || err);\n process.exitCode = 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 console.error('Error:', err.message || err);\n process.exitCode = 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 console.error('Error:', err.message || err);\n process.exitCode = 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 console.error('Error:', err.message || err);\n process.exitCode = 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 console.error('Error:', err.message || err);\n process.exitCode = 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 console.error('Error:', err.message || err);\n process.exitCode = 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 console.error('Error:', err.message || err);\n process.exitCode = 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 console.error('Error:', err.message || err);\n process.exitCode = 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 console.error('Error:', err.message || err);\n process.exitCode = 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 console.error('Error:', err.message || err);\n process.exitCode = 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 HTTP/SSE server')\n .option('-p, --port <port>', 'Port number', function(v) { return parseInt(v, 10); })\n .action(async function(opts) {\n _isLongRunning = true;\n var mod = ${requireExpr};\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 (Unix socket)')\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 socketPath = pathMod.join(socketDir, ${JSON.stringify(appName)} + '.sock');\n\n // Clean up stale socket file\n 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_SOCKET: socketPath,\n FRONTMCP_DAEMON_IDLE_TIMEOUT: String(opts.idleTimeout)\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 using runUnixSocket 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 'var mod = require(' + JSON.stringify(serverBundlePath) + ');' +\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 '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 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 fs.writeFileSync(pidPath, JSON.stringify({\n pid: child.pid,\n socketPath: socketPath,\n startedAt: new Date().toISOString()\n }));\n child.unref();\n\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\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 socketStatus = data.socketPath && fs.existsSync(data.socketPath) ? ', socket: active' : '';\n console.log('Running (PID: ' + data.pid + ', started: ' + data.startedAt + socketStatus + ')');\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 process.exit(process.exitCode || 0);\n}).catch(async function(err) {\n console.error('Fatal:', err.message || err);\n await closeClient();\n process.exit(1);\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"]}
|
|
@@ -4,7 +4,18 @@
|
|
|
4
4
|
* Uses vectoriadb's TFIDFVectoria for proper TF-IDF similarity search with
|
|
5
5
|
* weighted document fields: description 3x, tags 2x, name 1x, category 1x.
|
|
6
6
|
*/
|
|
7
|
-
|
|
7
|
+
interface SkillReferenceExample {
|
|
8
|
+
name: string;
|
|
9
|
+
description: string;
|
|
10
|
+
level: 'basic' | 'intermediate' | 'advanced';
|
|
11
|
+
tags: string[];
|
|
12
|
+
features: string[];
|
|
13
|
+
}
|
|
14
|
+
interface SkillReference {
|
|
15
|
+
name: string;
|
|
16
|
+
description: string;
|
|
17
|
+
examples?: SkillReferenceExample[];
|
|
18
|
+
}
|
|
8
19
|
interface SkillEntry {
|
|
9
20
|
name: string;
|
|
10
21
|
category: string;
|
|
@@ -14,7 +25,7 @@ interface SkillEntry {
|
|
|
14
25
|
hasResources: boolean;
|
|
15
26
|
tags: string[];
|
|
16
27
|
bundle?: string[];
|
|
17
|
-
references?:
|
|
28
|
+
references?: SkillReference[];
|
|
18
29
|
}
|
|
19
30
|
interface SkillManifest {
|
|
20
31
|
version: number;
|
|
@@ -12,7 +12,6 @@ exports.searchCatalog = searchCatalog;
|
|
|
12
12
|
const tslib_1 = require("tslib");
|
|
13
13
|
const fs = tslib_1.__importStar(require("fs"));
|
|
14
14
|
const path = tslib_1.__importStar(require("path"));
|
|
15
|
-
const vectoriadb_1 = require("vectoriadb");
|
|
16
15
|
const STOP_WORDS = new Set([
|
|
17
16
|
// Articles & determiners
|
|
18
17
|
'the',
|
|
@@ -207,8 +206,11 @@ function getCatalogDir() {
|
|
|
207
206
|
function getSearchIndex() {
|
|
208
207
|
if (cachedIndex)
|
|
209
208
|
return cachedIndex;
|
|
209
|
+
// Lazy-load vectoriadb to avoid triggering TF/HF model initialization
|
|
210
|
+
// when only loadCatalog() is needed (e.g., skills list command).
|
|
211
|
+
const { TFIDFVectoria: TFIDFVectoriaImpl } = require('vectoriadb');
|
|
210
212
|
const manifest = loadCatalog();
|
|
211
|
-
|
|
213
|
+
const index = new TFIDFVectoriaImpl({
|
|
212
214
|
defaultTopK: 10,
|
|
213
215
|
defaultSimilarityThreshold: 0.0,
|
|
214
216
|
});
|
|
@@ -217,9 +219,10 @@ function getSearchIndex() {
|
|
|
217
219
|
text: buildSearchableText(skill),
|
|
218
220
|
metadata: { id: skill.name, skill },
|
|
219
221
|
}));
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
222
|
+
index.addDocuments(documents);
|
|
223
|
+
index.reindex();
|
|
224
|
+
cachedIndex = index;
|
|
225
|
+
return index;
|
|
223
226
|
}
|
|
224
227
|
/**
|
|
225
228
|
* Build weighted searchable text for TF-IDF indexing.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../../../src/commands/skills/catalog.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Catalog loader and TF-IDF search engine for skills.\n *\n * Uses vectoriadb's TFIDFVectoria for proper TF-IDF similarity search with\n * weighted document fields: description 3x, tags 2x, name 1x, category 1x.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { TFIDFVectoria } from 'vectoriadb';\nimport type { SkillReferenceEntry } from '@frontmcp/skills';\n\ninterface SkillEntry {\n name: string;\n category: string;\n description: string;\n path: string;\n targets: string[];\n hasResources: boolean;\n tags: string[];\n bundle?: string[];\n references?: SkillReferenceEntry[];\n}\n\ninterface SkillManifest {\n version: number;\n skills: SkillEntry[];\n}\n\nexport interface SearchResult {\n skill: SkillEntry;\n score: number;\n}\n\ninterface SkillDocMetadata {\n id: string;\n skill: SkillEntry;\n}\n\nconst STOP_WORDS = new Set([\n // Articles & determiners\n 'the',\n 'a',\n 'an',\n 'this',\n 'that',\n 'these',\n 'those',\n 'each',\n 'every',\n 'some',\n 'any',\n 'no',\n // Conjunctions & prepositions\n 'and',\n 'or',\n 'but',\n 'nor',\n 'for',\n 'yet',\n 'so',\n 'with',\n 'from',\n 'into',\n 'onto',\n 'about',\n 'by',\n 'at',\n 'in',\n 'on',\n 'to',\n 'of',\n 'as',\n 'if',\n 'than',\n 'then',\n 'between',\n 'through',\n 'after',\n 'before',\n 'during',\n 'without',\n 'within',\n 'along',\n 'across',\n 'against',\n 'under',\n 'over',\n 'above',\n 'below',\n // Pronouns\n 'your',\n 'you',\n 'it',\n 'its',\n 'we',\n 'our',\n 'they',\n 'them',\n 'their',\n 'he',\n 'she',\n 'his',\n 'her',\n 'who',\n 'which',\n 'what',\n 'where',\n 'when',\n 'how',\n 'why',\n // Verbs (auxiliary / common)\n 'is',\n 'am',\n 'are',\n 'was',\n 'were',\n 'be',\n 'been',\n 'being',\n 'have',\n 'has',\n 'had',\n 'having',\n 'do',\n 'does',\n 'did',\n 'will',\n 'would',\n 'shall',\n 'should',\n 'may',\n 'might',\n 'must',\n 'can',\n 'could',\n 'need',\n 'use',\n 'using',\n 'used',\n // Adverbs & modifiers\n 'not',\n 'very',\n 'also',\n 'just',\n 'only',\n 'more',\n 'most',\n 'less',\n 'well',\n 'even',\n 'still',\n 'already',\n 'always',\n 'never',\n 'often',\n 'too',\n 'here',\n 'there',\n 'now',\n // Common filler\n 'all',\n 'both',\n 'other',\n 'another',\n 'such',\n 'like',\n 'get',\n 'set',\n 'new',\n 'make',\n 'see',\n 'way',\n 'etc',\n 'via',\n]);\n\nlet cachedManifest: SkillManifest | undefined;\nlet cachedIndex: TFIDFVectoria<SkillDocMetadata> | undefined;\n\n/**\n * Load the catalog manifest via the @frontmcp/skills package.\n * Works in both monorepo (workspace symlink) and installed (npx/npm) environments.\n */\nexport function loadCatalog(): SkillManifest {\n if (cachedManifest) return cachedManifest;\n\n const manifestPath = resolveManifestPath();\n cachedManifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8')) as SkillManifest;\n return cachedManifest;\n}\n\n/**\n * Resolve the path to skills-manifest.json from the @frontmcp/skills package.\n */\nfunction resolveManifestPath(): string {\n // Primary: resolve directly from the @frontmcp/skills package\n try {\n return require.resolve('@frontmcp/skills/catalog/skills-manifest.json');\n } catch {\n // Not resolvable via subpath — try via package root\n }\n\n // Fallback: find the package root and navigate to catalog/\n try {\n const pkgJsonPath = require.resolve('@frontmcp/skills/package.json');\n const pkgRoot = path.dirname(pkgJsonPath);\n const manifestPath = path.join(pkgRoot, 'catalog', 'skills-manifest.json');\n if (fs.existsSync(manifestPath)) return manifestPath;\n } catch {\n // Package not found at all\n }\n\n // Monorepo dev fallback: walk up from __dirname to find libs/skills/catalog/\n let dir = __dirname;\n for (let i = 0; i < 8; i++) {\n const candidate = path.join(dir, 'libs', 'skills', 'catalog', 'skills-manifest.json');\n if (fs.existsSync(candidate)) return candidate;\n dir = path.dirname(dir);\n }\n\n throw new Error(\n 'Skills catalog not found. Make sure @frontmcp/skills is installed or you are in the FrontMCP monorepo.',\n );\n}\n\n/**\n * Resolve the catalog directory path.\n */\nexport function getCatalogDir(): string {\n return path.dirname(resolveManifestPath());\n}\n\n/**\n * Build and cache the TF-IDF search index from the catalog manifest.\n */\nfunction getSearchIndex(): TFIDFVectoria<SkillDocMetadata> {\n if (cachedIndex) return cachedIndex;\n\n const manifest = loadCatalog();\n cachedIndex = new TFIDFVectoria<SkillDocMetadata>({\n defaultTopK: 10,\n defaultSimilarityThreshold: 0.0,\n });\n\n const documents = manifest.skills.map((skill) => ({\n id: skill.name,\n text: buildSearchableText(skill),\n metadata: { id: skill.name, skill },\n }));\n\n cachedIndex.addDocuments(documents);\n cachedIndex.reindex();\n\n return cachedIndex;\n}\n\n/**\n * Build weighted searchable text for TF-IDF indexing.\n * Follows the same weighting pattern as the SDK's MemorySkillProvider.\n */\nfunction buildSearchableText(skill: SkillEntry): string {\n const parts: string[] = [];\n\n // Name tokens (1x)\n const nameParts = skill.name.split(/[-_.\\s]/).filter(Boolean);\n parts.push(...nameParts);\n\n // Description (3x weight — repeat for TF-IDF term frequency boost)\n if (skill.description) {\n parts.push(skill.description, skill.description, skill.description);\n\n // Extract key terms from description (additional boost for meaningful words)\n const keyTerms = skill.description\n .toLowerCase()\n .split(/\\s+/)\n .filter((word) => word.length >= 4 && !STOP_WORDS.has(word));\n parts.push(...keyTerms);\n }\n\n // Tags (2x weight)\n for (const tag of skill.tags) {\n parts.push(tag, tag);\n }\n\n // Category (1x weight)\n parts.push(skill.category);\n\n // Reference names and descriptions (1x weight each)\n if (skill.references) {\n for (const ref of skill.references) {\n const refNameParts = ref.name.split(/[-_.\\s]/).filter(Boolean);\n parts.push(...refNameParts);\n if (ref.description) {\n const refTerms = ref.description\n .toLowerCase()\n .split(/\\s+/)\n .filter((word) => word.length >= 4 && !STOP_WORDS.has(word));\n parts.push(...refTerms);\n }\n }\n }\n\n return parts.join(' ');\n}\n\n/**\n * Search skills using TF-IDF similarity via vectoriadb.\n */\nexport function searchCatalog(\n query: string,\n options?: { tag?: string; category?: string; limit?: number },\n): SearchResult[] {\n const index = getSearchIndex();\n const topK = options?.limit ?? 10;\n\n const filter = (metadata: SkillDocMetadata): boolean => {\n if (options?.tag && !metadata.skill.tags.includes(options.tag)) return false;\n if (options?.category && metadata.skill.category !== options.category) return false;\n return true;\n };\n\n const results = index.search(query, {\n topK,\n threshold: 0.01,\n filter,\n });\n\n return results.map((r) => ({\n skill: r.metadata.skill,\n score: r.score,\n }));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../../../src/commands/skills/catalog.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Catalog loader and TF-IDF search engine for skills.\n *\n * Uses vectoriadb's TFIDFVectoria for proper TF-IDF similarity search with\n * weighted document fields: description 3x, tags 2x, name 1x, category 1x.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport type { TFIDFVectoria } from 'vectoriadb';\n\ninterface SkillReferenceExample {\n name: string;\n description: string;\n level: 'basic' | 'intermediate' | 'advanced';\n tags: string[];\n features: string[];\n}\n\ninterface SkillReference {\n name: string;\n description: string;\n examples?: SkillReferenceExample[];\n}\n\ninterface SkillEntry {\n name: string;\n category: string;\n description: string;\n path: string;\n targets: string[];\n hasResources: boolean;\n tags: string[];\n bundle?: string[];\n references?: SkillReference[];\n}\n\ninterface SkillManifest {\n version: number;\n skills: SkillEntry[];\n}\n\nexport interface SearchResult {\n skill: SkillEntry;\n score: number;\n}\n\ninterface SkillDocMetadata {\n id: string;\n skill: SkillEntry;\n}\n\nconst STOP_WORDS = new Set([\n // Articles & determiners\n 'the',\n 'a',\n 'an',\n 'this',\n 'that',\n 'these',\n 'those',\n 'each',\n 'every',\n 'some',\n 'any',\n 'no',\n // Conjunctions & prepositions\n 'and',\n 'or',\n 'but',\n 'nor',\n 'for',\n 'yet',\n 'so',\n 'with',\n 'from',\n 'into',\n 'onto',\n 'about',\n 'by',\n 'at',\n 'in',\n 'on',\n 'to',\n 'of',\n 'as',\n 'if',\n 'than',\n 'then',\n 'between',\n 'through',\n 'after',\n 'before',\n 'during',\n 'without',\n 'within',\n 'along',\n 'across',\n 'against',\n 'under',\n 'over',\n 'above',\n 'below',\n // Pronouns\n 'your',\n 'you',\n 'it',\n 'its',\n 'we',\n 'our',\n 'they',\n 'them',\n 'their',\n 'he',\n 'she',\n 'his',\n 'her',\n 'who',\n 'which',\n 'what',\n 'where',\n 'when',\n 'how',\n 'why',\n // Verbs (auxiliary / common)\n 'is',\n 'am',\n 'are',\n 'was',\n 'were',\n 'be',\n 'been',\n 'being',\n 'have',\n 'has',\n 'had',\n 'having',\n 'do',\n 'does',\n 'did',\n 'will',\n 'would',\n 'shall',\n 'should',\n 'may',\n 'might',\n 'must',\n 'can',\n 'could',\n 'need',\n 'use',\n 'using',\n 'used',\n // Adverbs & modifiers\n 'not',\n 'very',\n 'also',\n 'just',\n 'only',\n 'more',\n 'most',\n 'less',\n 'well',\n 'even',\n 'still',\n 'already',\n 'always',\n 'never',\n 'often',\n 'too',\n 'here',\n 'there',\n 'now',\n // Common filler\n 'all',\n 'both',\n 'other',\n 'another',\n 'such',\n 'like',\n 'get',\n 'set',\n 'new',\n 'make',\n 'see',\n 'way',\n 'etc',\n 'via',\n]);\n\nlet cachedManifest: SkillManifest | undefined;\nlet cachedIndex: TFIDFVectoria<SkillDocMetadata> | undefined;\n\n/**\n * Load the catalog manifest via the @frontmcp/skills package.\n * Works in both monorepo (workspace symlink) and installed (npx/npm) environments.\n */\nexport function loadCatalog(): SkillManifest {\n if (cachedManifest) return cachedManifest;\n\n const manifestPath = resolveManifestPath();\n cachedManifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8')) as SkillManifest;\n return cachedManifest;\n}\n\n/**\n * Resolve the path to skills-manifest.json from the @frontmcp/skills package.\n */\nfunction resolveManifestPath(): string {\n // Primary: resolve directly from the @frontmcp/skills package\n try {\n return require.resolve('@frontmcp/skills/catalog/skills-manifest.json');\n } catch {\n // Not resolvable via subpath — try via package root\n }\n\n // Fallback: find the package root and navigate to catalog/\n try {\n const pkgJsonPath = require.resolve('@frontmcp/skills/package.json');\n const pkgRoot = path.dirname(pkgJsonPath);\n const manifestPath = path.join(pkgRoot, 'catalog', 'skills-manifest.json');\n if (fs.existsSync(manifestPath)) return manifestPath;\n } catch {\n // Package not found at all\n }\n\n // Monorepo dev fallback: walk up from __dirname to find libs/skills/catalog/\n let dir = __dirname;\n for (let i = 0; i < 8; i++) {\n const candidate = path.join(dir, 'libs', 'skills', 'catalog', 'skills-manifest.json');\n if (fs.existsSync(candidate)) return candidate;\n dir = path.dirname(dir);\n }\n\n throw new Error(\n 'Skills catalog not found. Make sure @frontmcp/skills is installed or you are in the FrontMCP monorepo.',\n );\n}\n\n/**\n * Resolve the catalog directory path.\n */\nexport function getCatalogDir(): string {\n return path.dirname(resolveManifestPath());\n}\n\n/**\n * Build and cache the TF-IDF search index from the catalog manifest.\n */\nfunction getSearchIndex(): TFIDFVectoria<SkillDocMetadata> {\n if (cachedIndex) return cachedIndex;\n\n // Lazy-load vectoriadb to avoid triggering TF/HF model initialization\n // when only loadCatalog() is needed (e.g., skills list command).\n const { TFIDFVectoria: TFIDFVectoriaImpl } = require('vectoriadb') as {\n TFIDFVectoria: typeof TFIDFVectoria;\n };\n\n const manifest = loadCatalog();\n const index = new TFIDFVectoriaImpl<SkillDocMetadata>({\n defaultTopK: 10,\n defaultSimilarityThreshold: 0.0,\n });\n\n const documents = manifest.skills.map((skill) => ({\n id: skill.name,\n text: buildSearchableText(skill),\n metadata: { id: skill.name, skill },\n }));\n\n index.addDocuments(documents);\n index.reindex();\n\n cachedIndex = index;\n return index;\n}\n\n/**\n * Build weighted searchable text for TF-IDF indexing.\n * Follows the same weighting pattern as the SDK's MemorySkillProvider.\n */\nfunction buildSearchableText(skill: SkillEntry): string {\n const parts: string[] = [];\n\n // Name tokens (1x)\n const nameParts = skill.name.split(/[-_.\\s]/).filter(Boolean);\n parts.push(...nameParts);\n\n // Description (3x weight — repeat for TF-IDF term frequency boost)\n if (skill.description) {\n parts.push(skill.description, skill.description, skill.description);\n\n // Extract key terms from description (additional boost for meaningful words)\n const keyTerms = skill.description\n .toLowerCase()\n .split(/\\s+/)\n .filter((word) => word.length >= 4 && !STOP_WORDS.has(word));\n parts.push(...keyTerms);\n }\n\n // Tags (2x weight)\n for (const tag of skill.tags) {\n parts.push(tag, tag);\n }\n\n // Category (1x weight)\n parts.push(skill.category);\n\n // Reference names and descriptions (1x weight each)\n if (skill.references) {\n for (const ref of skill.references) {\n const refNameParts = ref.name.split(/[-_.\\s]/).filter(Boolean);\n parts.push(...refNameParts);\n if (ref.description) {\n const refTerms = ref.description\n .toLowerCase()\n .split(/\\s+/)\n .filter((word) => word.length >= 4 && !STOP_WORDS.has(word));\n parts.push(...refTerms);\n }\n }\n }\n\n return parts.join(' ');\n}\n\n/**\n * Search skills using TF-IDF similarity via vectoriadb.\n */\nexport function searchCatalog(\n query: string,\n options?: { tag?: string; category?: string; limit?: number },\n): SearchResult[] {\n const index = getSearchIndex();\n const topK = options?.limit ?? 10;\n\n const filter = (metadata: SkillDocMetadata): boolean => {\n if (options?.tag && !metadata.skill.tags.includes(options.tag)) return false;\n if (options?.category && metadata.skill.category !== options.category) return false;\n return true;\n };\n\n const results = index.search(query, {\n topK,\n threshold: 0.01,\n filter,\n });\n\n return results.map((r) => ({\n skill: r.metadata.skill,\n score: r.score,\n }));\n}\n"]}
|
package/src/core/cli.js
CHANGED
|
@@ -13,13 +13,11 @@ async function main() {
|
|
|
13
13
|
try {
|
|
14
14
|
const program = (0, program_1.createProgram)();
|
|
15
15
|
await program.parseAsync(process.argv);
|
|
16
|
-
process.
|
|
17
|
-
return;
|
|
16
|
+
process.exit(0);
|
|
18
17
|
}
|
|
19
18
|
catch (err) {
|
|
20
19
|
console.error('\n' + (0, colors_1.c)('red', err instanceof Error ? err.stack || err.message : String(err)));
|
|
21
|
-
process.
|
|
22
|
-
return;
|
|
20
|
+
process.exit(1);
|
|
23
21
|
}
|
|
24
22
|
}
|
|
25
23
|
main();
|
package/src/core/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../../src/core/cli.ts"],"names":[],"mappings":";;AACA;;;;;GAKG;;AAEH,uCAA0C;AAC1C,qCAA6B;AAE7B,KAAK,UAAU,IAAI;IACjB,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,IAAA,uBAAa,GAAE,CAAC;QAChC,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACvC,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../../src/core/cli.ts"],"names":[],"mappings":";;AACA;;;;;GAKG;;AAEH,uCAA0C;AAC1C,qCAA6B;AAE7B,KAAK,UAAU,IAAI;IACjB,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,IAAA,uBAAa,GAAE,CAAC;QAChC,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACvC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,OAAO,CAAC,KAAK,CAAC,IAAI,GAAG,IAAA,UAAC,EAAC,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC9F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC","sourcesContent":["#!/usr/bin/env node\n/**\n * frontmcp - FrontMCP command line interface\n *\n * Uses commander.js for argument parsing, command management, and\n * auto-generated help. Interactive TUI is handled by @clack/prompts.\n */\n\nimport { createProgram } from './program';\nimport { c } from './colors';\n\nasync function main(): Promise<void> {\n try {\n const program = createProgram();\n await program.parseAsync(process.argv);\n process.exit(0);\n } catch (err: unknown) {\n console.error('\\n' + c('red', err instanceof Error ? err.stack || err.message : String(err)));\n process.exit(1);\n }\n}\n\nmain();\n"]}
|