From 13128b51d3bd9d3905a0a29184cd652c46e10eaa Mon Sep 17 00:00:00 2001 From: Paul Carleton Date: Tue, 11 Nov 2025 14:32:45 +0000 Subject: [PATCH 1/2] add back interactive mode, todo: print instructions for running w/ command and fix optional error message on command --- src/index.ts | 18 ++++++++++++++---- src/schemas.ts | 20 ++++++++++++++++++-- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/index.ts b/src/index.ts index d35c676..e1672c7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,7 +7,8 @@ import { printClientResults, runServerConformanceTest, printServerResults, - printServerSummary + printServerSummary, + runInteractiveMode } from './runner'; import { listScenarios, listClientScenarios } from './scenarios'; import { ConformanceCheck } from './types'; @@ -24,8 +25,10 @@ program // Client command - tests a client implementation against scenarios program .command('client') - .description('Run conformance tests against a client implementation') - .requiredOption('--command ', 'Command to run the client') + .description( + 'Run conformance tests against a client implementation or start interactive mode' + ) + .option('--command ', 'Command to run the client') .requiredOption('--scenario ', 'Scenario to test') .option('--timeout ', 'Timeout in milliseconds', '30000') .option('--verbose', 'Show verbose output') @@ -34,10 +37,17 @@ program // Validate options with Zod const validated = ClientOptionsSchema.parse(options); + // If no command provided, run in interactive mode + if (!validated.command) { + await runInteractiveMode(validated.scenario); + process.exit(0); + } + + // Otherwise run conformance test const result = await runConformanceTest( validated.command, validated.scenario, - validated.timeout + validated.timeout ?? 30000 ); const { failed } = printClientResults( diff --git a/src/schemas.ts b/src/schemas.ts index 5f22fc6..5e81c8c 100644 --- a/src/schemas.ts +++ b/src/schemas.ts @@ -3,7 +3,7 @@ import { getScenario, getClientScenario } from './scenarios'; // Client command options schema export const ClientOptionsSchema = z.object({ - command: z.string().min(1, 'Command cannot be empty'), + command: z.string().min(1, 'Command cannot be empty').optional(), scenario: z .string() .min(1, 'Scenario cannot be empty') @@ -21,7 +21,8 @@ export const ClientOptionsSchema = z.object({ .number() .positive('Timeout must be a positive number') .int('Timeout must be an integer') - ), + ) + .optional(), verbose: z.boolean().optional() }); @@ -42,3 +43,18 @@ export const ServerOptionsSchema = z.object({ }); export type ServerOptions = z.infer; + +// Interactive command options schema +export const InteractiveOptionsSchema = z.object({ + scenario: z + .string() + .min(1, 'Scenario cannot be empty') + .refine( + (scenario) => getScenario(scenario) !== undefined, + (scenario) => ({ + message: `Unknown scenario '${scenario}'` + }) + ) +}); + +export type InteractiveOptions = z.infer; From f47ce8b7ab83e8f4745791cf442e094b3b2a7d1d Mon Sep 17 00:00:00 2001 From: Paul Carleton Date: Tue, 11 Nov 2025 17:46:15 +0000 Subject: [PATCH 2/2] add verbose checking --- src/index.ts | 5 ++++- src/runner/client.ts | 11 +++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/index.ts b/src/index.ts index e1672c7..4afddff 100644 --- a/src/index.ts +++ b/src/index.ts @@ -39,7 +39,10 @@ program // If no command provided, run in interactive mode if (!validated.command) { - await runInteractiveMode(validated.scenario); + await runInteractiveMode( + validated.scenario, + validated.verbose ?? false + ); process.exit(0); } diff --git a/src/runner/client.ts b/src/runner/client.ts index 8f3ff1a..d7f8105 100644 --- a/src/runner/client.ts +++ b/src/runner/client.ts @@ -170,7 +170,10 @@ export function printClientResults( return { passed, failed, denominator }; } -export async function runInteractiveMode(scenarioName: string): Promise { +export async function runInteractiveMode( + scenarioName: string, + verbose: boolean = false +): Promise { await ensureResultsDir(); const resultDir = createResultDir(scenarioName); await fs.mkdir(resultDir, { recursive: true }); @@ -193,7 +196,11 @@ export async function runInteractiveMode(scenarioName: string): Promise { JSON.stringify(checks, null, 2) ); - console.log(`\nChecks:\n${JSON.stringify(checks, null, 2)}`); + if (verbose) { + console.log(`\nChecks:\n${JSON.stringify(checks, null, 2)}`); + } else { + console.log(`\nChecks:\n${formatPrettyChecks(checks)}`); + } console.log(`\nChecks saved to ${resultDir}/checks.json`); await scenario.stop();