Skip to content

Commit e7f5121

Browse files
committed
feat: improve package ai guideline install using Roster->packages()
messy WIP for MCP Installation - still exploring
1 parent b549392 commit e7f5121

File tree

18 files changed

+173
-107
lines changed

18 files changed

+173
-107
lines changed

.ai/core.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ The Laravel Boost Guidelines are specifically curated by Laravel maintainers for
55
{project.purpose}
66
</purpose-of-this-project>
77

8-
TODO: Add project structure / relevant models / etc.. ? Kind of like Claude's /init, but for every Laravel developer regardless of IDE ? But if they already have that in Claude.md then that's gonna be doubling up and wasting tokens
8+
# Conventions
9+
Follow existing conventions. When creating or editing a file, check sibling files for the correct structure, approach, naming.
File renamed without changes.
File renamed without changes.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1+
## InertiaJS Laravel Package
2+
13
Super core inertia js laravel package

README.md

Lines changed: 10 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,56 +7,36 @@
77
<a href="https://packagist.org/packages/laravel/boost"><img src="https://img.shields.io/packagist/l/boost" alt="License"></a>
88
</p>
99

10-
> This is a template repository for new Laravel AI
11-
> Assistants. [Start a new repo with this](https://github.com/laravel/boost/generate), clone it locally and search &
12-
> replace the relevant things below:
13-
>
14-
> - `Laravel AI Assistant` with the package name (e.g. `Laravel Horizon`)
15-
> - `boost` references to the vendor name / GitHub url (e.g. `laravel/horizon`) (*)
16-
> - `boost` references to the publishing name (e.g. `horizon`) (*)
17-
> - `Laravel\Boost` references to the package namespace (e.g. `Laravel\Horizon`) (*)
18-
> - `Boost` references to the short package name (e.g. `Horizon`) (*)
19-
> - `BOOST_` references to the env variable names (e.g. `HORIZON`) (*)
20-
>
21-
> (*) Name cannot contain spaces.
22-
>
23-
> After replacing keywords, take the following steps:
24-
>
25-
> 1. Rename any `Boost` prefixes in `.php` file names in [`src`](./src) to the package name (e.g. `Horizon`)
26-
> 2. Remove things you don't need like migrations, routes, resources, etc
27-
> 3. Fill the package short intro and keywords in the [composer.json](./composer.json) file
28-
> 4. Set the same short intro and keywords in the GitHub repository sidebar and set the website url to the package docs
2910
> 5. Fill out the package long introduction in the readme
30-
> 6. Set the correct link to the docs in the readme
3111
> 7. Replace the `art/logo.svg` with the new package logo
3212
> 8. Replace the `public/favicon.ico` with the new package favicon (optional)
3313
> 9. Remove this quote block from your readme
34-
>
35-
> All that's left for you is to start building your new package! 🛠
14+
> 10. Write a great README
3615
3716
## Introduction
3817

39-
Package introduction...
40-
./artisan vendor:publish --tag=boost-config
18+
- `composer require laravel/boost`
19+
- `./artisan vendor:publish --tag=boost-config`
20+
- `./artisan boost:install`
21+
22+
> [!IMPORTANT]
23+
> Boost is currently in Beta, is subject to change prior to the v1.0.0 release, and will be updated frequently. All notable changes will be documented in the [changelog](./CHANGELOG.md).
4124
4225
## Official Documentation
4326

4427
Documentation for Boost can be found on the [Laravel website](https://laravel.com/docs).
4528

4629
## Contributing
4730

48-
Thank you for considering contributing to Boost! The contribution guide can be found in
49-
the [Laravel documentation](https://laravel.com/docs/contributions).
31+
Thank you for considering contributing to Boost! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).
5032

5133
## Code of Conduct
5234

53-
In order to ensure that the Laravel community is welcoming to all, please review and abide by
54-
the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).
35+
In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).
5536

5637
## Security Vulnerabilities
5738

58-
Please review [our security policy](https://github.com/laravel/envoy/security/policy) on how to report security
59-
vulnerabilities.
39+
Please review [our security policy](https://github.com/laravel/boost/security/policy) on how to report security vulnerabilities.
6040

6141
## License
6242

src/Console/InstallCommand.php

Lines changed: 68 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use Laravel\Roster\Enums\Packages;
1414
use Laravel\Roster\Roster;
1515
use Symfony\Component\Console\Attribute\AsCommand;
16+
use Symfony\Component\Finder\Exception\DirectoryNotFoundException;
1617
use Symfony\Component\Finder\Finder;
1718

1819
use function Laravel\Prompts\intro;
@@ -82,20 +83,28 @@ protected function query()
8283
// $this->boostToolsToDisable = $this->boostToolsToDisable(); // Not useful to start
8384

8485
$this->projectPurpose = $this->projectPurpose();
85-
$this->enforceTests = $this->shouldEnforceTests(ask: false); // TODO: Only add 'all new code must have a test' guideline if enforced
86-
$this->idesToInstallTo = $this->idesToInstallTo(); // To add boost:mcp to the correct file
86+
$this->enforceTests = $this->shouldEnforceTests(ask: false);
8787

88-
// TODO: Only if in $boosttoInstall or whatever
88+
$this->idesToInstallTo = $this->idesToInstallTo(); // To add boost:mcp to the correct file
8989
$this->agentsToInstallTo = $this->agentsToInstallTo(); // AI Guidelines, which file do they go, are they separated, or all in one file?
9090
}
9191

9292
protected function enact()
9393
{
94-
$composedAiGuidelines = $this->compose();
95-
if ($this->installingGuidelines()) {
96-
$this->enactGuidelines($composedAiGuidelines);
94+
if ($this->installingGuidelines() && !empty($this->agentsToInstallTo)) {
95+
$this->enactGuidelines($this->compose());
96+
}
97+
98+
if ($this->installingMcp() && !empty($this->idesToInstallTo)) {
99+
echo "\ninstalling mcps now to: ";
100+
dump($this->idesToInstallTo);
101+
}
102+
103+
if ($this->installingHerdMcp() && !empty($this->idesToInstallTo)) {
104+
echo "\ninstalling herd mcp now to: ";
105+
dump($this->idesToInstallTo);
97106
}
98-
// $this->enactMcp();
107+
99108

100109
if (in_array('other', $this->idesToInstallTo)) {
101110
$this->newLine();
@@ -108,6 +117,8 @@ protected function compose(): string
108117
// TODO: Just move to blade views and compact public properties?
109118
$composed = collect(['core' => $this->guideline('core.md', [
110119
'{project.purpose}' => $this->projectPurpose,
120+
// TODO: Add package info, php version, laravel version, existing approaches, directory structure, models? General Laravel guidance that applies to all projects somehow? 'Follow existing conventions - if you are creating or editing a file, check sibling files for structure/approach/naming
121+
// TODO: Add project structure / relevant models / etc.. ? Kind of like Claude's /init, but for every Laravel developer regardless of IDE ? But if they already have that in Claude.md then that's gonna be doubling up and wasting tokens
111122
])]);
112123

113124
if (str_contains(config('app.url'), '.test') && $this->isHerdInstalled()) {
@@ -116,44 +127,61 @@ protected function compose(): string
116127
]));
117128
}
118129

119-
// TODO: Improve • this is a horrible way to do this
130+
if ($this->installingStyleGuidelines()) {
131+
$composed->put('laravel/style', $this->guideline('laravel/style.md'));
132+
}
133+
134+
// Add all core.md and version specific docs for Roster supported packages
135+
// We don't add guidelines for packages not supported by Roster right now
136+
foreach ($this->roster->packages() as $package) {
137+
$guidelineDir = str_replace('_', '-', strtolower($package->name()));
138+
$coreGuidelines = $this->guideline($guidelineDir . '/core.md'); // Add core
139+
if ($coreGuidelines) {
140+
$composed->put($guidelineDir . '/core', $coreGuidelines);
141+
}
120142

121-
if ($this->roster->usesVersion(Packages::INERTIA_LARAVEL, '2.0.0', '>=')) {
122-
$composed->put('inertiajs-laravel/core', $this->guideline('inertiajs-laravel/core.md', []));
123-
$composed->put('inertiajs-laravel/v2', $this->guidelines('inertiajs-laravel/2/'));
143+
$composed->put(
144+
$guidelineDir . '/v' . $package->majorVersion(),
145+
$this->guidelines($guidelineDir . '/' . $package->majorVersion())
146+
);
124147
}
125148

126-
if ($this->shouldEnforceTests()) {
149+
if ($this->enforceTests) {
127150
$composed->put('tests', $this->guideline('enforce-tests.md'));
128151
}
129-
return $composed->map(fn($content, $key) => "# {$key}\n{$content}\n")
152+
153+
return $composed->whereNotNull()->map(fn($content, $key) => "# {$key}\n{$content}\n")
130154
->join("\n\n====\n\n");
131155
}
132156

133-
protected function guidelines(string $dirPath, array $replacements = []): string
157+
protected function guidelines(string $dirPath, array $replacements = []): ?string
134158
{
135159
$dirPath = str_replace('/', DIRECTORY_SEPARATOR, __DIR__ . '/../../.ai/' . $dirPath);
136-
$finder = Finder::create()
137-
->files()
138-
->in($dirPath)
139-
->name('*.md');
160+
try {
161+
$finder = Finder::create()
162+
->files()
163+
->in($dirPath)
164+
->name('*.md');
165+
} catch (DirectoryNotFoundException $e) {
166+
return null;
167+
}
140168

141169
$guidelines = '';
142170
foreach ($finder as $file) {
143-
$guidelines .= $this->guideline($file->getRealPath(), $replacements);
171+
$guidelines .= $this->guideline($file->getRealPath(), $replacements) ?? '';
144172
}
145173

146174
return $guidelines;
147175
}
148176

149-
protected function guideline(string $path, array $replacements = []): string
177+
protected function guideline(string $path, array $replacements = []): ?string
150178
{
151179
if (!file_exists($path)) {
152180
$path = str_replace('/', DIRECTORY_SEPARATOR, __DIR__ . '/../../.ai/' . $path);
153181
}
154182

155183
if (!file_exists($path)) {
156-
throw new \Exception("$path does not exist");
184+
return null;
157185
}
158186

159187
$contents = file_get_contents($path);
@@ -300,13 +328,13 @@ private function intro()
300328
HEADER
301329
);
302330
intro('✦ Laravel Boost :: Install :: We Must Ship ✦');
303-
$this->line(' Let\'s setup Laravel Boost in your IDEs for ' . $this->colors->bgYellow($this->colors->black($this->projectName)));
331+
$this->line(' Let\'s give ' . $this->colors->bgYellow($this->colors->black($this->projectName)) . ' a Boost');
304332
}
305333

306334
protected function projectPurpose(): string
307335
{
308336
return text(
309-
label: 'What does this project do? (optional)',
337+
label: sprintf('What does %s project do? (optional)', $this->projectName),
310338
placeholder: 'i.e. SaaS platform selling concert tickets, integrates with Stripe and Twilio, lots of CS using Nova backend',
311339
hint: 'This helps guides AI. How would you explain it to a new developer?'
312340
);
@@ -431,7 +459,7 @@ protected function agentsToInstallTo(): Collection
431459
ksort($agents);
432460

433461
$selectedAgentClasses = collect(multiselect(
434-
label: 'Which agents need AI guidelines?',
462+
label: sprintf('Which agents need AI guidelines for %s?', $this->projectName),
435463
options: $agents,
436464
default: ['Laravel\\Boost\\Install\\Agents\\ClaudeCode'],//array_keys($agents),
437465
scroll: 4, // TODO: use detection to auto-select
@@ -496,6 +524,21 @@ protected function enactGuidelines(string $composedAiGuidelines): void
496524

497525
protected function installingGuidelines(): bool
498526
{
499-
return in_array('ai_guidelines', $this->boostToInstall);
527+
return in_array('ai_guidelines', $this->boostToInstall, true);
528+
}
529+
530+
protected function installingStyleGuidelines(): bool
531+
{
532+
return in_array('style_guidelines', $this->boostToInstall, true);
533+
}
534+
535+
protected function installingMcp(): bool
536+
{
537+
return in_array('mcp_server', $this->boostToInstall, true);
538+
}
539+
540+
protected function installingHerdMcp(): bool
541+
{
542+
return in_array('herd_mcp', $this->boostToInstall, true);
500543
}
501544
}

src/Contracts/Agent.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// We give Agents AI Rules
66
interface Agent
77
{
8-
public function path(): string;
8+
public function guidelinesPath(): string;
99

1010
public function frontmatter(): bool;
1111
}

src/Contracts/Ide.php

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,5 @@ interface Ide
77
{
88
// Things to note: supports relative (absolute path required)? global mcp only? Prefer local file, but if global only we have to add the project name to the server name
99

10-
/**
11-
* Install MCP server to this IDE.
12-
* Should be safe to re-run.
13-
* Should work well with others.
14-
*/
15-
public function installMcp(string $command, array $args): bool;
10+
1611
}

src/Install/Agents/ClaudeCode.php

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33
namespace Laravel\Boost\Install\Agents;
44

55
use Laravel\Boost\Contracts\Agent;
6-
use Laravel\Boost\Contracts\Ide;
6+
use Laravel\Boost\Install\Agents\ShellMcpIde;
77

8-
class ClaudeCode implements Agent, Ide
8+
class ClaudeCode extends ShellMcpIde implements Agent
99
{
10-
public function path(): string
10+
protected string $shellCommand = 'claude mcp add laravel-boost {command} {args}';
11+
12+
public function guidelinesPath(): string
1113
{
1214
return 'CLAUDE.md';
1315
}
@@ -16,9 +18,4 @@ public function frontmatter(): bool
1618
{
1719
return false;
1820
}
19-
20-
public function installMcp(string $command, array $args): bool
21-
{
22-
return true;
23-
}
2421
}

src/Install/Agents/Copilot.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
class Copilot implements Agent
88
{
9-
public function path(): string
9+
public function guidelinesPath(): string
1010
{
1111
// VS Code supports multiple files in .github/instructions/
1212
// But, other IDEs don't
@@ -15,6 +15,9 @@ public function path(): string
1515

1616
public function frontmatter(): bool
1717
{
18+
// If we use the multi file approach we can use frontmatter
19+
// In VSCode at least https://docs.github.com/en/copilot/how-tos/configure-custom-instructions/add-repository-instructions?tool=vscode
20+
1821
return false;
1922
}
2023
}

0 commit comments

Comments
 (0)