From 1a8ba9a43bcf08c4c372f18a7c62f885f0f8ea0e Mon Sep 17 00:00:00 2001 From: Jeremy Date: Tue, 14 Apr 2026 05:50:47 -0500 Subject: [PATCH] fix(cli): restore --help handling when it follows a subcommand or unknown flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The #4162 refactor removed parseCliArgs' inline --help handler assuming loader.ts's fast-path covered it, but loader.ts only intercepts --help/-h as argv[1]. That broke: - gsd update --help — fell through to runUpdate() (subcommand help check sat dead-code below the update handler) - gsd --unknown --help in non-TTY — tripped the TTY gate and exited 1 Move the subcommand-help check ahead of every subcommand handler and fall back to general help when no subcommand matches, so --help wins whenever it appears anywhere in argv. Co-Authored-By: Claude Opus 4.6 --- src/cli.ts | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/cli.ts b/src/cli.ts index 18da35109..b0af332ed 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -20,7 +20,7 @@ import { migratePiCredentials } from './pi-migration.js' import { shouldRunOnboarding, runOnboarding } from './onboarding.js' import chalk from 'chalk' import { checkForUpdates } from './update-check.js' -import { printSubcommandHelp } from './help-text.js' +import { printHelp, printSubcommandHelp } from './help-text.js' import { applySecurityOverrides } from './security-overrides.js' import { validateConfiguredModel } from './startup-model-validation.js' import { @@ -126,6 +126,20 @@ async function reapplyValidatedModelOnFallback( const cliFlags = parseCliArgs(process.argv) const isPrintMode = cliFlags.print || cliFlags.mode !== undefined +// `gsd [subcommand] --help` / `-h` — print help before any subcommand runs. +// loader.ts only catches --help/-h as the *first* arg; here we handle the +// case where it appears later (e.g. `gsd update --help`, `gsd --foo --help`). +// Prefer subcommand-specific help when the first positional is a known +// subcommand, otherwise fall back to general help. +if (process.argv.includes('--help') || process.argv.includes('-h')) { + const helpSubcommand = cliFlags.messages[0] + const version = process.env.GSD_VERSION || '0.0.0' + if (!helpSubcommand || !printSubcommandHelp(helpSubcommand, version)) { + printHelp(version) + } + process.exit(0) +} + // RTK bootstrap — runs once per process, memoized via a module-level promise // so concurrent callers await the same initialization. let rtkBootstrapPromise: Promise | undefined @@ -167,14 +181,6 @@ if (!process.stdin.isTTY && !isPrintMode && !hasSubcommand && !cliFlags.listMode printNonTtyErrorAndExit(undefined, false) } -// `gsd --help` — show subcommand-specific help -const subcommand = cliFlags.messages[0] -if (subcommand && process.argv.includes('--help')) { - if (printSubcommandHelp(subcommand, process.env.GSD_VERSION || '0.0.0')) { - process.exit(0) - } -} - const packageCommand = await runPackageCommand({ appName: 'gsd', args: process.argv.slice(2),