UNPKG

hackages

Version:

CLI tool for learning software development concepts through test-driven development

107 lines (106 loc) 3.56 kB
#!/usr/bin/env node import { Command } from "commander"; import dotenv from "dotenv"; import { generateCommand } from "./commands/generate.js"; import { testCommand } from "./commands/test.js"; import { reviewCommand } from "./commands/review.js"; import { interactiveCommand } from "./commands/interactive.js"; import { loginCommand, logoutCommand } from "./commands/login.js"; import { onboardingCommand } from "./commands/onboarding.js"; import { loadCommand } from "./commands/load.js"; import { hintCommand } from "./commands/hint.js"; import { checkIfLearningJSONIsEmpty, getCurrentUser } from "./services/auth.js"; // Load environment variables dotenv.config(); const program = new Command(); const currentUser = getCurrentUser(); const userStatus = currentUser ? `\nLogged in as: ${currentUser.name || currentUser.login}` : ""; program .name("hackages") .description("🎯 Learn software development concepts through test-driven development\n" + "Run 'hackages' to start your learning journey!" + userStatus) .version("0.4.0") .option("-l, --load <exercise-id>", "Load an exercise from the Hackages API"); // Test command - runs the tests for current exercise program .command("test") .description("Run tests for the current exercise") .action(async () => { await testCommand(); }); // Review command - gets feedback on implementation program .command("review") .description("Get AI-powered code review and feedback") .action(async () => { await reviewCommand(); }); // Continue command - interactive mode for existing exercises program .command("continue") .description("Continue working on existing exercise (interactive mode)") .action(async () => { await interactiveCommand(); }); // Login command - authenticate with GitHub program .command("login") .description("Login with your GitHub account") .action(async () => { await loginCommand(); }); // Logout command - clear authentication program .command("logout") .description("Logout from your account") .action(async () => { await logoutCommand(); }); // Load command - load an exercise from the API program .command("load") .description("Load an exercise from the Hackages API") .argument("<exercise-id>", "The exercise ID to load") .action(async (exerciseId) => { await loadCommand(exerciseId); }); // Hint command - watch for code changes and get real-time hints program .command("hint") .description("Watch your code and get real-time AI-powered hints") .action(async () => { await hintCommand(); }); // Handle -l or --load flag before any command runs program.hook('preAction', async (thisCommand, actionCommand) => { const opts = thisCommand.opts(); if (opts.load) { await loadCommand(opts.load); process.exit(0); } }); // Default behavior - start learning journey program.action(async () => { // check if there is a learning.json file in the .hackages directory at HOME directory if (checkIfLearningJSONIsEmpty()) { await onboardingCommand(); } else { // Existing user - use full flow with authentication const learningGoals = await generateCommand(); if (!learningGoals) { return; // Exit if no learning goals were collected } await generateCommand(learningGoals); } }); // Handle legacy --continue flag for backward compatibility if (process.argv.includes("--continue")) { interactiveCommand(); } else { program.parse(); }