Skip to content

Commit 8ed8e23

Browse files
authored
Merge branch 'main' into update_rector_rules
2 parents 21e9ba5 + 35ad5a9 commit 8ed8e23

16 files changed

+302
-50
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
# Release Notes
22

3-
## [Unreleased](https://github.com/laravel/boost/compare/v1.5.1...main)
3+
## [Unreleased](https://github.com/laravel/boost/compare/v1.6.0...main)
4+
5+
## [v1.6.0](https://github.com/laravel/boost/compare/v1.5.1...v1.6.0) - 2025-10-28
6+
7+
* [1.x] Add support for markdown files by [@adrum](https://github.com/adrum) in https://github.com/laravel/boost/pull/319
48

59
## [v1.5.1](https://github.com/laravel/boost/compare/v1.5.0...v1.5.1) - 2025-10-25
610

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ You may also automate this process by adding it to your Composer "post-update-cm
145145

146146
## Adding Custom AI Guidelines
147147

148-
To augment Laravel Boost with your own custom AI guidelines, add `.blade.php` files to your application's `.ai/guidelines/*` directory. These files will automatically be included with Laravel Boost's guidelines when you run `boost:install`.
148+
To augment Laravel Boost with your own custom AI guidelines, add `.blade.php` or `.md` files to your application's `.ai/guidelines/*` directory. These files will automatically be included with Laravel Boost's guidelines when you run `boost:install`.
149149

150150
### Overriding Boost AI Guidelines
151151

src/BoostManager.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Laravel\Boost\Install\CodeEnvironment\Codex;
1111
use Laravel\Boost\Install\CodeEnvironment\Copilot;
1212
use Laravel\Boost\Install\CodeEnvironment\Cursor;
13+
use Laravel\Boost\Install\CodeEnvironment\OpenCode;
1314
use Laravel\Boost\Install\CodeEnvironment\PhpStorm;
1415
use Laravel\Boost\Install\CodeEnvironment\VSCode;
1516

@@ -23,6 +24,7 @@ class BoostManager
2324
'claudecode' => ClaudeCode::class,
2425
'codex' => Codex::class,
2526
'copilot' => Copilot::class,
27+
'opencode' => OpenCode::class,
2628
];
2729

2830
/**

src/Install/CodeEnvironment/ClaudeCode.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public function systemDetectionConfig(Platform $platform): array
2525
{
2626
return match ($platform) {
2727
Platform::Darwin, Platform::Linux => [
28-
'command' => 'which claude',
28+
'command' => 'command -v claude',
2929
],
3030
Platform::Windows => [
3131
'command' => 'where claude 2>nul',

src/Install/CodeEnvironment/CodeEnvironment.php

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,12 @@ public function mcpConfigKey(): string
129129
return 'mcpServers';
130130
}
131131

132+
/** @return array<string, mixed> */
133+
public function defaultMcpConfig(): array
134+
{
135+
return [];
136+
}
137+
132138
/**
133139
* Install MCP server using the appropriate strategy.
134140
*
@@ -144,6 +150,22 @@ public function installMcp(string $key, string $command, array $args = [], array
144150
};
145151
}
146152

153+
/**
154+
* Build the MCP server configuration payload for file-based installation.
155+
*
156+
* @param array<int, string> $args
157+
* @param array<string, string> $env
158+
* @return array<string, mixed>
159+
*/
160+
public function mcpServerConfig(string $command, array $args = [], array $env = []): array
161+
{
162+
return [
163+
'command' => $command,
164+
'args' => $args,
165+
'env' => $env,
166+
];
167+
}
168+
147169
/**
148170
* Install MCP server using a shell command strategy.
149171
*
@@ -198,9 +220,9 @@ protected function installFileMcp(string $key, string $command, array $args = []
198220
return false;
199221
}
200222

201-
return (new FileWriter($path))
223+
return (new FileWriter($path, $this->defaultMcpConfig()))
202224
->configKey($this->mcpConfigKey())
203-
->addServer($key, $command, $args, $env)
225+
->addServerConfig($key, $this->mcpServerConfig($command, $args, $env))
204226
->save();
205227
}
206228
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Laravel\Boost\Install\CodeEnvironment;
6+
7+
use Laravel\Boost\Contracts\Agent;
8+
use Laravel\Boost\Contracts\McpClient;
9+
use Laravel\Boost\Install\Enums\McpInstallationStrategy;
10+
use Laravel\Boost\Install\Enums\Platform;
11+
12+
class OpenCode extends CodeEnvironment implements Agent, McpClient
13+
{
14+
public function name(): string
15+
{
16+
return 'opencode';
17+
}
18+
19+
public function displayName(): string
20+
{
21+
return 'OpenCode';
22+
}
23+
24+
public function systemDetectionConfig(Platform $platform): array
25+
{
26+
return match ($platform) {
27+
Platform::Darwin, Platform::Linux => [
28+
'command' => 'command -v opencode',
29+
],
30+
Platform::Windows => [
31+
'command' => 'where opencode 2>nul',
32+
],
33+
};
34+
}
35+
36+
public function projectDetectionConfig(): array
37+
{
38+
return [
39+
'files' => ['AGENTS.md', 'opencode.json'],
40+
];
41+
}
42+
43+
public function mcpInstallationStrategy(): McpInstallationStrategy
44+
{
45+
return McpInstallationStrategy::FILE;
46+
}
47+
48+
public function mcpConfigPath(): string
49+
{
50+
return 'opencode.json';
51+
}
52+
53+
public function guidelinesPath(): string
54+
{
55+
return 'AGENTS.md';
56+
}
57+
58+
public function mcpConfigKey(): string
59+
{
60+
return 'mcp';
61+
}
62+
63+
/** {@inheritDoc} */
64+
public function defaultMcpConfig(): array
65+
{
66+
return [
67+
'$schema' => 'https://opencode.ai/config.json',
68+
];
69+
}
70+
71+
/** {@inheritDoc} */
72+
public function mcpServerConfig(string $command, array $args = [], array $env = []): array
73+
{
74+
return [
75+
'type' => 'local',
76+
'enabled' => true,
77+
'command' => [$command, ...$args],
78+
'environment' => $env,
79+
];
80+
}
81+
}

src/Install/CodeEnvironment/VSCode.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public function systemDetectionConfig(Platform $platform): array
2626
'paths' => ['/Applications/Visual Studio Code.app'],
2727
],
2828
Platform::Linux => [
29-
'command' => 'which code',
29+
'command' => 'command -v code',
3030
],
3131
Platform::Windows => [
3232
'paths' => [

src/Install/GuidelineComposer.php

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -244,14 +244,38 @@ protected function guidelinesDir(string $dirPath, bool $thirdParty = false): arr
244244
$finder = Finder::create()
245245
->files()
246246
->in($dirPath)
247-
->name('*.blade.php');
247+
->name('*.blade.php')
248+
->name('*.md');
248249
} catch (DirectoryNotFoundException) {
249250
return [];
250251
}
251252

252253
return array_map(fn (SplFileInfo $file): array => $this->guideline($file->getRealPath(), $thirdParty), iterator_to_array($finder));
253254
}
254255

256+
protected function renderContent(string $content, string $path): string
257+
{
258+
$isBladeTemplate = str_ends_with($path, '.blade.php');
259+
260+
if (! $isBladeTemplate) {
261+
return $content;
262+
}
263+
264+
// Temporarily replace backticks and PHP opening tags with placeholders before Blade processing
265+
// This prevents Blade from trying to execute PHP code examples and supports inline code
266+
$placeholders = [
267+
'`' => '___SINGLE_BACKTICK___',
268+
'<?php' => '___OPEN_PHP_TAG___',
269+
];
270+
271+
$content = str_replace(array_keys($placeholders), array_values($placeholders), $content);
272+
$rendered = Blade::render($content, [
273+
'assist' => $this->guidelineAssist,
274+
]);
275+
276+
return str_replace(array_values($placeholders), array_keys($placeholders), $rendered);
277+
}
278+
255279
/**
256280
* @return array{content: string, name: string, description: string, path: ?string, custom: bool, third_party: bool}
257281
*/
@@ -272,18 +296,8 @@ protected function guideline(string $path, bool $thirdParty = false): array
272296
$content = file_get_contents($path);
273297
$content = $this->processBoostSnippets($content);
274298

275-
// Temporarily replace backticks and PHP opening tags with placeholders before Blade processing
276-
// This prevents Blade from trying to execute PHP code examples and supports inline code
277-
$placeholders = [
278-
'`' => '___SINGLE_BACKTICK___',
279-
'<?php' => '___OPEN_PHP_TAG___',
280-
];
299+
$rendered = $this->renderContent($content, $path);
281300

282-
$content = str_replace(array_keys($placeholders), array_values($placeholders), $content);
283-
$rendered = Blade::render($content, [
284-
'assist' => $this->guidelineAssist,
285-
]);
286-
$rendered = str_replace(array_values($placeholders), array_keys($placeholders), $rendered);
287301
$rendered = str_replace(array_keys($this->storedSnippets), array_values($this->storedSnippets), $rendered);
288302

289303
$this->storedSnippets = []; // Clear for next use
@@ -298,7 +312,7 @@ protected function guideline(string $path, bool $thirdParty = false): array
298312

299313
return [
300314
'content' => trim($rendered),
301-
'name' => str_replace('.blade.php', '', basename($path)),
315+
'name' => str_replace(['.blade.php', '.md'], '', basename($path)),
302316
'description' => $description,
303317
'path' => $path,
304318
'custom' => str_contains($path, $this->customGuidelinePath()),
@@ -326,16 +340,21 @@ protected function processBoostSnippets(string $content): string
326340

327341
protected function prependPackageGuidelinePath(string $path): string
328342
{
329-
$path = preg_replace('/\.blade\.php$/', '', $path);
330-
331-
return str_replace('/', DIRECTORY_SEPARATOR, __DIR__.'/../../.ai/'.$path.'.blade.php');
343+
return $this->prependGuidelinePath($path, __DIR__.'/../../.ai/');
332344
}
333345

334346
protected function prependUserGuidelinePath(string $path): string
335347
{
336-
$path = preg_replace('/\.blade\.php$/', '', $path);
348+
return $this->prependGuidelinePath($path, $this->customGuidelinePath());
349+
}
350+
351+
private function prependGuidelinePath(string $path, string $basePath): string
352+
{
353+
if (! str_ends_with($path, '.md') && ! str_ends_with($path, '.blade.php')) {
354+
$path .= '.blade.php';
355+
}
337356

338-
return str_replace('/', DIRECTORY_SEPARATOR, $this->customGuidelinePath($path.'.blade.php'));
357+
return str_replace('/', DIRECTORY_SEPARATOR, $basePath.$path);
339358
}
340359

341360
protected function guidelinePath(string $path): ?string

src/Install/Mcp/FileWriter.php

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class FileWriter
1515

1616
protected int $defaultIndentation = 8;
1717

18-
public function __construct(protected string $filePath) {}
18+
public function __construct(protected string $filePath, protected array $baseConfig = []) {}
1919

2020
public function configKey(string $key): self
2121
{
@@ -25,17 +25,28 @@ public function configKey(string $key): self
2525
}
2626

2727
/**
28-
* @param string $key MCP Server Name
28+
* @deprecated Use addServerConfig() for array-based configuration.
29+
*
2930
* @param array<int, string> $args
3031
* @param array<string, string> $env
3132
*/
3233
public function addServer(string $key, string $command, array $args = [], array $env = []): self
3334
{
34-
$this->serversToAdd[$key] = collect([
35+
return $this->addServerConfig($key, collect([
3536
'command' => $command,
3637
'args' => $args,
3738
'env' => $env,
38-
])->filter()->toArray();
39+
])->filter(fn ($value): bool => ! in_array($value, [[], null, ''], true))->toArray());
40+
}
41+
42+
/**
43+
* @param array<string, mixed> $config
44+
*/
45+
public function addServerConfig(string $key, array $config): self
46+
{
47+
$this->serversToAdd[$key] = collect($config)
48+
->filter(fn ($value): bool => ! in_array($value, [[], null, ''], true))
49+
->toArray();
3950

4051
return $this;
4152
}
@@ -358,7 +369,7 @@ protected function hasUnquotedComments(string $content): bool
358369

359370
protected function createNewFile(): bool
360371
{
361-
$config = [];
372+
$config = $this->baseConfig;
362373
$this->addServersToConfig($config);
363374

364375
return $this->writeJsonConfig($config);

0 commit comments

Comments
 (0)