Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/BoostServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,10 @@ protected function registerCommands(): void
Console\StartCommand::class,
Console\InstallCommand::class,
Console\UpdateCommand::class,
Console\UpdateSkillsCommand::class,
Console\ExecuteToolCommand::class,
Console\AddSkillCommand::class,
Console\RemoveSkillCommand::class,
]);
}
}
Expand Down
21 changes: 21 additions & 0 deletions src/Console/AddSkillCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@
use Laravel\Boost\Skills\Remote\AuditResult;
use Laravel\Boost\Skills\Remote\GitHubRepository;
use Laravel\Boost\Skills\Remote\GitHubSkillProvider;
use Laravel\Boost\Skills\Remote\InstalledSkill;
use Laravel\Boost\Skills\Remote\RemoteSkill;
use Laravel\Boost\Skills\Remote\SkillAuditor;
use Laravel\Boost\Support\SkillsLock;
use Laravel\Prompts\Terminal;
use RuntimeException;

Expand Down Expand Up @@ -181,6 +183,7 @@ protected function installSkills(): int

grid($results['installedNames']);

$this->writeSkillsLock($skillsToInstall);
$this->runBoostUpdate();
$this->showOutro();
}
Expand Down Expand Up @@ -402,6 +405,24 @@ protected function runBoostUpdate(): void
$this->callSilently(UpdateCommand::class);
}

protected function writeSkillsLock(Collection $skills): void
{
$lock = new SkillsLock;

foreach ($skills as $skill) {
$hash = $this->fetcher->getSkillHash($skill);

if ($hash !== null) {
$lock->addSkill(new InstalledSkill(
name: $skill->name,
source: $skill->repo,
sourceType: 'github',
hash: $hash,
));
}
}
}

protected function showOutro(): void
{
$this->displayOutro('Enjoy the boost 🚀', terminalWidth: $this->terminal->cols());
Expand Down
131 changes: 131 additions & 0 deletions src/Console/RemoveSkillCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
<?php

declare(strict_types=1);

namespace Laravel\Boost\Console;

use const DIRECTORY_SEPARATOR;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;
use Laravel\Boost\Concerns\DisplayHelper;
use Laravel\Boost\Skills\Remote\InstalledSkill;
use Laravel\Boost\Support\SkillsLock;
use Laravel\Prompts\Terminal;

use function Laravel\Prompts\confirm;
use function Laravel\Prompts\grid;
use function Laravel\Prompts\multiselect;

class RemoveSkillCommand extends Command
{
use DisplayHelper;

protected $signature = 'boost:remove-skill';

protected $description = 'Remove installed skills';

protected string $defaultSkillsPath = '.ai/skills';

public function __construct(private readonly Terminal $terminal)
{
parent::__construct();
}

public function handle(): int
{
$this->displayHeader();

$lock = new SkillsLock;

if (! $lock->isValid()) {
$this->error('No skills lock file found.');

return self::FAILURE;
}

$installedSkills = $lock->getSkills();

if ($installedSkills === []) {
$this->warn('No skills found in lock file.');

return self::SUCCESS;
}

$selectedSkills = $this->selectSkills($installedSkills);

if ($selectedSkills === []) {
$this->info('No skills selected.');

return self::SUCCESS;
}

if (stream_isatty(STDIN) && ! confirm(label: 'Remove '.count($selectedSkills).' skill(s)?')) {
return self::SUCCESS;
}

$removedSkills = $this->removeSkills($lock, $selectedSkills);

$this->info('Skills removed:');
grid($removedSkills);

$this->info('Skill removal completed.');

return self::SUCCESS;
}

/**
* @param array<string, InstalledSkill> $installedSkills
* @return array<int, string>
*/
protected function selectSkills(array $installedSkills): array
{
$options = [];

foreach ($installedSkills as $name => $skill) {
$options[$name] = sprintf('%s (%s)', $name, $skill->source);
}

/** @var array<int, string> $selected */
$selected = multiselect(
label: 'Select skills to remove',
options: $options,
scroll: 10,
required: false,
hint: 'Leave empty to cancel',
);

return $selected;
}

/**
* @param array<int, string> $selectedSkills
* @return array<int, string>
*/
protected function removeSkills(SkillsLock $lock, array $selectedSkills): array
{
$removedSkills = [];

foreach ($selectedSkills as $skillName) {
$lock->removeSkill($skillName);

$path = base_path($this->defaultSkillsPath.DIRECTORY_SEPARATOR.$skillName);

if (is_dir($path)) {
File::deleteDirectory($path);
}

$removedSkills[] = $skillName;
}

sort($removedSkills);

return $removedSkills;
}

protected function displayHeader(): void
{
$this->terminal->initDimensions();
$this->displayBoostHeader('Skill Remove', config('app.name'));
}
}
13 changes: 11 additions & 2 deletions src/Console/UpdateCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ class UpdateCommand extends Command
/** @var string */
protected $signature = 'boost:update
{--discover : Discover and prompt for newly available guidelines and skills}
{--ignore-skills : Skip updating the skills directory}';
{--ignore-skills : Skip updating the skills directory}
{--update-skills : Update installed skills to latest versions}';

public function handle(Config $config): int
{
Expand All @@ -28,6 +29,10 @@ public function handle(Config $config): int
return self::FAILURE;
}

if ($this->option('update-skills')) {
return $this->updateInstalledSkills();
}

if ($this->option('discover')) {
$this->discoverNewContent($config);
}
Expand All @@ -50,12 +55,16 @@ public function handle(Config $config): int
return self::SUCCESS;
}

protected function updateInstalledSkills(): int
{
return $this->call(UpdateSkillsCommand::class);
}

protected function discoverNewContent(Config $config): void
{
$newPackages = $this->resolveNewPackages($config);

if ($newPackages->isNotEmpty()) {
/** @var array<int, string> $selectedPackages */
$selectedPackages = multiselect(
label: 'New packages with guidelines/skills discovered! Which would you like to add?',
options: $newPackages
Expand Down
Loading
Loading