From 5f0a4462e166349f61efe5f5000966bfa48e1d57 Mon Sep 17 00:00:00 2001 From: Ashley Hindle Date: Thu, 14 Aug 2025 12:26:59 +0100 Subject: [PATCH 01/10] Fix PHPStorm on Windows v1 From aaf038d83b08b2da5592e3f0bf4f7a738296ef8e Mon Sep 17 00:00:00 2001 From: Ashley Hindle Date: Thu, 14 Aug 2025 13:40:57 +0100 Subject: [PATCH 02/10] feat: use absolute path for phpstorm with test --- src/Console/InstallCommand.php | 19 ++++++++-- src/Contracts/McpClient.php | 5 +++ .../CodeEnvironment/CodeEnvironment.php | 5 +++ .../Console/InstallCommandPhpPathTest.php | 37 +++++++++++++++++++ 4 files changed, 62 insertions(+), 4 deletions(-) create mode 100644 tests/Unit/Console/InstallCommandPhpPathTest.php diff --git a/src/Console/InstallCommand.php b/src/Console/InstallCommand.php index 135f7580..75191cd8 100644 --- a/src/Console/InstallCommand.php +++ b/src/Console/InstallCommand.php @@ -462,17 +462,18 @@ private function installMcpServerConfig(): void )->toArray() ); - /** @var CodeEnvironment $mcpClient */ + /** @var McpClient $mcpClient */ foreach ($this->selectedTargetMcpClient as $mcpClient) { $ideName = $mcpClient->mcpClientName(); $ideDisplay = str_pad($ideName, $longestIdeName); $this->output->write(" {$ideDisplay}... "); $results = []; + $php = $this->getPhpPathForMcpClient($mcpClient); if ($this->shouldInstallMcp()) { try { - $artisan = $mcpClient->useAbsolutePathForMcp ? base_path('artisan') : './artisan'; - $result = $mcpClient->installMcp('laravel-boost', 'php', [$artisan, 'boost:mcp']); + $artisan = $this->getArtisanPathForMcpClient($mcpClient); + $result = $mcpClient->installMcp('laravel-boost', $php, [$artisan, 'boost:mcp']); if ($result) { $results[] = $this->greenTick.' Boost'; @@ -491,7 +492,7 @@ private function installMcpServerConfig(): void try { $result = $mcpClient->installMcp( key: 'herd', - command: 'php', + command: $this->getPhpPathForMcpClient($mcpClient), args: [$this->herd->mcpPath()], env: ['SITE_PATH' => base_path()] ); @@ -523,6 +524,16 @@ private function installMcpServerConfig(): void } } + private function getPhpPathForMcpClient(McpClient $mcpClient): string + { + return $mcpClient->useAbsolutePathForMcp() ? PHP_BINARY : 'php'; + } + + private function getArtisanPathForMcpClient(McpClient $mcpClient): string + { + return $mcpClient->useAbsolutePathForMcp() ? base_path('artisan') : './artisan'; + } + /** * Is the project actually using localization for their new features? */ diff --git a/src/Contracts/McpClient.php b/src/Contracts/McpClient.php index 74629d3f..19c9b6d0 100644 --- a/src/Contracts/McpClient.php +++ b/src/Contracts/McpClient.php @@ -16,6 +16,11 @@ interface McpClient */ public function mcpClientName(): ?string; + /** + * Whether to use absolute paths for MCP commands. + */ + public function useAbsolutePathForMcp(): bool; + /** * Install an MCP server configuration in this IDE. * diff --git a/src/Install/CodeEnvironment/CodeEnvironment.php b/src/Install/CodeEnvironment/CodeEnvironment.php index fe4a4b5a..9b1e1310 100644 --- a/src/Install/CodeEnvironment/CodeEnvironment.php +++ b/src/Install/CodeEnvironment/CodeEnvironment.php @@ -35,6 +35,11 @@ public function mcpClientName(): ?string return $this->displayName(); } + public function useAbsolutePathForMcp(): bool + { + return $this->useAbsolutePathForMcp; + } + /** * Get the detection configuration for system-wide installation detection. * diff --git a/tests/Unit/Console/InstallCommandPhpPathTest.php b/tests/Unit/Console/InstallCommandPhpPathTest.php new file mode 100644 index 00000000..d6aa0b98 --- /dev/null +++ b/tests/Unit/Console/InstallCommandPhpPathTest.php @@ -0,0 +1,37 @@ +toBe(PHP_BINARY); +}); + +test('getPhpPathForMcpClient returns php string for Cursor', function () { + $installCommand = new InstallCommand; + $strategyFactory = Mockery::mock(DetectionStrategyFactory::class); + $cursor = new Cursor($strategyFactory); + + $phpPath = invokePrivateMethod($installCommand, 'getPhpPathForMcpClient', [$cursor]); + + expect($phpPath)->toBe('php'); +}); + +function invokePrivateMethod(object $object, string $methodName, array $parameters = []): mixed +{ + $reflection = new ReflectionClass($object); + $method = $reflection->getMethod($methodName); + $method->setAccessible(true); + + return $method->invokeArgs($object, $parameters); +} From e17226623fde80047c8cf9ebc7155e362f1d4357 Mon Sep 17 00:00:00 2001 From: Pushpak Chhajed Date: Thu, 14 Aug 2025 18:35:29 +0530 Subject: [PATCH 03/10] refactor: streamline path resolution and simplify the MCP client interface --- src/Console/InstallCommand.php | 15 ++----- src/Contracts/McpClient.php | 10 +++++ .../CodeEnvironment/CodeEnvironment.php | 19 +++++++++ .../Console/InstallCommandPhpPathTest.php | 37 ------------------ .../CodeEnvironmentPathResolutionTest.php | 39 +++++++++++++++++++ 5 files changed, 71 insertions(+), 49 deletions(-) delete mode 100644 tests/Unit/Console/InstallCommandPhpPathTest.php create mode 100644 tests/Unit/Install/CodeEnvironment/CodeEnvironmentPathResolutionTest.php diff --git a/src/Console/InstallCommand.php b/src/Console/InstallCommand.php index 75191cd8..06738945 100644 --- a/src/Console/InstallCommand.php +++ b/src/Console/InstallCommand.php @@ -469,10 +469,10 @@ private function installMcpServerConfig(): void $this->output->write(" {$ideDisplay}... "); $results = []; - $php = $this->getPhpPathForMcpClient($mcpClient); + $php = $mcpClient->getPhpPath(); if ($this->shouldInstallMcp()) { try { - $artisan = $this->getArtisanPathForMcpClient($mcpClient); + $artisan = $mcpClient->getArtisanPath(); $result = $mcpClient->installMcp('laravel-boost', $php, [$artisan, 'boost:mcp']); if ($result) { @@ -492,7 +492,7 @@ private function installMcpServerConfig(): void try { $result = $mcpClient->installMcp( key: 'herd', - command: $this->getPhpPathForMcpClient($mcpClient), + command: $mcpClient->getPhpPath(), args: [$this->herd->mcpPath()], env: ['SITE_PATH' => base_path()] ); @@ -524,15 +524,6 @@ private function installMcpServerConfig(): void } } - private function getPhpPathForMcpClient(McpClient $mcpClient): string - { - return $mcpClient->useAbsolutePathForMcp() ? PHP_BINARY : 'php'; - } - - private function getArtisanPathForMcpClient(McpClient $mcpClient): string - { - return $mcpClient->useAbsolutePathForMcp() ? base_path('artisan') : './artisan'; - } /** * Is the project actually using localization for their new features? diff --git a/src/Contracts/McpClient.php b/src/Contracts/McpClient.php index 19c9b6d0..68c106b1 100644 --- a/src/Contracts/McpClient.php +++ b/src/Contracts/McpClient.php @@ -21,6 +21,16 @@ public function mcpClientName(): ?string; */ public function useAbsolutePathForMcp(): bool; + /** + * Get the PHP executable path for this MCP client. + */ + public function getPhpPath(): string; + + /** + * Get the artisan path for this MCP client. + */ + public function getArtisanPath(): string; + /** * Install an MCP server configuration in this IDE. * diff --git a/src/Install/CodeEnvironment/CodeEnvironment.php b/src/Install/CodeEnvironment/CodeEnvironment.php index 9b1e1310..11ea31a0 100644 --- a/src/Install/CodeEnvironment/CodeEnvironment.php +++ b/src/Install/CodeEnvironment/CodeEnvironment.php @@ -40,6 +40,25 @@ public function useAbsolutePathForMcp(): bool return $this->useAbsolutePathForMcp; } + public function getPhpPath(): string + { + return $this->useAbsolutePathForMcp() ? PHP_BINARY : 'php'; + } + + public function getArtisanPath(): string + { + if (! $this->useAbsolutePathForMcp()) { + return './artisan'; + } + + // Try to get the base path from Laravel app, fallback to getcwd + try { + return base_path('artisan'); + } catch (\Throwable) { + return getcwd().'/artisan'; + } + } + /** * Get the detection configuration for system-wide installation detection. * diff --git a/tests/Unit/Console/InstallCommandPhpPathTest.php b/tests/Unit/Console/InstallCommandPhpPathTest.php deleted file mode 100644 index d6aa0b98..00000000 --- a/tests/Unit/Console/InstallCommandPhpPathTest.php +++ /dev/null @@ -1,37 +0,0 @@ -toBe(PHP_BINARY); -}); - -test('getPhpPathForMcpClient returns php string for Cursor', function () { - $installCommand = new InstallCommand; - $strategyFactory = Mockery::mock(DetectionStrategyFactory::class); - $cursor = new Cursor($strategyFactory); - - $phpPath = invokePrivateMethod($installCommand, 'getPhpPathForMcpClient', [$cursor]); - - expect($phpPath)->toBe('php'); -}); - -function invokePrivateMethod(object $object, string $methodName, array $parameters = []): mixed -{ - $reflection = new ReflectionClass($object); - $method = $reflection->getMethod($methodName); - $method->setAccessible(true); - - return $method->invokeArgs($object, $parameters); -} diff --git a/tests/Unit/Install/CodeEnvironment/CodeEnvironmentPathResolutionTest.php b/tests/Unit/Install/CodeEnvironment/CodeEnvironmentPathResolutionTest.php new file mode 100644 index 00000000..415f7f71 --- /dev/null +++ b/tests/Unit/Install/CodeEnvironment/CodeEnvironmentPathResolutionTest.php @@ -0,0 +1,39 @@ +getPhpPath())->toBe(PHP_BINARY); +}); + +test('PhpStorm returns absolute artisan path', function () { + $strategyFactory = Mockery::mock(DetectionStrategyFactory::class); + $phpStorm = new PhpStorm($strategyFactory); + + $artisanPath = $phpStorm->getArtisanPath(); + + // Should be an absolute path ending with 'artisan' + expect($artisanPath)->toEndWith('artisan') + ->and($artisanPath)->not()->toBe('./artisan'); +}); + +test('Cursor returns relative php string', function () { + $strategyFactory = Mockery::mock(DetectionStrategyFactory::class); + $cursor = new Cursor($strategyFactory); + + expect($cursor->getPhpPath())->toBe('php'); +}); + +test('Cursor returns relative artisan path', function () { + $strategyFactory = Mockery::mock(DetectionStrategyFactory::class); + $cursor = new Cursor($strategyFactory); + + expect($cursor->getArtisanPath())->toBe('./artisan'); +}); From 2bc02f86160689cbee4e0a106d2211540802beba Mon Sep 17 00:00:00 2001 From: pushpak1300 <31663512+pushpak1300@users.noreply.github.com> Date: Thu, 14 Aug 2025 13:06:14 +0000 Subject: [PATCH 04/10] Fix code styling --- src/Console/InstallCommand.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Console/InstallCommand.php b/src/Console/InstallCommand.php index 06738945..1905843e 100644 --- a/src/Console/InstallCommand.php +++ b/src/Console/InstallCommand.php @@ -524,7 +524,6 @@ private function installMcpServerConfig(): void } } - /** * Is the project actually using localization for their new features? */ From 6e29dbf823f44e53176c295af349b86166a2f4a6 Mon Sep 17 00:00:00 2001 From: Pushpak Chhajed Date: Thu, 14 Aug 2025 18:38:17 +0530 Subject: [PATCH 05/10] refactor: simplify artisan path resolution by removing fallback --- src/Install/CodeEnvironment/CodeEnvironment.php | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Install/CodeEnvironment/CodeEnvironment.php b/src/Install/CodeEnvironment/CodeEnvironment.php index 11ea31a0..e6c68344 100644 --- a/src/Install/CodeEnvironment/CodeEnvironment.php +++ b/src/Install/CodeEnvironment/CodeEnvironment.php @@ -12,6 +12,7 @@ use Laravel\Boost\Install\Detection\DetectionStrategyFactory; use Laravel\Boost\Install\Enums\McpInstallationStrategy; use Laravel\Boost\Install\Enums\Platform; +use Throwable; abstract class CodeEnvironment { @@ -51,12 +52,8 @@ public function getArtisanPath(): string return './artisan'; } - // Try to get the base path from Laravel app, fallback to getcwd - try { - return base_path('artisan'); - } catch (\Throwable) { - return getcwd().'/artisan'; - } + return base_path('artisan'); + } /** From a517e34b5befe010b8a6e640d98c4acea6c03413 Mon Sep 17 00:00:00 2001 From: pushpak1300 <31663512+pushpak1300@users.noreply.github.com> Date: Thu, 14 Aug 2025 13:08:55 +0000 Subject: [PATCH 06/10] Fix code styling --- src/Install/CodeEnvironment/CodeEnvironment.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Install/CodeEnvironment/CodeEnvironment.php b/src/Install/CodeEnvironment/CodeEnvironment.php index e6c68344..16b756b4 100644 --- a/src/Install/CodeEnvironment/CodeEnvironment.php +++ b/src/Install/CodeEnvironment/CodeEnvironment.php @@ -12,7 +12,6 @@ use Laravel\Boost\Install\Detection\DetectionStrategyFactory; use Laravel\Boost\Install\Enums\McpInstallationStrategy; use Laravel\Boost\Install\Enums\Platform; -use Throwable; abstract class CodeEnvironment { From 01204b824498b363809323cde37a03e5ed86cf43 Mon Sep 17 00:00:00 2001 From: Pushpak Chhajed Date: Thu, 14 Aug 2025 18:39:27 +0530 Subject: [PATCH 07/10] refactor: simplify artisan path resolution logic --- src/Install/CodeEnvironment/CodeEnvironment.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Install/CodeEnvironment/CodeEnvironment.php b/src/Install/CodeEnvironment/CodeEnvironment.php index 16b756b4..88876193 100644 --- a/src/Install/CodeEnvironment/CodeEnvironment.php +++ b/src/Install/CodeEnvironment/CodeEnvironment.php @@ -47,11 +47,7 @@ public function getPhpPath(): string public function getArtisanPath(): string { - if (! $this->useAbsolutePathForMcp()) { - return './artisan'; - } - - return base_path('artisan'); + return $this->useAbsolutePathForMcp() ? base_path('artisan') : './artisan'; } From cbba494311647088dcdaf76e1581b3b5defb3c45 Mon Sep 17 00:00:00 2001 From: Pushpak Chhajed Date: Thu, 14 Aug 2025 18:58:43 +0530 Subject: [PATCH 08/10] refactor: update artisan path resolution to use current working directory --- src/Install/CodeEnvironment/CodeEnvironment.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Install/CodeEnvironment/CodeEnvironment.php b/src/Install/CodeEnvironment/CodeEnvironment.php index 88876193..3ba0ede4 100644 --- a/src/Install/CodeEnvironment/CodeEnvironment.php +++ b/src/Install/CodeEnvironment/CodeEnvironment.php @@ -47,7 +47,7 @@ public function getPhpPath(): string public function getArtisanPath(): string { - return $this->useAbsolutePathForMcp() ? base_path('artisan') : './artisan'; + return $this->useAbsolutePathForMcp() ? getcwd().'/artisan' : './artisan'; } From e0a03cc9726d07dfbdd0ef87c08904edc28275f3 Mon Sep 17 00:00:00 2001 From: Ashley Hindle Date: Thu, 14 Aug 2025 15:16:51 +0100 Subject: [PATCH 09/10] reuse $php for herd install --- src/Console/InstallCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Console/InstallCommand.php b/src/Console/InstallCommand.php index 1905843e..081213f4 100644 --- a/src/Console/InstallCommand.php +++ b/src/Console/InstallCommand.php @@ -492,7 +492,7 @@ private function installMcpServerConfig(): void try { $result = $mcpClient->installMcp( key: 'herd', - command: $mcpClient->getPhpPath(), + command: $php, args: [$this->herd->mcpPath()], env: ['SITE_PATH' => base_path()] ); From 51ce47b3375e75c34c7d078137c517fe00b24ba1 Mon Sep 17 00:00:00 2001 From: Pushpak Chhajed Date: Thu, 14 Aug 2025 20:05:29 +0530 Subject: [PATCH 10/10] refactor: use `base_path` for artisan path resolution --- src/Install/CodeEnvironment/CodeEnvironment.php | 2 +- .../CodeEnvironment/CodeEnvironmentPathResolutionTest.php | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename tests/{Unit => Feature}/Install/CodeEnvironment/CodeEnvironmentPathResolutionTest.php (100%) diff --git a/src/Install/CodeEnvironment/CodeEnvironment.php b/src/Install/CodeEnvironment/CodeEnvironment.php index 3ba0ede4..88876193 100644 --- a/src/Install/CodeEnvironment/CodeEnvironment.php +++ b/src/Install/CodeEnvironment/CodeEnvironment.php @@ -47,7 +47,7 @@ public function getPhpPath(): string public function getArtisanPath(): string { - return $this->useAbsolutePathForMcp() ? getcwd().'/artisan' : './artisan'; + return $this->useAbsolutePathForMcp() ? base_path('artisan') : './artisan'; } diff --git a/tests/Unit/Install/CodeEnvironment/CodeEnvironmentPathResolutionTest.php b/tests/Feature/Install/CodeEnvironment/CodeEnvironmentPathResolutionTest.php similarity index 100% rename from tests/Unit/Install/CodeEnvironment/CodeEnvironmentPathResolutionTest.php rename to tests/Feature/Install/CodeEnvironment/CodeEnvironmentPathResolutionTest.php