@snapcommit/cli
Version:
Instant AI commits. Beautiful progress tracking. Never write commit messages again.
277 lines (276 loc) ⢠9.03 kB
JavaScript
;
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})`);
}