/* - Date: 2026-06-29 Spec: plans/2026-06-29-claude-code-raw-replay-harness-plan.md Relationship: Vendors OpenAI Codex app-server generated TypeScript protocol schemas as a single declaration bundle so Commander replay/coverage tests can type-check against the real JSON-RPC protocol surface without committing the upstream one-file-per-type layout. */ import { cp, mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'; import { existsSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { dirname, join, relative, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; import { spawn } from 'node:child_process'; type VendorOptions = { readonly sourceRepo: string | undefined; readonly sourceUrl: string; readonly sourceRef: string; readonly outFile: string; readonly manifestFile: string; readonly keepTemp: boolean; readonly check: boolean; }; type PreparedSource = { readonly repoPath: string; readonly cleanup: (() => Promise) | undefined; }; const thisFile = fileURLToPath(import.meta.url); const packageRoot = resolve(dirname(thisFile), '..'); const protocolSubtree = 'codex-rs/app-server-protocol/schema/typescript'; const defaultSourceUrl = 'https://github.com/openai/codex.git'; const vendorModuleName = '@linzumi/vendor/codex-app-server-protocol'; const defaultOutFile = join( packageRoot, 'src/vendor/codex-app-server-protocol.d.ts' ); const defaultManifestFile = join( packageRoot, 'src/vendor/codex-app-server-protocol-manifest.json' ); async function main(): Promise { const args = process.argv.slice(2); if (args.includes('--help')) { printHelp(); return; } const options = parseArgs(args); const source = await prepareSource(options); try { const sourceDir = join(source.repoPath, protocolSubtree); if (!existsSync(sourceDir)) { throw new Error( `Codex protocol schema directory not found: ${sourceDir}` ); } const sourceCommit = await git(source.repoPath, ['rev-parse', 'HEAD']); if (options.check) { await checkVendoredOutput(options, sourceDir, sourceCommit.trim()); process.stdout.write( `verified Codex app-server protocol declaration bundle\n` ); } else { await writeDeclarationBundle(options, sourceDir, sourceCommit.trim()); await writeManifest(options, sourceCommit.trim()); process.stdout.write( `vendored Codex app-server protocol declaration bundle\n` ); } process.stdout.write(` source: ${options.sourceUrl}\n`); process.stdout.write(` ref: ${options.sourceRef}\n`); process.stdout.write(` commit: ${sourceCommit.trim()}\n`); process.stdout.write(` module: ${vendorModuleName}\n`); process.stdout.write(` out: ${options.outFile}\n`); process.stdout.write(` manifest: ${options.manifestFile}\n`); } finally { await source.cleanup?.(); } } function parseArgs(args: readonly string[]): VendorOptions { return { sourceRepo: optionalResolvedArg(args, '--codex-repo'), sourceUrl: argValue(args, '--source-url') ?? defaultSourceUrl, sourceRef: argValue(args, '--ref') ?? 'main', outFile: optionalResolvedArg(args, '--out-file') ?? defaultOutFile, manifestFile: optionalResolvedArg(args, '--manifest-file') ?? defaultManifestFile, keepTemp: args.includes('--keep-temp'), check: args.includes('--check'), }; } async function checkVendoredOutput( options: VendorOptions, sourceDir: string, sourceCommit: string ): Promise { const checkRoot = await mkdtemp( join(packageRoot, '.linzumi-codex-protocol-check-') ); try { const expectedOutFile = join(checkRoot, 'codex-app-server-protocol.d.ts'); const expectedManifestFile = join( checkRoot, 'codex-app-server-protocol-manifest.json' ); const expectedOptions = { ...options, outFile: expectedOutFile, manifestFile: expectedManifestFile, check: false, }; await writeDeclarationBundle(expectedOptions, sourceDir, sourceCommit); await writeManifest(expectedOptions, sourceCommit); await normalizeExpectedManifestForCommittedPaths( expectedManifestFile, options.outFile ); await assertSameFile(expectedOutFile, options.outFile); await assertSameFile(expectedManifestFile, options.manifestFile); } finally { await rm(checkRoot, { recursive: true, force: true }); } } async function normalizeExpectedManifestForCommittedPaths( manifestPath: string, committedOutFile: string ): Promise { const manifest = JSON.parse(await readFile(manifestPath, 'utf8')) as Record< string, unknown >; const normalized = { ...manifest, declarationFile: relative(packageRoot, committedOutFile), }; await writeFile( manifestPath, `${JSON.stringify(normalized, null, 2)}\n`, 'utf8' ); } async function assertSameFile( expectedPath: string, actualPath: string ): Promise { const expected = await readFile(expectedPath, 'utf8'); const actual = await readFile(actualPath, 'utf8'); if (expected !== actual) { throw new Error( `vendored Codex protocol drift detected: ${actualPath} does not match regenerated output` ); } } async function prepareSource(options: VendorOptions): Promise { if (options.sourceRepo !== undefined) { return { repoPath: options.sourceRepo, cleanup: undefined }; } const repoPath = await mkdtemp(join(tmpdir(), 'linzumi-openai-codex-')); await git(undefined, [ 'clone', '--filter=blob:none', '--sparse', options.sourceUrl, repoPath, ]); await git(repoPath, ['sparse-checkout', 'set', protocolSubtree]); await git(repoPath, ['fetch', '--depth', '1', 'origin', options.sourceRef]); await git(repoPath, ['checkout', 'FETCH_HEAD']); return { repoPath, cleanup: options.keepTemp ? undefined : async () => { await rm(repoPath, { recursive: true, force: true }); }, }; } async function writeDeclarationBundle( options: VendorOptions, sourceDir: string, sourceCommit: string ): Promise { const bundleRoot = await mkdtemp( join(tmpdir(), 'linzumi-codex-protocol-dts-') ); try { const copiedProtocolDir = join(bundleRoot, 'protocol'); const entryFile = join(bundleRoot, 'entry.ts'); const rawBundleFile = join(bundleRoot, 'raw-bundle.d.ts'); await cp(sourceDir, copiedProtocolDir, { recursive: true }); await writeFile( entryFile, [ "export * from './protocol/index';", "export * as v2 from './protocol/v2/index';", '', ].join('\n'), 'utf8' ); await command(packageRoot, [ 'pnpm', 'exec', 'tsc', '--declaration', '--emitDeclarationOnly', '--outFile', rawBundleFile, '--module', 'amd', '--moduleResolution', 'node', '--target', 'ES2022', '--skipLibCheck', entryFile, ]); const rawBundle = await readFile(rawBundleFile, 'utf8'); const bundled = rawBundle .replaceAll( 'declare module "protocol/', `declare module "${vendorModuleName}/` ) .replaceAll('from "protocol/', `from "${vendorModuleName}/`) .replace( 'declare module "entry" {', `declare module "${vendorModuleName}" {` ); const header = [ '// GENERATED CODE! DO NOT MODIFY BY HAND!', '// Bundled from OpenAI Codex app-server protocol TypeScript schemas.', `// Source commit: ${sourceCommit}`, `// Module: ${vendorModuleName}`, '', ].join('\n'); await mkdir(dirname(options.outFile), { recursive: true }); await writeFile(options.outFile, `${header}${bundled}`, 'utf8'); await formatGeneratedFile(options.outFile); } finally { await rm(bundleRoot, { recursive: true, force: true }); } } async function formatGeneratedFile(path: string): Promise { await command(packageRoot, [ 'pnpm', 'exec', 'biome', 'format', '--write', '--no-errors-on-unmatched', path, ]); } async function writeManifest( options: VendorOptions, sourceCommit: string ): Promise { const manifest = { source: 'openai/codex codex-rs/app-server-protocol/schema/typescript', sourceUrl: options.sourceUrl, requestedRef: options.sourceRef, sourceCommit, protocolSubtree, moduleName: vendorModuleName, declarationFile: relative(packageRoot, options.outFile), updateCommand: 'pnpm --filter @linzumi/cli run vendor:codex-app-server-protocol -- --ref ', }; await mkdir(dirname(options.manifestFile), { recursive: true }); await writeFile( options.manifestFile, `${JSON.stringify(manifest, null, 2)}\n`, 'utf8' ); } function optionalResolvedArg( args: readonly string[], name: string ): string | undefined { const value = argValue(args, name); return value === undefined ? undefined : resolve(value); } function argValue(args: readonly string[], name: string): string | undefined { const index = args.indexOf(name); if (index === -1) { return undefined; } const value = args[index + 1]; if (value === undefined) { throw new Error(`${name} requires a value`); } return value; } function git( cwd: string | undefined, args: readonly string[] ): Promise { return command(cwd, ['git', ...args]); } function command( cwd: string | undefined, args: readonly string[] ): Promise { return new Promise((resolvePromise, reject) => { const [commandName, ...commandArgs] = args; if (commandName === undefined) { reject(new Error('command requires at least one argument')); return; } const child = spawn(commandName, commandArgs, { cwd, stdio: ['ignore', 'pipe', 'pipe'], }); const stdout: string[] = []; const stderr: string[] = []; child.stdout.on('data', (chunk) => stdout.push(String(chunk))); child.stderr.on('data', (chunk) => stderr.push(String(chunk))); child.on('error', reject); child.on('close', (code) => { if (code === 0) { resolvePromise(stdout.join('')); return; } reject( new Error( `${args.join(' ')} failed with exit ${code}: ${stderr.join('')}` ) ); }); }); } function printHelp(): void { process.stdout.write( `Usage: pnpm run vendor:codex-app-server-protocol -- [options]\n\nOptions:\n --codex-repo Bundle from an existing OpenAI Codex checkout\n --ref Git ref to vendor when cloning. Default: main\n --source-url Codex git URL. Default: ${defaultSourceUrl}\n --out-file Declaration bundle path. Default: src/vendor/codex-app-server-protocol.d.ts\n --manifest-file Manifest path. Default: src/vendor/codex-app-server-protocol-manifest.json\n --keep-temp Keep temporary clone when cloning\n --check Regenerate into a temp directory and fail if committed files differ\n\nExamples:\n pnpm --filter @linzumi/cli run vendor:codex-app-server-protocol -- --ref main\n pnpm --filter @linzumi/cli run vendor:codex-app-server-protocol -- --codex-repo /tmp/openai-codex\n pnpm --filter @linzumi/cli run vendor:codex-app-server-protocol -- --codex-repo /tmp/openai-codex --check\n` ); } main().catch((error) => { process.stderr.write( `${error instanceof Error ? (error.stack ?? error.message) : String(error)}\n` ); process.exitCode = 1; });