Add git commit automation, update assets and config
- Add git-commit.js script and README instructions - Add .env.example for OpenRouter API key - Update .gitignore to ignore utils/.env - Add commit command to package.json scripts - Delete obsolete placeholder images (avif/jpeg) - Switch BaseHead.astro and Hero.astro to use avif images - Update imports to reflect new image formats
1
.gitignore
vendored
@ -16,6 +16,7 @@ pnpm-debug.log*
|
||||
# environment variables
|
||||
.env
|
||||
.env.production
|
||||
src/utils/.env
|
||||
|
||||
# macOS-specific files
|
||||
.DS_Store
|
||||
|
||||
@ -12,7 +12,8 @@
|
||||
"convert:avif": "node src/utils/convert-to-avif.js",
|
||||
"convert:avif:all": "node src/utils/convert-to-avif.js --all",
|
||||
"convert:avif:jpeg": "node src/utils/convert-to-avif.js --jpeg",
|
||||
"convert:avif:png": "node src/utils/convert-to-avif.js --png"
|
||||
"convert:avif:png": "node src/utils/convert-to-avif.js --png",
|
||||
"commit": "node src/utils/git-commit.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/cloudflare": "^12.6.12",
|
||||
|
||||
|
Before Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 7.7 KiB |
|
Before Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 1.6 MiB |
|
Before Width: | Height: | Size: 907 KiB |
|
Before Width: | Height: | Size: 163 KiB |
|
Before Width: | Height: | Size: 3.3 MiB |
|
Before Width: | Height: | Size: 199 KiB |
@ -3,7 +3,7 @@
|
||||
// all pages through the use of the <BaseHead /> component.
|
||||
import '../styles/global.css';
|
||||
import type { ImageMetadata } from 'astro';
|
||||
import DefaultOGImage from '../assets/nicholai-medium-portrait.jpg';
|
||||
import DefaultOGImage from '../assets/nicholai-medium-portrait.avif';
|
||||
import { SITE_TITLE, SITE_DESCRIPTION, SOCIAL_LINKS } from '../consts';
|
||||
|
||||
interface Props {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
---
|
||||
import { Picture } from 'astro:assets';
|
||||
import heroPortrait from '../../assets/nicholai-closeup-portrait.JPEG';
|
||||
import heroPortrait from '../../assets/nicholai-closeup-portrait.avif';
|
||||
|
||||
interface Props {
|
||||
headlineLine1: string;
|
||||
|
||||
4
src/utils/.env.example
Normal file
@ -0,0 +1,4 @@
|
||||
# OpenRouter API Configuration
|
||||
# Get your API key from: https://openrouter.ai/keys
|
||||
|
||||
OPENROUTER_API_KEY=your_api_key_here
|
||||
@ -2,6 +2,93 @@
|
||||
|
||||
This directory contains utility scripts for the project.
|
||||
|
||||
## Git Commit Automation Script
|
||||
|
||||
### git-commit.js
|
||||
|
||||
Automatically generates commit messages using OpenRouter AI (inception/mercury-coder) based on your staged changes. The script analyzes both the git diff and status to create meaningful commit messages, then allows you to review, edit, and approve before committing.
|
||||
|
||||
**Prerequisites:**
|
||||
- OpenRouter API key (free to get started)
|
||||
- Sign up: [openrouter.ai](https://openrouter.ai)
|
||||
- Get your API key: [openrouter.ai/keys](https://openrouter.ai/keys)
|
||||
- Create a `.env` file in `src/utils/` directory:
|
||||
```bash
|
||||
# Copy the example file
|
||||
cp src/utils/.env.example src/utils/.env
|
||||
|
||||
# Edit the file and add your API key
|
||||
OPENROUTER_API_KEY=your_actual_api_key_here
|
||||
```
|
||||
|
||||
**Usage:**
|
||||
|
||||
```bash
|
||||
# 1. Stage your changes
|
||||
git add <files>
|
||||
|
||||
# 2. Run the commit script
|
||||
pnpm commit
|
||||
|
||||
# 3. Review the AI-generated message
|
||||
# 4. Choose to [A]ccept, [E]dit, or [C]ancel
|
||||
# 5. Optionally push to remote
|
||||
```
|
||||
|
||||
**Workflow:**
|
||||
1. **Staged Files Check** - Verifies you have changes staged
|
||||
2. **Context Gathering** - Collects git diff and status
|
||||
3. **AI Generation** - Calls OpenRouter API (inception/mercury-coder model) to generate commit message
|
||||
4. **Review & Edit** - Shows message and prompts for approval
|
||||
5. **Commit** - Creates the commit with approved message
|
||||
6. **Optional Push** - Asks if you want to push to remote
|
||||
|
||||
**Features:**
|
||||
- AI-powered commit message generation
|
||||
- Interactive approval process
|
||||
- Message editing capability
|
||||
- Optional automatic push
|
||||
- Follows project commit message conventions
|
||||
- Detailed error messages and help text
|
||||
|
||||
**Example session:**
|
||||
```
|
||||
🚀 Git Commit Automation
|
||||
|
||||
🔍 Gathering git context...
|
||||
🤖 Generating commit message with OpenRouter...
|
||||
|
||||
📝 Generated commit message:
|
||||
────────────────────────────────────────────────────────────
|
||||
Add git commit automation script with OpenRouter integration
|
||||
|
||||
- Create interactive commit message generator using inception/mercury-coder
|
||||
- Support message editing and approval workflow
|
||||
- Add optional push to remote after commit
|
||||
────────────────────────────────────────────────────────────
|
||||
|
||||
[A]ccept / [E]dit / [C]ancel? a
|
||||
|
||||
📦 Creating commit...
|
||||
✅ Commit created successfully!
|
||||
|
||||
Push to remote? [y/N] y
|
||||
🚀 Pushing to remote...
|
||||
✅ Pushed successfully!
|
||||
|
||||
✨ Done!
|
||||
```
|
||||
|
||||
**Options:**
|
||||
- `--help`, `-h` - Show help message
|
||||
|
||||
**Troubleshooting:**
|
||||
- If you get ".env file not found" error, create `src/utils/.env` with your OpenRouter API key
|
||||
- Get your API key from: https://openrouter.ai/keys
|
||||
- If you get "401 Unauthorized", check that your API key is correct in the `.env` file
|
||||
- The script requires staged changes - use `git add` first
|
||||
- Make sure `.env` is git-ignored (already configured in `.gitignore`)
|
||||
|
||||
## Image Conversion Script
|
||||
|
||||
### convert-to-avif.js
|
||||
|
||||
464
src/utils/git-commit.js
Normal file
@ -0,0 +1,464 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Git Commit Automation Script
|
||||
*
|
||||
* Automatically generates commit messages using OpenRouter AI (inception/mercury-coder)
|
||||
* based on staged changes. Supports message editing and optional pushing.
|
||||
*
|
||||
* Usage:
|
||||
* 1. Stage your changes: git add <files>
|
||||
* 2. Run: pnpm commit
|
||||
* 3. Review/edit the generated message
|
||||
* 4. Approve and optionally push
|
||||
*/
|
||||
|
||||
import { execSync, spawnSync } from 'child_process';
|
||||
import { createInterface } from 'readline';
|
||||
import { readFileSync, writeFileSync, unlinkSync } from 'fs';
|
||||
import { join, dirname } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { tmpdir } from 'os';
|
||||
|
||||
// Get current directory for ES modules
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
// Load environment variables from .env file
|
||||
function loadEnv() {
|
||||
try {
|
||||
const envPath = join(__dirname, '.env');
|
||||
const envContent = readFileSync(envPath, 'utf-8');
|
||||
const lines = envContent.split('\n');
|
||||
|
||||
for (const line of lines) {
|
||||
const trimmed = line.trim();
|
||||
if (!trimmed || trimmed.startsWith('#')) continue;
|
||||
|
||||
const [key, ...valueParts] = trimmed.split('=');
|
||||
const value = valueParts.join('=').trim();
|
||||
|
||||
if (key && value) {
|
||||
process.env[key.trim()] = value.replace(/^["']|["']$/g, '');
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`${colors.red}❌ Failed to load .env file${colors.reset}`);
|
||||
console.error(`${colors.yellow}💡 Create a .env file in src/utils/ with:${colors.reset}`);
|
||||
console.error(` ${colors.dim}OPENROUTER_API_KEY=your_api_key_here${colors.reset}\n`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Configuration
|
||||
const OPENROUTER_API_URL = 'https://openrouter.ai/api/v1';
|
||||
const MODEL_NAME = 'inception/mercury-coder';
|
||||
|
||||
// Color codes for terminal output
|
||||
const colors = {
|
||||
reset: '\x1b[0m',
|
||||
bright: '\x1b[1m',
|
||||
dim: '\x1b[2m',
|
||||
red: '\x1b[31m',
|
||||
green: '\x1b[32m',
|
||||
yellow: '\x1b[33m',
|
||||
blue: '\x1b[34m',
|
||||
cyan: '\x1b[36m',
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute a git command and return the output
|
||||
*/
|
||||
function git(command, silent = false) {
|
||||
try {
|
||||
return execSync(`git ${command}`, {
|
||||
encoding: 'utf-8',
|
||||
stdio: silent ? 'pipe' : ['pipe', 'pipe', 'pipe']
|
||||
}).trim();
|
||||
} catch (error) {
|
||||
if (!silent) {
|
||||
console.error(`${colors.red}❌ Git command failed: ${command}${colors.reset}`);
|
||||
console.error(error.message);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if there are staged changes
|
||||
*/
|
||||
function checkStagedChanges() {
|
||||
const stagedFiles = git('diff --staged --name-only', true);
|
||||
return stagedFiles && stagedFiles.length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get git context for AI commit message generation
|
||||
*/
|
||||
function getGitContext() {
|
||||
console.log(`${colors.cyan}🔍 Gathering git context...${colors.reset}`);
|
||||
|
||||
const status = git('status --short');
|
||||
const diff = git('diff --staged');
|
||||
const stagedFiles = git('diff --staged --name-only');
|
||||
|
||||
return {
|
||||
status,
|
||||
diff,
|
||||
stagedFiles
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Call OpenRouter API to generate commit message
|
||||
*/
|
||||
async function generateCommitMessage(context) {
|
||||
console.log(`${colors.cyan}🤖 Generating commit message with OpenRouter...${colors.reset}`);
|
||||
|
||||
const systemPrompt = `You are a helpful assistant that generates concise, clear git commit messages.
|
||||
|
||||
Generate commit messages following these guidelines:
|
||||
- Use imperative mood (e.g., "Add", "Fix", "Update", "Refactor")
|
||||
- Keep it concise but descriptive
|
||||
- First line should be a short summary (50-72 characters)
|
||||
- If needed, add a blank line and then bullet points for details
|
||||
- Focus on WHAT changed and WHY, not HOW
|
||||
|
||||
Generate ONLY the commit message, nothing else. Do not include any explanations or meta-commentary.`;
|
||||
|
||||
const userPrompt = `Based on the following git changes, generate a commit message:
|
||||
|
||||
Staged files:
|
||||
${context.stagedFiles}
|
||||
|
||||
Git status:
|
||||
${context.status}
|
||||
|
||||
Git diff:
|
||||
${context.diff.slice(0, 8000)}${context.diff.length > 8000 ? '\n... (diff truncated)' : ''}`;
|
||||
|
||||
try {
|
||||
const apiKey = process.env.OPENROUTER_API_KEY;
|
||||
|
||||
if (!apiKey) {
|
||||
throw new Error('OPENROUTER_API_KEY not found in environment variables');
|
||||
}
|
||||
|
||||
const response = await fetch(`${OPENROUTER_API_URL}/chat/completions`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${apiKey}`,
|
||||
'HTTP-Referer': 'https://github.com/yourusername/git-commit-automation',
|
||||
'X-Title': 'Git Commit Automation',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: MODEL_NAME,
|
||||
messages: [
|
||||
{ role: 'system', content: systemPrompt },
|
||||
{ role: 'user', content: userPrompt }
|
||||
],
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
throw new Error(`OpenRouter API error: ${response.status} ${response.statusText}\n${JSON.stringify(errorData, null, 2)}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!data.choices || !data.choices[0] || !data.choices[0].message) {
|
||||
throw new Error('Unexpected API response format');
|
||||
}
|
||||
|
||||
return data.choices[0].message.content.trim();
|
||||
} catch (error) {
|
||||
console.error(`${colors.red}❌ Failed to generate commit message${colors.reset}`);
|
||||
console.error(error.message);
|
||||
|
||||
// Check for common errors
|
||||
if (error.message.includes('OPENROUTER_API_KEY not found')) {
|
||||
console.log(`\n${colors.yellow}💡 Make sure you have a .env file in src/utils/ with:${colors.reset}`);
|
||||
console.log(` ${colors.dim}OPENROUTER_API_KEY=your_api_key_here${colors.reset}`);
|
||||
console.log(`\n${colors.yellow}💡 Get your API key from:${colors.reset}`);
|
||||
console.log(` ${colors.dim}https://openrouter.ai/keys${colors.reset}`);
|
||||
} else if (error.message.includes('ECONNREFUSED') || error.message.includes('fetch failed')) {
|
||||
console.log(`\n${colors.yellow}💡 Check your internet connection${colors.reset}`);
|
||||
} else if (error.message.includes('401')) {
|
||||
console.log(`\n${colors.yellow}💡 Invalid API key. Check your OPENROUTER_API_KEY in .env${colors.reset}`);
|
||||
}
|
||||
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create readline interface for user input
|
||||
*/
|
||||
function createReadlineInterface() {
|
||||
return createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Ask user a question and get input
|
||||
*/
|
||||
function question(rl, query) {
|
||||
return new Promise((resolve) => {
|
||||
rl.question(query, resolve);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Open neovim to edit the commit message
|
||||
*/
|
||||
function editInNeovim(message) {
|
||||
// Create a temporary file for editing
|
||||
const tempFile = join(tmpdir(), `git-commit-${Date.now()}.txt`);
|
||||
|
||||
try {
|
||||
// Write the current message to the temp file
|
||||
writeFileSync(tempFile, message, 'utf-8');
|
||||
|
||||
console.log(`\n${colors.cyan}✏️ Opening neovim to edit commit message...${colors.reset}`);
|
||||
|
||||
// Open neovim with the temp file
|
||||
const result = spawnSync('nvim', [tempFile], {
|
||||
stdio: 'inherit',
|
||||
shell: false
|
||||
});
|
||||
|
||||
if (result.error) {
|
||||
throw new Error(`Failed to open neovim: ${result.error.message}`);
|
||||
}
|
||||
|
||||
// Read the edited content
|
||||
const editedMessage = readFileSync(tempFile, 'utf-8').trim();
|
||||
|
||||
// Clean up temp file
|
||||
unlinkSync(tempFile);
|
||||
|
||||
return editedMessage;
|
||||
} catch (error) {
|
||||
// Clean up temp file if it exists
|
||||
try {
|
||||
unlinkSync(tempFile);
|
||||
} catch {}
|
||||
|
||||
console.error(`${colors.red}❌ Failed to edit in neovim${colors.reset}`);
|
||||
console.error(error.message);
|
||||
|
||||
if (error.message.includes('Failed to open neovim')) {
|
||||
console.log(`\n${colors.yellow}💡 Make sure neovim is installed:${colors.reset}`);
|
||||
console.log(` ${colors.dim}# Arch Linux${colors.reset}`);
|
||||
console.log(` ${colors.dim}sudo pacman -S neovim${colors.reset}`);
|
||||
}
|
||||
|
||||
// Return the original message if editing fails
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the commit message and get user approval
|
||||
*/
|
||||
async function getUserApproval(message, rl) {
|
||||
console.log(`\n${colors.bright}${colors.green}📝 Generated commit message:${colors.reset}`);
|
||||
console.log(`${colors.dim}${'─'.repeat(60)}${colors.reset}`);
|
||||
console.log(message);
|
||||
console.log(`${colors.dim}${'─'.repeat(60)}${colors.reset}\n`);
|
||||
|
||||
while (true) {
|
||||
const answer = await question(
|
||||
rl,
|
||||
`${colors.yellow}[A]ccept / [E]dit / [C]ancel?${colors.reset} `
|
||||
);
|
||||
|
||||
const choice = answer.trim().toLowerCase();
|
||||
|
||||
if (choice === 'a' || choice === 'accept') {
|
||||
return { approved: true, message };
|
||||
} else if (choice === 'e' || choice === 'edit') {
|
||||
// Close readline to give full control to neovim
|
||||
rl.pause();
|
||||
|
||||
// Open neovim for editing
|
||||
const editedMessage = editInNeovim(message);
|
||||
|
||||
// Resume readline
|
||||
rl.resume();
|
||||
|
||||
// Show the edited message and ask for approval again
|
||||
return getUserApproval(editedMessage, rl);
|
||||
} else if (choice === 'c' || choice === 'cancel') {
|
||||
return { approved: false, message: null };
|
||||
} else {
|
||||
console.log(`${colors.red}Invalid option. Please enter A, E, or C.${colors.reset}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the commit with the approved message
|
||||
*/
|
||||
function createCommit(message) {
|
||||
console.log(`\n${colors.cyan}📦 Creating commit...${colors.reset}`);
|
||||
|
||||
try {
|
||||
// Use a temporary file for the commit message to handle multi-line messages
|
||||
execSync(`git commit -F -`, {
|
||||
input: message,
|
||||
encoding: 'utf-8',
|
||||
stdio: ['pipe', 'inherit', 'inherit']
|
||||
});
|
||||
|
||||
console.log(`${colors.green}✅ Commit created successfully!${colors.reset}`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error(`${colors.red}❌ Failed to create commit${colors.reset}`);
|
||||
console.error(error.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ask if user wants to push to remote
|
||||
*/
|
||||
async function askToPush(rl) {
|
||||
const answer = await question(
|
||||
rl,
|
||||
`\n${colors.yellow}Push to remote? [y/N]${colors.reset} `
|
||||
);
|
||||
|
||||
return answer.trim().toLowerCase() === 'y' || answer.trim().toLowerCase() === 'yes';
|
||||
}
|
||||
|
||||
/**
|
||||
* Push to remote repository
|
||||
*/
|
||||
function pushToRemote() {
|
||||
console.log(`${colors.cyan}🚀 Pushing to remote...${colors.reset}`);
|
||||
|
||||
try {
|
||||
// Get current branch
|
||||
const branch = git('rev-parse --abbrev-ref HEAD');
|
||||
|
||||
execSync(`git push origin ${branch}`, {
|
||||
encoding: 'utf-8',
|
||||
stdio: 'inherit'
|
||||
});
|
||||
|
||||
console.log(`${colors.green}✅ Pushed successfully!${colors.reset}`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error(`${colors.red}❌ Failed to push${colors.reset}`);
|
||||
console.error(error.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show help message
|
||||
*/
|
||||
function showHelp() {
|
||||
console.log(`
|
||||
${colors.bright}Git Commit Automation Script${colors.reset}
|
||||
${colors.dim}Generates commit messages using OpenRouter AI${colors.reset}
|
||||
|
||||
${colors.bright}Usage:${colors.reset}
|
||||
1. Stage your changes:
|
||||
${colors.cyan}git add <files>${colors.reset}
|
||||
|
||||
2. Run this script:
|
||||
${colors.cyan}pnpm commit${colors.reset}
|
||||
|
||||
3. Review the AI-generated commit message
|
||||
|
||||
4. Choose to accept, edit, or cancel
|
||||
|
||||
5. Optionally push to remote
|
||||
|
||||
${colors.bright}Requirements:${colors.reset}
|
||||
- OpenRouter API key in .env file
|
||||
- Create ${colors.dim}src/utils/.env${colors.reset} with:
|
||||
${colors.dim}OPENROUTER_API_KEY=your_api_key_here${colors.reset}
|
||||
- Get your key from: ${colors.dim}https://openrouter.ai/keys${colors.reset}
|
||||
|
||||
${colors.bright}Options:${colors.reset}
|
||||
--help, -h Show this help message
|
||||
`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main function
|
||||
*/
|
||||
async function main() {
|
||||
// Check for help flag
|
||||
const args = process.argv.slice(2);
|
||||
if (args.includes('--help') || args.includes('-h')) {
|
||||
showHelp();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Load environment variables
|
||||
loadEnv();
|
||||
|
||||
console.log(`${colors.bright}${colors.blue}🚀 Git Commit Automation${colors.reset}\n`);
|
||||
|
||||
// Check if we're in a git repository
|
||||
if (!git('rev-parse --git-dir', true)) {
|
||||
console.error(`${colors.red}❌ Not a git repository${colors.reset}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Check for staged changes
|
||||
if (!checkStagedChanges()) {
|
||||
console.error(`${colors.red}❌ No staged changes found${colors.reset}`);
|
||||
console.log(`\n${colors.yellow}💡 Stage your changes first:${colors.reset}`);
|
||||
console.log(` ${colors.dim}git add <files>${colors.reset}\n`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Get git context
|
||||
const context = getGitContext();
|
||||
|
||||
// Generate commit message using OpenRouter
|
||||
const generatedMessage = await generateCommitMessage(context);
|
||||
|
||||
// Get user approval
|
||||
const rl = createReadlineInterface();
|
||||
const { approved, message } = await getUserApproval(generatedMessage, rl);
|
||||
|
||||
if (!approved) {
|
||||
console.log(`\n${colors.yellow}⏭️ Commit cancelled${colors.reset}`);
|
||||
rl.close();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Create the commit
|
||||
const commitSuccess = createCommit(message);
|
||||
|
||||
if (!commitSuccess) {
|
||||
rl.close();
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Ask to push
|
||||
const shouldPush = await askToPush(rl);
|
||||
rl.close();
|
||||
|
||||
if (shouldPush) {
|
||||
pushToRemote();
|
||||
}
|
||||
|
||||
console.log(`\n${colors.green}✨ Done!${colors.reset}\n`);
|
||||
}
|
||||
|
||||
// Run the script
|
||||
main().catch((error) => {
|
||||
console.error(`${colors.red}❌ Unexpected error:${colors.reset}`, error);
|
||||
process.exit(1);
|
||||
});
|
||||