#!/usr/bin/env node /** * cli:gitflow-init * Initializes GitFlow configuration for a repository. * Detects platform, provider, and branches. * Creates .claude/gitflow/config.json. * * Exit codes: 0 = OK, 1 = warnings, 2 = blockers * * Usage: * npx ts-node index.ts --spec '' [--workdir ] [--json] */ import { parseArgs } from 'node:util'; import { readFileSync, existsSync } from 'node:fs'; import { validate } from './validate.js'; import { execute } from './execute.js'; import type { InitResult } from './types.js'; const { values, positionals } = parseArgs({ options: { spec: { type: 'string' }, workdir: { type: 'string' }, help: { type: 'boolean', short: 'h' }, json: { type: 'boolean' }, }, allowPositionals: true, }); if (values.help) { console.log(` cli:gitflow-init — SmartStack Studio Initializes GitFlow configuration for a repository. Detects platform, provider, branches, and version. Creates .claude/gitflow/config.json. Usage: npx ts-node index.ts --spec '' [--workdir ] [--json] Options: --spec JSON string or path to a JSON file with init spec --workdir Working directory for git operations (defaults to cwd) --json Output result as JSON --help, -h Show this help `); process.exit(0); } // ── Validate args ───────────────────────────────────────── const specArg = values.spec; const workdir = values.workdir || process.cwd(); if (!specArg) { const result = { success: false, blockers: ['Missing required arg: --spec'], warnings: [] }; if (values.json) console.log(JSON.stringify(result, null, 2)); else console.error('[BLOCKER] Missing required arg: --spec'); process.exit(2); } // ── Parse spec (JSON string or file path) ────────────────── let rawSpec: unknown; try { if (existsSync(specArg)) { rawSpec = JSON.parse(readFileSync(specArg, 'utf-8')); } else { rawSpec = JSON.parse(specArg); } } catch (err) { const result = { success: false, blockers: [`Invalid JSON spec: ${(err as Error).message}`], warnings: [] }; if (values.json) console.log(JSON.stringify(result, null, 2)); else console.error(`[BLOCKER] Invalid JSON spec: ${(err as Error).message}`); process.exit(2); } // ── Validate ────────────────────────────────────────────── const validation = validate(rawSpec); if (!validation.valid || !validation.data) { const result = { success: false, blockers: validation.blockers, warnings: validation.warnings }; if (values.json) { console.log(JSON.stringify(result, null, 2)); } else { for (const b of validation.blockers) console.error(`[BLOCKER] ${b}`); for (const w of validation.warnings) console.warn(`[WARNING] ${w}`); } process.exit(2); } // Log warnings if (!values.json) { for (const w of validation.warnings) console.warn(`[WARNING] ${w}`); } // ── Execute ─────────────────────────────────────────────── let result: InitResult; try { result = await execute(validation.data, workdir); if (validation.warnings.length > 0) { result.validation = result.validation || { blockers: [], warnings: [] }; result.validation.warnings = [...(result.validation.warnings || []), ...validation.warnings]; } } catch (err) { const errResult = { success: false, blockers: [(err as Error).message], warnings: validation.warnings }; if (values.json) console.log(JSON.stringify(errResult, null, 2)); else console.error(`[BLOCKER] ${(err as Error).message}`); process.exit(2); } // ── Output ──────────────────────────────────────────────── if (values.json) { console.log(JSON.stringify(result, null, 2)); } else if (result.needsInput) { if (result.proposal) { console.log(`Proposed name: ${result.proposal.name} (root: ${result.proposal.root})`); if (result.proposal.exists) { console.log(`⚠ Target exists and is not empty — alternates: ${result.proposal.alternates.join(', ') || '(none free)'}`); } } else { console.log('GitFlow init requires a repository URL: gitflow init '); } } else if (result.success && result.structure) { console.log(`✓ GitFlow initialized at ${result.structure.root}`); console.log(` main: ${result.structure.main}`); console.log(` develop: ${result.structure.develop}`); console.log(` config: ${result.structure.configPath}`); } else if (!result.success) { console.error(`✗ ${result.error}`); } const hasBlockers = result.validation?.blockers?.length ?? 0 > 0; const hasWarnings = result.validation?.warnings?.length ?? 0 > 0; process.exit(hasBlockers ? 2 : hasWarnings ? 1 : 0);