UNPKG

@snapcommit/cli

Version:

Instant AI commits. Beautiful progress tracking. Never write commit messages again.

277 lines (276 loc) • 9.03 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.loadRepos = loadRepos; exports.getCurrentRepoPath = getCurrentRepoPath; exports.getRepoName = getRepoName; exports.saveCurrentRepo = saveCurrentRepo; exports.listRepos = listRepos; exports.switchToRepo = switchToRepo; exports.getRepoContext = getRepoContext; const child_process_1 = require("child_process"); const fs = __importStar(require("fs")); const path = __importStar(require("path")); const os = __importStar(require("os")); const chalk_1 = __importDefault(require("chalk")); const REPOS_CONFIG_PATH = path.join(os.homedir(), '.snapcommit', 'repos.json'); /** * Load saved repositories */ function loadRepos() { try { if (!fs.existsSync(REPOS_CONFIG_PATH)) { return []; } const data = fs.readFileSync(REPOS_CONFIG_PATH, 'utf-8'); return JSON.parse(data); } catch (error) { return []; } } /** * Save repositories */ function saveRepos(repos) { try { const dir = path.dirname(REPOS_CONFIG_PATH); if (!fs.existsSync(dir)) { fs.mkdirSync(dir, { recursive: true }); } fs.writeFileSync(REPOS_CONFIG_PATH, JSON.stringify(repos, null, 2)); } catch (error) { console.error(chalk_1.default.red('Failed to save repo config')); } } /** * Get current repository path */ function getCurrentRepoPath() { try { const repoPath = (0, child_process_1.execSync)('git rev-parse --show-toplevel', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'ignore'] }).trim(); return repoPath; } catch (error) { return null; } } /** * Get repository name from path */ function getRepoName(repoPath) { return path.basename(repoPath); } /** * Add current repository to saved repos */ function saveCurrentRepo() { const repoPath = getCurrentRepoPath(); if (!repoPath) { return; } const repos = loadRepos(); const name = getRepoName(repoPath); // Get current branch let branch; try { branch = (0, child_process_1.execSync)('git rev-parse --abbrev-ref HEAD', { encoding: 'utf-8', cwd: repoPath, stdio: ['pipe', 'pipe', 'ignore'] }).trim(); } catch (error) { branch = 'unknown'; } // Update or add repo const existingIndex = repos.findIndex(r => r.path === repoPath); if (existingIndex >= 0) { repos[existingIndex].lastUsed = Date.now(); repos[existingIndex].branch = branch; } else { repos.push({ name, path: repoPath, lastUsed: Date.now(), branch, }); } saveRepos(repos); } /** * List all saved repositories */ function listRepos() { const repos = loadRepos(); if (repos.length === 0) { console.log(chalk_1.default.gray('\n No saved repositories\n')); return; } // Sort by last used repos.sort((a, b) => b.lastUsed - a.lastUsed); console.log(chalk_1.default.bold('\nšŸ“ Saved Repositories:\n')); const currentPath = getCurrentRepoPath(); repos.forEach((repo, index) => { const isCurrent = repo.path === currentPath; const icon = isCurrent ? chalk_1.default.green('→') : ' '; const nameColor = isCurrent ? chalk_1.default.green.bold : chalk_1.default.cyan; console.log(` ${icon} ${nameColor(repo.name)}`); console.log(chalk_1.default.gray(` ${repo.path}`)); if (repo.branch) { console.log(chalk_1.default.gray(` Branch: ${repo.branch}`)); } console.log(''); }); } /** * Switch to a repository by name or index */ async function switchToRepo(nameOrIndex) { const repos = loadRepos(); if (repos.length === 0) { console.log(chalk_1.default.red('\nāŒ No saved repositories\n')); return false; } // Sort by last used repos.sort((a, b) => b.lastUsed - a.lastUsed); let targetRepo; if (typeof nameOrIndex === 'number') { targetRepo = repos[nameOrIndex]; } else { // Try to match by name (case-insensitive) const search = nameOrIndex.toLowerCase(); targetRepo = repos.find(r => r.name.toLowerCase().includes(search) || r.path.toLowerCase().includes(search)); } if (!targetRepo) { console.log(chalk_1.default.red(`\nāŒ Repository "${nameOrIndex}" not found\n`)); return false; } // Check if repo path still exists if (!fs.existsSync(targetRepo.path)) { console.log(chalk_1.default.red(`\nāŒ Repository path no longer exists: ${targetRepo.path}\n`)); console.log(chalk_1.default.yellow(' Removing from saved repos...\n')); // Remove from saved repos const filtered = repos.filter(r => r.path !== targetRepo.path); saveRepos(filtered); return false; } // Check if it's a git repo try { (0, child_process_1.execSync)('git rev-parse --git-dir', { cwd: targetRepo.path, stdio: ['pipe', 'pipe', 'ignore'] }); } catch (error) { console.log(chalk_1.default.red(`\nāŒ Not a valid git repository: ${targetRepo.path}\n`)); return false; } // Change to the directory try { process.chdir(targetRepo.path); // Update last used targetRepo.lastUsed = Date.now(); saveRepos(repos); // Get current branch let branch = 'unknown'; try { branch = (0, child_process_1.execSync)('git rev-parse --abbrev-ref HEAD', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'ignore'] }).trim(); } catch (error) { // Ignore } // Get status let statusLine = ''; try { const status = (0, child_process_1.execSync)('git status --short', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'ignore'] }).trim(); const changedFiles = status.split('\n').filter(line => line.trim()).length; if (changedFiles > 0) { statusLine = chalk_1.default.yellow(` | ${changedFiles} file${changedFiles > 1 ? 's' : ''} changed`); } else { statusLine = chalk_1.default.green(' | Clean'); } } catch (error) { // Ignore } console.log(chalk_1.default.green(`\nāœ… Switched to ${chalk_1.default.bold(targetRepo.name)}`)); console.log(chalk_1.default.gray(` Branch: ${branch}${statusLine}`)); console.log(chalk_1.default.gray(` Path: ${targetRepo.path}\n`)); return true; } catch (error) { console.log(chalk_1.default.red(`\nāŒ Failed to switch: ${error.message}\n`)); return false; } } /** * Get repo context for display */ function getRepoContext() { const repoPath = getCurrentRepoPath(); if (!repoPath) { return chalk_1.default.gray('(not in a git repo)'); } const name = getRepoName(repoPath); let branch = 'unknown'; try { branch = (0, child_process_1.execSync)('git rev-parse --abbrev-ref HEAD', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'ignore'] }).trim(); } catch (error) { // Ignore } return chalk_1.default.cyan(`${name}`) + chalk_1.default.gray(` (${branch})`); }