@@ -3,6 +3,7 @@ import fs from "fs-extra";
33import chalk from "chalk" ;
44import ora from "ora" ;
55import prompts from "prompts" ;
6+ import { distance } from "fastest-levenshtein" ;
67import { validateProjectName } from "./utils/validation.js" ;
78import { PackageInstaller } from "./installers/package-installer.js" ;
89import { TemplateManager } from "./utils/template-manager.js" ;
@@ -12,6 +13,7 @@ import { GitUtils } from "./utils/git-utils.js";
1213import { GitCloner } from "./utils/git-cloner.js" ;
1314import { RequirementChecker } from "./utils/requirement-checker.js" ;
1415import { SetupGuide } from "./utils/setup-guide.js" ;
16+ import { debug , enableDebug } from "./utils/debug.js" ;
1517import {
1618 detectPackageManager ,
1719 getPackageManagerInfo ,
@@ -34,14 +36,46 @@ export interface CreateAppOptions {
3436 verbose ?: boolean ;
3537}
3638
39+ /**
40+ * Find the closest matching template name for typo suggestions
41+ */
42+ function findSimilarTemplate ( input : string ) : string | null {
43+ const templates = getAllTemplates ( )
44+ . filter ( ( t ) => t . available )
45+ . map ( ( t ) => t . name ) ;
46+
47+ let closest = templates [ 0 ] ;
48+ let minDistance = distance ( input . toLowerCase ( ) , closest . toLowerCase ( ) ) ;
49+
50+ for ( const template of templates ) {
51+ const d = distance ( input . toLowerCase ( ) , template . toLowerCase ( ) ) ;
52+ if ( d < minDistance ) {
53+ minDistance = d ;
54+ closest = template ;
55+ }
56+ }
57+
58+ // Only suggest if it's close enough (threshold: 3 characters difference)
59+ return minDistance <= 3 ? closest : null ;
60+ }
61+
3762export async function createApp (
3863 projectDirectory : string | undefined ,
3964 options : CreateAppOptions
4065) : Promise < void > {
66+ // Enable debug mode if verbose flag is set
67+ if ( options . verbose ) {
68+ enableDebug ( ) ;
69+ debug ( "Debug mode enabled" ) ;
70+ debug ( "Options:" , options ) ;
71+ }
72+
4173 let projectName = projectDirectory ;
4274 let selectedTemplate = options . template || "hello-world" ;
4375 let packageManager : PackageManager ;
4476
77+ debug ( "Starting project creation" , { projectName, selectedTemplate } ) ;
78+
4579 // Interactive mode if no project name provided
4680 if ( ! projectName ) {
4781 const response = await prompts ( {
@@ -96,7 +130,7 @@ export async function createApp(
96130 const template = getTemplate ( selectedTemplate ) ;
97131 if ( template && template . comingSoon ) {
98132 console . error (
99- chalk . red ( `✖ Template "${ selectedTemplate } " is coming soon!` )
133+ chalk . red ( `\n ✖ Template "${ selectedTemplate } " is coming soon!` )
100134 ) ;
101135 console . log ( chalk . yellow ( "\n📢 Available templates:" ) ) ;
102136 getAllTemplates ( )
@@ -105,31 +139,53 @@ export async function createApp(
105139 console . log ( ` • ${ chalk . cyan ( t . name ) } - ${ t . description } ` ) ;
106140 } ) ;
107141 } else {
108- console . error ( chalk . red ( `✖ Template "${ selectedTemplate } " not found.` ) ) ;
142+ console . error ( chalk . red ( `\n✖ Template "${ selectedTemplate } " not found.` ) ) ;
143+
144+ // Suggest similar template if typo detected
145+ const suggestion = findSimilarTemplate ( selectedTemplate ) ;
146+ if ( suggestion ) {
147+ console . log (
148+ chalk . yellow ( `\n💡 Did you mean "${ chalk . cyan ( suggestion ) } "?` )
149+ ) ;
150+ }
151+
152+ console . log ( chalk . gray ( "\nAvailable templates:" ) ) ;
153+ getAllTemplates ( )
154+ . filter ( ( t ) => t . available )
155+ . forEach ( ( t ) => {
156+ console . log ( ` • ${ chalk . cyan ( t . name ) } - ${ t . description } ` ) ;
157+ } ) ;
109158 }
110159 process . exit ( 1 ) ;
111160 }
112161
113162 // Detect or select package manager
114163 if ( options . useNpm ) {
115164 packageManager = "npm" ;
165+ debug ( "Package manager set to npm via --use-npm flag" ) ;
116166 } else if ( options . useYarn ) {
117167 packageManager = "yarn" ;
168+ debug ( "Package manager set to yarn via --use-yarn flag" ) ;
118169 } else if ( options . usePnpm ) {
119170 packageManager = "pnpm" ;
171+ debug ( "Package manager set to pnpm via --use-pnpm flag" ) ;
120172 } else if ( options . useBun ) {
121173 packageManager = "bun" ;
174+ debug ( "Package manager set to bun via --use-bun flag" ) ;
122175 } else {
123176 packageManager = detectPackageManager ( ) ;
177+ debug ( "Auto-detected package manager:" , packageManager ) ;
124178 console . log (
125179 chalk . bold ( "[" + chalk . blue ( "i" ) + "] " ) +
126180 chalk . gray ( `package manager: ${ chalk . cyan ( packageManager ) } \n` )
127181 ) ;
128182 }
129183
130184 const pmInfo = getPackageManagerInfo ( packageManager ) ;
185+ debug ( "Package manager info:" , pmInfo ) ;
131186
132187 const validation = validateProjectName ( projectName ! ) ;
188+ debug ( "Project name validation:" , validation ) ;
133189 if ( ! validation . valid ) {
134190 console . error (
135191 chalk . red ( `✖ Invalid project name: ${ validation . problems ! [ 0 ] } ` )
@@ -138,9 +194,11 @@ export async function createApp(
138194 }
139195
140196 const projectPath = path . resolve ( projectName ! ) ;
197+ debug ( "Project path resolved:" , projectPath ) ;
141198
142199 // Check if directory exists
143200 if ( fs . existsSync ( projectPath ) ) {
201+ debug ( "Directory already exists, prompting for overwrite" ) ;
144202 const { overwrite } = await prompts ( {
145203 type : "confirm" ,
146204 name : "overwrite" ,
0 commit comments