@cristiancorreau/forge 3.0.1 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +265 -109
  3. package/assets/adapters/claude-code/commands/laravel-eloquent.md +7 -0
  4. package/assets/adapters/claude-code/commands/laravel-mcp.md +7 -0
  5. package/assets/adapters/claude-code/commands/laravel-pest.md +7 -0
  6. package/assets/adapters/claude-code/commands/laravel-security.md +7 -0
  7. package/assets/adapters/claude-code/commands/laravel-verify.md +7 -0
  8. package/assets/core/hooks/pre-bash-check.js +46 -0
  9. package/assets/core/hooks/pre-edit-check.js +24 -1
  10. package/assets/core/schemas/project.schema.json +3 -1
  11. package/assets/core/skills/laravel-eloquent/SKILL.md +453 -0
  12. package/assets/core/skills/laravel-mcp/SKILL.md +468 -0
  13. package/assets/core/skills/laravel-pest/SKILL.md +686 -0
  14. package/assets/core/skills/laravel-security/SKILL.md +658 -0
  15. package/assets/core/skills/laravel-verify/SKILL.md +462 -0
  16. package/assets/manifest.json +27 -2
  17. package/assets/profiles/astro/agents/frontend-engineer.md +2 -0
  18. package/assets/profiles/django/agents/api-engineer.md +2 -0
  19. package/assets/profiles/expo/agents/mobile-engineer.md +2 -0
  20. package/assets/profiles/express/agents/api-engineer.md +2 -0
  21. package/assets/profiles/fastapi/agents/api-engineer.md +2 -0
  22. package/assets/profiles/flask/agents/api-engineer.md +2 -0
  23. package/assets/profiles/flutter/agents/mobile-engineer.md +12 -10
  24. package/assets/profiles/go-gin/agents/api-engineer.md +3 -1
  25. package/assets/profiles/hono-drizzle/agents/api-engineer.md +2 -0
  26. package/assets/profiles/laravel/README.md +16 -2
  27. package/assets/profiles/laravel/agents/api-engineer.md +2 -0
  28. package/assets/profiles/laravel/agents/fullstack-engineer.md +4 -2
  29. package/assets/profiles/laravel/agents/laravel-specialist.md +607 -0
  30. package/assets/profiles/laravel/agents/laravel-test-engineer.md +448 -0
  31. package/assets/profiles/nestjs/agents/api-engineer.md +3 -1
  32. package/assets/profiles/nextjs-admin/agents/admin-engineer.md +2 -0
  33. package/assets/profiles/playwright-crawler/agents/scanner-engineer.md +2 -0
  34. package/assets/profiles/rails/agents/fullstack-engineer.md +2 -0
  35. package/assets/profiles/rust/agents/api-engineer.md +2 -0
  36. package/assets/profiles/springboot/agents/api-engineer.md +11 -9
  37. package/assets/profiles/sveltekit/agents/frontend-engineer.md +4 -2
  38. package/assets/profiles/vuenuxt/agents/frontend-engineer.md +12 -10
  39. package/assets/profiles/wordpress/agents/divi-engineer.md +2 -0
  40. package/assets/profiles/wordpress/agents/elementor-engineer.md +2 -0
  41. package/dist/cli.js +15 -0
  42. package/dist/cli.js.map +1 -1
  43. package/dist/commands/add.d.ts +2 -0
  44. package/dist/commands/add.d.ts.map +1 -0
  45. package/dist/commands/add.js +187 -0
  46. package/dist/commands/add.js.map +1 -0
  47. package/dist/commands/mcp.d.ts +42 -0
  48. package/dist/commands/mcp.d.ts.map +1 -0
  49. package/dist/commands/mcp.js +141 -0
  50. package/dist/commands/mcp.js.map +1 -0
  51. package/dist/commands/update.d.ts +30 -0
  52. package/dist/commands/update.d.ts.map +1 -0
  53. package/dist/commands/update.js +180 -0
  54. package/dist/commands/update.js.map +1 -0
  55. package/dist/commands/validate.d.ts.map +1 -1
  56. package/dist/commands/validate.js +40 -1
  57. package/dist/commands/validate.js.map +1 -1
  58. package/dist/lib/catalog.d.ts +7 -0
  59. package/dist/lib/catalog.d.ts.map +1 -1
  60. package/dist/lib/catalog.js +20 -0
  61. package/dist/lib/catalog.js.map +1 -1
  62. package/dist/lib/mcp-tools.d.ts +37 -0
  63. package/dist/lib/mcp-tools.d.ts.map +1 -0
  64. package/dist/lib/mcp-tools.js +124 -0
  65. package/dist/lib/mcp-tools.js.map +1 -0
  66. package/dist/lib/skill-security.d.ts +66 -0
  67. package/dist/lib/skill-security.d.ts.map +1 -0
  68. package/dist/lib/skill-security.js +225 -0
  69. package/dist/lib/skill-security.js.map +1 -0
  70. package/dist/lib/skill-source.d.ts +29 -0
  71. package/dist/lib/skill-source.d.ts.map +1 -0
  72. package/dist/lib/skill-source.js +94 -0
  73. package/dist/lib/skill-source.js.map +1 -0
  74. package/dist/tui/dashboard.d.ts.map +1 -1
  75. package/dist/tui/dashboard.js +3 -6
  76. package/dist/tui/dashboard.js.map +1 -1
  77. package/dist/tui/panel.d.ts.map +1 -1
  78. package/dist/tui/panel.js +3 -6
  79. package/dist/tui/panel.js.map +1 -1
  80. package/dist/tui/wizard.d.ts.map +1 -1
  81. package/dist/tui/wizard.js +3 -13
  82. package/dist/tui/wizard.js.map +1 -1
  83. package/dist/ui/colors.d.ts +3 -1
  84. package/dist/ui/colors.d.ts.map +1 -1
  85. package/dist/ui/colors.js +11 -2
  86. package/dist/ui/colors.js.map +1 -1
  87. package/dist/ui/header.d.ts.map +1 -1
  88. package/dist/ui/header.js +4 -3
  89. package/dist/ui/header.js.map +1 -1
  90. package/dist/ui/theme.d.ts +24 -0
  91. package/dist/ui/theme.d.ts.map +1 -0
  92. package/dist/ui/theme.js +32 -0
  93. package/dist/ui/theme.js.map +1 -0
  94. package/dist/version.d.ts +1 -1
  95. package/dist/version.js +1 -1
  96. package/package.json +2 -2
@@ -0,0 +1,462 @@
1
+ # Skill: laravel-verify
2
+
3
+ Loop de verificación reproducible para Laravel antes de commit/PR: formato (Pint),
4
+ análisis estático (Larastan/PHPStan), tests con coverage (Pest), audit de dependencias
5
+ y checks de configuración. Devuelve **PASA / FALLA** con acciones concretas.
6
+
7
+ Triggers: /laravel-verify, "verificar antes de commit", "loop de verificación laravel",
8
+ "chequeo previo a PR", "pint phpstan pest", "está listo para mergear", "correr el quality gate".
9
+
10
+ ---
11
+
12
+ ## Cuándo usar este skill
13
+
14
+ - Antes de cada `git commit` o de abrir un PR en un proyecto Laravel.
15
+ - Como gate de CI (GitHub Actions) en `pull_request` y `push`.
16
+ - Como hook de pre-commit local para evitar romper `main`.
17
+ - Cuando el `forge-quality-reviewer` pide la corrida completa de verificación.
18
+
19
+ Requisitos del proyecto (Laravel / PHP 8.3+):
20
+
21
+ ```bash
22
+ composer require --dev laravel/pint larastan/larastan pestphp/pest \
23
+ pestphp/pest-plugin-laravel
24
+ ```
25
+
26
+ Coverage de Pest necesita `xdebug` (modo `coverage`) o `pcov`. En CI usa `pcov` por
27
+ velocidad. El orden del loop es **rápido → costoso**: primero falla lo barato (Pint),
28
+ después lo caro (Pest), para acortar el ciclo de feedback.
29
+
30
+ ---
31
+
32
+ ## El loop, de un vistazo
33
+
34
+ | # | Paso | Comando | Falla si… |
35
+ |---|------|---------|-----------|
36
+ | 1 | Formato | `./vendor/bin/pint --test` | hay archivos sin formatear |
37
+ | 2 | Estático | `./vendor/bin/phpstan analyse` | hay errores fuera del baseline |
38
+ | 3 | Tests + coverage | `./vendor/bin/pest --coverage --min=80` | falla un test o coverage < 80% |
39
+ | 4 | Dependencias | `composer audit` | hay CVE en dependencias |
40
+ | 5 | Config | `php artisan about` + asserts | `APP_DEBUG=true` o `APP_ENV` mal seteado |
41
+
42
+ Regla de oro: **no se hace commit con ningún paso en rojo.** Cada paso de abajo trae el
43
+ comando exacto, qué mirar y la acción concreta para arreglarlo.
44
+
45
+ ---
46
+
47
+ ## Paso 1 — Pint (formato de código)
48
+
49
+ Pint es el formateador oficial (envoltorio sobre PHP-CS-Fixer). En el loop se corre en
50
+ modo `--test` (no modifica nada, solo reporta). El autofix queda explícito.
51
+
52
+ ```bash
53
+ # Verifica sin modificar — esto es lo que corre el gate
54
+ ./vendor/bin/pint --test
55
+
56
+ # Solo archivos con cambios (git working tree) — ideal para pre-commit, mucho más rápido
57
+ ./vendor/bin/pint --test --dirty
58
+ ```
59
+
60
+ **Acción si FALLA:** corre el autofix y vuelve a verificar.
61
+
62
+ ```bash
63
+ ./vendor/bin/pint --dirty # formatea solo lo modificado
64
+ ./vendor/bin/pint # formatea todo el proyecto
65
+ ./vendor/bin/pint --test # confirma que ya pasa
66
+ ```
67
+
68
+ Define el preset en `pint.json` en la raíz del proyecto (recomendado: `laravel`):
69
+
70
+ ```json
71
+ {
72
+ "preset": "laravel",
73
+ "rules": {
74
+ "declare_strict_types": true,
75
+ "ordered_imports": { "sort_algorithm": "alpha" },
76
+ "no_unused_imports": true
77
+ },
78
+ "exclude": ["bootstrap/cache", "storage"]
79
+ }
80
+ ```
81
+
82
+ En CI puedes emitir un reporte parseable con `--format=checkstyle --report=pint-report.xml`
83
+ (útil con `cs2pr` para anotar el PR); localmente deja el output por defecto, que lista cada
84
+ archivo con su diff.
85
+
86
+ ---
87
+
88
+ ## Paso 2 — Larastan / PHPStan (análisis estático)
89
+
90
+ Larastan extiende PHPStan con reglas conscientes de Laravel (entiende `Model::find()`,
91
+ facades, relaciones Eloquent, etc.). Se instala como extensión y PHPStan la autodescubre.
92
+
93
+ `phpstan.neon` en la raíz:
94
+
95
+ ```neon
96
+ includes:
97
+ - vendor/larastan/larastan/extension.neon
98
+ - phpstan-baseline.neon
99
+
100
+ parameters:
101
+ level: 6
102
+ paths:
103
+ - app/
104
+ - bootstrap/app.php
105
+ - config/
106
+ - database/
107
+ - routes/
108
+ # Regla de Larastan que valida nombres de propiedades de modelo en argumentos tipados.
109
+ checkModelProperties: true
110
+ # PHPStan 2.x (que usa Larastan 3) ya NO tiene checkMissingIterableValueType.
111
+ # Para tolerar arrays sin value-type se ignora por identificador de error:
112
+ ignoreErrors:
113
+ - identifier: missingType.iterableValue
114
+ ```
115
+
116
+ Corrida del gate:
117
+
118
+ ```bash
119
+ ./vendor/bin/phpstan analyse # usa phpstan.neon
120
+ ./vendor/bin/phpstan analyse --memory-limit=2G
121
+ ```
122
+
123
+ ### Subida gradual de nivel (0 → 10)
124
+
125
+ No subas a nivel 9 de golpe en un código existente: te llenas de errores. Estrategia:
126
+
127
+ ```bash
128
+ # Empieza donde el proyecto esté limpio (típico: 5 o 6 en código Laravel maduro)
129
+ ./vendor/bin/phpstan analyse --level=6
130
+
131
+ # Cuando level N pasa sin errores, sube a N+1 y arregla lo nuevo:
132
+ ./vendor/bin/phpstan analyse --level=7
133
+ ```
134
+
135
+ Metas razonables en Laravel: **level 6** como mínimo de merge, **level 8** como objetivo
136
+ del proyecto. Niveles 9–10 (chequeo estricto de `mixed`/null) solo si el equipo se compromete.
137
+
138
+ ### Baseline — congelar la deuda existente
139
+
140
+ El baseline registra los errores actuales para que el gate solo falle ante errores **nuevos**.
141
+ Es la herramienta que permite subir de nivel sin bloquear el desarrollo.
142
+
143
+ ```bash
144
+ # Genera/regenera el baseline con los errores actuales del nivel configurado
145
+ ./vendor/bin/phpstan analyse --generate-baseline
146
+ ```
147
+
148
+ Esto crea `phpstan-baseline.neon` (ya incluido en `phpstan.neon` arriba). Reglas:
149
+
150
+ - **Regenera el baseline solo cuando bajas deuda**, nunca para silenciar un error nuevo
151
+ que acabas de introducir — ese hay que arreglarlo.
152
+ - Haz commit del baseline. Forma parte del contrato del repo.
153
+ - Revisa el diff del baseline en cada PR: si **crece**, alguien metió deuda; si **encoge**,
154
+ se pagó deuda (bien).
155
+
156
+ **Acción si FALLA:** lee el error, corrige el tipo/lógica. Si es un falso positivo legítimo
157
+ (p. ej. un magic method de un paquete), usa `@phpstan-ignore-next-line` con comentario del
158
+ porqué, o ignora ese identificador de error en `phpstan.neon` — pero esto es la excepción,
159
+ no el patrón.
160
+
161
+ > Las versiones recientes de Laravel usan estructura slim (sin `app/Http/Kernel.php` ni
162
+ > `app/Console/Kernel.php`); verifica leyendo `bootstrap/app.php`, donde vive la config de
163
+ > middleware (`->withMiddleware(...)`). Incluye `bootstrap/app.php` en `paths` por eso.
164
+ > **No** referencies los Kernel legacy si tu proyecto ya usa la estructura slim.
165
+
166
+ ---
167
+
168
+ ## Paso 3 — Pest con coverage mínimo
169
+
170
+ Pest 3 es el runner de tests. El gate exige un piso de coverage del 80%.
171
+
172
+ ```bash
173
+ # Tests + coverage con piso del 80% — falla si baja
174
+ ./vendor/bin/pest --coverage --min=80
175
+
176
+ # En paralelo (más rápido en CI con varios cores)
177
+ ./vendor/bin/pest --parallel --coverage --min=80
178
+
179
+ # Solo lo afectado durante desarrollo (no en el gate final)
180
+ ./vendor/bin/pest --dirty
181
+ ./vendor/bin/pest --filter="UserTest"
182
+ ```
183
+
184
+ Habilita el driver de coverage. En CI con `pcov`:
185
+
186
+ ```bash
187
+ php -d pcov.enabled=1 ./vendor/bin/pest --coverage --min=80
188
+ ```
189
+
190
+ Configura el filtro de coverage en `phpunit.xml` (así el `--min` y el reporte miden solo el
191
+ código de la app, no vendor ni config):
192
+
193
+ ```xml
194
+ <source>
195
+ <include>
196
+ <directory>app</directory>
197
+ </include>
198
+ <exclude>
199
+ <directory>app/Console</directory>
200
+ </exclude>
201
+ </source>
202
+ ```
203
+
204
+ Ejemplo de test Pest 3 sobre una API Resource de Laravel (`toResource()` + JSON:API). El
205
+ método `toResource()` de auto-discovery existe en las versiones recientes; verifica que esté
206
+ disponible en tu versión instalada:
207
+
208
+ ```php
209
+ <?php
210
+
211
+ use App\Models\Post;
212
+
213
+ it('serializa el post via auto-discovery de resource', function () {
214
+ $post = Post::factory()->create(['title' => 'Hola']);
215
+
216
+ // toResource() autodescubre App\Http\Resources\PostResource en Laravel reciente
217
+ $payload = $post->toResource()->toArray(request());
218
+
219
+ expect($payload['title'])->toBe('Hola');
220
+ });
221
+
222
+ it('lista posts sin lazy loading', function () {
223
+ Post::factory()->count(3)->for(\App\Models\User::factory(), 'author')->create();
224
+
225
+ // preventLazyLoading activo en testing: si la relación no está eager-loaded, lanza
226
+ $this->getJson('/api/posts?include=author')
227
+ ->assertOk()
228
+ ->assertJsonCount(3, 'data');
229
+ });
230
+ ```
231
+
232
+ **Acción si FALLA:**
233
+
234
+ - *Test roto:* lee el assert, corrige el código (no el test, salvo que el test esté mal).
235
+ - *Coverage < 80%:* identifica qué falta cubrir y agrega tests sobre el código nuevo.
236
+
237
+ ```bash
238
+ # Reporte HTML para ver línea por línea qué quedó sin cubrir
239
+ ./vendor/bin/pest --coverage --coverage-html=coverage-report
240
+ ```
241
+
242
+ Sube el coverage cubriendo el **código que tocaste** en este cambio — no inflando con
243
+ tests triviales de getters. El piso es un guardrail, no una meta a gamear.
244
+
245
+ ---
246
+
247
+ ## Paso 4 — composer audit (vulnerabilidades en dependencias)
248
+
249
+ ```bash
250
+ composer audit # falla con exit code ≠ 0 si hay CVE
251
+ composer audit --format=json # output parseable para CI
252
+ composer audit --no-dev # solo dependencias de producción
253
+ ```
254
+
255
+ **Acción si FALLA:**
256
+
257
+ ```bash
258
+ composer why vulnerable/package # ver quién la trae
259
+ composer update vulnerable/package # subir a versión parcheada
260
+ composer update vulnerable/package --with-dependencies
261
+ ```
262
+
263
+ Si no hay parche disponible aún y el riesgo es aceptable para esta entrega, documenta la
264
+ excepción en el PR (paquete, CVE, por qué se acepta, fecha de revisión) — no la silencies
265
+ sin dejar registro. El audit corre también en CI: una dependencia nueva con CVE bloquea el
266
+ merge.
267
+
268
+ ---
269
+
270
+ ## Paso 5 — Checks de configuración (`php artisan about` + asserts)
271
+
272
+ `php artisan about` resume el estado del entorno. El gate verifica que la config sea sana
273
+ **antes** de mergear, para que no se filtre `APP_DEBUG=true` a producción.
274
+
275
+ ```bash
276
+ php artisan about # resumen completo legible
277
+ php artisan about --only=environment # solo el bloque de entorno
278
+ php artisan about --json # output parseable para asserts en CI
279
+ ```
280
+
281
+ Asserts concretos del gate (fallan el loop si no se cumplen):
282
+
283
+ ```bash
284
+ # APP_DEBUG debe estar en false fuera de local (config cacheada o env real)
285
+ php artisan tinker --execute="exit(config('app.debug') === false ? 0 : 1);" \
286
+ || { echo 'FALLA: APP_DEBUG=true'; exit 1; }
287
+
288
+ # APP_KEY debe existir
289
+ php artisan tinker --execute="exit(config('app.key') ? 0 : 1);" \
290
+ || { echo 'FALLA: APP_KEY vacía — corre php artisan key:generate'; exit 1; }
291
+ ```
292
+
293
+ Checks adicionales útiles antes de PR:
294
+
295
+ ```bash
296
+ php artisan config:clear # evita asserts contra config cacheada vieja
297
+ php artisan route:list # confirma que las rutas registran sin error
298
+ php artisan migrate:status # no quedan migraciones pendientes sin aplicar en test
299
+ ```
300
+
301
+ **Acción si FALLA:** ajusta `.env` / `.env.example`, corre `php artisan key:generate` si
302
+ falta la key, y confirma que `APP_ENV` y `APP_DEBUG` correspondan al entorno
303
+ (`local` → debug ok; `production`/`staging` → `APP_DEBUG=false`).
304
+
305
+ ---
306
+
307
+ ## Salida del loop — formato PASA / FALLA
308
+
309
+ El skill termina con un veredicto único y accionable. Plantilla de reporte:
310
+
311
+ ```
312
+ laravel-verify — VEREDICTO: FALLA
313
+
314
+ [✓] Pint — formato OK
315
+ [✗] PHPStan (lvl 6) — 2 errores nuevos (fuera de baseline)
316
+ [✓] Pest — 84 passed, coverage 86% (min 80%)
317
+ [✓] composer audit — sin CVE
318
+ [✓] Config — APP_DEBUG=false, APP_KEY presente
319
+
320
+ ACCIONES:
321
+ 1. app/Http/Controllers/PostController.php:42 — método undefined en relación.
322
+ → Eager-load `author` o corrige el tipo del retorno.
323
+ 2. app/Models/Post.php:18 — cast legacy detectado.
324
+ → Migra de `protected $casts` a `protected function casts(): array`.
325
+
326
+ No hacer commit hasta que todos los pasos estén en verde.
327
+ ```
328
+
329
+ Si todos pasan: `VEREDICTO: PASA — listo para commit/PR.`
330
+
331
+ ---
332
+
333
+ ## Cableado en CI — GitHub Actions
334
+
335
+ `.github/workflows/verify.yml`:
336
+
337
+ ```yaml
338
+ name: laravel-verify
339
+
340
+ on:
341
+ pull_request:
342
+ push:
343
+ branches: [main]
344
+
345
+ jobs:
346
+ verify:
347
+ runs-on: ubuntu-latest
348
+ steps:
349
+ - uses: actions/checkout@v4
350
+
351
+ - name: Setup PHP
352
+ uses: shivammathur/setup-php@v2
353
+ with:
354
+ php-version: '8.3'
355
+ coverage: pcov
356
+ tools: composer:v2
357
+
358
+ - name: Install dependencies
359
+ run: composer install --prefer-dist --no-interaction --no-progress
360
+
361
+ - name: Prepare environment
362
+ run: |
363
+ cp .env.example .env
364
+ php artisan key:generate
365
+
366
+ # Paso 1 — Pint
367
+ - name: Pint (formato)
368
+ run: ./vendor/bin/pint --test
369
+
370
+ # Paso 2 — PHPStan / Larastan
371
+ - name: PHPStan (estático)
372
+ run: ./vendor/bin/phpstan analyse --no-progress --memory-limit=2G
373
+
374
+ # Paso 3 — Pest + coverage
375
+ - name: Pest (tests + coverage)
376
+ run: ./vendor/bin/pest --parallel --coverage --min=80
377
+
378
+ # Paso 4 — Dependencias
379
+ - name: composer audit
380
+ run: composer audit
381
+
382
+ # Paso 5 — Config
383
+ - name: Config checks
384
+ run: |
385
+ php artisan about --only=environment
386
+ php artisan tinker --execute="exit(config('app.debug') === false ? 0 : 1);"
387
+ ```
388
+
389
+ Notas:
390
+
391
+ - `pcov` es más rápido que Xdebug para coverage en CI.
392
+ - Cada paso es un step independiente: el log de Actions muestra exactamente cuál falló.
393
+ - Si necesitas base de datos para Pest, agrega un servicio `postgres`. Las versiones recientes
394
+ de Laravel con pgvector usan `Schema::ensureVectorExtensionExists()`; usa la imagen
395
+ `pgvector/pgvector` y verifica que el helper esté disponible en tu versión instalada.
396
+
397
+ ---
398
+
399
+ ## Cableado como pre-commit (local)
400
+
401
+ Engancha el loop al hook de Git para que falle **antes** de crear el commit. Usa `--dirty`
402
+ en Pint y Pest para que sea rápido sobre solo lo modificado.
403
+
404
+ `.git/hooks/pre-commit` (o gestiónalo con un gestor de hooks versionado):
405
+
406
+ ```bash
407
+ #!/usr/bin/env bash
408
+ set -e
409
+
410
+ echo "→ Pint (dirty)..."
411
+ ./vendor/bin/pint --test --dirty
412
+
413
+ echo "→ PHPStan..."
414
+ ./vendor/bin/phpstan analyse --no-progress
415
+
416
+ echo "→ Pest (dirty)..."
417
+ ./vendor/bin/pest --dirty
418
+
419
+ echo "✓ laravel-verify OK — commit permitido."
420
+ ```
421
+
422
+ ```bash
423
+ chmod +x .git/hooks/pre-commit
424
+ ```
425
+
426
+ Recomendación: el pre-commit corre el subconjunto rápido (`--dirty`, sin `composer audit`
427
+ ni coverage completo) para no entorpecer el flujo; el gate **completo** (coverage 80%,
428
+ audit, config checks) corre en CI. Así local es ágil y CI es la autoridad final.
429
+
430
+ Para versionar el hook en el repo (sin depender del `.git/hooks` de cada quien), usa un
431
+ gestor de hooks como `captainhook/captainhook`:
432
+
433
+ ```bash
434
+ composer require --dev captainhook/captainhook # hooks versionados en captainhook.json
435
+ ```
436
+
437
+ ---
438
+
439
+ ## Qué NO hacer
440
+
441
+ - **No** silencies un error nuevo de PHPStan regenerando el baseline — el baseline solo
442
+ congela deuda **vieja**; lo nuevo se arregla.
443
+ - **No** bajes `--min=80` para que pase el coverage — cubre el código que escribiste.
444
+ - **No** referencies `app/Http/Kernel.php` ni `app/Console/Kernel.php` si tu proyecto usa la
445
+ estructura slim de Laravel: ahí no existen. La config de middleware vive en
446
+ `bootstrap/app.php`; verifica leyendo ese archivo.
447
+ - **No** uses `protected $casts` ni pares `getXAttribute()/setXAttribute()` — PHPStan +
448
+ el preset de Pint te lo van a marcar; usa `casts(): array` y `Attribute::make()`.
449
+ - **No** uses `checkMissingIterableValueType` en `phpstan.neon`: lo removió PHPStan 2.x.
450
+ Ignora ese caso por identificador (`missingType.iterableValue`) si hace falta.
451
+ - **No** hagas commit con `APP_DEBUG=true` apuntando a entornos no-locales.
452
+ - **No** dejes `composer audit` en rojo sin un motivo documentado en el PR.
453
+
454
+ ---
455
+
456
+ ## Relación con otros skills
457
+
458
+ - `new-feature` invoca este skill como gate final antes de cerrar la feature.
459
+ - El `forge-quality-reviewer` lo corre como parte de su review de PR.
460
+ - Es complementario a `laravel-security`: este verifica calidad/regresión, aquel verifica
461
+ seguridad de endpoints. Corre ambos antes de mergear rutas protegidas.
462
+ - No depende de otros skills para ejecutarse (es standalone).
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forge",
3
- "version": "3.0.1",
3
+ "version": "3.2.0",
4
4
  "description": "Agentic development framework for Claude Code, OpenCode, Codex and Kiro",
5
5
  "license": "Apache-2.0",
6
6
  "repository": "https://github.com/cristiancorreau/forge",
@@ -133,7 +133,7 @@
133
133
  {
134
134
  "id": "laravel",
135
135
  "stack": "Laravel + PHP",
136
- "agents": ["api-engineer", "fullstack-engineer", "migration-specialist"]
136
+ "agents": ["api-engineer", "fullstack-engineer", "migration-specialist", "laravel-specialist", "laravel-test-engineer"]
137
137
  },
138
138
  {
139
139
  "id": "nestjs",
@@ -197,6 +197,31 @@
197
197
  "dir": "core/skills/db-migrate",
198
198
  "description": "Database migration orchestration"
199
199
  },
200
+ {
201
+ "id": "laravel-eloquent",
202
+ "dir": "core/skills/laravel-eloquent",
203
+ "description": "Eloquent (Laravel 13): relationships, eager loading, N+1, casts, scopes, pgvector"
204
+ },
205
+ {
206
+ "id": "laravel-mcp",
207
+ "dir": "core/skills/laravel-mcp",
208
+ "description": "Laravel 13 agents/MCP: Boost, laravel/mcp servers, AI SDK, embeddings/pgvector"
209
+ },
210
+ {
211
+ "id": "laravel-pest",
212
+ "dir": "core/skills/laravel-pest",
213
+ "description": "TDD with Pest 3 (and PHPUnit): factories, fakes, HTTP tests, coverage"
214
+ },
215
+ {
216
+ "id": "laravel-security",
217
+ "dir": "core/skills/laravel-security",
218
+ "description": "Laravel security: auth, policies, Form Requests, CSRF, rate limiting, secure deploy"
219
+ },
220
+ {
221
+ "id": "laravel-verify",
222
+ "dir": "core/skills/laravel-verify",
223
+ "description": "Laravel verification loop: Pint, Larastan/PHPStan, Pest coverage, composer audit"
224
+ },
200
225
  {
201
226
  "id": "local2prod",
202
227
  "dir": "core/skills/local2prod",
@@ -14,6 +14,8 @@ Construís sitios web con Astro: desde sitios estáticos puros hasta apps con SS
14
14
  usando islands architecture. Tu scope es `src/` y `public/`. No tocás infraestructura
15
15
  ni backend fuera de las integraciones de Astro.
16
16
 
17
+ > **No asumas una versión mayor.** Antes de escribir código, lee el manifiesto del proyecto (`package.json`/`package-lock.json`, `astro.config.*`) y contrasta los patrones que vas a usar contra el código realmente instalado (estructura de carpetas en `src/`, archivos de configuración/bootstrap como `astro.config.mjs`, paquetes presentes como `astro` e integraciones, y sus versiones). Consulta la documentación oficial de tu versión instalada (deriva la URL del major detectado) y el CHANGELOG/UPGRADE del paquete antes de afirmar capacidades específicas de versión (adaptadores, Content Layer, directivas de islands, helpers de imágenes).
18
+
17
19
  ## Stack
18
20
 
19
21
  - **Framework:** Astro (última versión estable)
@@ -12,6 +12,8 @@ last_verified: "2026-06"
12
12
 
13
13
  Implementás el backend del proyecto. Tu scope es `apps/` y `config/` (estructura Two Scoops of Django). Leé el `CLAUDE.md` del proyecto antes de empezar.
14
14
 
15
+ > **No asumas una versión mayor.** Antes de escribir código, lee el manifiesto del proyecto (`pyproject.toml` / `requirements.txt`, y el `manage.py`) y contrasta los patrones que vas a usar contra el código realmente instalado (estructura de carpetas como `config/settings/`, archivos de configuración/bootstrap como `manage.py`, `asgi.py`/`wsgi.py`, paquetes presentes y sus versiones — Django, DRF, Django Ninja, Celery). Consulta la documentación oficial de tu versión instalada (deriva la URL del major detectado, p. ej. `https://docs.djangoproject.com/en/<major.minor>/`) y el CHANGELOG/UPGRADE del paquete (release notes de Django y de DRF/Ninja) antes de afirmar capacidades específicas de versión.
16
+
15
17
  ## Stack
16
18
 
17
19
  - **Runtime:** Python 3.11+
@@ -14,6 +14,8 @@ Construís la app o SDK móvil del proyecto. Tu scope es el directorio móvil de
14
14
  `CLAUDE.md` del proyecto (típicamente `packages/mobile/` o `apps/mobile/`).
15
15
  Leé ese archivo antes de empezar.
16
16
 
17
+ > **No asumas una versión mayor.** Antes de escribir código, lee el manifiesto del proyecto (`package.json`/`package-lock.json` y `app.json`/`app.config.*`) y contrasta los patrones que vas a usar contra el código realmente instalado (estructura de carpetas, archivos de configuración/bootstrap como `app.json`/`app.config.ts`, paquetes presentes y sus versiones —Expo SDK, `react-native`, `expo-router`—). Consulta la documentación oficial de tu versión instalada (deriva la URL del major detectado) y el CHANGELOG/UPGRADE del paquete antes de afirmar capacidades específicas de versión.
18
+
17
19
  ## Stack
18
20
 
19
21
  - **Framework:** Expo SDK (versión definida en el `CLAUDE.md` del proyecto).
@@ -13,6 +13,8 @@ last_verified: "2026-06"
13
13
  Implementás el backend del proyecto. Tu scope es el directorio de API definido en el `CLAUDE.md`
14
14
  del proyecto (típicamente `src/` o `packages/api/`). Leé ese archivo antes de empezar.
15
15
 
16
+ > **No asumas una versión mayor.** Antes de escribir código, lee el manifiesto del proyecto (`package.json` / `package-lock.json`) y contrasta los patrones que vas a usar contra el código realmente instalado (estructura de carpetas, archivos de configuración/bootstrap como `tsconfig.json` o el entrypoint del servidor, paquetes presentes en `node_modules` y sus versiones). Consulta la documentación oficial de tu versión instalada de Express, Node.js y el ORM (deriva la URL del major detectado) y el CHANGELOG/UPGRADE del paquete antes de afirmar capacidades específicas de versión.
17
+
16
18
  ## Stack
17
19
 
18
20
  - **Runtime:** Node.js 20 LTS (o Bun si el proyecto lo especifica).
@@ -13,6 +13,8 @@ last_verified: "2026-06"
13
13
  Implementás el backend del proyecto. Tu scope es el directorio de API definido en el `CLAUDE.md`
14
14
  del proyecto (típicamente `app/` o `src/`). Leé ese archivo antes de empezar.
15
15
 
16
+ > **No asumas una versión mayor.** Antes de escribir código, lee el manifiesto del proyecto (`pyproject.toml` o `requirements.txt`) y contrasta los patrones que vas a usar contra el código realmente instalado (estructura de carpetas, archivos de configuración/bootstrap como `app/main.py` y `alembic.ini`, paquetes presentes y sus versiones en el entorno o el lockfile). Consulta la documentación oficial de tu versión instalada de FastAPI, SQLAlchemy y Pydantic (deriva la URL del major detectado) y el CHANGELOG/UPGRADE de cada paquete antes de afirmar capacidades específicas de versión.
17
+
16
18
  ## Stack
17
19
 
18
20
  - **Runtime:** Python 3.11+.
@@ -14,6 +14,8 @@ Implementás el backend del proyecto con Flask. Tu scope es el paquete de la apl
14
14
  (típicamente `app/` o `src/`) definido en el `CLAUDE.md` del proyecto. Leé ese archivo
15
15
  antes de empezar.
16
16
 
17
+ > **No asumas una versión mayor.** Antes de escribir código, lee el manifiesto del proyecto (`pyproject.toml` / `requirements.txt`) y contrasta los patrones que vas a usar contra el código realmente instalado (estructura de carpetas, archivos de configuración/bootstrap como `create_app()` y `config.py`, paquetes presentes y sus versiones vía `pip show flask` / `pip freeze`). Consulta la documentación oficial de tu versión instalada (deriva la URL del major detectado) y el CHANGELOG/UPGRADE del paquete antes de afirmar capacidades específicas de versión.
18
+
17
19
  ## Stack
18
20
 
19
21
  - **Runtime:** Python 3.11+.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: mobile-engineer
3
- description: "Construye la app móvil del proyecto. Flutter 3 + Dart 3 + Riverpod + go_router. Scope: el directorio lib/ del paquete móvil."
3
+ description: "Construye la app móvil del proyecto. Flutter + Dart 3 + Riverpod + go_router. Scope: el directorio lib/ del paquete móvil."
4
4
  model: sonnet
5
5
  tools: Read, Grep, Glob, Bash, Edit, Write
6
6
  tier: 2
@@ -10,19 +10,21 @@ last_verified: "2026-06"
10
10
 
11
11
  # Mobile Engineer — Flutter
12
12
 
13
- Construís la app móvil del proyecto con Flutter. Tu scope es el directorio `lib/` del
14
- paquete móvil (y su `test/`), definido en el `CLAUDE.md` del proyecto. Leé ese archivo
13
+ Construyes la app móvil del proyecto con Flutter. Tu scope es el directorio `lib/` del
14
+ paquete móvil (y su `test/`), definido en el `CLAUDE.md` del proyecto. Lee ese archivo
15
15
  antes de empezar para confirmar el approach de state management y de navegación que usa
16
16
  el proyecto.
17
17
 
18
+ > **No asumas una versión mayor.** Antes de escribir código, lee el manifiesto del proyecto (`pubspec.yaml`/`pubspec.lock`, y en su caso `android/build.gradle` o `ios/Podfile`) y contrasta los patrones que vas a usar contra el código realmente instalado (estructura de carpetas, archivos de bootstrap, paquetes presentes y sus versiones).
19
+
18
20
  ## Stack
19
21
 
20
- - **Framework:** Flutter 3 (canal stable). **Lenguaje:** Dart 3 con null-safety y sound types.
21
- - **State management:** Riverpod por defecto (`@riverpod` + code-gen). Si el proyecto ya usa Bloc/Cubit, seguí ese patrón — no mezcles dos approaches en el mismo módulo.
22
+ - **Framework:** Flutter (canal stable). **Lenguaje:** Dart 3 con null-safety y sound types.
23
+ - **State management:** Riverpod por defecto (`@riverpod` + code-gen). Si el proyecto ya usa Bloc/Cubit, sigue ese patrón — no mezcles dos approaches en el mismo módulo.
22
24
  - **Navegación:** `go_router` (rutas declarativas, deep links). NO usar `Navigator.push` imperativo disperso por la app.
23
25
  - **Networking:** `dio` o `http` con un cliente centralizado y manejo de errores tipado. Modelos con `freezed` + `json_serializable`.
24
26
  - **Storage seguro:** `flutter_secure_store` (Keychain en iOS, EncryptedSharedPreferences en Android) para tokens/PII. `shared_preferences` solo para datos no sensibles.
25
- - **Dependencias:** `pub` (`pubspec.yaml`). Fijar versiones; correr `flutter pub get` tras editar.
27
+ - **Dependencias:** `pub` (`pubspec.yaml`). Fija versiones; corre `flutter pub get` tras editar.
26
28
  - **Tests:** `flutter test` (widget + unit), `mocktail` para mocks. `integration_test` para flujos E2E.
27
29
  - **Lint:** `flutter analyze` con `flutter_lints` (o `very_good_analysis`) en `analysis_options.yaml`.
28
30
 
@@ -84,13 +86,13 @@ flutter build apk # / ios / appbundle # build de release
84
86
  ## No hagas
85
87
 
86
88
  - No mezcles dos soluciones de state management en el mismo proyecto.
87
- - No uses `setState` para estado compartido entre pantallas — usá el provider/bloc del proyecto.
89
+ - No uses `setState` para estado compartido entre pantallas — usa el provider/bloc del proyecto.
88
90
  - No hagas networking ni I/O dentro de `build()`.
89
- - No uses `dynamic` ni `as` casts sin verificación; mantené el tipado estricto.
90
- - No commitees archivos generados a mano — regenerá con `build_runner`.
91
+ - No uses `dynamic` ni `as` casts sin verificación; mantén el tipado estricto.
92
+ - No commitees archivos generados a mano — regenera con `build_runner`.
91
93
  - No toques `pubspec.yaml`, `android/`, `ios/` ni la firma de la app sin instrucción del orchestrator.
92
94
  - No guardes tokens en `shared_preferences` ni los loguees.
93
- - No implementes sin spec aprobada — pedí al orchestrator que la cree primero.
95
+ - No implementes sin spec aprobada — pide al orchestrator que la cree primero.
94
96
 
95
97
  ## Forge v2
96
98
 
@@ -13,6 +13,8 @@ last_verified: "2026-06"
13
13
  Implementás el backend del proyecto en Go. Tu scope es `internal/` y `cmd/`. Leé el
14
14
  `CLAUDE.md` del proyecto antes de empezar.
15
15
 
16
+ > **No asumas una versión mayor.** Antes de escribir código, lee el manifiesto del proyecto (`go.mod` / `go.sum`) y contrasta los patrones que vas a usar contra el código realmente instalado (estructura de carpetas, archivos de configuración/bootstrap como `cmd/api/main.go`, la directiva `go` y los módulos presentes con sus versiones — por ejemplo `github.com/gin-gonic/gin`, `github.com/golang-jwt/jwt`). Consulta la documentación oficial de tu versión instalada (deriva la URL del major detectado, p. ej. `pkg.go.dev/github.com/gin-gonic/gin@<versión>`) y el CHANGELOG/UPGRADE del paquete antes de afirmar capacidades específicas de versión.
17
+
16
18
  ## Stack
17
19
 
18
20
  - **Lenguaje:** Go 1.21+
@@ -96,4 +98,4 @@ sqlc generate
96
98
  - No uses `init()` para lógica de negocio — solo para registro de drivers.
97
99
  - No retornes errores de base de datos directos al cliente — mapearlos a errores de dominio.
98
100
  - No toques archivos fuera de `internal/` y `cmd/`.
99
- - No implementes sin spec aprobada.
101
+ - No implementes sin spec aprobada.
@@ -15,6 +15,8 @@ del proyecto (típicamente `packages/api/` o `src/api/`). Leé ese archivo antes
15
15
 
16
16
  ## Stack
17
17
 
18
+ > **No asumas una versión mayor.** Antes de escribir código, lee el manifiesto del proyecto (`package.json` / `package-lock.json`) y contrasta los patrones que vas a usar contra el código realmente instalado (estructura de carpetas, archivos de configuración/bootstrap como `drizzle.config.ts` y el entrypoint de Hono, paquetes presentes y sus versiones de `hono`, `drizzle-orm`, `drizzle-kit` y `zod`). Consulta la documentación oficial de tu versión instalada (deriva la URL del major detectado) y el CHANGELOG/UPGRADE del paquete antes de afirmar capacidades específicas de versión.
19
+
18
20
  - **Runtime:** Bun en dev, Node 22 LTS en prod (el código debe correr en ambos).
19
21
  - **Framework HTTP:** Hono.
20
22
  - **ORM:** Drizzle. NO usar Prisma, TypeORM ni query builders ad-hoc.