UNPKG

ai-coding-assistants-setup

Version:

Setup tool for integrating AI coding assistants into development workflows

171 lines (149 loc) 4.54 kB
import fs from 'fs-extra'; import path from 'path'; import chalk from 'chalk'; // Required scripts for CI/CD workflows const requiredScripts = { lint: 'echo "lint not configured yet"', typecheck: 'echo "typecheck not configured yet"', 'format:check': 'echo "format:check not configured yet"', build: 'echo "build not configured yet"', test: 'echo "test not configured yet"', 'test:unit': 'echo "test:unit not configured yet"', 'test:integration': 'echo "test:integration not configured yet"', 'test:e2e': 'echo "test:e2e not configured yet"', }; interface PackageJson { name?: string; version?: string; scripts?: Record<string, string>; [key: string]: any; } export interface ScriptUpdateResult { success: boolean; addedScripts: string[]; skippedScripts: string[]; error?: string; } /** * Updates package.json with required CI/CD scripts * Only adds missing scripts, preserves existing ones */ export async function updatePackageScripts( projectRoot: string ): Promise<ScriptUpdateResult> { const pkgPath = path.join(projectRoot, 'package.json'); try { // Check if package.json exists if (!(await fs.pathExists(pkgPath))) { console.log( chalk.yellow('⚠️ No package.json found, skipping script updates') ); return { success: false, addedScripts: [], skippedScripts: [], error: 'No package.json found', }; } // Read and parse package.json const pkgContent = await fs.readFile(pkgPath, 'utf8'); let pkg: PackageJson; try { pkg = JSON.parse(pkgContent); } catch (parseError) { console.error(chalk.red('❌ Failed to parse package.json')); return { success: false, addedScripts: [], skippedScripts: [], error: 'Invalid JSON in package.json', }; } // Initialize scripts object if it doesn't exist pkg.scripts = pkg.scripts || {}; // Track what we add and skip const addedScripts: string[] = []; const skippedScripts: string[] = []; // Add only missing scripts for (const [scriptName, scriptCommand] of Object.entries(requiredScripts)) { if (!pkg.scripts[scriptName]) { pkg.scripts[scriptName] = scriptCommand; addedScripts.push(scriptName); } else { skippedScripts.push(scriptName); } } // Only write back if we made changes if (addedScripts.length > 0) { // Preserve formatting style from original file const indent = detectIndent(pkgContent); const formatted = `${JSON.stringify(pkg, null, indent)}\n`; await fs.writeFile(pkgPath, formatted); console.log(chalk.green('✅ Updated package.json with missing scripts')); console.log(chalk.gray(` Added: ${addedScripts.join(', ')}`)); if (skippedScripts.length > 0) { console.log( chalk.gray(` Preserved existing: ${skippedScripts.join(', ')}`) ); } } else { console.log(chalk.gray('ℹ️ All required scripts already exist')); } return { success: true, addedScripts, skippedScripts, }; } catch (error) { console.error(chalk.red('❌ Failed to update package.json scripts')); console.error(error); return { success: false, addedScripts: [], skippedScripts: [], error: error instanceof Error ? error.message : 'Unknown error', }; } } /** * Detects the indentation used in a JSON string */ function detectIndent(jsonString: string): number { const lines = jsonString.split('\n'); for (const line of lines) { const match = line.match(/^(\s+)"/); if (match) { return match[1].length; } } return 2; // Default to 2 spaces } /** * Gets information about existing scripts in package.json */ export async function getExistingScripts( projectRoot: string ): Promise<Record<string, string> | null> { const pkgPath = path.join(projectRoot, 'package.json'); try { if (!(await fs.pathExists(pkgPath))) { return null; } const pkg: PackageJson = await fs.readJson(pkgPath); return pkg.scripts || {}; } catch { return null; } } /** * Checks if all required scripts exist in package.json */ export async function hasAllRequiredScripts( projectRoot: string ): Promise<boolean> { const existingScripts = await getExistingScripts(projectRoot); if (!existingScripts) return false; return Object.keys(requiredScripts).every( script => script in existingScripts ); }