diff --git a/.cursorrules b/.cursorrules index b79a0c9..87356e0 100644 --- a/.cursorrules +++ b/.cursorrules @@ -1,37 +1 @@ -# Cloud CLI Guidelines - -## Project Overview - -This is a Laravel Zero CLI tool for deploying applications to Laravel Cloud. - -## Code Style - -- Follow Laravel/PSR-12 conventions -- Run `./vendor/bin/pint --dirty` after modifying PHP files -- Use Laravel Prompts for all user interactions (confirm, select, text, password, info, warning, error) - -## Architecture - -- Commands live in `app/Commands/` -- `app/Git.php` handles all git and GitHub CLI operations -- `app/ConfigRepository.php` manages user config stored in `~/.config/cloud/config.json` -- `app/ProcessResult.php` wraps command execution results - -## Conventions - -- Use `gh` CLI for GitHub API interactions rather than direct HTTP calls -- Constructor methods with empty bodies should contain a single empty comment -- Non-public methods/properties should be `protected`, not `private` -- Limit comments to non-obvious code only -- For long command signatures, separate the arguments and concatonate them in the property to make it more readable (leading space) -- Never use the helper methods in `Command`, always use Prompts helper functions - -## Dependencies - -- Laravel Zero 12.x -- PHP 8.2+ -- Requires GitHub CLI (`gh`) to be installed and authenticated - -## Cloud API - -https://cloud.laravel.com/docs/api/introduction +See CLAUDE.md in the project root for project guidelines, layout, and conventions. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..1a2c47b --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,56 @@ +# Cloud CLI + +Laravel Zero CLI for managing apps on [Laravel Cloud](https://cloud.laravel.com). PHP 8.3+. Run locally with `php cloud `. + +## Commands to run + +```sh +vendor/bin/pest # tests +vendor/bin/pest --filter=Cache # single test +vendor/bin/pint --dirty # format (run after editing PHP) +vendor/bin/phpstan analyse # static analysis, level 5 +``` + +Point at a local API with `CLOUD_BASE_URL` in `.env`. `LARAVEL_CLOUD_TOKEN` overrides stored tokens. + +## Layout + +| Path | What | +| --- | --- | +| `app/Commands/` | One class per command, all extend `BaseCommand` | +| `app/Client/` | Saloon SDK for the Cloud API — see `app/Client/README.md` | +| `app/Client/Resources/Resource.php` | Method-per-endpoint facade over the request classes | +| `app/Client/Requests/*RequestData.php` | Typed request payloads (spatie/laravel-data) | +| `app/Dto/` | Typed API responses; also drive `--json` output and `--fields` | +| `app/Resolvers/` | Turn a user-supplied ID/name into a DTO, prompting when interactive | +| `app/Prompts/` | Custom Laravel Prompts renderers (tables, monitors, slide-ins) | +| `app/Support/Form.php` | Merges options/arguments with prompts for mixed interactive/flag input | +| `app/Middleware/` | Command middleware (auth, JSON output suppression), registered in `AppServiceProvider` | +| `app/helpers.php` | Global output helpers: `answered()`, `success()`, `dataList()`, `dataTable()`, `codeBlock()` | +| `app/Git.php` | All git and `gh` CLI work | +| `app/ConfigRepository.php` | User config at `~/.config/cloud/config.json` | + +## Conventions + +- Every command supports `--json`, `--fields`, `--show-sensitive`, and `--no-interaction`. `BaseCommand::wantsJson()` is true when `--json` is passed *or* the run is non-interactive, so a command must work headlessly. +- Set `$jsonDataClass` (and `$jsonDataIsCollection`) on a command so `--json` and the help text know the field list. +- Emit JSON with `outputJsonIfWanted()` (exits) or `writeJsonIfWanted()` (continues) before any human-facing output. +- Never use `Command` output helpers (`$this->info()` etc.) — use Laravel Prompts functions and the helpers in `app/helpers.php`. +- Destructive commands call `confirmDestructive()`; it requires `--force` when non-interactive. +- Fetch through `spin(...)`, resolve arguments through `$this->resolvers()`, prompt through `$this->form()->prompt()`. +- Non-public members are `protected`, never `private`. Empty constructor bodies get a single `//` comment. +- Long signatures go one option per line, indented. +- Comments explain *why*, never *what*. + +## Adding a command + +1. Request class in `app/Client/Resources//`, payload in `app/Client/Requests/` if it takes a body. +2. Method on the matching `*Resource.php`; DTO in `app/Dto/` for the response. +3. Command in `app/Commands/`; Laravel Zero autoloads it, no registration needed. +4. Test in `tests/Feature/` using Saloon's `MockClient` and `Prompt::fake()` — see `tests/Feature/ApplicationCommandsTest.php` and the fixtures in `tests/Helpers.php`. + +## Related docs + +- `AI_CLI_DESIGN_PRINCIPLES.md` — why the CLI is shaped for agents as well as people +- `skills/deploying-laravel-cloud/` — the skill `cloud skills:install` ships to users +- API reference: https://cloud.laravel.com/docs/api/introduction