@@ -67,42 +67,55 @@ func versionCmd() *cobra.Command {
6767func newCmd () * cobra.Command {
6868 // New architecture/frontend flags
6969 var archFlag , frontendFlag , style string
70+ var inPlace , force bool
7071
7172 // Legacy flags (backward compatibility)
7273 var apiOnly , includeExpo , mobileOnly , full bool
7374
7475 cmd := & cobra.Command {
75- Use : "new <project-name>" ,
76+ Use : "new <project-name|. >" ,
7677 Short : "Create a new Grit project" ,
77- Long : "Scaffold a new Grit project. Interactive by default — select architecture and frontend.\n Use flags to skip prompts: grit new my-app --single --vite" ,
78+ Long : "Scaffold a new Grit project. Interactive by default — select architecture and frontend.\n Use flags to skip prompts: grit new my-app --single --vite\n Use `grit new .` to scaffold in the current directory. " ,
7879 Args : cobra .ExactArgs (1 ),
7980 RunE : func (cmd * cobra.Command , args []string ) error {
80- projectName := args [0 ]
81+ projectArg := strings .TrimSpace (args [0 ])
82+ projectName := projectArg
8183
82- // Support "grit new ." to scaffold into current directory
83- if projectName == "." {
84+ if filepath .Clean (projectArg ) == "." {
8485 cwd , err := os .Getwd ()
8586 if err != nil {
8687 return fmt .Errorf ("getting current directory: %w" , err )
8788 }
8889 projectName = filepath .Base (cwd )
89- } else {
90- if err := scaffold .ValidateProjectName (projectName ); err != nil {
91- return err
90+ inPlace = true
91+ }
92+
93+ if err := scaffold .ValidateProjectName (projectName ); err != nil {
94+ if filepath .Clean (projectArg ) == "." {
95+ return fmt .Errorf ("invalid current directory name %q for project generation: %w" , projectName , err )
9296 }
97+ return err
9398 }
9499
95100 opts := scaffold.Options {
96101 ProjectName : projectName ,
97- InPlace : args [0 ] == "." ,
98102 Style : style ,
103+ InPlace : inPlace ,
104+ Force : force ,
99105 // Legacy flags
100106 APIOnly : apiOnly ,
101107 IncludeExpo : includeExpo ,
102108 MobileOnly : mobileOnly ,
103109 Full : full ,
104110 }
105111
112+ if ! opts .InPlace {
113+ cwd , err := os .Getwd ()
114+ if err == nil && filepath .Base (cwd ) == projectName {
115+ opts .InPlace = true
116+ }
117+ }
118+
106119 // Map architecture shorthand flags
107120 switch archFlag {
108121 case "single" :
@@ -133,16 +146,23 @@ func newCmd() *cobra.Command {
133146 return fmt .Errorf ("invalid frontend %q: must be next, vite, or tanstack" , frontendFlag )
134147 }
135148
136- // Apply legacy flag mappings
137- opts .Normalize ()
138-
139- // Only show interactive prompt if NO explicit flags were set
140- anyFlagSet := archFlag != "" || frontendFlag != "" ||
141- apiOnly || mobileOnly || full || includeExpo
142-
143- if ! anyFlagSet {
149+ // Show interactive selector only when the user did not provide any
150+ // architecture/frontend shortcuts or explicit long-form flags.
151+ anyScaffoldSelection := cmd .Flags ().Changed ("arch" ) ||
152+ cmd .Flags ().Changed ("frontend" ) ||
153+ cmd .Flags ().Changed ("single" ) ||
154+ cmd .Flags ().Changed ("double" ) ||
155+ cmd .Flags ().Changed ("triple" ) ||
156+ cmd .Flags ().Changed ("vite" ) ||
157+ cmd .Flags ().Changed ("next" ) ||
158+ cmd .Flags ().Changed ("api" ) ||
159+ cmd .Flags ().Changed ("mobile" ) ||
160+ cmd .Flags ().Changed ("expo" ) ||
161+ cmd .Flags ().Changed ("full" )
162+
163+ if ! anyScaffoldSelection {
144164 printLogo ()
145- // Reset to empty so prompt shows
165+ // Keep empty values so the prompt can collect architecture/frontend.
146166 opts .Architecture = ""
147167 opts .Frontend = ""
148168 if err := prompt .RunNewProjectPrompt (& opts ); err != nil {
@@ -215,14 +235,16 @@ func newCmd() *cobra.Command {
215235 cmd .Flags ().Bool ("single" , false , "Shorthand for --arch=single" )
216236 cmd .Flags ().Bool ("double" , false , "Shorthand for --arch=double" )
217237 cmd .Flags ().Bool ("triple" , false , "Shorthand for --arch=triple" )
238+ cmd .Flags ().BoolVar (& inPlace , "here" , false , "Scaffold into the current directory instead of creating a new folder" )
239+ cmd .Flags ().BoolVar (& force , "force" , false , "Allow scaffolding into a non-empty directory (use with --here)" )
218240
219241 return cmd
220242}
221243
222244func generateCmd () * cobra.Command {
223245 cmd := & cobra.Command {
224- Use : "generate" ,
225- Short : "Generate code for your Grit project" ,
246+ Use : "generate" ,
247+ Short : "Generate code for your Grit project" ,
226248 Aliases : []string {"g" },
227249 }
228250
@@ -233,8 +255,8 @@ func generateCmd() *cobra.Command {
233255
234256func removeCmd () * cobra.Command {
235257 cmd := & cobra.Command {
236- Use : "remove" ,
237- Short : "Remove components from your Grit project" ,
258+ Use : "remove" ,
259+ Short : "Remove components from your Grit project" ,
238260 Aliases : []string {"rm" },
239261 }
240262
@@ -741,7 +763,9 @@ func printSuccess(name string, opts scaffold.Options) {
741763
742764 white .Println (" Next steps:" )
743765 fmt .Println ()
744- cyan .Printf (" cd %s\n " , name )
766+ if ! opts .InPlace {
767+ cyan .Printf (" cd %s\n " , name )
768+ }
745769 cyan .Println (" docker compose up -d" )
746770
747771 switch opts .Architecture {
@@ -1010,4 +1034,4 @@ func deployCmd() *cobra.Command {
10101034 cmd .Flags ().StringVar (& appPort , "app-port" , "8080" , "Port the app runs on" )
10111035
10121036 return cmd
1013- }
1037+ }
0 commit comments