@codejoy/terminal-pet
Version:
A virtual pet that lives in your terminal and grows with your coding activity
354 lines (299 loc) ⢠10.6 kB
JavaScript
const { Command } = require('commander');
const inquirer = require('inquirer');
const figlet = require('figlet');
const chalk = require('chalk');
const Pet = require('../lib/Pet');
const PetDisplay = require('../lib/PetDisplay');
const GitIntegration = require('../lib/GitIntegration');
const program = new Command();
const git = new GitIntegration();
program
.name('pet')
.description('A virtual pet that lives in your terminal')
.version('1.0.0');
// Main status command
program
.command('status')
.description('View your pet\'s current status')
.action(async () => {
const pet = Pet.load();
if (!pet) {
console.log(PetDisplay.displayMessage('No pet found! Use "pet adopt" to get your first pet.', 'warning'));
return;
}
if (!pet.isAlive) {
console.log(PetDisplay.displayMessage('Your pet has died! š Use "pet adopt" to get a new one.', 'error'));
console.log(PetDisplay.displayPet(pet));
return;
}
console.log(PetDisplay.displayPet(pet));
// Show git integration status
const isGitRepo = await git.isGitRepository();
if (isGitRepo) {
const todaysCommits = await git.getTodaysCommits();
console.log(PetDisplay.displayMessage(`Today's commits: ${todaysCommits}`, 'info'));
} else {
console.log(PetDisplay.displayMessage('Not in a git repository. Your pet won\'t get commit bonuses!', 'warning'));
}
});
// Feed command
program
.command('feed')
.description('Feed your pet')
.action(() => {
const pet = Pet.load();
if (!pet) {
console.log(PetDisplay.displayMessage('No pet found! Use "pet adopt" to get your first pet.', 'warning'));
return;
}
if (!pet.isAlive) {
console.log(PetDisplay.displayMessage('Your pet is dead and cannot be fed. š', 'error'));
return;
}
const success = pet.feed();
if (success) {
console.log(PetDisplay.displayMessage(`${pet.name} enjoyed the meal! š`, 'success'));
pet.save();
console.log(PetDisplay.displayPet(pet));
} else {
console.log(PetDisplay.displayMessage('Something went wrong while feeding your pet.', 'error'));
}
});
// Play command
program
.command('play')
.description('Play with your pet')
.action(() => {
const pet = Pet.load();
if (!pet) {
console.log(PetDisplay.displayMessage('No pet found! Use "pet adopt" to get your first pet.', 'warning'));
return;
}
if (!pet.isAlive) {
console.log(PetDisplay.displayMessage('Your pet is dead and cannot play. š', 'error'));
return;
}
const success = pet.play();
if (success) {
console.log(PetDisplay.displayMessage(`${pet.name} had fun playing! š¾`, 'success'));
pet.save();
console.log(PetDisplay.displayPet(pet));
} else {
console.log(PetDisplay.displayMessage(`${pet.name} is too tired to play. Let them sleep first! š“`, 'warning'));
}
});
// Sleep command
program
.command('sleep')
.description('Let your pet sleep and recover energy')
.action(() => {
const pet = Pet.load();
if (!pet) {
console.log(PetDisplay.displayMessage('No pet found! Use "pet adopt" to get your first pet.', 'warning'));
return;
}
if (!pet.isAlive) {
console.log(PetDisplay.displayMessage('Your pet is dead and cannot sleep. š', 'error'));
return;
}
const success = pet.sleep();
if (success) {
console.log(PetDisplay.displayMessage(`${pet.name} had a refreshing nap! š“`, 'success'));
pet.save();
console.log(PetDisplay.displayPet(pet));
} else {
console.log(PetDisplay.displayMessage('Something went wrong while your pet was sleeping.', 'error'));
}
});
// Stats command
program
.command('stats')
.description('View detailed stats and achievements')
.action(async () => {
const pet = Pet.load();
if (!pet) {
console.log(PetDisplay.displayMessage('No pet found! Use "pet adopt" to get your first pet.', 'warning'));
return;
}
console.log(PetDisplay.displayStats(pet));
// Show git stats if available
const isGitRepo = await git.isGitRepository();
if (isGitRepo) {
const analysis = await git.analyzeCommitActivity();
if (analysis) {
console.log(chalk.bold.cyan('\nš Git Activity Analysis'));
console.log(chalk.gray('Recent Commits:'), chalk.green(analysis.totalCommits));
console.log(chalk.gray('Bug Fixes:'), chalk.red(analysis.bugFixes));
console.log(chalk.gray('Features:'), chalk.blue(analysis.features));
console.log(chalk.gray('Refactors:'), chalk.yellow(analysis.refactors));
console.log(chalk.gray('Avg Message Length:'), chalk.white(analysis.averageMessageLength));
}
}
});
// Adopt command
program
.command('adopt')
.description('Adopt a new pet (this will replace your current pet!)')
.action(async () => {
const existingPet = Pet.load();
if (existingPet && existingPet.isAlive) {
const { confirm } = await inquirer.prompt([
{
type: 'confirm',
name: 'confirm',
message: `This will replace your current pet "${existingPet.name}". Are you sure?`,
default: false
}
]);
if (!confirm) {
console.log(PetDisplay.displayMessage('Adoption cancelled.', 'info'));
return;
}
}
// Show adoption center
const petTypes = ['cat', 'dog', 'dragon'];
console.log(PetDisplay.displayAdoption(petTypes));
const { petType } = await inquirer.prompt([
{
type: 'list',
name: 'petType',
message: 'Choose your pet type:',
choices: petTypes.map((type, index) => ({
name: `${type.charAt(0).toUpperCase() + type.slice(1)}`,
value: type
}))
}
]);
const { petName } = await inquirer.prompt([
{
type: 'input',
name: 'petName',
message: 'What would you like to name your pet?',
default: 'CodeBuddy',
validate: (input) => {
if (input.trim().length === 0) {
return 'Pet name cannot be empty!';
}
if (input.length > 20) {
return 'Pet name must be 20 characters or less!';
}
return true;
}
}
]);
// Create new pet
Pet.reset();
const newPet = new Pet(petName.trim(), petType);
newPet.save();
console.log(figlet.textSync('Welcome!', { horizontalLayout: 'full' }));
console.log(PetDisplay.displayMessage(`š Congratulations! You've adopted ${petName}!`, 'success'));
console.log(PetDisplay.displayPet(newPet));
// Offer to set up git hooks
const isGitRepo = await git.isGitRepository();
if (isGitRepo) {
const { setupHooks } = await inquirer.prompt([
{
type: 'confirm',
name: 'setupHooks',
message: 'Would you like to set up git hooks so your pet gets fed automatically on commits?',
default: true
}
]);
if (setupHooks) {
const success = await git.setupGitHooks(newPet);
if (success) {
console.log(PetDisplay.displayMessage('Git hooks set up successfully! Your pet will now get rewards for commits! š£', 'success'));
} else {
console.log(PetDisplay.displayMessage('Failed to set up git hooks. You can still feed your pet manually!', 'warning'));
}
}
}
console.log(PetDisplay.displayMessage('Use "pet help" to see all available commands!', 'info'));
});
// Hidden commit command (called by git hooks)
program
.command('commit')
.argument('[message]', 'commit message')
.description('Handle commit event (internal use)')
.action((message = '') => {
const pet = Pet.load();
if (!pet || !pet.isAlive) {
return;
}
const leveledUp = pet.checkLevelUp();
pet.onCommit(message);
const newAchievements = pet.checkAchievements('commit');
pet.save();
// Show notifications
if (leveledUp) {
console.log(PetDisplay.displayLevelUp(pet));
}
if (newAchievements.length > 0) {
console.log(PetDisplay.displayNewAchievements(newAchievements));
}
console.log(PetDisplay.displayMessage(`${pet.name} is happy about your commit! (+${10 + Math.min(pet.streak * 2, 20)} XP)`, 'success'));
});
// Help command
program
.command('help')
.description('Show help information')
.action(() => {
console.log(PetDisplay.displayHelp());
});
// Git integration commands
program
.command('git-setup')
.description('Set up git hooks for automatic pet feeding')
.action(async () => {
const isGitRepo = await git.isGitRepository();
if (!isGitRepo) {
console.log(PetDisplay.displayMessage('Not in a git repository!', 'error'));
return;
}
const pet = Pet.load();
if (!pet) {
console.log(PetDisplay.displayMessage('No pet found! Use "pet adopt" first.', 'warning'));
return;
}
const success = await git.setupGitHooks(pet);
if (success) {
console.log(PetDisplay.displayMessage('Git hooks set up successfully! š£', 'success'));
} else {
console.log(PetDisplay.displayMessage('Failed to set up git hooks.', 'error'));
}
});
program
.command('git-remove')
.description('Remove git hooks')
.action(async () => {
const success = await git.removeGitHooks();
if (success) {
console.log(PetDisplay.displayMessage('Git hooks removed successfully.', 'success'));
} else {
console.log(PetDisplay.displayMessage('No terminal pet git hooks found.', 'info'));
}
});
// Default action when no command is provided
program.action(() => {
const pet = Pet.load();
if (!pet) {
console.log(figlet.textSync('Terminal Pet', { horizontalLayout: 'full' }));
console.log(PetDisplay.displayMessage('Welcome to Terminal Pet! š¾', 'info'));
console.log(PetDisplay.displayMessage('Use "pet adopt" to get your first pet!', 'info'));
return;
}
// Show status by default
program.commands.find(cmd => cmd.name() === 'status').action();
});
// Error handling
program.on('command:*', () => {
console.log(PetDisplay.displayMessage(`Unknown command: ${program.args.join(' ')}`, 'error'));
console.log(PetDisplay.displayMessage('Use "pet help" to see available commands.', 'info'));
});
// Parse command line arguments
program.parse();
// If no arguments provided, show default action
if (!process.argv.slice(2).length) {
program.action();
}