@@ -14,6 +14,15 @@ const ElixirToolDetector = require("../../languages/elixir/tool-detector");
1414const PlatformDetector = require ( "../lib/platform-detector" ) ;
1515const { defaultErrorHandler } = require ( "../lib/error-handler" ) ;
1616
17+ // Import shared utilities
18+ const {
19+ ConfigUtils,
20+ FileUtils,
21+ ProjectUtils,
22+ LoggingUtils,
23+ ensureDir,
24+ } = require ( "../lib" ) ;
25+
1726class ElixirCommandRunner {
1827 constructor ( projectPath = process . cwd ( ) ) {
1928 this . projectPath = projectPath ;
@@ -29,42 +38,132 @@ class ElixirCommandRunner {
2938 * Initialize command runner with Elixir-specific setup
3039 */
3140 async initialize ( ) {
32- // Load configuration
33- this . config = this . configManager . loadConfig ( ) ;
34- if ( ! this . config ) {
35- throw new Error ( "Project not configured. Run /elixir-setup first." ) ;
36- }
41+ // First, validate that we're in an Elixir project using ProjectUtils
42+ try {
43+ const projectInfo = ProjectUtils . detectProjectType ( this . projectPath ) ;
3744
38- // Get Elixir configuration
39- this . elixirConfig = this . config . elixir ;
40- if ( ! this . elixirConfig ) {
41- throw new Error (
42- "Elixir configuration not found. Run /elixir-setup first." ,
43- ) ;
45+ if ( projectInfo . type !== "elixir" && projectInfo . confidence < 0.7 ) {
46+ LoggingUtils . warn (
47+ `Project detection: ${ projectInfo . type } (confidence: ${ projectInfo . confidence } )` ,
48+ ) ;
49+ LoggingUtils . warn (
50+ "This may not be an Elixir project. Some features may not work correctly." ,
51+ ) ;
52+ } else if ( projectInfo . type === "elixir" ) {
53+ LoggingUtils . debug (
54+ `Detected Elixir project: ${ projectInfo . framework || "standard Elixir" } ` ,
55+ ) ;
56+ }
57+
58+ // Log detected languages if available
59+ if ( projectInfo . languages && projectInfo . languages . length > 0 ) {
60+ LoggingUtils . debug (
61+ `Detected languages: ${ projectInfo . languages . join ( ", " ) } ` ,
62+ ) ;
63+ }
64+ } catch ( error ) {
65+ LoggingUtils . debug ( "Project detection failed:" , error . message ) ;
4466 }
4567
46- // Detect tools
47- this . detectedTools = await this . toolDetector . detectTools ( ) ;
68+ // Load configuration using ConfigUtils
69+ try {
70+ this . config = ConfigUtils . loadConfig ( this . projectPath ) ;
71+ if ( ! this . config ) {
72+ throw new Error ( "Project not configured. Run /elixir-setup first." ) ;
73+ }
74+
75+ // Get Elixir configuration
76+ this . elixirConfig = this . config . elixir ;
77+ if ( ! this . elixirConfig ) {
78+ throw new Error (
79+ "Elixir configuration not found. Run /elixir-setup first." ,
80+ ) ;
81+ }
82+
83+ // Validate Elixir configuration schema
84+ ConfigUtils . validateConfig ( this . elixirConfig , "elixir" ) ;
4885
49- return true ;
86+ // Detect tools
87+ this . detectedTools = await this . toolDetector . detectTools ( ) ;
88+
89+ return true ;
90+ } catch ( error ) {
91+ // Use LoggingUtils for better error display
92+ LoggingUtils . error (
93+ "Failed to initialize Elixir command runner:" ,
94+ error . message ,
95+ ) ;
96+ LoggingUtils . info ( "Run /elixir-setup to configure your Elixir project" ) ;
97+ throw error ;
98+ }
5099 }
51100
52101 /**
53102 * Check if a specific tool is available
54103 */
55104 hasTool ( toolName , required = true ) {
56- const toolInfo = this . elixirConfig . tools ?. [ toolName ] ;
105+ try {
106+ // Use ConfigUtils to check if tool is installed
107+ const isInstalled = ConfigUtils . checkToolInstalled (
108+ this . elixirConfig ,
109+ toolName ,
110+ required ,
111+ ) ;
57112
58- if ( ! toolInfo || ! toolInfo . installed ) {
59- if ( required ) {
113+ if ( ! isInstalled && required ) {
60114 throw new Error (
61115 `Required Elixir tool '${ toolName } ' is not installed. Run /elixir-setup to install it.` ,
62116 ) ;
63117 }
64- return false ;
118+
119+ return isInstalled ;
120+ } catch ( error ) {
121+ // Use LoggingUtils for better error display
122+ if ( required ) {
123+ LoggingUtils . error (
124+ `Elixir tool '${ toolName } ' check failed:` ,
125+ error . message ,
126+ ) ;
127+ LoggingUtils . info ( `Run /elixir-setup to install '${ toolName } '` ) ;
128+ }
129+ throw error ;
65130 }
131+ }
66132
67- return true ;
133+ /**
134+ * Find Elixir files in the project
135+ */
136+ findElixirFiles ( pattern = "**/*.{ex,exs}" , excludePatterns = [ ] ) {
137+ try {
138+ return FileUtils . findFilesByPattern ( this . projectPath , [ pattern ] , {
139+ exclude : excludePatterns ,
140+ language : "elixir" ,
141+ } ) ;
142+ } catch ( error ) {
143+ LoggingUtils . warn ( "Failed to find Elixir files:" , error . message ) ;
144+ return [ ] ;
145+ }
146+ }
147+
148+ /**
149+ * Get Elixir project metadata
150+ */
151+ getElixirProjectInfo ( ) {
152+ try {
153+ const info = {
154+ hasMixExs : fs . existsSync ( path . join ( this . projectPath , "mix.exs" ) ) ,
155+ hasMixLock : fs . existsSync ( path . join ( this . projectPath , "mix.lock" ) ) ,
156+ hasConfig : fs . existsSync ( path . join ( this . projectPath , "config" ) ) ,
157+ hasLib : fs . existsSync ( path . join ( this . projectPath , "lib" ) ) ,
158+ hasTest : fs . existsSync ( path . join ( this . projectPath , "test" ) ) ,
159+ elixirFiles : this . findElixirFiles ( ) . length ,
160+ } ;
161+
162+ return info ;
163+ } catch ( error ) {
164+ LoggingUtils . debug ( "Failed to get Elixir project info:" , error . message ) ;
165+ return null ;
166+ }
68167 }
69168
70169 /**
@@ -107,7 +206,7 @@ class ElixirCommandRunner {
107206 : defaultOptions . env ,
108207 } ;
109208
110- console . log ( `🚀 Executing: mix ${ command } ${ args . join ( " " ) } ` ) ;
209+ LoggingUtils . info ( `🚀 Executing: mix ${ command } ${ args . join ( " " ) } ` ) ;
111210
112211 return await new Promise ( ( resolve , reject ) => {
113212 const { exec } = require ( "child_process" ) ;
@@ -124,13 +223,15 @@ class ElixirCommandRunner {
124223 } ) ;
125224
126225 const cmd = `${ mixPath } ${ command } ${ args . join ( " " ) } ` ;
127- console . log ( `🔍 Executing: ${ cmd } ` ) ;
128- console . log ( `🔍 CWD: ${ finalOptions . cwd } ` ) ;
129- console . log ( `🔍 Platform: ${ this . platformDetector . getPlatformName ( ) } ` ) ;
226+ LoggingUtils . debug ( `🔍 Executing: ${ cmd } ` ) ;
227+ LoggingUtils . debug ( `🔍 CWD: ${ finalOptions . cwd } ` ) ;
228+ LoggingUtils . debug (
229+ `🔍 Platform: ${ this . platformDetector . getPlatformName ( ) } ` ,
230+ ) ;
130231
131232 exec ( cmd , finalOptions , ( error , stdout , stderr ) => {
132233 if ( error ) {
133- console . log ( `🔍 Exec error: ${ error . message } ` ) ;
234+ LoggingUtils . debug ( `🔍 Exec error: ${ error . message } ` ) ;
134235 reject (
135236 new Error ( `Failed to execute mix ${ command } : ${ error . message } ` ) ,
136237 ) ;
@@ -156,12 +257,16 @@ class ElixirCommandRunner {
156257
157258 const errorInfo = defaultErrorHandler . handleError ( error , context ) ;
158259
159- // Log user-friendly error message
160- console . error ( "\n" + errorInfo . userMessage ) ;
161- console . error ( "\n💡 Recovery steps:" ) ;
162- errorInfo . recoverySteps . forEach ( ( step , i ) => {
163- console . error ( ` ${ i + 1 } . ${ step } ` ) ;
164- } ) ;
260+ // Log user-friendly error message using LoggingUtils
261+ LoggingUtils . error ( errorInfo . userMessage ) ;
262+
263+ // Log recovery steps using LoggingUtils
264+ if ( errorInfo . recoverySteps && errorInfo . recoverySteps . length > 0 ) {
265+ LoggingUtils . info ( "💡 Recovery steps:" ) ;
266+ errorInfo . recoverySteps . forEach ( ( step , i ) => {
267+ LoggingUtils . info ( ` ${ i + 1 } . ${ step } ` ) ;
268+ } ) ;
269+ }
165270
166271 // Re-throw enhanced error
167272 const enhancedError = new Error ( errorInfo . userMessage ) ;
@@ -214,6 +319,13 @@ class ElixirCommandRunner {
214319 }
215320
216321 try {
322+ // Log compilation information
323+ const projectInfo = this . getElixirProjectInfo ( ) ;
324+ if ( projectInfo ) {
325+ LoggingUtils . debug ( `Elixir files: ${ projectInfo . elixirFiles } ` ) ;
326+ LoggingUtils . debug ( `Has mix.exs: ${ projectInfo . hasMixExs } ` ) ;
327+ }
328+
217329 const result = await this . executeMixCommand ( "compile" , args , options ) ;
218330
219331 // Elixir-specific: Show compilation information
@@ -536,12 +648,12 @@ class ElixirCommandRunner {
536648 } ,
537649 ) ;
538650
539- console . log ( "\n📊 Compilation Information:" ) ;
540- console . log ( "=" . repeat ( 50 ) ) ;
541- console . log ( `Elixir: ${ versionResult . stdout . trim ( ) } ` ) ;
542- console . log ( `Project: ${ projectResult . stdout . trim ( ) } ` ) ;
543- console . log ( `Environment: ${ options . env || "dev" } ` ) ;
544- console . log ( "=" . repeat ( 50 ) ) ;
651+ LoggingUtils . info ( "\n📊 Compilation Information:" ) ;
652+ LoggingUtils . info ( "=" . repeat ( 50 ) ) ;
653+ LoggingUtils . info ( `Elixir: ${ versionResult . stdout . trim ( ) } ` ) ;
654+ LoggingUtils . info ( `Project: ${ projectResult . stdout . trim ( ) } ` ) ;
655+ LoggingUtils . info ( `Environment: ${ options . env || "dev" } ` ) ;
656+ LoggingUtils . info ( "=" . repeat ( 50 ) ) ;
545657 } catch ( error ) {
546658 // Silently fail - this is just informational
547659 }
@@ -562,101 +674,107 @@ class ElixirCommandRunner {
562674 * Suggest compilation fixes
563675 */
564676 suggestCompilationFix ( errorMessage ) {
565- console . log ( "\n💡 Compilation Error Suggestions:" ) ;
677+ LoggingUtils . info ( "\n💡 Compilation Error Suggestions:" ) ;
566678
567679 if ( errorMessage . includes ( "Dependency" ) ) {
568- console . log ( " • Run 'mix deps.get' to fetch dependencies" ) ;
569- console . log ( " • Check mix.exs for correct dependency versions" ) ;
680+ LoggingUtils . info ( " • Run 'mix deps.get' to fetch dependencies" ) ;
681+ LoggingUtils . info ( " • Check mix.exs for correct dependency versions" ) ;
570682 }
571683
572684 if ( errorMessage . includes ( "undefined function" ) ) {
573- console . log ( " • Check function name and arity" ) ;
574- console . log ( " • Ensure module is compiled and available" ) ;
575- console . log ( " • Check imports and aliases" ) ;
685+ LoggingUtils . info ( " • Check function name and arity" ) ;
686+ LoggingUtils . info ( " • Ensure module is compiled and available" ) ;
687+ LoggingUtils . info ( " • Check imports and aliases" ) ;
576688 }
577689
578690 if ( errorMessage . includes ( "module not found" ) ) {
579- console . log ( " • Check module name spelling" ) ;
580- console . log ( " • Ensure file exists in lib/ directory" ) ;
581- console . log ( " • Check file extension (.ex vs .exs)" ) ;
691+ LoggingUtils . info ( " • Check module name spelling" ) ;
692+ LoggingUtils . info ( " • Ensure file exists in lib/ directory" ) ;
693+ LoggingUtils . info ( " • Check file extension (.ex vs .exs)" ) ;
582694 }
583695 }
584696
585697 /**
586698 * Suggest test fixes
587699 */
588700 suggestTestFix ( errorMessage ) {
589- console . log ( "\n💡 Test Error Suggestions:" ) ;
701+ LoggingUtils . info ( "\n💡 Test Error Suggestions:" ) ;
590702
591703 if ( errorMessage . includes ( "assert" ) ) {
592- console . log ( " • Check assertion values match expected" ) ;
593- console . log ( " • Use assert_in_delta for floating point comparisons" ) ;
594- console . log ( " • Check test setup and teardown" ) ;
704+ LoggingUtils . info ( " • Check assertion values match expected" ) ;
705+ LoggingUtils . info (
706+ " • Use assert_in_delta for floating point comparisons" ,
707+ ) ;
708+ LoggingUtils . info ( " • Check test setup and teardown" ) ;
595709 }
596710
597711 if ( errorMessage . includes ( "timeout" ) ) {
598- console . log ( " • Increase timeout with --timeout option" ) ;
599- console . log ( " • Check for infinite loops or long-running operations" ) ;
600- console . log ( " • Consider using async: false for integration tests" ) ;
712+ LoggingUtils . info ( " • Increase timeout with --timeout option" ) ;
713+ LoggingUtils . info (
714+ " • Check for infinite loops or long-running operations" ,
715+ ) ;
716+ LoggingUtils . info (
717+ " • Consider using async: false for integration tests" ,
718+ ) ;
601719 }
602720 }
603721
604722 /**
605723 * Suggest formatting fixes
606724 */
607725 suggestFormatFix ( errorMessage ) {
608- console . log ( "\n💡 Formatting Error Suggestions:" ) ;
726+ LoggingUtils . info ( "\n💡 Formatting Error Suggestions:" ) ;
609727
610728 if ( errorMessage . includes ( "not formatted" ) ) {
611- console . log ( " • Run 'mix format' to fix formatting" ) ;
612- console . log ( " • Check .formatter.exs configuration" ) ;
613- console . log ( " • Ensure line length is within limits" ) ;
729+ LoggingUtils . info ( " • Run 'mix format' to fix formatting" ) ;
730+ LoggingUtils . info ( " • Check .formatter.exs configuration" ) ;
731+ LoggingUtils . info ( " • Ensure line length is within limits" ) ;
614732 }
615733 }
616734
617735 /**
618736 * Suggest linting fixes
619737 */
620738 suggestLintFix ( errorMessage ) {
621- console . log ( "\n💡 Linting Error Suggestions:" ) ;
739+ LoggingUtils . info ( "\n💡 Linting Error Suggestions:" ) ;
622740
623741 if ( errorMessage . includes ( "Credo" ) ) {
624- console . log ( " • Install Credo: mix archive.install hex credo" ) ;
625- console . log ( " • Check .credo.exs configuration" ) ;
626- console . log ( " • Run 'mix credo --strict' for detailed analysis" ) ;
742+ LoggingUtils . info ( " • Install Credo: mix archive.install hex credo" ) ;
743+ LoggingUtils . info ( " • Check .credo.exs configuration" ) ;
744+ LoggingUtils . info ( " • Run 'mix credo --strict' for detailed analysis" ) ;
627745 }
628746 }
629747
630748 /**
631749 * Suggest type checking fixes
632750 */
633751 suggestTypeCheckFix ( errorMessage ) {
634- console . log ( "\n💡 Type Checking Error Suggestions:" ) ;
752+ LoggingUtils . info ( "\n💡 Type Checking Error Suggestions:" ) ;
635753
636754 if ( errorMessage . includes ( "Dialyzer" ) ) {
637- console . log (
755+ LoggingUtils . info (
638756 ' • Add dialyxir to mix.exs: {:dialyxir, "~> 1.4", only: [:dev]}' ,
639757 ) ;
640- console . log ( " • Run 'mix dialyzer --plt' to build PLT" ) ;
641- console . log ( " • Check type specifications with @spec" ) ;
758+ LoggingUtils . info ( " • Run 'mix dialyzer --plt' to build PLT" ) ;
759+ LoggingUtils . info ( " • Check type specifications with @spec" ) ;
642760 }
643761 }
644762
645763 /**
646764 * Suggest dependency fixes
647765 */
648766 suggestDepsFix ( errorMessage ) {
649- console . log ( "\n💡 Dependency Error Suggestions:" ) ;
767+ LoggingUtils . info ( "\n💡 Dependency Error Suggestions:" ) ;
650768
651769 if ( errorMessage . includes ( "Hex" ) ) {
652- console . log ( " • Install Hex: mix local.hex" ) ;
653- console . log ( " • Check internet connection for Hex.pm" ) ;
654- console . log ( " • Verify package name and version in mix.exs" ) ;
770+ LoggingUtils . info ( " • Install Hex: mix local.hex" ) ;
771+ LoggingUtils . info ( " • Check internet connection for Hex.pm" ) ;
772+ LoggingUtils . info ( " • Verify package name and version in mix.exs" ) ;
655773 }
656774
657775 if ( errorMessage . includes ( "lock" ) ) {
658- console . log ( " • Run 'mix deps.unlock --all' to clear lock" ) ;
659- console . log ( " • Run 'mix deps.get' to refetch dependencies" ) ;
776+ LoggingUtils . info ( " • Run 'mix deps.unlock --all' to clear lock" ) ;
777+ LoggingUtils . info ( " • Run 'mix deps.get' to refetch dependencies" ) ;
660778 }
661779 }
662780
0 commit comments