44using System . Diagnostics ;
55using System . Linq ;
66using System . Text ;
7+ using System . Threading ;
78using System . Threading . Tasks ;
89using System . Windows . Forms ;
910using FlowVision . lib . Classes ;
@@ -13,13 +14,18 @@ namespace FlowVision.lib.Plugins
1314{
1415 class CMDPlugin
1516 {
17+ private static readonly string [ ] BrowserProcesses = { "msedge" , "chrome" , "firefox" , "iexplore" , "opera" } ;
18+ private static readonly string [ ] NonWaitingCommands = { "start " , "explorer " } ;
1619
1720 [ KernelFunction , Description ( "Executes a CMD command and returns the output." ) ]
1821 public async Task < string > ExecuteCommand ( [ Description ( "Command Prompt Command" ) ] string command )
1922 {
2023 // Log the plugin usage
2124 PluginLogger . LogPluginUsage ( "CMDPlugin" , "ExecuteCommand" , command ) ;
2225
26+ // Detect if this is likely launching an external application
27+ bool shouldWaitForExit = ! ShouldSkipWaiting ( command ) ;
28+
2329 try
2430 {
2531 var startInfo = new ProcessStartInfo ( )
@@ -35,13 +41,32 @@ public async Task<string> ExecuteCommand([Description("Command Prompt Command")]
3541 using ( var process = new Process { StartInfo = startInfo } )
3642 {
3743 process . Start ( ) ;
38- string output = await process . StandardOutput . ReadToEndAsync ( ) ;
39- string errors = await process . StandardError . ReadToEndAsync ( ) ;
40- process . WaitForExit ( ) ;
44+
45+ // Use tasks to read output with timeout
46+ var outputTask = process . StandardOutput . ReadToEndAsync ( ) ;
47+ var errorTask = process . StandardError . ReadToEndAsync ( ) ;
48+
49+ if ( shouldWaitForExit )
50+ {
51+ // Wait for process with reasonable timeout
52+ if ( ! process . WaitForExit ( 10000 ) ) // 10 second timeout
53+ {
54+ return $ "Command started but may still be running: { command } ";
55+ }
56+ }
57+ else
58+ {
59+ // For non-waiting commands, give a short time to collect initial output
60+ await Task . Delay ( 500 ) ;
61+ return $ "Command launched: { command } ";
62+ }
63+
64+ // Complete reading output
65+ string output = await outputTask ;
66+ string errors = await errorTask ;
4167
4268 if ( ! string . IsNullOrWhiteSpace ( errors ) )
4369 {
44-
4570 return $ "Error: { errors } ";
4671 }
4772
@@ -53,5 +78,60 @@ public async Task<string> ExecuteCommand([Description("Command Prompt Command")]
5378 return $ "Exception: { ex . Message } ";
5479 }
5580 }
81+
82+ [ KernelFunction , Description ( "Launches an external application without waiting for it to exit." ) ]
83+ public string LaunchApplication ( [ Description ( "Application to launch" ) ] string application ,
84+ [ Description ( "Arguments for the application" ) ] string arguments = "" )
85+ {
86+ // Log the plugin usage
87+ PluginLogger . LogPluginUsage ( "CMDPlugin" , "LaunchApplication" , $ "{ application } { arguments } ") ;
88+
89+ try
90+ {
91+ var startInfo = new ProcessStartInfo ( )
92+ {
93+ FileName = application ,
94+ Arguments = arguments ,
95+ UseShellExecute = true ,
96+ CreateNoWindow = false
97+ } ;
98+
99+ Process . Start ( startInfo ) ;
100+ return $ "Successfully launched: { application } ";
101+ }
102+ catch ( Exception ex )
103+ {
104+ return $ "Failed to launch { application } : { ex . Message } ";
105+ }
106+ }
107+
108+ private bool ShouldSkipWaiting ( string command )
109+ {
110+ if ( string . IsNullOrWhiteSpace ( command ) )
111+ return false ;
112+
113+ // Check if command contains any browser names (case-insensitive)
114+ if ( BrowserProcesses . Any ( browser =>
115+ command . IndexOf ( browser , StringComparison . OrdinalIgnoreCase ) >= 0 ) )
116+ {
117+ return true ;
118+ }
119+
120+ // Check for commands that typically launch external processes
121+ if ( NonWaitingCommands . Any ( cmd =>
122+ command . StartsWith ( cmd , StringComparison . OrdinalIgnoreCase ) ) )
123+ {
124+ return true ;
125+ }
126+
127+ // Check for URLs or web addresses
128+ if ( command . IndexOf ( "http://" , StringComparison . OrdinalIgnoreCase ) >= 0 ||
129+ command . IndexOf ( "https://" , StringComparison . OrdinalIgnoreCase ) >= 0 )
130+ {
131+ return true ;
132+ }
133+
134+ return false ;
135+ }
56136 }
57137}
0 commit comments