import * as fs from 'node:fs'; import * as path from 'node:path'; import { dispatchCsoCommand, type CsoCliDependencies } from '../../lib/cso/cli'; import { validateRuntimeCatalog, type QualifiedRuntime, type RuntimeCatalog, type RuntimePlatform } from '../../lib/cso/runtime-catalog'; import { completeRuntimeCatalogFixture, installStagedRuntime } from './cso-runtime-catalog'; export interface QualifiedCsoCli { readonly catalog: RuntimeCatalog; readonly runtime: QualifiedRuntime; command(args: string[]): Promise; } /** Bind a staged Node image to the real command dispatcher without adding a production override. */ export function qualifiedNodeCli(options: { image: string; versions: Record; watchdogPath: string; platform: RuntimePlatform; }): QualifiedCsoCli { if (!path.isAbsolute(options.watchdogPath) || !fs.statSync(options.watchdogPath).isFile()) { throw new Error('Node lifecycle qualification requires an absolute compiled watchdog path'); } for (const key of ['node', 'npm', 'cso-preparation']) { if (!/^\d+\.\d+\.\d+$/.test(options.versions[key] ?? '')) { throw new Error(`Node lifecycle qualification requires exact ${key} version metadata`); } } if (options.versions['cso-preparation'] !== '1.0.0') { throw new Error('Node lifecycle qualification requires cso-preparation 1.0.0'); } const catalog = completeRuntimeCatalogFixture('node-lifecycle-fixture'); const fixture = catalog.runtimes.find(item => item.stack === 'node' && item.platform === options.platform); if (!fixture) throw new Error('Node lifecycle catalog fixture is incomplete'); const runtime = installStagedRuntime(catalog, { ...fixture, image: options.image, versions: options.versions }); validateRuntimeCatalog(catalog); const dependencies: CsoCliDependencies = Object.freeze({ runtimeCatalog: catalog, watchdogPath: () => options.watchdogPath, }); return Object.freeze({ catalog, runtime, async command(args: string[]): Promise { const [command, ...commandArgs] = args; if (!command) throw new Error('CSO qualification command is required'); return await dispatchCsoCommand(command, commandArgs, dependencies) as T; }, }); }