diff --git a/src/Install/CodeEnvironment/ClaudeCode.php b/src/Install/CodeEnvironment/ClaudeCode.php index daefbcc0..3932fb46 100644 --- a/src/Install/CodeEnvironment/ClaudeCode.php +++ b/src/Install/CodeEnvironment/ClaudeCode.php @@ -25,7 +25,7 @@ public function systemDetectionConfig(Platform $platform): array { return match ($platform) { Platform::Darwin, Platform::Linux => [ - 'command' => 'which claude', + 'command' => 'command -v claude', ], Platform::Windows => [ 'command' => 'where claude 2>null', diff --git a/src/Install/CodeEnvironment/CodeEnvironment.php b/src/Install/CodeEnvironment/CodeEnvironment.php index fe4a4b5a..0b79409e 100644 --- a/src/Install/CodeEnvironment/CodeEnvironment.php +++ b/src/Install/CodeEnvironment/CodeEnvironment.php @@ -100,6 +100,12 @@ public function mcpConfigKey(): string return 'mcpServers'; } + /** @return array */ + public function newMcpConfig(): array + { + return []; + } + /** * Install MCP server using the appropriate strategy. * @@ -174,17 +180,30 @@ protected function installFileMcp(string $key, string $command, array $args = [] $config = File::exists($path) ? json_decode(File::get($path), true) ?: [] - : []; + : $this->newMcpConfig(); $mcpKey = $this->mcpConfigKey(); - data_set($config, "{$mcpKey}.{$key}", collect([ - 'command' => $command, - 'args' => $args, - 'env' => $env, - ])->filter()->toArray()); + $mcpConfig = $this->buildMcpConfig($command, $args, $env); + data_set($config, "{$mcpKey}.{$key}", $mcpConfig); $json = json_encode($config, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); return $json && File::put($path, $json); } + + /** + * Build MCP config array. + * + * @param array $args + * @param array $env + * @return array + */ + protected function buildMcpConfig(string $command, array $args = [], array $env = []): array + { + return collect([ + 'command' => $command, + 'args' => $args, + 'env' => $env, + ])->filter()->toArray(); + } } diff --git a/src/Install/CodeEnvironment/OpenCode.php b/src/Install/CodeEnvironment/OpenCode.php new file mode 100644 index 00000000..5fff4a44 --- /dev/null +++ b/src/Install/CodeEnvironment/OpenCode.php @@ -0,0 +1,81 @@ + [ + 'command' => 'command -v opencode', + ], + Platform::Windows => [ + 'command' => 'where opencode 2>null', + ], + }; + } + + public function projectDetectionConfig(): array + { + return [ + 'files' => ['AGENTS.md', 'opencode.json'], + ]; + } + + public function mcpInstallationStrategy(): McpInstallationStrategy + { + return McpInstallationStrategy::FILE; + } + + public function mcpConfigPath(): string + { + return 'opencode.json'; + } + + public function guidelinesPath(): string + { + return 'AGENTS.md'; + } + + public function mcpConfigKey(): string + { + return 'mcp'; + } + + /** @inheritDoc */ + public function newMcpConfig(): array + { + return [ + '$schema' => 'https://opencode.ai/config.json', + ]; + } + + /** @inheritDoc */ + protected function buildMcpConfig(string $command, array $args = [], array $env = []): array + { + return collect([ + 'type' => 'local', + 'enabled' => true, + 'command' => [$command, ...$args], + 'env' => $env, + ])->filter()->toArray(); + } +} diff --git a/src/Install/CodeEnvironment/VSCode.php b/src/Install/CodeEnvironment/VSCode.php index 97f891af..4a1d2ae6 100644 --- a/src/Install/CodeEnvironment/VSCode.php +++ b/src/Install/CodeEnvironment/VSCode.php @@ -26,7 +26,7 @@ public function systemDetectionConfig(Platform $platform): array 'paths' => ['/Applications/Visual Studio Code.app'], ], Platform::Linux => [ - 'command' => 'which code', + 'command' => 'command -v code', ], Platform::Windows => [ 'paths' => [ diff --git a/src/Install/CodeEnvironmentsDetector.php b/src/Install/CodeEnvironmentsDetector.php index 530c0ee8..0c83b6f0 100644 --- a/src/Install/CodeEnvironmentsDetector.php +++ b/src/Install/CodeEnvironmentsDetector.php @@ -10,6 +10,7 @@ use Laravel\Boost\Install\CodeEnvironment\CodeEnvironment; use Laravel\Boost\Install\CodeEnvironment\Copilot; use Laravel\Boost\Install\CodeEnvironment\Cursor; +use Laravel\Boost\Install\CodeEnvironment\OpenCode; use Laravel\Boost\Install\CodeEnvironment\PhpStorm; use Laravel\Boost\Install\CodeEnvironment\VSCode; use Laravel\Boost\Install\Enums\Platform; @@ -23,6 +24,7 @@ class CodeEnvironmentsDetector 'cursor' => Cursor::class, 'claudecode' => ClaudeCode::class, 'copilot' => Copilot::class, + 'opencode' => OpenCode::class, ]; public function __construct( diff --git a/tests/Unit/Install/CodeEnvironmentsDetectorTest.php b/tests/Unit/Install/CodeEnvironmentsDetectorTest.php index 5ec57c38..d3bc457d 100644 --- a/tests/Unit/Install/CodeEnvironmentsDetectorTest.php +++ b/tests/Unit/Install/CodeEnvironmentsDetectorTest.php @@ -40,6 +40,7 @@ $container->bind(\Laravel\Boost\Install\CodeEnvironment\VSCode::class, fn () => $program2); $container->bind(\Laravel\Boost\Install\CodeEnvironment\Cursor::class, fn () => $program3); $container->bind(\Laravel\Boost\Install\CodeEnvironment\ClaudeCode::class, fn () => $otherProgram); + $container->bind(\Laravel\Boost\Install\CodeEnvironment\OpenCode::class, fn () => $otherProgram); $container->bind(\Laravel\Boost\Install\CodeEnvironment\Copilot::class, fn () => $otherProgram); $detector = new CodeEnvironmentsDetector($container); @@ -64,6 +65,7 @@ $container->bind(\Laravel\Boost\Install\CodeEnvironment\VSCode::class, fn () => $otherProgram); $container->bind(\Laravel\Boost\Install\CodeEnvironment\Cursor::class, fn () => $otherProgram); $container->bind(\Laravel\Boost\Install\CodeEnvironment\ClaudeCode::class, fn () => $otherProgram); + $container->bind(\Laravel\Boost\Install\CodeEnvironment\OpenCode::class, fn () => $otherProgram); $container->bind(\Laravel\Boost\Install\CodeEnvironment\Copilot::class, fn () => $otherProgram); $detector = new CodeEnvironmentsDetector($container); @@ -174,6 +176,20 @@ rmdir($tempDir); }); +test('discoverProjectInstalledCodeEnvironments detects opencode with file', function (string $file) { + $tempDir = sys_get_temp_dir().'/boost_test_'.uniqid(); + mkdir($tempDir); + file_put_contents($tempDir.'/'.$file, 'test'); + + $detected = $this->detector->discoverProjectInstalledCodeEnvironments($tempDir); + + expect($detected)->toContain('opencode'); + + // Cleanup + unlink($tempDir.'/'.$file); + rmdir($tempDir); +})->with(['AGENTS.md', 'opencode.json']); + test('discoverProjectInstalledCodeEnvironments detects phpstorm with idea directory', function () { $tempDir = sys_get_temp_dir().'/boost_test_'.uniqid(); mkdir($tempDir);