From 64cb55da9c16b71ca1b99fdc8f0c83d54458601b Mon Sep 17 00:00:00 2001 From: unknown <> Date: Tue, 24 Feb 2026 19:11:39 +0000 Subject: [PATCH 1/2] feat(codegen): add CLI entry point generation option (cli.entryPoint) - Add cli-entry.ts template with CLI bootstrap code (inquirerer, --version, --tty) - Add generateEntryPointFile() to utils-generator.ts (template-copy pattern) - Add entryPoint option to CliConfig interface (default: false) - Wire up in generateCli() and generateMultiTargetCli() - Pass entryPoint through generateMulti() for unified CLI - When enabled, generates index.ts in cli/ output directory This removes the last remaining hack from the constructive-hub CLI e2e test script (manual index.ts generation at test time). --- graphql/codegen/src/core/codegen/cli/index.ts | 18 +++++++++-- .../src/core/codegen/cli/utils-generator.ts | 18 +++++++++++ .../src/core/codegen/templates/cli-entry.ts | 32 +++++++++++++++++++ graphql/codegen/src/core/generate.ts | 1 + graphql/codegen/src/types/config.ts | 9 ++++++ 5 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 graphql/codegen/src/core/codegen/templates/cli-entry.ts diff --git a/graphql/codegen/src/core/codegen/cli/index.ts b/graphql/codegen/src/core/codegen/cli/index.ts index 5acbe7e21..4a2d747a4 100644 --- a/graphql/codegen/src/core/codegen/cli/index.ts +++ b/graphql/codegen/src/core/codegen/cli/index.ts @@ -11,7 +11,7 @@ import { generateMultiTargetContextCommand, } from './infra-generator'; import { generateTableCommand } from './table-command-generator'; -import { generateUtilsFile, generateNodeFetchFile } from './utils-generator'; +import { generateUtilsFile, generateNodeFetchFile, generateEntryPointFile } from './utils-generator'; export interface GenerateCliOptions { tables: CleanTable[]; @@ -91,6 +91,13 @@ export function generateCli(options: GenerateCliOptions): GenerateCliResult { ); files.push(commandMapFile); + // Generate entry point if configured + const generateEntryPoint = + typeof cliConfig === 'object' && !!cliConfig.entryPoint; + if (generateEntryPoint) { + files.push(generateEntryPointFile()); + } + return { files, stats: { @@ -123,6 +130,8 @@ export interface GenerateMultiTargetCliOptions { targets: MultiTargetCliTarget[]; /** Enable NodeHttpAdapter for *.localhost subdomain routing */ nodeHttpAdapter?: boolean; + /** Generate a runnable index.ts entry point */ + entryPoint?: boolean; } export function resolveBuiltinNames( @@ -232,6 +241,11 @@ export function generateMultiTargetCli( }); files.push(commandMapFile); + // Generate entry point if configured + if (options.entryPoint) { + files.push(generateEntryPointFile()); + } + return { files, stats: { @@ -267,5 +281,5 @@ export { export type { MultiTargetDocsInput } from './docs-generator'; export { resolveDocsConfig } from '../docs-utils'; export type { GeneratedDocFile, McpTool } from '../docs-utils'; -export { generateUtilsFile } from './utils-generator'; +export { generateUtilsFile, generateEntryPointFile } from './utils-generator'; export type { GeneratedFile, MultiTargetExecutorInput } from './executor-generator'; diff --git a/graphql/codegen/src/core/codegen/cli/utils-generator.ts b/graphql/codegen/src/core/codegen/cli/utils-generator.ts index a669132cb..5eb59fffc 100644 --- a/graphql/codegen/src/core/codegen/cli/utils-generator.ts +++ b/graphql/codegen/src/core/codegen/cli/utils-generator.ts @@ -76,3 +76,21 @@ export function generateNodeFetchFile(): GeneratedFile { ), }; } + +/** + * Generate an index.ts entry point file for the CLI. + * + * Creates a runnable entry point that imports the command map, + * handles --version and --tty flags, and starts the CLI. + * This is off by default (cliEntryPoint: false) since many projects + * provide their own entry point with custom configuration. + */ +export function generateEntryPointFile(): GeneratedFile { + return { + fileName: 'index.ts', + content: readTemplateFile( + 'cli-entry.ts', + 'CLI entry point', + ), + }; +} diff --git a/graphql/codegen/src/core/codegen/templates/cli-entry.ts b/graphql/codegen/src/core/codegen/templates/cli-entry.ts new file mode 100644 index 000000000..862355171 --- /dev/null +++ b/graphql/codegen/src/core/codegen/templates/cli-entry.ts @@ -0,0 +1,32 @@ +/** + * CLI entry point for running the generated CLI application. + * + * Creates an inquirerer CLI instance with the generated command map, + * handles --version and --tty flags, and runs the CLI. + * + * NOTE: This file is read at codegen time and written to output. + * Any changes here will affect all generated CLI entry points. + */ + +import { CLI, CLIOptions } from 'inquirerer'; +import { commands } from './commands'; + +if (process.argv.includes('--version') || process.argv.includes('-v')) { + console.log('0.0.1'); + process.exit(0); +} + +// Check for --tty false to enable non-interactive mode (noTty) +const ttyIdx = process.argv.indexOf('--tty'); +const noTty = ttyIdx !== -1 && process.argv[ttyIdx + 1] === 'false'; + +const options: Partial = { + noTty, + minimistOpts: { alias: { v: 'version', h: 'help' } }, +}; + +const app = new CLI(commands, options); +app.run().catch((e) => { + console.error('Unexpected error:', e); + process.exit(1); +}); diff --git a/graphql/codegen/src/core/generate.ts b/graphql/codegen/src/core/generate.ts index f8fb73179..a61344bdb 100644 --- a/graphql/codegen/src/core/generate.ts +++ b/graphql/codegen/src/core/generate.ts @@ -696,6 +696,7 @@ export async function generateMulti( builtinNames: cliConfig.builtinNames, targets: cliTargets, nodeHttpAdapter: multiNodeHttpAdapter, + entryPoint: cliConfig.entryPoint, }); const cliFilesToWrite = files.map((file) => ({ diff --git a/graphql/codegen/src/types/config.ts b/graphql/codegen/src/types/config.ts index 7f572a564..aadc50bb8 100644 --- a/graphql/codegen/src/types/config.ts +++ b/graphql/codegen/src/types/config.ts @@ -199,6 +199,15 @@ export interface CliConfig { * context -> 'context' (renamed to 'env' on collision) */ builtinNames?: BuiltinNames; + + /** + * Generate a runnable index.ts entry point for the CLI. + * When true, generates an index.ts that imports the command map, + * handles --version and --tty flags, and starts the inquirerer CLI. + * Useful for projects that want a ready-to-run CLI without a custom entry point. + * @default false + */ + entryPoint?: boolean; } /** From 51cf3152e2dc89fff375990a528c361bc2e4bc7c Mon Sep 17 00:00:00 2001 From: unknown <> Date: Tue, 24 Feb 2026 19:36:14 +0000 Subject: [PATCH 2/2] fix(codegen): use getPackageJson for --version instead of hardcoded '0.0.1' Uses getPackageJson(__dirname) from inquirerer to read the actual package.json version at runtime, matching the pattern used by cnc and pgpm CLIs. --- graphql/codegen/src/core/codegen/templates/cli-entry.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/graphql/codegen/src/core/codegen/templates/cli-entry.ts b/graphql/codegen/src/core/codegen/templates/cli-entry.ts index 862355171..b0a68394c 100644 --- a/graphql/codegen/src/core/codegen/templates/cli-entry.ts +++ b/graphql/codegen/src/core/codegen/templates/cli-entry.ts @@ -8,11 +8,12 @@ * Any changes here will affect all generated CLI entry points. */ -import { CLI, CLIOptions } from 'inquirerer'; +import { CLI, CLIOptions, getPackageJson } from 'inquirerer'; import { commands } from './commands'; if (process.argv.includes('--version') || process.argv.includes('-v')) { - console.log('0.0.1'); + const pkg = getPackageJson(__dirname); + console.log(pkg.version); process.exit(0); }