33using System ;
44using System . Collections . Generic ;
55using System . Collections . Immutable ;
6+ using System . IO ;
67using System . Linq ;
78using System . Reflection ;
9+ using System . Runtime . InteropServices ;
810using System . Text ;
911using System . Text . Json ;
1012using System . Text . RegularExpressions ;
@@ -139,10 +141,23 @@ void HandleOutput( string line )
139141 }
140142 }
141143
144+ // Resolve the Claude CLI executable on PATH. The npm install ships claude.cmd on Windows;
145+ // the native installer ships claude.exe; on Unix it is plain "claude".
146+ if ( ! TryResolveClaudeExecutable ( out var claudeExecutable ) )
147+ {
148+ console . WriteError (
149+ "Claude CLI not found on PATH. Install it via 'npm i -g @anthropic-ai/claude-code' or the native installer from https://claude.com/claude-code." ) ;
150+ prBodyText = "" ;
151+
152+ return false ;
153+ }
154+
155+ console . WriteMessage ( $ "Using Claude executable: { claudeExecutable } " ) ;
156+
142157 // Invoke claude with custom output handler
143158 var success = ToolInvocationHelper . InvokeTool (
144159 console ,
145- "claude.cmd" ,
160+ claudeExecutable ,
146161 claudeArgs ,
147162 workingDirectory ,
148163 out var exitCode ,
@@ -511,4 +526,48 @@ This conclusion will be extracted and placed at the TOP of the PR description.
511526 Begin now.
512527 """ ;
513528 }
529+
530+ /// <summary>
531+ /// Probes PATH for a Claude CLI launcher. The npm package installs <c>claude.cmd</c> on Windows,
532+ /// the native installer ships <c>claude.exe</c>, and on Unix the binary is named <c>claude</c>.
533+ /// Returns the resolved absolute path so <see cref="System.Diagnostics.Process"/> doesn't have to
534+ /// rely on PATHEXT (which is not consulted when <c>UseShellExecute</c> is false).
535+ /// </summary>
536+ private static bool TryResolveClaudeExecutable ( out string path )
537+ {
538+ var candidates = RuntimeInformation . IsOSPlatform ( OSPlatform . Windows )
539+ ? new [ ] { "claude.cmd" , "claude.exe" , "claude.bat" , "claude" }
540+ : new [ ] { "claude" } ;
541+
542+ var pathEnv = Environment . GetEnvironmentVariable ( "PATH" ) ?? "" ;
543+
544+ foreach ( var dir in pathEnv . Split ( Path . PathSeparator , StringSplitOptions . RemoveEmptyEntries ) )
545+ {
546+ foreach ( var candidate in candidates )
547+ {
548+ string fullPath ;
549+
550+ try
551+ {
552+ fullPath = Path . Combine ( dir . Trim ( ) . Trim ( '"' ) , candidate ) ;
553+ }
554+ catch ( ArgumentException )
555+ {
556+ // Skip malformed PATH entries.
557+ continue ;
558+ }
559+
560+ if ( File . Exists ( fullPath ) )
561+ {
562+ path = fullPath ;
563+
564+ return true ;
565+ }
566+ }
567+ }
568+
569+ path = "" ;
570+
571+ return false ;
572+ }
514573}
0 commit comments