hackages
Version:
CLI tool for learning software development concepts through test-driven development
122 lines (121 loc) ⢠5.86 kB
JavaScript
import { reviewCode } from "../services/claude.service.js";
import { displayFeedback, getAllSourceFiles, saveFeedbackToMarkdown, saveFeedbackToTemplate, generateFeedbackHTML, openFeedbackHTML, getLearningInformation, createNextExercise, } from "../services/file-manager.js";
import { printError, printHeader, printSuccess } from "../utils/console.js";
import chalk from "chalk";
import prompts from "prompts";
/**
* Prompts user to select next learning step
* @param suggestions Array of learning suggestions
* @returns Selected option or custom learning goal
*/
async function promptNextLearningStep(suggestions) {
console.log("\n" + chalk.cyan("=".repeat(50)));
console.log(chalk.bold.yellow("š Continue Your Learning Journey"));
console.log(chalk.cyan("=".repeat(50)));
console.log(chalk.gray("Choose your next learning step:\n"));
let index = 0;
const choices = [
...suggestions.map((suggestion) => ({
title: `${++index}. ${suggestion.title}`,
description: suggestion.description,
value: suggestion.title + " - " + suggestion.description
})),
{ title: `${++index}. Write your next learning goal`, description: "Take control of your next learning challenge...", value: "custom" }
];
const response = await prompts({
type: "select",
name: "nextStep",
message: "Select your next learning step:",
choices,
initial: 0,
});
if (!response.nextStep) {
console.log(chalk.gray("\nš Happy learning! Come back when you're ready for more."));
return null;
}
if (response.nextStep === "custom") {
const customResponse = await prompts({
type: "text",
name: "customGoal",
message: "I would like to learn about:",
validate: (value) => value.length > 0 ? true : "Please enter a learning goal",
});
return customResponse.customGoal || null;
}
return response.nextStep;
}
export async function reviewCommand() {
try {
// Find all source files in the src directory
const sourceFiles = getAllSourceFiles();
if (sourceFiles == null || Object.keys(sourceFiles).length === 0) {
printError("ā No source files found. Please make sure you have files in the src/ directory");
return;
}
// Extract goal from file content
const learningInformation = getLearningInformation();
console.log("\n");
printHeader("Code Review");
// Display which files will be reviewed
console.log(chalk.cyan("š Files to be reviewed:"));
Object.keys(sourceFiles).forEach(filename => {
console.log(chalk.green(` ā ${filename}`));
});
// TODO: dynamic technology
const data = await reviewCode({
topic: learningInformation.topic,
sourceFiles: sourceFiles,
skillLevel: learningInformation.skillLevel,
technology: learningInformation.selectedTech,
});
// Display feedback in terminal
displayFeedback(data.feedback);
// Save feedback to template folder
const feedbackPath = saveFeedbackToTemplate(data.feedback, 1, learningInformation.selectedTech);
// Generate HTML page
const htmlPath = generateFeedbackHTML(data.feedback, 1);
// Also save to .hackages for backup
saveFeedbackToMarkdown(data.feedback, learningInformation.selectedTech, learningInformation.id);
console.log("\n");
printSuccess("š Code review completed!");
if (feedbackPath) {
console.log(chalk.blue(`š Feedback saved to: ${feedbackPath}`));
}
if (htmlPath) {
console.log(chalk.blue(`š HTML page generated: ${htmlPath}`));
console.log(chalk.gray("š” Opening feedback page in browser..."));
// Open HTML page in browser
openFeedbackHTML(htmlPath);
}
// Extract learning suggestions and prompt for next step
const nextLearningGoal = await promptNextLearningStep(data.nextLearningSteps);
if (nextLearningGoal) {
console.log("\n" + chalk.yellow("š Generating your next exercise..."));
// Create new learning goal for the next exercise
const nextGoal = {
...learningInformation,
id: learningInformation.id + "-next",
topic: nextLearningGoal,
};
// Generate next exercise
await createNextExercise(nextGoal, 2); // exercise-2
console.log("\n" + chalk.bold.green("š Your next exercise is ready!"));
console.log(chalk.cyan("=".repeat(50)));
console.log(chalk.bold("š Next exercise created:"));
console.log(chalk.green(` ā tests/exercise-2.spec.ts`), chalk.dim("(Your test cases)"));
console.log(chalk.green(` ā src/exercise-2.ts`), chalk.dim("(Your implementation file)"));
console.log(chalk.green(` ā instructions/exercise-2.mdx`), chalk.dim("(Exercise instructions)"));
console.log("\n" + chalk.bold.yellow("š Next steps:"));
console.log(chalk.white("1. Read the instructions and test file to understand what to implement"));
console.log(chalk.white("2. Open src/exercise-2.ts and start coding"));
console.log(chalk.white("3. Run 'npx hackages test' to validate your implementation"));
console.log(chalk.white("4. Run 'npx hackages review' to get AI feedback on your code"));
}
else {
console.log(chalk.gray("\nš Happy learning! Come back when you're ready for more."));
}
}
catch (error) {
printError(`ā Error during code review: ${error}`);
}
}