/** * CLI for the split-plan tool: parse PR URL and options. * WHY Commander: Same as prr/pill/story; consistent option parsing and help output. * WHY PR URL only: Decomposition only makes sense for an existing PR; we need getPRInfo, getPRCommits, getPRFilesWithPatches from the GitHub PR API. */ import { Command } from 'commander'; import chalk from 'chalk'; export interface SplitPlanOptions { output?: string; verbose: boolean; /** Budget for total patch content in the prompt (chars). WHY: Prevents context overflow on large PRs. */ maxPatchChars: number; /** Run pill analysis on the output log when the run finishes. */ pill: boolean; } export interface SplitPlanParsedArgs { prUrl: string; options: SplitPlanOptions; } export function createCLI(): Command { const program = new Command(); program .name('split-plan') .description( 'Analyze a PR and output a human-editable decomposition plan (.split-plan.md). Accepts a PR URL only.' ) .argument( '', 'PR URL (e.g. https://github.com/owner/repo/pull/123 or owner/repo#123)' ) .option('-o, --output ', 'Write plan to this file (default: .split-plan.md in cwd)') .option('-v, --verbose', 'Verbose logging', false) .option( '--max-patch-chars ', 'Max total patch content in prompt (chars). Default 120000.', '120000' ) .option('--pill', 'Run pill analysis on the output log when the run finishes', false); return program; } export function parseArgs(program: Command): SplitPlanParsedArgs { program.parse(); const args = program.args as string[]; const opts = program.opts(); if (args.length === 0) { program.outputHelp(); process.exit(1); } // WHY parseInt: Commander returns option values as strings; we must parse and validate. const maxPatchChars = parseInt(String(opts.maxPatchChars ?? '120000'), 10); if (Number.isNaN(maxPatchChars) || maxPatchChars < 10000) { console.error(chalk.red('Error:'), '--max-patch-chars must be a number >= 10000'); process.exit(1); } const output = opts.output ? String(opts.output).trim() : undefined; return { prUrl: args[0], options: { output: output && output.length > 0 ? output : undefined, verbose: opts.verbose ?? false, maxPatchChars, pill: opts.pill ?? false, }, }; }