From 9946cc7f790189c12cee6a185c8429b39a1543fe Mon Sep 17 00:00:00 2001 From: satinath-nit Date: Fri, 16 Jan 2026 20:48:22 -0600 Subject: [PATCH] feat: add AGENTS.md generator wizard - Add interactive 4-step wizard for creating AGENTS.md files - Support package manager presets (npm, yarn, pnpm, bun, pip, poetry, cargo, go) - Include code style options and guidelines sections - Add preview, copy to clipboard, and download functionality --- components/GeneratorWizard.tsx | 556 +++++++++++++++++++++++++++++++++ pages/index.tsx | 3 +- 2 files changed, 558 insertions(+), 1 deletion(-) create mode 100644 components/GeneratorWizard.tsx diff --git a/components/GeneratorWizard.tsx b/components/GeneratorWizard.tsx new file mode 100644 index 0000000..bfee5b5 --- /dev/null +++ b/components/GeneratorWizard.tsx @@ -0,0 +1,556 @@ +import React, { useState } from "react"; +import Section from "@/components/Section"; +import CopyIcon from "./icons/CopyIcon"; + +interface WizardData { + projectName: string; + projectDescription: string; + packageManager: string; + installCommand: string; + devCommand: string; + buildCommand: string; + testCommand: string; + lintCommand: string; + codeStyle: string[]; + customCodeStyle: string; + testingInstructions: string; + prGuidelines: string; + securityNotes: string; + additionalNotes: string; +} + +const initialData: WizardData = { + projectName: "", + projectDescription: "", + packageManager: "npm", + installCommand: "", + devCommand: "", + buildCommand: "", + testCommand: "", + lintCommand: "", + codeStyle: [], + customCodeStyle: "", + testingInstructions: "", + prGuidelines: "", + securityNotes: "", + additionalNotes: "", +}; + +const packageManagerCommands: Record = { + npm: { install: "npm install", dev: "npm run dev", build: "npm run build", test: "npm test", lint: "npm run lint" }, + yarn: { install: "yarn install", dev: "yarn dev", build: "yarn build", test: "yarn test", lint: "yarn lint" }, + pnpm: { install: "pnpm install", dev: "pnpm dev", build: "pnpm build", test: "pnpm test", lint: "pnpm lint" }, + bun: { install: "bun install", dev: "bun dev", build: "bun run build", test: "bun test", lint: "bun lint" }, + pip: { install: "pip install -r requirements.txt", dev: "python main.py", build: "", test: "pytest", lint: "ruff check ." }, + poetry: { install: "poetry install", dev: "poetry run python main.py", build: "poetry build", test: "poetry run pytest", lint: "poetry run ruff check ." }, + cargo: { install: "cargo build", dev: "cargo run", build: "cargo build --release", test: "cargo test", lint: "cargo clippy" }, + go: { install: "go mod download", dev: "go run .", build: "go build", test: "go test ./...", lint: "golangci-lint run" }, + other: { install: "", dev: "", build: "", test: "", lint: "" }, +}; + +const codeStyleOptions = [ + { id: "typescript-strict", label: "TypeScript strict mode" }, + { id: "single-quotes", label: "Single quotes" }, + { id: "double-quotes", label: "Double quotes" }, + { id: "no-semicolons", label: "No semicolons" }, + { id: "semicolons", label: "Use semicolons" }, + { id: "functional", label: "Prefer functional patterns" }, + { id: "tabs", label: "Use tabs for indentation" }, + { id: "spaces-2", label: "Use 2 spaces for indentation" }, + { id: "spaces-4", label: "Use 4 spaces for indentation" }, +]; + +export default function GeneratorWizard() { + const [step, setStep] = useState(1); + const [data, setData] = useState(initialData); + const [copied, setCopied] = useState(false); + const [showPreview, setShowPreview] = useState(false); + + const totalSteps = 4; + + const updateData = (field: keyof WizardData, value: string | string[]) => { + setData((prev) => ({ ...prev, [field]: value })); + }; + + const handlePackageManagerChange = (pm: string) => { + updateData("packageManager", pm); + const commands = packageManagerCommands[pm]; + if (commands) { + updateData("installCommand", commands.install); + updateData("devCommand", commands.dev); + updateData("buildCommand", commands.build); + updateData("testCommand", commands.test); + updateData("lintCommand", commands.lint); + } + }; + + const toggleCodeStyle = (styleId: string) => { + const current = data.codeStyle; + if (current.includes(styleId)) { + updateData("codeStyle", current.filter((s) => s !== styleId)); + } else { + updateData("codeStyle", [...current, styleId]); + } + }; + + const generateMarkdown = (): string => { + const lines: string[] = []; + + lines.push("# AGENTS.md"); + lines.push(""); + + if (data.projectName || data.projectDescription) { + lines.push("## Project Overview"); + if (data.projectName) { + lines.push(`This is the ${data.projectName} project.`); + } + if (data.projectDescription) { + lines.push(data.projectDescription); + } + lines.push(""); + } + + const hasCommands = data.installCommand || data.devCommand || data.buildCommand || data.testCommand || data.lintCommand; + if (hasCommands) { + lines.push("## Setup Commands"); + if (data.installCommand) lines.push(`- Install dependencies: \`${data.installCommand}\``); + if (data.devCommand) lines.push(`- Start dev server: \`${data.devCommand}\``); + if (data.buildCommand) lines.push(`- Build project: \`${data.buildCommand}\``); + if (data.testCommand) lines.push(`- Run tests: \`${data.testCommand}\``); + if (data.lintCommand) lines.push(`- Run linter: \`${data.lintCommand}\``); + lines.push(""); + } + + const hasCodeStyle = data.codeStyle.length > 0 || data.customCodeStyle; + if (hasCodeStyle) { + lines.push("## Code Style"); + data.codeStyle.forEach((styleId) => { + const option = codeStyleOptions.find((o) => o.id === styleId); + if (option) { + lines.push(`- ${option.label}`); + } + }); + if (data.customCodeStyle) { + data.customCodeStyle.split("\n").forEach((line) => { + if (line.trim()) lines.push(`- ${line.trim()}`); + }); + } + lines.push(""); + } + + if (data.testingInstructions) { + lines.push("## Testing Instructions"); + data.testingInstructions.split("\n").forEach((line) => { + if (line.trim()) lines.push(`- ${line.trim()}`); + }); + lines.push(""); + } + + if (data.prGuidelines) { + lines.push("## PR Guidelines"); + data.prGuidelines.split("\n").forEach((line) => { + if (line.trim()) lines.push(`- ${line.trim()}`); + }); + lines.push(""); + } + + if (data.securityNotes) { + lines.push("## Security Considerations"); + data.securityNotes.split("\n").forEach((line) => { + if (line.trim()) lines.push(`- ${line.trim()}`); + }); + lines.push(""); + } + + if (data.additionalNotes) { + lines.push("## Additional Notes"); + lines.push(data.additionalNotes); + lines.push(""); + } + + return lines.join("\n"); + }; + + const copyToClipboard = async () => { + try { + await navigator.clipboard.writeText(generateMarkdown()); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + } catch (err) { + console.error("Failed to copy to clipboard:", err); + } + }; + + const downloadFile = () => { + const content = generateMarkdown(); + const blob = new Blob([content], { type: "text/markdown" }); + const url = URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = "AGENTS.md"; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); + }; + + const renderStep1 = () => ( +
+
+ + updateData("projectName", e.target.value)} + placeholder="e.g., My Awesome App" + className="w-full px-4 py-3 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 text-gray-900 dark:text-white focus:ring-2 focus:ring-black dark:focus:ring-white focus:border-transparent" + /> +
+
+ +