From 79045a0d439074994812d9cd682f933b9e415706 Mon Sep 17 00:00:00 2001 From: whyour Date: Mon, 31 Aug 2026 01:43:41 +0800 Subject: [PATCH] refactor(ql3): keep application CLI boundary thin --- packages/ql3-local-application/src/cli.ts | 54 +++---------------- .../src/production-process/cliCommand.ts | 49 +++++++++++++++++ 2 files changed, 57 insertions(+), 46 deletions(-) create mode 100644 packages/ql3-local-application/src/production-process/cliCommand.ts diff --git a/packages/ql3-local-application/src/cli.ts b/packages/ql3-local-application/src/cli.ts index 5ec1b1bf..2c81a5e6 100644 --- a/packages/ql3-local-application/src/cli.ts +++ b/packages/ql3-local-application/src/cli.ts @@ -7,6 +7,10 @@ import { type LocalApplicationProcessSignalSource, } from './production-process/processApplication'; import { runProductionLocalApplicationCutoverProbe } from './production-process/cutoverProbeProcess'; +import { + localApplicationCliFailureFact, + parseLocalApplicationCliCommand, +} from './production-process/cliCommand'; const USAGE = 'Usage: ql3-local-application [--cutover-probe] --config /absolute/private-config.json'; @@ -34,56 +38,12 @@ function emit(record: Readonly): void { process.stdout.write(`${JSON.stringify(record)}\n`); } -function failureFact(error: unknown): Readonly> { - const candidate = error as { - readonly name?: unknown; - readonly code?: unknown; - }; - return Object.freeze({ - schemaVersion: 1, - component: 'qinglong3-local-application', - level: 'error', - event: 'process_failed', - name: - typeof candidate?.name === 'string' && candidate.name.length <= 128 - ? candidate.name - : 'Error', - ...(typeof candidate?.code === 'string' && candidate.code.length <= 128 - ? { code: candidate.code } - : {}), - }); -} - -function configFileArgument(argv: readonly string[]): Readonly<{ - configFilePath: string; - mode: 'application' | 'cutover_probe'; -}> | null { - if (argv.length === 2 && argv[0] === '--config' && argv[1]) { - return Object.freeze({ - configFilePath: argv[1], - mode: 'application' as const, - }); - } - if ( - argv.length === 3 && - argv[0] === '--cutover-probe' && - argv[1] === '--config' && - argv[2] - ) { - return Object.freeze({ - configFilePath: argv[2], - mode: 'cutover_probe' as const, - }); - } - return null; -} - async function main(argv: readonly string[]): Promise { if (argv.length === 1 && (argv[0] === '--help' || argv[0] === '-h')) { process.stdout.write(`${USAGE}\n`); return; } - const command = configFileArgument(argv); + const command = parseLocalApplicationCliCommand(argv); if (command === null) { process.stderr.write( `${JSON.stringify({ @@ -109,7 +69,9 @@ async function main(argv: readonly string[]): Promise { }); if (stopResult !== 'stopped') process.exitCode = 1; } catch (error) { - process.stderr.write(`${JSON.stringify(failureFact(error))}\n`); + process.stderr.write( + `${JSON.stringify(localApplicationCliFailureFact(error))}\n`, + ); process.exitCode = 1; } } diff --git a/packages/ql3-local-application/src/production-process/cliCommand.ts b/packages/ql3-local-application/src/production-process/cliCommand.ts new file mode 100644 index 00000000..c15f9588 --- /dev/null +++ b/packages/ql3-local-application/src/production-process/cliCommand.ts @@ -0,0 +1,49 @@ +export type LocalApplicationCliCommand = Readonly<{ + configFilePath: string; + mode: 'application' | 'cutover_probe'; +}>; + +export function localApplicationCliFailureFact( + error: unknown, +): Readonly> { + const candidate = error as { + readonly name?: unknown; + readonly code?: unknown; + }; + return Object.freeze({ + schemaVersion: 1, + component: 'qinglong3-local-application', + level: 'error', + event: 'process_failed', + name: + typeof candidate?.name === 'string' && candidate.name.length <= 128 + ? candidate.name + : 'Error', + ...(typeof candidate?.code === 'string' && candidate.code.length <= 128 + ? { code: candidate.code } + : {}), + }); +} + +export function parseLocalApplicationCliCommand( + argv: readonly string[], +): LocalApplicationCliCommand | null { + if (argv.length === 2 && argv[0] === '--config' && argv[1]) { + return Object.freeze({ + configFilePath: argv[1], + mode: 'application' as const, + }); + } + if ( + argv.length === 3 && + argv[0] === '--cutover-probe' && + argv[1] === '--config' && + argv[2] + ) { + return Object.freeze({ + configFilePath: argv[2], + mode: 'cutover_probe' as const, + }); + } + return null; +}