diff --git a/src/cli/args.ts b/src/cli/args.ts index badc3ee..f836d25 100644 --- a/src/cli/args.ts +++ b/src/cli/args.ts @@ -396,6 +396,16 @@ export function parseCliArgs(argv: string[] = process.argv.slice(2)): ParsedArgs // Handle setup-app command if (positionals.includes('setup-app')) { + const port = values.port ? parseInt(values.port as string, 10) : 3000; + if (Number.isNaN(port)) { + console.error(`Invalid --port value: ${values.port}`); + process.exit(1); + } + const timeout = values.timeout ? parseInt(values.timeout as string, 10) : 300; + if (Number.isNaN(timeout)) { + console.error(`Invalid --timeout value: ${values.timeout}`); + process.exit(1); + } return { command: 'setup-app', options: CLIOptionsSchema.parse({ @@ -404,8 +414,8 @@ export function parseCliArgs(argv: string[] = process.argv.slice(2)): ParsedArgs }), setupAppOptions: { org: values.org as string | undefined, - port: values.port ? parseInt(values.port as string, 10) : 3000, - timeout: values.timeout ? parseInt(values.timeout as string, 10) : 300, + port, + timeout, name: values.name as string | undefined, open: !values['no-open'], }, diff --git a/src/cli/commands/add.ts b/src/cli/commands/add.ts index d279d44..3e7912a 100644 --- a/src/cli/commands/add.ts +++ b/src/cli/commands/add.ts @@ -187,6 +187,28 @@ async function promptRemoteSkillSelection( } } +/** + * Resolve which skill to add from explicit option, interactive prompt, or error. + * Returns the skill name, or null if the user cancelled, or a numeric exit code on error. + */ +async function resolveSkillName( + options: CLIOptions, + reporter: Reporter, + prompt: () => Promise, + usageTip: string, +): Promise { + if (options.skill) { + return options.skill; + } + if (reporter.mode.isTTY) { + const selected = await prompt(); + return selected ?? 0; + } + reporter.error('Skill name required when not running interactively.'); + reporter.tip(usageTip); + return 1; +} + const DEFAULT_TRIGGERS = [ { type: 'pull_request' as const, @@ -271,21 +293,15 @@ async function runAddRemote( } // Get skill to add (from --skill or interactive prompt) - let skillName: string | null; - - if (options.skill) { - skillName = options.skill; - } else if (reporter.mode.isTTY) { - reporter.blank(); - skillName = await promptRemoteSkillSelection(remoteSkills, configuredSkills, reporter); - if (!skillName) { - return 0; // User quit or no skills available - } - } else { - reporter.error('Skill name required when not running interactively.'); - reporter.tip(`Use: warden add --remote ${remote} --skill `); - return 1; - } + if (!options.skill && reporter.mode.isTTY) reporter.blank(); + const resolved = await resolveSkillName( + options, + reporter, + () => promptRemoteSkillSelection(remoteSkills, configuredSkills, reporter), + `Use: warden add --remote ${remote} --skill `, + ); + if (typeof resolved === 'number') return resolved; + const skillName = resolved; // Validate skill exists in remote, retry with fresh fetch if using stale cache let availableSkills = remoteSkills; @@ -413,23 +429,14 @@ export async function runAdd(options: CLIOptions, reporter: Reporter): Promise or warden add --list'); - return 1; - } + const resolved = await resolveSkillName( + options, + reporter, + () => promptSkillSelection(skills, configuredSkills, reporter), + 'Use: warden add or warden add --list', + ); + if (typeof resolved === 'number') return resolved; + const skillName = resolved; // 9. Validate skill exists if (!skills.has(skillName)) {