@@ -14,6 +14,7 @@ import (
1414 "github.com/charmbracelet/huh"
1515 "github.com/databricks/cli/cmd/root"
1616 "github.com/databricks/cli/libs/apps/features"
17+ "github.com/databricks/cli/libs/apps/initializer"
1718 "github.com/databricks/cli/libs/apps/prompt"
1819 "github.com/databricks/cli/libs/cmdctx"
1920 "github.com/databricks/cli/libs/cmdio"
@@ -80,15 +81,19 @@ Environment variables:
8081 RunE : func (cmd * cobra.Command , args []string ) error {
8182 ctx := cmd .Context ()
8283 return runCreate (ctx , createOptions {
83- templatePath : templatePath ,
84- branch : branch ,
85- name : name ,
86- warehouseID : warehouseID ,
87- description : description ,
88- outputDir : outputDir ,
89- features : featuresFlag ,
90- deploy : deploy ,
91- run : run ,
84+ templatePath : templatePath ,
85+ branch : branch ,
86+ name : name ,
87+ nameProvided : cmd .Flags ().Changed ("name" ),
88+ warehouseID : warehouseID ,
89+ description : description ,
90+ outputDir : outputDir ,
91+ features : featuresFlag ,
92+ deploy : deploy ,
93+ deployChanged : cmd .Flags ().Changed ("deploy" ),
94+ run : run ,
95+ runChanged : cmd .Flags ().Changed ("run" ),
96+ featuresChanged : cmd .Flags ().Changed ("features" ),
9297 })
9398 },
9499 }
@@ -107,15 +112,19 @@ Environment variables:
107112}
108113
109114type createOptions struct {
110- templatePath string
111- branch string
112- name string
113- warehouseID string
114- description string
115- outputDir string
116- features []string
117- deploy bool
118- run string
115+ templatePath string
116+ branch string
117+ name string
118+ nameProvided bool // true if --name flag was explicitly set (enables "flags mode")
119+ warehouseID string
120+ description string
121+ outputDir string
122+ features []string
123+ deploy bool
124+ deployChanged bool // true if --deploy flag was explicitly set
125+ run string
126+ runChanged bool // true if --run flag was explicitly set
127+ featuresChanged bool // true if --features flag was explicitly set
119128}
120129
121130// templateVars holds the variables for template substitution.
@@ -170,7 +179,8 @@ func parseDeployAndRunFlags(deploy bool, run string) (bool, prompt.RunMode, erro
170179
171180// promptForFeaturesAndDeps prompts for features and their dependencies.
172181// Used when the template uses the feature-fragment system.
173- func promptForFeaturesAndDeps (ctx context.Context , preSelectedFeatures []string ) (* prompt.CreateProjectConfig , error ) {
182+ // skipDeployRunPrompt indicates whether to skip prompting for deploy/run (because flags were provided).
183+ func promptForFeaturesAndDeps (ctx context.Context , preSelectedFeatures []string , skipDeployRunPrompt bool ) (* prompt.CreateProjectConfig , error ) {
174184 config := & prompt.CreateProjectConfig {
175185 Dependencies : make (map [string ]string ),
176186 Features : preSelectedFeatures ,
@@ -260,10 +270,12 @@ func promptForFeaturesAndDeps(ctx context.Context, preSelectedFeatures []string)
260270 }
261271 prompt .PrintAnswered (ctx , "Description" , config .Description )
262272
263- // Step 4: Deploy and run options
264- config .Deploy , config .RunMode , err = prompt .PromptForDeployAndRun (ctx )
265- if err != nil {
266- return nil , err
273+ // Step 4: Deploy and run options (skip if any deploy/run flag was provided)
274+ if ! skipDeployRunPrompt {
275+ config .Deploy , config .RunMode , err = prompt .PromptForDeployAndRun (ctx )
276+ if err != nil {
277+ return nil , err
278+ }
267279 }
268280
269281 return config , nil
@@ -474,11 +486,17 @@ func runCreate(ctx context.Context, opts createOptions) error {
474486 // Step 3: Determine template type and gather configuration
475487 usesFeatureFragments := features .HasFeaturesDirectory (templateDir )
476488
489+ // When --name is provided, user is in "flags mode" - use defaults instead of prompting
490+ flagsMode := opts .nameProvided
491+
477492 if usesFeatureFragments {
478493 // Feature-fragment template: prompt for features and their dependencies
479- if isInteractive && len (selectedFeatures ) == 0 {
480- // Need to prompt for features (but we already have the name)
481- config , err := promptForFeaturesAndDeps (ctx , selectedFeatures )
494+ // Skip deploy/run prompts if in flags mode or if deploy/run flags were explicitly set
495+ skipDeployRunPrompt := flagsMode || opts .deployChanged || opts .runChanged
496+
497+ if isInteractive && ! opts .featuresChanged && ! flagsMode {
498+ // Interactive mode without --features flag: prompt for features, dependencies, description
499+ config , err := promptForFeaturesAndDeps (ctx , selectedFeatures , skipDeployRunPrompt )
482500 if err != nil {
483501 return err
484502 }
@@ -487,15 +505,41 @@ func runCreate(ctx context.Context, opts createOptions) error {
487505 if config .Description != "" {
488506 opts .description = config .Description
489507 }
490- shouldDeploy = config .Deploy
491- runMode = config .RunMode
508+ // Use prompted values for deploy/run (only set if we prompted)
509+ if ! skipDeployRunPrompt {
510+ shouldDeploy = config .Deploy
511+ runMode = config .RunMode
512+ }
492513
493514 // Get warehouse from dependencies if provided
494515 if wh , ok := dependencies ["sql_warehouse_id" ]; ok && wh != "" {
495516 opts .warehouseID = wh
496517 }
518+ } else if isInteractive && opts .featuresChanged && ! flagsMode {
519+ // Interactive mode with --features flag: validate features, prompt for deploy/run if no flags
520+ flagValues := map [string ]string {
521+ "warehouse-id" : opts .warehouseID ,
522+ }
523+ if len (selectedFeatures ) > 0 {
524+ if err := features .ValidateFeatureDependencies (selectedFeatures , flagValues ); err != nil {
525+ return err
526+ }
527+ }
528+ dependencies = make (map [string ]string )
529+ if opts .warehouseID != "" {
530+ dependencies ["sql_warehouse_id" ] = opts .warehouseID
531+ }
532+
533+ // Prompt for deploy/run if no flags were set
534+ if ! skipDeployRunPrompt {
535+ var err error
536+ shouldDeploy , runMode , err = prompt .PromptForDeployAndRun (ctx )
537+ if err != nil {
538+ return err
539+ }
540+ }
497541 } else {
498- // Non -interactive or features provided via flag
542+ // Flags mode or non -interactive: validate features and use flag values
499543 flagValues := map [string ]string {
500544 "warehouse-id" : opts .warehouseID ,
501545 }
@@ -508,6 +552,10 @@ func runCreate(ctx context.Context, opts createOptions) error {
508552 if opts .warehouseID != "" {
509553 dependencies ["sql_warehouse_id" ] = opts .warehouseID
510554 }
555+ }
556+
557+ // Apply flag values for deploy/run when in flags mode, flags were explicitly set, or non-interactive
558+ if skipDeployRunPrompt || ! isInteractive {
511559 var err error
512560 shouldDeploy , runMode , err = parseDeployAndRunFlags (opts .deploy , opts .run )
513561 if err != nil {
@@ -562,11 +610,13 @@ func runCreate(ctx context.Context, opts createOptions) error {
562610 }
563611 }
564612
565- // Prompt for description and post-creation actions
566- if isInteractive {
567- if opts .description == "" {
568- opts .description = prompt .DefaultAppDescription
569- }
613+ // Set default description if not provided
614+ if opts .description == "" {
615+ opts .description = prompt .DefaultAppDescription
616+ }
617+
618+ // Only prompt for deploy/run if not in flags mode and no deploy/run flags were set
619+ if isInteractive && ! flagsMode && ! opts .deployChanged && ! opts .runChanged {
570620 var deployVal bool
571621 var runVal prompt.RunMode
572622 deployVal , runVal , err = prompt .PromptForDeployAndRun (ctx )
@@ -576,6 +626,7 @@ func runCreate(ctx context.Context, opts createOptions) error {
576626 shouldDeploy = deployVal
577627 runMode = runVal
578628 } else {
629+ // Flags mode or explicit flags: use flag values (or defaults if not set)
579630 var err error
580631 shouldDeploy , runMode , err = parseDeployAndRunFlags (opts .deploy , opts .run )
581632 if err != nil {
@@ -659,21 +710,34 @@ func runCreate(ctx context.Context, opts createOptions) error {
659710 return runErr
660711 }
661712
662- // Run npm install
663- runErr = runNpmInstall (ctx , absOutputDir )
664- if runErr != nil {
665- return runErr
713+ // Initialize project based on type (Node.js, Python, etc.)
714+ var nextStepsCmd string
715+ projectInitializer := initializer .GetProjectInitializer (absOutputDir )
716+ if projectInitializer != nil {
717+ result := projectInitializer .Initialize (ctx , absOutputDir )
718+ if ! result .Success {
719+ if result .Error != nil {
720+ return fmt .Errorf ("%s: %w" , result .Message , result .Error )
721+ }
722+ return errors .New (result .Message )
723+ }
724+ nextStepsCmd = projectInitializer .NextSteps ()
666725 }
667726
668- // Run npm run setup
669- runErr = runNpmSetup (ctx , absOutputDir )
670- if runErr != nil {
671- return runErr
727+ // Validate dev-remote is only supported for appkit projects
728+ if runMode == prompt .RunModeDevRemote {
729+ if projectInitializer == nil || ! projectInitializer .SupportsDevRemote () {
730+ return errors .New ("--run=dev-remote is only supported for Node.js projects with @databricks/appkit" )
731+ }
672732 }
673733
674734 // Show next steps only if user didn't choose to deploy or run
675735 showNextSteps := ! shouldDeploy && runMode == prompt .RunModeNone
676- prompt .PrintSuccess (ctx , opts .name , absOutputDir , fileCount , showNextSteps )
736+ if showNextSteps {
737+ prompt .PrintSuccess (ctx , opts .name , absOutputDir , fileCount , nextStepsCmd )
738+ } else {
739+ prompt .PrintSuccess (ctx , opts .name , absOutputDir , fileCount , "" )
740+ }
677741
678742 // Execute post-creation actions (deploy and/or run)
679743 if shouldDeploy || runMode != prompt .RunModeNone {
@@ -694,7 +758,7 @@ func runCreate(ctx context.Context, opts createOptions) error {
694758
695759 if runMode != prompt .RunModeNone {
696760 cmdio .LogString (ctx , "" )
697- if err := runPostCreateDev (ctx , runMode ); err != nil {
761+ if err := runPostCreateDev (ctx , runMode , projectInitializer , absOutputDir ); err != nil {
698762 return err
699763 }
700764 }
@@ -716,15 +780,15 @@ func runPostCreateDeploy(ctx context.Context) error {
716780}
717781
718782// runPostCreateDev runs the dev or dev-remote command in the current directory.
719- func runPostCreateDev (ctx context.Context , mode prompt.RunMode ) error {
783+ func runPostCreateDev (ctx context.Context , mode prompt.RunMode , projectInit initializer. Initializer , workDir string ) error {
720784 switch mode {
721785 case prompt .RunModeDev :
722- cmdio . LogString ( ctx , "Starting development server (npm run dev)..." )
723- cmd := exec . CommandContext (ctx , "npm" , "run" , "dev" )
724- cmd . Stdout = os . Stdout
725- cmd . Stderr = os . Stderr
726- cmd . Stdin = os . Stdin
727- return cmd . Run ()
786+ if projectInit != nil {
787+ return projectInit . RunDev (ctx , workDir )
788+ }
789+ // Fallback for unknown project types
790+ cmdio . LogString ( ctx , "⚠ Unknown project type, cannot start development server automatically" )
791+ return nil
728792 case prompt .RunModeDevRemote :
729793 cmdio .LogString (ctx , "Starting remote development server..." )
730794 executable , err := os .Executable ()
@@ -741,39 +805,6 @@ func runPostCreateDev(ctx context.Context, mode prompt.RunMode) error {
741805 }
742806}
743807
744- // runNpmInstall runs npm install in the project directory.
745- func runNpmInstall (ctx context.Context , projectDir string ) error {
746- // Check if npm is available
747- if _ , err := exec .LookPath ("npm" ); err != nil {
748- cmdio .LogString (ctx , "⚠ npm not found. Please install Node.js and run 'npm install' manually." )
749- return nil
750- }
751-
752- return prompt .RunWithSpinnerCtx (ctx , "Installing dependencies..." , func () error {
753- cmd := exec .CommandContext (ctx , "npm" , "install" )
754- cmd .Dir = projectDir
755- cmd .Stdout = nil // Suppress output
756- cmd .Stderr = nil
757- return cmd .Run ()
758- })
759- }
760-
761- // runNpmSetup runs npx appkit-setup in the project directory.
762- func runNpmSetup (ctx context.Context , projectDir string ) error {
763- // Check if npx is available
764- if _ , err := exec .LookPath ("npx" ); err != nil {
765- return nil
766- }
767-
768- return prompt .RunWithSpinnerCtx (ctx , "Running setup..." , func () error {
769- cmd := exec .CommandContext (ctx , "npx" , "appkit-setup" , "--write" )
770- cmd .Dir = projectDir
771- cmd .Stdout = nil // Suppress output
772- cmd .Stderr = nil
773- return cmd .Run ()
774- })
775- }
776-
777808// renameFiles maps source file names to destination names (for files that can't use special chars).
778809var renameFiles = map [string ]string {
779810 "_gitignore" : ".gitignore" ,
0 commit comments