@@ -11,12 +11,24 @@ const { spawn } = require("child_process");
1111const { runCommand, commandExists } = require ( "../lib/utils" ) ;
1212const ConfigManager = require ( "../interactive/config-manager" ) ;
1313const PineScriptToolDetector = require ( "../../languages/pinescript/tool-detector" ) ;
14+ const PlatformDetector = require ( "../lib/platform-detector" ) ;
15+ const { defaultErrorHandler } = require ( "../lib/error-handler" ) ;
16+
17+ // Import shared utilities
18+ const {
19+ ConfigUtils,
20+ FileUtils,
21+ ProjectUtils,
22+ LoggingUtils,
23+ ensureDir,
24+ } = require ( "../lib" ) ;
1425
1526class PineCommandRunner {
1627 constructor ( projectPath = process . cwd ( ) ) {
1728 this . projectPath = projectPath ;
1829 this . configManager = new ConfigManager ( projectPath ) ;
1930 this . toolDetector = new PineScriptToolDetector ( ) ;
31+ this . platformDetector = new PlatformDetector ( ) ;
2032 this . config = null ;
2133 this . pineConfig = null ;
2234 this . detectedTools = null ;
@@ -26,42 +38,135 @@ class PineCommandRunner {
2638 * Initialize command runner
2739 */
2840 async initialize ( ) {
29- // Load configuration
30- this . config = this . configManager . loadConfig ( ) ;
31- if ( ! this . config ) {
32- throw new Error ( "Project not configured. Run /pine-setup first." ) ;
33- }
41+ // First, validate that we're in a PineScript project using ProjectUtils
42+ try {
43+ const projectInfo = ProjectUtils . detectProjectType ( this . projectPath ) ;
3444
35- // Get PineScript configuration
36- this . pineConfig = this . config . pinescript ;
37- if ( ! this . pineConfig ) {
38- throw new Error (
39- "PineScript configuration not found. Run /pine-setup first." ,
40- ) ;
45+ if ( projectInfo . type !== "pinescript" && projectInfo . confidence < 0.7 ) {
46+ LoggingUtils . warn (
47+ `Project detection: ${ projectInfo . type } (confidence: ${ projectInfo . confidence } )` ,
48+ ) ;
49+ LoggingUtils . warn (
50+ "This may not be a PineScript project. Some features may not work correctly." ,
51+ ) ;
52+ } else if ( projectInfo . type === "pinescript" ) {
53+ LoggingUtils . debug (
54+ `Detected PineScript project: ${ projectInfo . framework || "standard PineScript" } ` ,
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 ) ;
4166 }
4267
43- // Detect tools
44- 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 /pine-setup first." ) ;
73+ }
74+
75+ // Get PineScript configuration
76+ this . pineConfig = this . config . pinescript ;
77+ if ( ! this . pineConfig ) {
78+ throw new Error (
79+ "PineScript configuration not found. Run /pine-setup first." ,
80+ ) ;
81+ }
82+
83+ // Validate PineScript configuration schema
84+ ConfigUtils . validateConfig ( this . pineConfig , "pinescript" ) ;
85+
86+ // Detect tools
87+ this . detectedTools = await this . toolDetector . detectTools ( ) ;
4588
46- return true ;
89+ return true ;
90+ } catch ( error ) {
91+ // Use LoggingUtils for better error display
92+ LoggingUtils . error (
93+ "Failed to initialize PineScript command runner:" ,
94+ error . message ,
95+ ) ;
96+ LoggingUtils . info ( "Run /pine-setup to configure your PineScript project" ) ;
97+ throw error ;
98+ }
4799 }
48100
49101 /**
50102 * Check if required tool is installed
51103 */
52- async checkTool ( toolName , required = true ) {
53- const toolInfo = this . detectedTools ?. [ toolName ] ;
104+ checkTool ( toolName , required = true ) {
105+ try {
106+ // Use ConfigUtils to check if tool is installed
107+ const isInstalled = ConfigUtils . checkToolInstalled (
108+ this . pineConfig ,
109+ toolName ,
110+ required ,
111+ ) ;
54112
55- if ( ! toolInfo || ! toolInfo . installed ) {
56- if ( required ) {
113+ if ( ! isInstalled && required ) {
57114 throw new Error (
58115 `${ toolName } is not installed. Install it or check tool recommendations.` ,
59116 ) ;
60117 }
61- return false ;
118+
119+ return isInstalled ;
120+ } catch ( error ) {
121+ // Use LoggingUtils for better error display
122+ if ( required ) {
123+ LoggingUtils . error (
124+ `PineScript tool '${ toolName } ' check failed:` ,
125+ error . message ,
126+ ) ;
127+ LoggingUtils . info ( `Run /pine-setup to install '${ toolName } '` ) ;
128+ }
129+ throw error ;
62130 }
131+ }
63132
64- return true ;
133+ /**
134+ * Find PineScript files in the project
135+ */
136+ findPineScriptFiles ( pattern = "**/*.pine" , excludePatterns = [ ] ) {
137+ try {
138+ return FileUtils . findFilesByPattern ( this . projectPath , [ pattern ] , {
139+ exclude : excludePatterns ,
140+ language : "pinescript" ,
141+ } ) ;
142+ } catch ( error ) {
143+ LoggingUtils . warn ( "Failed to find PineScript files:" , error . message ) ;
144+ return [ ] ;
145+ }
146+ }
147+
148+ /**
149+ * Get PineScript project metadata
150+ */
151+ getPineScriptProjectInfo ( ) {
152+ try {
153+ const info = {
154+ hasPineFiles : this . findPineScriptFiles ( ) . length > 0 ,
155+ pineScriptFiles : this . findPineScriptFiles ( ) . length ,
156+ hasConfig : fs . existsSync ( path . join ( this . projectPath , "config" ) ) ,
157+ hasScripts : fs . existsSync ( path . join ( this . projectPath , "scripts" ) ) ,
158+ hasIndicators : fs . existsSync ( path . join ( this . projectPath , "indicators" ) ) ,
159+ hasStrategies : fs . existsSync ( path . join ( this . projectPath , "strategies" ) ) ,
160+ } ;
161+
162+ return info ;
163+ } catch ( error ) {
164+ LoggingUtils . debug (
165+ "Failed to get PineScript project info:" ,
166+ error . message ,
167+ ) ;
168+ return null ;
169+ }
65170 }
66171
67172 /**
@@ -150,7 +255,7 @@ class PineCommandRunner {
150255 async executeCommand ( command , args = [ ] , options = { } ) {
151256 return new Promise ( ( resolve , reject ) => {
152257 const fullCommand = [ command , ...args ] . join ( " " ) ;
153- console . log ( `\n🚀 Executing: ${ fullCommand } ` ) ;
258+ LoggingUtils . info ( `\n🚀 Executing: ${ fullCommand } ` ) ;
154259
155260 const child = spawn ( command , args , {
156261 cwd : this . projectPath ,
@@ -210,7 +315,7 @@ class PineCommandRunner {
210315 }
211316
212317 if ( versionCheck . warning ) {
213- console . log ( `⚠️ Warning: ${ versionCheck . warning } ` ) ;
318+ LoggingUtils . warn ( `⚠️ Warning: ${ versionCheck . warning } ` ) ;
214319 }
215320
216321 // Basic validation checks
@@ -395,83 +500,66 @@ class PineCommandRunner {
395500 * Generate validation report
396501 */
397502 generateValidationReport ( results , options = { } ) {
398- console . log ( "\n📋 Validation Report" ) ;
399- console . log ( "=" . repeat ( 50 ) ) ;
400- console . log ( `File: ${ results . file } ` ) ;
401- console . log ( `Version: ${ results . version } ` ) ;
402- console . log ( `Checks: ${ results . checks . length } ` ) ;
503+ LoggingUtils . info ( "\n📋 Validation Report" ) ;
504+ LoggingUtils . info ( "=" . repeat ( 50 ) ) ;
505+ LoggingUtils . info ( `File: ${ results . file } ` ) ;
506+ LoggingUtils . info ( `Version: ${ results . version } ` ) ;
507+ LoggingUtils . info ( `Checks: ${ results . checks . length } ` ) ;
403508
404509 const errors = results . checks . filter ( ( c ) => c . type === "error" ) ;
405510 const warnings = results . checks . filter ( ( c ) => c . type === "warning" ) ;
406511 const info = results . checks . filter ( ( c ) => c . type === "info" && ! c . debug ) ;
407512 const debugSuggestions = results . checks . filter ( ( c ) => c . debug ) ;
408513
409514 if ( errors . length > 0 ) {
410- console . log ( "\n❌ Errors:" ) ;
515+ LoggingUtils . error ( "\n❌ Errors:" ) ;
411516 errors . forEach ( ( check , i ) => {
412- console . log ( ` ${ i + 1 } . ${ check . message } ` ) ;
517+ LoggingUtils . error ( ` ${ i + 1 } . ${ check . message } ` ) ;
413518 if ( check . suggestion ) {
414- console . log ( ` 💡 ${ check . suggestion } ` ) ;
519+ LoggingUtils . info ( ` 💡 ${ check . suggestion } ` ) ;
415520 }
416521 } ) ;
417522 }
418523
419524 if ( warnings . length > 0 ) {
420- console . log ( "\n⚠️ Warnings:" ) ;
525+ LoggingUtils . warn ( "\n⚠️ Warnings:" ) ;
421526 warnings . forEach ( ( check , i ) => {
422- console . log ( ` ${ i + 1 } . ${ check . message } ` ) ;
527+ LoggingUtils . warn ( ` ${ i + 1 } . ${ check . message } ` ) ;
423528 if ( check . suggestion ) {
424- console . log ( ` 💡 ${ check . suggestion } ` ) ;
529+ LoggingUtils . info ( ` 💡 ${ check . suggestion } ` ) ;
425530 }
426531 } ) ;
427532 }
428533
429534 if ( info . length > 0 ) {
430- console . log ( "\nℹ️ Info:" ) ;
535+ LoggingUtils . info ( "\nℹ️ Info:" ) ;
431536 info . forEach ( ( check , i ) => {
432- console . log ( ` ${ i + 1 } . ${ check . message } ` ) ;
537+ LoggingUtils . info ( ` ${ i + 1 } . ${ check . message } ` ) ;
433538 if ( check . suggestion ) {
434- console . log ( ` 💡 ${ check . suggestion } ` ) ;
539+ LoggingUtils . info ( ` 💡 ${ check . suggestion } ` ) ;
435540 }
436541 } ) ;
437542 }
438543
439544 if ( debugSuggestions . length > 0 ) {
440- console . log ( "\n🔧 Debugging Suggestions:" ) ;
545+ LoggingUtils . info ( "\n🔧 Debugging Suggestions:" ) ;
441546 debugSuggestions . forEach ( ( check , i ) => {
442547 const icon = check . type === "warning" ? "⚠️" : "💡" ;
443- console . log ( ` ${ i + 1 } . ${ icon } ${ check . message } ` ) ;
548+ LoggingUtils . info ( ` ${ i + 1 } . ${ icon } ${ check . message } ` ) ;
444549 if ( check . suggestion ) {
445- console . log ( ` 🛠️ ${ check . suggestion } ` ) ;
550+ LoggingUtils . info ( ` 🛠️ ${ check . suggestion } ` ) ;
446551 }
447552 } ) ;
448553
449- console . log ( "\n🚀 Quick Debugging Commands:" ) ;
450- console . log ( " /pine-debug inspect --var VARIABLE_NAME" ) ;
451- console . log ( " /pine-debug trace --var VARIABLE_NAME --plot" ) ;
452- console . log ( " /pine-debug profile --metrics complexity" ) ;
453- console . log ( " /pine-debug helpers --output debug-helpers.pine" ) ;
454- }
455-
456- if ( warnings . length > 0 ) {
457- console . log ( "\n⚠️ Warnings:" ) ;
458- warnings . forEach ( ( check , i ) => {
459- console . log ( ` ${ i + 1 } . ${ check . message } ` ) ;
460- if ( check . suggestion ) {
461- console . log ( ` 💡 ${ check . suggestion } ` ) ;
462- }
463- } ) ;
464- }
465-
466- if ( info . length > 0 ) {
467- console . log ( "\nℹ️ Info:" ) ;
468- info . forEach ( ( check , i ) => {
469- console . log ( ` ${ i + 1 } . ${ check . message } ` ) ;
470- } ) ;
554+ LoggingUtils . info ( "\n🚀 Quick Debugging Commands:" ) ;
555+ LoggingUtils . info ( " /pine-debug inspect --var VARIABLE_NAME" ) ;
556+ LoggingUtils . info ( " /pine-debug trace --var VARIABLE_NAME --plot" ) ;
557+ LoggingUtils . info ( " /pine-debug profile --metrics complexity" ) ;
558+ LoggingUtils . info ( " /pine-debug helpers --output debug-helpers.pine" ) ;
471559 }
472560
473561 if ( errors . length === 0 && warnings . length === 0 ) {
474- console . log ( "\n✅ No issues found!" ) ;
562+ LoggingUtils . info ( "\n✅ No issues found!" ) ;
475563 }
476564
477565 return {
@@ -533,51 +621,53 @@ Examples:
533621 const results = await runner . runValidation ( args [ 1 ] ) ;
534622 runner . generateValidationReport ( results ) ;
535623 } catch ( error ) {
536- console . error ( `❌ Validation failed: ${ error . message } ` ) ;
624+ LoggingUtils . error ( `❌ Validation failed: ${ error . message } ` ) ;
537625 process . exit ( 1 ) ;
538626 }
539627 } )
540628 . catch ( ( error ) => {
541- console . error ( `❌ Initialization failed: ${ error . message } ` ) ;
629+ LoggingUtils . error ( `❌ Initialization failed: ${ error . message } ` ) ;
542630 process . exit ( 1 ) ;
543631 } ) ;
544632 } else if ( args [ 0 ] === "config" ) {
545633 runner
546634 . initialize ( )
547635 . then ( ( ) => {
548636 const summary = runner . getConfigSummary ( ) ;
549- console . log ( "\n📊 PineScript Configuration Summary:" ) ;
550- console . log ( ` • Version: v${ summary . version } ` ) ;
551- console . log ( ` • Project Type: ${ summary . projectType } ` ) ;
552- console . log (
637+ LoggingUtils . info ( "\n📊 PineScript Configuration Summary:" ) ;
638+ LoggingUtils . info ( ` • Version: v${ summary . version } ` ) ;
639+ LoggingUtils . info ( ` • Project Type: ${ summary . projectType } ` ) ;
640+ LoggingUtils . info (
553641 ` • Backtesting: ${ summary . backtesting ? "Enabled" : "Disabled" } ` ,
554642 ) ;
555- console . log ( ` • Alerts: ${ summary . alerts ? "Enabled" : "Disabled" } ` ) ;
556- console . log (
643+ LoggingUtils . info (
644+ ` • Alerts: ${ summary . alerts ? "Enabled" : "Disabled" } ` ,
645+ ) ;
646+ LoggingUtils . info (
557647 ` • TradingView Publish: ${ summary . tradingview ? "Enabled" : "Disabled" } ` ,
558648 ) ;
559649 } )
560650 . catch ( ( error ) => {
561- console . error ( `❌ Failed to load configuration: ${ error . message } ` ) ;
651+ LoggingUtils . error ( `❌ Failed to load configuration: ${ error . message } ` ) ;
562652 process . exit ( 1 ) ;
563653 } ) ;
564654 } else if ( args [ 0 ] === "tools" ) {
565655 runner
566656 . initialize ( )
567657 . then ( async ( ) => {
568- console . log ( "\n🔧 Detected Tools:" ) ;
658+ LoggingUtils . info ( "\n🔧 Detected Tools:" ) ;
569659 Object . entries ( runner . detectedTools || { } ) . forEach ( ( [ name , info ] ) => {
570- console . log (
660+ LoggingUtils . info (
571661 ` ${ info . installed ? "✅" : "❌" } ${ name } : ${ info . installed ? `v${ info . version } ` : "Not installed" } ` ,
572662 ) ;
573663 } ) ;
574664 } )
575665 . catch ( ( error ) => {
576- console . error ( `❌ Failed to load tools: ${ error . message } ` ) ;
666+ LoggingUtils . error ( `❌ Failed to load tools: ${ error . message } ` ) ;
577667 process . exit ( 1 ) ;
578668 } ) ;
579669 } else {
580- console . error ( "Unknown command. Use --help for usage information." ) ;
670+ LoggingUtils . error ( "Unknown command. Use --help for usage information." ) ;
581671 process . exit ( 1 ) ;
582672 }
583673}
0 commit comments