Fix global help and version flags

This commit is contained in:
Peter Steinberger 2025-11-07 14:57:58 +00:00
parent 7466b178b8
commit fe7d10389d
2 changed files with 110 additions and 11 deletions

View File

@ -27,15 +27,15 @@ export { handleInspectCli } from './cli/inspect-cli-command.js';
export { extractListFlags, handleList } from './cli/list-command.js';
export { resolveCallTimeout } from './cli/timeouts.js';
// main parses CLI flags and dispatches to list/call commands.
async function main(): Promise<void> {
const argv = process.argv.slice(2);
if (argv.length === 0) {
export async function runCli(argv: string[]): Promise<void> {
const args = [...argv];
if (args.length === 0) {
printHelp();
process.exit(1);
return;
}
const globalFlags = extractFlags(argv, ['--config', '--root', '--log-level']);
const globalFlags = extractFlags(args, ['--config', '--root', '--log-level']);
if (globalFlags['--log-level']) {
try {
const parsedLevel = parseLogLevel(globalFlags['--log-level'], getActiveLogLevel());
@ -44,22 +44,35 @@ async function main(): Promise<void> {
const message = error instanceof Error ? error.message : String(error);
logError(message, error instanceof Error ? error : undefined);
process.exit(1);
return;
}
}
const command = argv.shift();
const command = args.shift();
if (!command) {
printHelp();
process.exit(1);
return;
}
if (isHelpToken(command)) {
printHelp();
process.exitCode = 0;
return;
}
if (isVersionToken(command)) {
await printVersion();
return;
}
if (command === 'generate-cli') {
await handleGenerateCli(argv, globalFlags);
await handleGenerateCli(args, globalFlags);
return;
}
if (command === 'inspect-cli') {
await handleInspectCli(argv);
await handleInspectCli(args);
return;
}
@ -70,7 +83,7 @@ async function main(): Promise<void> {
logger: getActiveLogger(),
});
try {
await handleEmitTs(runtime, argv);
await handleEmitTs(runtime, args);
} finally {
await runtime.close().catch(() => {});
}
@ -83,7 +96,7 @@ async function main(): Promise<void> {
logger: getActiveLogger(),
});
const inference = inferCommandRouting(command, argv, runtime.getDefinitions());
const inference = inferCommandRouting(command, args, runtime.getDefinitions());
if (inference.kind === 'abort') {
process.exitCode = inference.exitCode;
return;
@ -143,11 +156,15 @@ async function main(): Promise<void> {
}
}
}
printHelp(`Unknown command '${resolvedCommand}'.`);
process.exit(1);
}
// main parses CLI flags and dispatches to list/call commands.
async function main(): Promise<void> {
await runCli(process.argv.slice(2));
}
// printHelp explains available commands and global flags.
function printHelp(message?: string): void {
if (message) {
@ -195,6 +212,27 @@ Examples:
`);
}
async function printVersion(): Promise<void> {
try {
const packageJsonPath = new URL('../package.json', import.meta.url);
const buffer = await fsPromises.readFile(packageJsonPath, 'utf8');
const pkg = JSON.parse(buffer) as { version?: string };
console.log(pkg.version ?? '0.0.0');
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
logError(`Failed to read mcporter version: ${message}`, error instanceof Error ? error : undefined);
process.exit(1);
}
}
function isHelpToken(token: string): boolean {
return token === '--help' || token === '-h' || token === 'help';
}
function isVersionToken(token: string): boolean {
return token === '--version' || token === '-v' || token === '-V';
}
if (process.env.MCPORTER_DISABLE_AUTORUN !== '1') {
main().catch((error) => {
if (error instanceof CliUsageError) {

View File

@ -0,0 +1,61 @@
import fsPromises from 'node:fs/promises';
import { afterEach, describe, expect, it, vi } from 'vitest';
process.env.MCPORTER_DISABLE_AUTORUN = '1';
const cliModulePromise = import('../src/cli.js');
const packageJsonPath = new URL('../package.json', import.meta.url);
async function readPackageVersion(): Promise<string> {
const buffer = await fsPromises.readFile(packageJsonPath, 'utf8');
const pkg = JSON.parse(buffer) as { version?: string };
return pkg.version ?? '0.0.0';
}
describe('mcporter global shortcuts', () => {
afterEach(() => {
vi.restoreAllMocks();
process.exitCode = undefined;
});
it('prints global help before inference when --help is provided', async () => {
const { runCli } = await cliModulePromise;
const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
await runCli(['--help']);
expect(errorSpy).toHaveBeenCalledWith(expect.stringContaining('Usage: mcporter'));
expect(process.exitCode).toBe(0);
});
it('prints global help when the bare help token is provided', async () => {
const { runCli } = await cliModulePromise;
const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
await runCli(['help']);
expect(errorSpy).toHaveBeenCalledWith(expect.stringContaining('Usage: mcporter'));
expect(process.exitCode).toBe(0);
});
it('prints the package version when --version is provided', async () => {
const { runCli } = await cliModulePromise;
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
const expectedVersion = await readPackageVersion();
await runCli(['--version']);
expect(logSpy).toHaveBeenCalledWith(expectedVersion);
expect(process.exitCode).toBeUndefined();
});
it('prints the package version when -v is provided', async () => {
const { runCli } = await cliModulePromise;
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
const expectedVersion = await readPackageVersion();
await runCli(['-v']);
expect(logSpy).toHaveBeenCalledWith(expectedVersion);
expect(process.exitCode).toBeUndefined();
});
});